diff --git a/.env b/.env new file mode 100644 index 00000000..c464cdec --- /dev/null +++ b/.env @@ -0,0 +1,75 @@ +# AI Service +NEXT_PUBLIC_SELECT_AI_SERVICE="" +NEXT_PUBLIC_SELECT_AI_MODEL="" + +# Local LLM +NEXT_PUBLIC_LOCAL_LLM_URL="" +NEXT_PUBLIC_LOCAL_LLM_MODEL="" + +# Voice +NEXT_PUBLIC_SELECT_VOICE="" + +# VoiceVox +NEXT_PUBLIC_VOICEVOX_SPEAKER="" +NEXT_PUBLIC_VOICEVOX_SPEED="" +NEXT_PUBLIC_VOICEVOX_PITCH="" +NEXT_PUBLIC_VOICEVOX_INTONATION="" + +# KoeiroMap +NEXT_PUBLIC_KOEIROMAP_KEY="" + +# Google TTS +NEXT_PUBLIC_GOOGLE_TTS_TYPE="" + +# StyleBertVits2 +NEXT_PUBLIC_STYLEBERTVITS2_MODEL_ID="" +NEXT_PUBLIC_STYLEBERTVITS2_STYLE="" +NEXT_PUBLIC_STYLEBERTVITS2_SDP_RATIO="" +NEXT_PUBLIC_STYLEBERTVITS2_LENGTH="" + +STYLEBERTVITS2_SERVER_URL="" +STYLEBERTVITS2_API_KEY="" + +# ElevenLabs +ELEVENLABS_API_KEY="" + +# GSVI TTS +NEXT_PUBLIC_GSVI_TTS_URL="" +NEXT_PUBLIC_GSVI_TTS_MODEL_ID="" +NEXT_PUBLIC_GSVI_TTS_BATCH_SIZE="" +NEXT_PUBLIC_GSVI_TTS_SPEECH_RATE="" + +# Youtube +NEXT_PUBLIC_YOUTUBE_API_KEY="" +NEXT_PUBLIC_YOUTUBE_MODE="" +NEXT_PUBLIC_YOUTUBE_LIVE_ID="" + +# Language +NEXT_PUBLIC_SELECT_LANGUAGE="" +NEXT_PUBLIC_SELECT_VOICE_LANGUAGE="" + +# Other +NEXT_PUBLIC_BACKGROUND_IMAGE_PATH="/bg-c.png" +NEXT_PUBLIC_SHOW_INTRODUCTION="false" +NEXT_PUBLIC_CHARACTER_NAME="" +NEXT_PUBLIC_SHOW_ASSISTANT_TEXT="" +NEXT_PUBLIC_SHOW_CHARACTER_NAME="" +NEXT_PUBLIC_CHANGE_ENGLISH_TO_JAPANESE="" +NEXT_PUBLIC_SHOW_CONTROL_PANEL="" +NEXT_PUBLIC_WEBSOCKET_MODE="" +NEXT_PUBLIC_SLIDE_MODE="" + +# AI API Keys +OPENAI_KEY="" +ANTHROPIC_KEY="" +GOOGLE_KEY="" +AZURE_KEY="" +GROQ_KEY="" +COHERE_KEY="" +MISTRALAI_KEY="" +PERPLEXITY_KEY="" +FIREWORKS_KEY="" + +# Dify +DIFY_KEY="" +DIFY_URL="" diff --git a/.env.example b/.env.example index 7bc01782..c464cdec 100644 --- a/.env.example +++ b/.env.example @@ -1,10 +1,75 @@ -GOOGLE_APPLICATION_CREDENTIALS="./credentials.json" -NEXT_PUBLIC_OPEN_AI_KEY="" -NEXT_PUBLIC_ANTHROPIC_KEY="" -NEXT_PUBLIC_GOOGLE_KEY="" -NEXT_PUBLIC_GROQ_KEY="" +# AI Service +NEXT_PUBLIC_SELECT_AI_SERVICE="" +NEXT_PUBLIC_SELECT_AI_MODEL="" + +# Local LLM NEXT_PUBLIC_LOCAL_LLM_URL="" NEXT_PUBLIC_LOCAL_LLM_MODEL="" -NEXT_PUBLIC_DIFY_KEY="" -NEXT_PUBLIC_DIFY_URL="" + +# Voice +NEXT_PUBLIC_SELECT_VOICE="" + +# VoiceVox +NEXT_PUBLIC_VOICEVOX_SPEAKER="" +NEXT_PUBLIC_VOICEVOX_SPEED="" +NEXT_PUBLIC_VOICEVOX_PITCH="" +NEXT_PUBLIC_VOICEVOX_INTONATION="" + +# KoeiroMap +NEXT_PUBLIC_KOEIROMAP_KEY="" + +# Google TTS NEXT_PUBLIC_GOOGLE_TTS_TYPE="" + +# StyleBertVits2 +NEXT_PUBLIC_STYLEBERTVITS2_MODEL_ID="" +NEXT_PUBLIC_STYLEBERTVITS2_STYLE="" +NEXT_PUBLIC_STYLEBERTVITS2_SDP_RATIO="" +NEXT_PUBLIC_STYLEBERTVITS2_LENGTH="" + +STYLEBERTVITS2_SERVER_URL="" +STYLEBERTVITS2_API_KEY="" + +# ElevenLabs +ELEVENLABS_API_KEY="" + +# GSVI TTS +NEXT_PUBLIC_GSVI_TTS_URL="" +NEXT_PUBLIC_GSVI_TTS_MODEL_ID="" +NEXT_PUBLIC_GSVI_TTS_BATCH_SIZE="" +NEXT_PUBLIC_GSVI_TTS_SPEECH_RATE="" + +# Youtube +NEXT_PUBLIC_YOUTUBE_API_KEY="" +NEXT_PUBLIC_YOUTUBE_MODE="" +NEXT_PUBLIC_YOUTUBE_LIVE_ID="" + +# Language +NEXT_PUBLIC_SELECT_LANGUAGE="" +NEXT_PUBLIC_SELECT_VOICE_LANGUAGE="" + +# Other +NEXT_PUBLIC_BACKGROUND_IMAGE_PATH="/bg-c.png" +NEXT_PUBLIC_SHOW_INTRODUCTION="false" +NEXT_PUBLIC_CHARACTER_NAME="" +NEXT_PUBLIC_SHOW_ASSISTANT_TEXT="" +NEXT_PUBLIC_SHOW_CHARACTER_NAME="" +NEXT_PUBLIC_CHANGE_ENGLISH_TO_JAPANESE="" +NEXT_PUBLIC_SHOW_CONTROL_PANEL="" +NEXT_PUBLIC_WEBSOCKET_MODE="" +NEXT_PUBLIC_SLIDE_MODE="" + +# AI API Keys +OPENAI_KEY="" +ANTHROPIC_KEY="" +GOOGLE_KEY="" +AZURE_KEY="" +GROQ_KEY="" +COHERE_KEY="" +MISTRALAI_KEY="" +PERPLEXITY_KEY="" +FIREWORKS_KEY="" + +# Dify +DIFY_KEY="" +DIFY_URL="" diff --git a/.gitignore b/.gitignore index 20b435df..247cf22e 100644 --- a/.gitignore +++ b/.gitignore @@ -41,7 +41,6 @@ credentials.json .tool-versions certificates -.env /public/slides/* !/public/slides/demo/ diff --git a/docs/README_ko.md b/docs/README_ko.md index 794e9c57..5dc7f293 100644 --- a/docs/README_ko.md +++ b/docs/README_ko.md @@ -45,7 +45,6 @@ - Node.js: ^20.0.0 - npm: 10.8.1 - ## 공통 사전 준비 1. 리포지토리를 로컬에 클론합니다. diff --git a/docs/README_zh.md b/docs/README_zh.md index a2500795..33603454 100644 --- a/docs/README_zh.md +++ b/docs/README_zh.md @@ -45,7 +45,6 @@ - Node.js: ^20.0.0 - npm: 10.8.1 - ## 共同準備 1. 將存儲庫克隆到本地。 diff --git a/locales/en/translation.json b/locales/en/translation.json index cc101320..07bb062e 100644 --- a/locales/en/translation.json +++ b/locales/en/translation.json @@ -59,15 +59,18 @@ "VoicevoxIntonation": "Intonation", "UsingGoogleTTS": "Google TTS", "UsingStyleBertVITS2": "Style-Bert-VITS2", - "StyleBertVITS2Info": "Using Style-Bert-VITS2. It supports only Japanese, English, and Chinese. It uses a local API, you need to download and launch the app that suits your environment from the site below.", + "StyleBertVITS2Info": "Using Style-Bert-VITS2. It supports only Japanese, English, and Chinese. If using a local API, you need to download and launch the app that suits your environment from the site below. Please also set up an API key if necessary.", "SpeakerSelection": "Speaker Selection", "GoogleTTSInfo": "Using Google Cloud Text-to-Speech. It supports multiple languages.", "AuthFileInstruction": "Obtain the authentication JSON file below and place it in the root folder of the repository as 'credentials.json'.", "LanguageModelURL": "Select the language model from the URL below.", "LanguageChoice": "Language Choice", - "StyleBeatVITS2LocalServerURL": "Style-Bert-VITS2 Local Server URL", - "StyleBeatVITS2ModelID": "Style-Bert-VITS2 Model ID", - "StyleBeatVITS2Style": "Style-Bert-VITS2 Style", + "StyleBeatVITS2ServerURL": "Server URL", + "StyleBeatVITS2ApiKey": "API Key", + "StyleBeatVITS2ModelID": "Model ID", + "StyleBeatVITS2Style": "Style", + "StyleBeatVITS2SdpRatio": "SDP/DP Mixing Ratio", + "StyleBeatVITS2Length": "Speech Rate", "ConversationHistory": "Conversation History", "ConversationHistoryInfo": "The latest 10 conversation texts are stored as memories.", "ConversationHistoryReset": "Reset Conversation History", @@ -122,5 +125,14 @@ "PdfConvertLoading": "Converting...", "PdfConvertSuccess": "Conversion completed", "PdfConvertError": "Conversion failed", - "PdfConvertSubmitError": "Please make sure the PDF file, folder name, and API key are set." + "PdfConvertSubmitError": "Please make sure the PDF file, folder name, and API key are set.", + "LocalStorageReset": "Reset settings (page will be reloaded)", + "Errors": { + "EmptyAPIKey": "API key is not set", + "AIInvalidProperty": "AI service settings are incorrect", + "AIAPIError": "An error occurred while executing the AI API", + "InvalidAIService": "The selected AI service is not valid", + "MethodNotAllowed": "The request is not appropriate", + "UnexpectedError": "An unexpected error occurred" + } } diff --git a/locales/ja/translation.json b/locales/ja/translation.json index d3cc7267..568cba57 100644 --- a/locales/ja/translation.json +++ b/locales/ja/translation.json @@ -59,16 +59,19 @@ "VoicevoxIntonation": "抑揚", "UsingGoogleTTS": "Google TTSを使用する", "UsingStyleBertVITS2": "Style-Bert-VITS2を使用する", - "StyleBertVITS2Info": "Style-Bert-VITS2を使用しています。日・英・中のみに対応しています。ローカルAPIを使用するので下記のサイトから環境にあったアプリをダウンロードし、起動しておく必要があります。", + "StyleBertVITS2Info": "Style-Bert-VITS2を使用しています。日・英・中のみに対応しています。ローカルAPIを使用する場合は、下記のサイトから環境にあったアプリをダウンロードし起動しておく必要があります。必要な場合はAPIキーも設定してください。", "SpeakerSelection": "ボイスタイプ選択", "EnglishToJapanese": "英単語を日本語で読み上げる", "GoogleTTSInfo": "Google Cloud Text-to-Speechを使用しています。多言語に対応可能です。", "AuthFileInstruction": "認証用のJSONファイルを下記から取得し、リポジトリのルートフォルダに credentials.json という名称で配置してください。", "LanguageModelURL": "言語モデルは下記のURLから選択してください。", "LanguageChoice": "言語選択", - "StyleBeatVITS2LocalServerURL": "Style-Bert-VITS2 ローカルサーバーURL", - "StyleBeatVITS2ModelID": "Style-Bert-VITS2 モデルID", - "StyleBeatVITS2Style": "Style-Bert-VITS2 スタイル", + "StyleBeatVITS2ServerURL": "サーバーURL", + "StyleBeatVITS2ApiKey": "API キー", + "StyleBeatVITS2ModelID": "モデルID", + "StyleBeatVITS2Style": "スタイル", + "StyleBeatVITS2SdpRatio": "SDP/DP混合比", + "StyleBeatVITS2Length": "話速", "ConversationHistory": "会話履歴", "ConversationHistoryInfo": "直近の10会話文が記憶として保持されます。", "ConversationHistoryReset": "会話履歴リセット", @@ -123,5 +126,14 @@ "PdfConvertLoading": "変換中...", "PdfConvertSuccess": "変換が完了しました", "PdfConvertError": "変換に失敗しました", - "PdfConvertSubmitError": "PDFファイル、フォルダ名、APIキーが設定されているか確認をしてください" + "PdfConvertSubmitError": "PDFファイル、フォルダ名、APIキーが設定されているか確認をしてください", + "LocalStorageReset": "設定をリセットする(ページが再読み込みされます)", + "Errors": { + "EmptyAPIKey": "APIキーが設定されていません", + "AIInvalidProperty": "AIサービスの設定値が正しくありません", + "AIAPIError": "AI API実行時にエラーが発生しました", + "InvalidAIService": "選択しているAIサービスが正しくありません", + "MethodNotAllowed": "リクエストが適切でありません", + "UnexpectedError": "予期せぬエラーが発生しました" + } } diff --git a/locales/ko/translation.json b/locales/ko/translation.json index 9a9c26da..9e91783d 100644 --- a/locales/ko/translation.json +++ b/locales/ko/translation.json @@ -59,15 +59,18 @@ "VoicevoxIntonation": "억양", "UsingGoogleTTS": "Google TTS 사용", "UsingStyleBertVITS2": "Style-Bert-VITS2 사용", - "StyleBertVITS2Info": "Style-Bert-VITS2를 사용하고 있습니다. 일본어, 영어, 중국어만 지원됩니다. 로컬 API를 사용하기 때문에 아래 사이트에서 환경에 맞는 앱을 다운로드하고 실행해야 합니다.", + "StyleBertVITS2Info": "Style-Bert-VITS2를 사용하고 있습니다. 일본어, 영어, 중국어만 지원됩니다. 로컬 API를 사용하는 경우 아래 사이트에서 환경에 맞는 앱을 다운로드하고 실행해야 합니다. 필요한 경우 API 키도 설정해 주세요.", "SpeakerSelection": "보이스 타입 선택", "GoogleTTSInfo": "Google Cloud Text-to-Speech를 사용합니다. 다국어 지원이 가능합니다.", "AuthFileInstruction": "인증용 JSON 파일을 아래에서 얻어 리포지토리 루트 폴더에 credentials.json이라는 이름으로 배치하십시오.", "LanguageModelURL": "언어 모델은 아래 URL에서 선택하십시오.", "LanguageChoice": "언어 선택", - "StyleBeatVITS2LocalServerURL": "Style-Bert-VITS2 로컬 서버 URL", - "StyleBeatVITS2ModelID": "Style-Bert-VITS2 모델 ID", - "StyleBeatVITS2Style": "Style-Bert-VITS2 스타일", + "StyleBeatVITS2ServerURL": "서버 URL", + "StyleBeatVITS2ApiKey": "API 키", + "StyleBeatVITS2ModelID": "모델 ID", + "StyleBeatVITS2Style": "스타일", + "StyleBeatVITS2SdpRatio": "SDP/DP 혼합 비율", + "StyleBeatVITS2Length": "말하는 속도", "ConversationHistory": "대화 기록", "ConversationHistoryInfo": "최근 10개의 대화 문장이 기억으로 유지됩니다.", "ConversationHistoryReset": "대화 기록 재설정", @@ -122,5 +125,14 @@ "PdfConvertLoading": "변환 중...", "PdfConvertSuccess": "변환 완료", "PdfConvertError": "변환 실패", - "PdfConvertSubmitError": "PDF 파일, 폴더 이름, API 키가 설정되어 있는지 확인하세요." + "PdfConvertSubmitError": "PDF 파일, 폴더 이름, API 키가 설정되어 있는지 확인하세요.", + "LocalStorageReset": "설정을 재설정합니다 (페이지가 다시 로드됩니다)", + "Errors": { + "EmptyAPIKey": "API 키가 설정되지 않았습니다", + "AIInvalidProperty": "AI 서비스 설정값이 올바르지 않습니다", + "AIAPIError": "AI API 실행 중 오류가 발생했습니다", + "InvalidAIService": "선택한 AI 서비스가 올바르지 않습니다", + "MethodNotAllowed": "요청이 적절하지 않습니다", + "UnexpectedError": "예기치 않은 오류가 발생했습니다" + } } diff --git a/locales/zh/translation.json b/locales/zh/translation.json index f9b6643c..2eba9816 100644 --- a/locales/zh/translation.json +++ b/locales/zh/translation.json @@ -59,15 +59,18 @@ "VoicevoxIntonation": "語調", "UsingGoogleTTS": "使用 Google TTS", "UsingStyleBertVITS2": "使用 Style-Bert-VITS2", - "StyleBertVITS2Info": "使用 Style-Bert-VITS2。僅支援日語、英語和中文。它使用本地 API,您需要從以下網站下載並啟動適合您環境的應用程式。", + "StyleBertVITS2Info": "使用 Style-Bert-VITS2。僅支援日語、英語和中文。如果使用本地 API,您需要從以下網站下載並啟動適合您環境的應用程式。如有需要,請也設定 API 金鑰。", "SpeakerSelection": "選擇語音角色", "GoogleTTSInfo": "使用 Google Cloud 文字轉語音。支援多種語言。", "AuthFileInstruction": "在下方獲取認證 JSON 檔案,並將其放置於儲存庫的根目錄下,命名為 'credentials.json'。", "LanguageModelURL": "從下方 URL 選擇語言模型。", "LanguageChoice": "語言選擇", - "StyleBeatVITS2LocalServerURL": "Style-Bert-VITS2 本地伺服器URL", - "StyleBeatVITS2ModelID": "Style-Bert-VITS2 模型ID", - "StyleBeatVITS2Style": "Style-Bert-VITS2 風格", + "StyleBeatVITS2ServerURL": "伺服器 URL", + "StyleBeatVITS2ApiKey": "API 金鑰", + "StyleBeatVITS2ModelID": "模型 ID", + "StyleBeatVITS2Style": "風格", + "StyleBeatVITS2SdpRatio": "SDP/DP 混合比", + "StyleBeatVITS2Length": "語速", "ConversationHistory": "聊天記錄", "ConversationHistoryInfo": "最新的 10 個對話內容會被儲存為記憶。", "ConversationHistoryReset": "重設聊天記錄", @@ -122,5 +125,14 @@ "PdfConvertLoading": "转换中...", "PdfConvertSuccess": "转换完成", "PdfConvertError": "转换失败", - "PdfConvertSubmitError": "请确保已设置PDF文件、文件夹名称和API密钥。" + "PdfConvertSubmitError": "请确保已设置PDF文件、文件夹名称和API密钥。", + "LocalStorageReset": "重設設定(頁面會重新載入)", + "Errors": { + "EmptyAPIKey": "API 密钥未设置", + "AIInvalidProperty": "AI 服务设置值不正确", + "AIAPIError": "AI API 执行时发生错误", + "InvalidAIService": "选择的 AI 服务不正确", + "MethodNotAllowed": "请求不适当", + "UnexpectedError": "意外的错误发生" + } } diff --git a/src/components/iconButton.tsx b/src/components/iconButton.tsx index c598c141..d294f74a 100644 --- a/src/components/iconButton.tsx +++ b/src/components/iconButton.tsx @@ -3,12 +3,14 @@ import { ButtonHTMLAttributes } from 'react' type Props = ButtonHTMLAttributes & { iconName: keyof KnownIconType isProcessing: boolean + isProcessingIcon?: keyof KnownIconType label?: string } export const IconButton = ({ iconName, isProcessing, + isProcessingIcon, label, ...rest }: Props) => { @@ -20,7 +22,7 @@ export const IconButton = ({ `} > {isProcessing ? ( - + ) : ( )} diff --git a/src/components/introduction.tsx b/src/components/introduction.tsx index 526096bd..1fde4be4 100644 --- a/src/components/introduction.tsx +++ b/src/components/introduction.tsx @@ -12,19 +12,17 @@ import { } from '@/features/constants/settings' export const Introduction = () => { - const dontShowIntroduction = homeStore((s) => s.dontShowIntroduction) + const showIntroduction = homeStore((s) => s.showIntroduction) const selectLanguage = settingsStore((s) => s.selectLanguage) - const [showIntroduction, setShowIntroduction] = useState(false) + const [displayIntroduction, setDisplayIntroduction] = useState(false) const [opened, setOpened] = useState(true) const { t } = useTranslation() useEffect(() => { - // wait for local storage to be fully initialized - // to prevent a flash of - setShowIntroduction(!homeStore.getState().dontShowIntroduction) - }, [dontShowIntroduction]) + setDisplayIntroduction(homeStore.getState().showIntroduction) + }, [showIntroduction]) const updateLanguage = () => { console.log('i18n.language', i18n.language) @@ -54,7 +52,7 @@ export const Introduction = () => { }) } - return showIntroduction && opened ? ( + return displayIntroduction && opened ? (
{
- {/* dontShowIntroductionのチェックボックスを表示 */}