From cf15f1ebff00a718ae2c0292a576f8794885117d Mon Sep 17 00:00:00 2001 From: Arvin Xu Date: Wed, 18 Oct 2023 14:58:02 +0800 Subject: [PATCH] =?UTF-8?q?=E2=9C=A8=20feat:=20support=20translate=20messa?= =?UTF-8?q?ge=20to=20current=20language=20(#340)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * :truck: refactor: rename prompts to chains * :recycle: refactor: refactor Message Actions * :recycle: refactor: add translate action * :sparkles: feat: support translate * :recycle: refactor: refactor part of common locale to chat * :globe_with_meridians: style: update i18n --- locales/en_US/chat.json | 55 +++++++++++ locales/en_US/common.json | 68 ++++---------- locales/ja_JP/chat.json | 55 +++++++++++ locales/ja_JP/common.json | 62 +++--------- locales/ko_KR/chat.json | 55 +++++++++++ locales/ko_KR/common.json | 84 +++++------------ locales/ru_RU/chat.json | 55 +++++++++++ locales/ru_RU/common.json | 56 +++-------- locales/zh_CN/chat.json | 55 +++++++++++ locales/zh_CN/common.json | 56 +++-------- locales/zh_TW/chat.json | 55 +++++++++++ locales/zh_TW/common.json | 94 ++++++------------- package.json | 1 + .../chat/(desktop)/features/ChatHeader.tsx | 2 +- .../chat/(desktop)/features/SessionHeader.tsx | 2 +- src/app/chat/(mobile)/features/ChatHeader.tsx | 2 +- src/app/chat/(mobile)/features/TopicList.tsx | 2 +- .../features/ChatHeader/ShareButton/Inner.tsx | 2 +- .../ChatHeader/ShareButton/Preview.tsx | 2 +- .../ActionBar/ActionRight.tsx | 6 +- .../ChatInputContent/ActionBar/Token.tsx | 2 +- .../ChatInputContent/Footer/SaveTopic.tsx | 2 +- .../ChatInputContent/Footer/index.tsx | 2 +- .../chat/features/ChatInputContent/index.tsx | 2 +- .../ChatList/Actions/Assistant.tsx | 22 +++++ .../Conversation/ChatList/Actions/Error.tsx | 15 +++ .../System.tsx => Actions/Fallback.tsx} | 2 +- .../ChatList/Actions/Function.tsx | 14 +++ .../ChatList/{Messages => Actions}/User.tsx | 7 +- .../ChatList/Actions/customAction.ts | 21 +++++ .../Conversation/ChatList/Actions/index.ts | 13 +++ .../ChatList/Extras/Assistant.tsx | 39 ++++++++ .../ChatList/Extras/Translate.tsx | 75 +++++++++++++++ .../Conversation/ChatList/Extras/User.tsx | 24 +++++ .../Conversation/ChatList/Extras/index.ts | 9 ++ .../Conversation/ChatList/Loading.tsx | 53 +++++++++++ .../ChatList/Messages/Assistant.tsx | 63 +------------ .../ChatList/Messages/Default.tsx | 8 +- .../ChatList/Messages/Function.tsx | 27 +----- .../Conversation/ChatList/Messages/index.ts | 21 +---- .../ChatList/Plugins/FunctionCall.tsx | 2 - .../ChatList/Plugins/PluginMessage.tsx | 7 +- .../features/Conversation/ChatList/index.tsx | 19 +++- src/app/chat/features/Conversation/index.tsx | 5 +- .../SessionListContent/Inbox/index.tsx | 2 +- .../SessionListContent/List/AddButton.tsx | 2 +- .../chat/features/SessionSearchBar/index.tsx | 2 +- .../TopicListContent/Topic/DefaultContent.tsx | 2 +- .../TopicListContent/Topic/TopicContent.tsx | 2 +- .../features/TopicListContent/Topic/index.tsx | 2 +- .../TopicListContent/TopicSearchBar/index.tsx | 2 +- src/app/home/index.tsx | 4 +- src/{prompts => chains}/agent.ts | 0 src/chains/chat.ts | 77 +++++++++++++++ .../AgentSetting/AgentPrompt/index.tsx | 6 +- src/features/AgentSetting/store/action.ts | 2 +- src/layout/ResponsiveLayout.client.tsx | 6 +- src/locales/create.ts | 3 +- src/locales/default/chat.ts | 60 ++++++++++++ src/locales/default/common.ts | 55 ++--------- src/locales/options.ts | 10 ++ src/locales/resources/en_US.ts | 2 + src/locales/resources/index.ts | 2 +- src/locales/resources/ja_JP.ts | 2 + src/locales/resources/ko_KR.ts | 2 + src/locales/resources/ru_RU.ts | 2 + src/locales/resources/zh_CN.ts | 2 + src/locales/resources/zh_TW.ts | 2 + src/prompts/chat.ts | 32 ------- src/store/global/selectors/settings.ts | 4 + .../session/slices/chat/actions/index.ts | 8 +- .../session/slices/chat/actions/message.ts | 4 +- .../session/slices/chat/actions/topic.ts | 4 +- .../session/slices/chat/actions/translate.ts | 87 +++++++++++++++++ .../session/slices/chat/selectors/chat.ts | 40 ++++---- .../session/slices/chat/selectors/index.ts | 4 +- src/types/chatMessage.ts | 9 +- src/types/translate.ts | 4 + 78 files changed, 1111 insertions(+), 559 deletions(-) create mode 100644 locales/en_US/chat.json create mode 100644 locales/ja_JP/chat.json create mode 100644 locales/ko_KR/chat.json create mode 100644 locales/ru_RU/chat.json create mode 100644 locales/zh_CN/chat.json create mode 100644 locales/zh_TW/chat.json create mode 100644 src/app/chat/features/Conversation/ChatList/Actions/Assistant.tsx create mode 100644 src/app/chat/features/Conversation/ChatList/Actions/Error.tsx rename src/app/chat/features/Conversation/ChatList/{Messages/System.tsx => Actions/Fallback.tsx} (77%) create mode 100644 src/app/chat/features/Conversation/ChatList/Actions/Function.tsx rename src/app/chat/features/Conversation/ChatList/{Messages => Actions}/User.tsx (69%) create mode 100644 src/app/chat/features/Conversation/ChatList/Actions/customAction.ts create mode 100644 src/app/chat/features/Conversation/ChatList/Actions/index.ts create mode 100644 src/app/chat/features/Conversation/ChatList/Extras/Assistant.tsx create mode 100644 src/app/chat/features/Conversation/ChatList/Extras/Translate.tsx create mode 100644 src/app/chat/features/Conversation/ChatList/Extras/User.tsx create mode 100644 src/app/chat/features/Conversation/ChatList/Extras/index.ts create mode 100644 src/app/chat/features/Conversation/ChatList/Loading.tsx rename src/{prompts => chains}/agent.ts (100%) create mode 100644 src/chains/chat.ts create mode 100644 src/locales/default/chat.ts delete mode 100644 src/prompts/chat.ts create mode 100644 src/store/session/slices/chat/actions/translate.ts create mode 100644 src/types/translate.ts diff --git a/locales/en_US/chat.json b/locales/en_US/chat.json new file mode 100644 index 000000000000..3e41ef2bec34 --- /dev/null +++ b/locales/en_US/chat.json @@ -0,0 +1,55 @@ +{ + "agentDefaultMessage": "Hello, I'm **{{name}}**. You can start chatting with me right away or go to [Assistant Settings](/chat/settings#session={{id}}) to improve my information.", + "agentDefaultMessageWithSystemRole": "Hello, I'm **{{name}}**, {{systemRole}}. Let's start the conversation!", + "backToBottom": "Go to Latest Messages", + "clearCurrentMessages": "Clear Current Session Messages", + "confirmClearCurrentMessages": "You are about to clear the current session messages. Once cleared, they cannot be recovered. Please confirm your operation.", + "confirmRemoveSessionItemAlert": "You are about to delete this assistant. Once deleted, it cannot be recovered. Please confirm your operation.", + "defaultAgent": "Custom Assistant", + "defaultSession": "Custom Assistant", + "historyRange": "History Range", + "inbox": { + "defaultMessage": "Hello, I'm your intelligent assistant. You can ask me any questions, and I will do my best to answer you. If you need a more professional or customized assistant, you can click on `+` to create a custom assistant.", + "desc": "Activate brain clusters and spark thinking. Your intelligent assistant is here to communicate with you about everything.", + "title": "Chat Randomly" + }, + "newAgent": "Create New Assistant", + "noDescription": "No description available", + "regenerate": "Regenerate", + "roleAndArchive": "Roles and Archives", + "searchAgentPlaceholder": "Search assistants and conversations...", + "send": "Send", + "sendPlaceholder": "Enter chat content...", + "shareModal": { + "download": "Download Screenshot", + "imageType": "Image Format", + "screenshot": "Screenshot", + "settings": "Export Settings", + "shareToShareGPT": "Generate ShareGPT Sharing Link", + "withBackground": "Include Background Image", + "withFooter": "Include Footer", + "withPluginInfo": "Include Plugin Information", + "withSystemRole": "Include Assistant Role Setting" + }, + "stop": "Stop", + "temp": "Temporary", + "tokenDetail": "Role Setting: {{systemRoleToken}} · Chat History: {{chatsToken}}", + "tokenTag": { + "overload": "Exceeded Limit", + "remained": "Remaining", + "used": "Used" + }, + "topic": { + "confirmRemoveTopic": "You are about to delete this topic. Once deleted, it cannot be recovered. Please proceed with caution.", + "defaultTitle": "Default Topic", + "saveCurrentMessages": "Save Current Session as Topic", + "searchPlaceholder": "Search topics...", + "title": "Topic" + }, + "translate": { + "clear": "Clear Translation" + }, + "translateTo": "Translate", + "updateAgent": "Update Assistant Information", + "warp": "Line Break" +} diff --git a/locales/en_US/common.json b/locales/en_US/common.json index 155ef88faca0..bfa09e820377 100644 --- a/locales/en_US/common.json +++ b/locales/en_US/common.json @@ -1,24 +1,19 @@ { "about": "About", "advanceSettings": "Advanced Settings", - "agentDefaultMessage": "Hello, I'm **{{name}}**. You can start chatting with me right away or go to [Agent Settings](/chat/settings#session={{id}}) to complete my information.", - "agentDefaultMessageWithSystemRole": "Hello, I'm **{{name}}**, {{systemRole}}. Let's start chatting!", "agentMaxToken": "Max Session Length", "agentModel": "Model", - "agentProfile": "Agent Information", + "agentProfile": "Agent Profile", "appInitializing": "LobeChat is initializing, please wait...", "archive": "Archive", "autoGenerate": "Auto Generate", "autoGenerateTooltip": "Auto generate agent description based on prompts", - "backToBottom": "Go to Latest Messages", "cancel": "Cancel", "changelog": "Changelog", - "clearCurrentMessages": "Clear Current Session Messages", "close": "Close", - "confirmClearCurrentMessages": "You are about to clear the current session messages. Once cleared, they cannot be recovered. Please confirm your operation.", - "confirmRemoveSessionItemAlert": "You are about to delete this agent. Once deleted, it cannot be recovered. Please confirm your operation.", + "confirmRemoveSessionItemAlert": "You are about to delete this agent. Once deleted, it cannot be recovered. Please confirm your action.", "copy": "Copy", - "copySuccess": "Copy Success", + "copySuccess": "Copy Successful", "defaultAgent": "Custom Agent", "defaultSession": "Custom Agent", "delete": "Delete", @@ -35,17 +30,18 @@ "feedback": "Feedback", "historyRange": "History Range", "import": "Import Configuration", - "inbox": { - "defaultMessage": "Hello, I'm your intelligent agent. You can ask me any questions and I will do my best to answer you. If you need a more professional or customized agent, you can click `+` to create a custom agent.", - "desc": "Activate the brain cluster and spark your thinking. Your intelligent agent is here to communicate with you about everything.", - "title": "Chat Freely" + "lang": { + "en": "English", + "en-US": "English", + "ja-JP": "Japanese", + "ko-KR": "Korean", + "ru-RU": "Russian", + "zh": "Simplified Chinese", + "zh-CN": "Simplified Chinese", + "zh-TW": "Traditional Chinese" }, - "message": { - "function_loading": "Plugin request in progress..." - }, - "moreSetting": "More Settings...", - "newAgent": "New Agent", - "noDescription": "No Description", + "layoutInitializing": "Loading layout...", + "noDescription": "No description", "ok": "OK", "password": "Password", "pin": "Pin", @@ -54,51 +50,21 @@ "rename": "Rename", "reset": "Reset", "retry": "Retry", - "roleAndArchive": "Roles and Archives", - "searchAgentPlaceholder": "Search Agents and Conversations...", "send": "Send", - "sendPlaceholder": "Enter chat content...", "sessionList": "Agent List", "setting": "Settings", "share": "Share", - "shareModal": { - "download": "Download Screenshot", - "imageType": "Image Type", - "screenshot": "Screenshot", - "settings": "Export Settings", - "withBackground": "Include Background Image", - "withPluginInfo": "Include Plugin Information", - "withSystemRole": "Include Agent Role Setting", - "withFooter": "Including footer", - "shareToShareGPT": "Generate ShareGPT sharing link" - }, "stop": "Stop", - "switchMobileLayout": "Switching to mobile layout...", "tab": { "chat": "Chat", "market": "Discover", "setting": "Settings" }, "temp": "Temporary", - "tokenDetail": "Role Setting: {{systemRoleToken}} · Message History: {{chatsToken}}", - "tokenTag": { - "overload": "Exceeded Limit", - "remained": "Remaining", - "used": "Used" - }, - "topic": { - "confirmRemoveTopic": "You are about to delete this topic. Once deleted, it cannot be recovered. Please proceed with caution.", - "defaultTitle": "Default Topic", - "saveCurrentMessages": "Save the current session as a topic", - "searchPlaceholder": "Search Topics...", - "title": "Topic" - }, - "updateAgent": "Update Agent Information", - "updatePrompt": "Update Prompts", + "updateAgent": "Update Agent Profile", "upgradeVersion": { "action": "Upgrade Now", - "hasNew": "New Update Available", + "hasNew": "Update available", "newVersion": "New version available: {{version}}" - }, - "warp": "Line break" + } } diff --git a/locales/ja_JP/chat.json b/locales/ja_JP/chat.json new file mode 100644 index 000000000000..8542b2e6e92b --- /dev/null +++ b/locales/ja_JP/chat.json @@ -0,0 +1,55 @@ +{ + "agentDefaultMessage": "こんにちは、私は **{{name}}** です。すぐに会話を始めることができますし、[エージェント設定](/chat/settings#session={{id}}) に移動して私の情報を充実させることもできます。", + "agentDefaultMessageWithSystemRole": "こんにちは、私は **{{name}}** です、{{systemRole}}、さあ、会話を始めましょう!", + "backToBottom": "最新のメッセージを表示", + "clearCurrentMessages": "現在の会話メッセージをクリア", + "confirmClearCurrentMessages": "現在の会話メッセージをクリアします。クリア後は元に戻すことはできませんので、操作を確認してください", + "confirmRemoveSessionItemAlert": "このエージェントを削除します。削除後は元に戻すことはできませんので、操作を確認してください", + "defaultAgent": "デフォルトエージェント", + "defaultSession": "デフォルトエージェント", + "historyRange": "履歴範囲", + "inbox": { + "defaultMessage": "こんにちは、私はあなたのインテリジェントアシスタントです。何でも質問してください、できる限りお答えします。より専門的またはカスタマイズされたアシスタントが必要な場合は、`+` をクリックしてカスタムエージェントを作成できます", + "desc": "ブレインクラスタを起動し、思考の火花を引き起こします。あなたのインテリジェントアシスタントは、ここであなたとすべてを話します", + "title": "ちょっとおしゃべりしましょう" + }, + "newAgent": "新しいエージェントを作成", + "noDescription": "説明はありません", + "regenerate": "再生成", + "roleAndArchive": "役割とアーカイブ", + "searchAgentPlaceholder": "エージェントと会話を検索...", + "send": "送信", + "sendPlaceholder": "チャット内容を入力...", + "shareModal": { + "download": "スクリーンショットをダウンロード", + "imageType": "画像形式", + "screenshot": "スクリーンショット", + "settings": "エクスポート設定", + "shareToShareGPT": "ShareGPT共有リンクを生成", + "withBackground": "背景画像を含む", + "withFooter": "フッターを含む", + "withPluginInfo": "プラグイン情報を含む", + "withSystemRole": "エージェントの役割設定を含む" + }, + "stop": "停止", + "temp": "一時", + "tokenDetail": "役割設定: {{systemRoleToken}} · チャット履歴: {{chatsToken}}", + "tokenTag": { + "overload": "制限を超えています", + "remained": "残り", + "used": "使用済み" + }, + "topic": { + "confirmRemoveTopic": "このトピックを削除します。削除後は元に戻すことはできませんので、注意して操作してください", + "defaultTitle": "デフォルトトピック", + "saveCurrentMessages": "現在の会話をトピックとして保存", + "searchPlaceholder": "トピックを検索...", + "title": "トピック" + }, + "translate": { + "clear": "翻訳をクリア" + }, + "translateTo": "翻訳", + "updateAgent": "エージェント情報を更新", + "warp": "改行" +} diff --git a/locales/ja_JP/common.json b/locales/ja_JP/common.json index 1966328a16d0..f14a359c5697 100644 --- a/locales/ja_JP/common.json +++ b/locales/ja_JP/common.json @@ -1,22 +1,17 @@ { "about": "について", "advanceSettings": "詳細設定", - "agentDefaultMessage": "こんにちは、私は **{{name}}** です。すぐにチャットを始めることができますし、[エージェント設定](/chat/settings#session={{id}}) に移動して私の情報を完全にすることもできます。", - "agentDefaultMessageWithSystemRole": "こんにちは、私は **{{name}}** です。{{systemRole}}、さあ、チャットを始めましょう!", "agentMaxToken": "セッションの最大トークン数", "agentModel": "モデル", "agentProfile": "エージェント情報", - "appInitializing": "LobeChat を起動しています。お待ちください...", + "appInitializing": "LobeChatを起動中です。お待ちください...", "archive": "アーカイブ", "autoGenerate": "自動生成", "autoGenerateTooltip": "ヒントワードに基づいてエージェントの説明を自動生成します", - "backToBottom": "最新メッセージを表示", "cancel": "キャンセル", "changelog": "更新履歴", - "clearCurrentMessages": "現在のセッションのメッセージをクリア", "close": "閉じる", - "confirmClearCurrentMessages": "現在のセッションのメッセージをクリアします。クリア後は元に戻すことはできませんので、操作を確認してください", - "confirmRemoveSessionItemAlert": "このエージェントを削除します。削除後は元に戻すことはできませんので、操作を確認してください", + "confirmRemoveSessionItemAlert": "このエージェントを削除します。削除後は元に戻すことはできません。操作を確認してください", "copy": "コピー", "copySuccess": "コピーが成功しました", "defaultAgent": "デフォルトエージェント", @@ -35,16 +30,17 @@ "feedback": "フィードバック", "historyRange": "履歴範囲", "import": "設定のインポート", - "inbox": { - "defaultMessage": "こんにちは、私はあなたのインテリジェントエージェントです。何でも質問してください、できる限りお答えします。より専門的でカスタマイズされたエージェントが必要な場合は、`+` をクリックしてカスタムエージェントを作成できます", - "desc": "ブレインクラスタを起動し、思考の火花を引き起こします。あなたのインテリジェントアシスタントとのすべてのコミュニケーションはここで行われます", - "title": "気軽にチャット" + "lang": { + "en": "英語", + "en-US": "英語", + "ja-JP": "日本語", + "ko-KR": "韓国語", + "ru-RU": "ロシア語", + "zh": "簡体中国語", + "zh-CN": "簡体中国語", + "zh-TW": "繁体中国語" }, - "message": { - "function_loading": "プラグインリクエスト中..." - }, - "moreSetting": "その他の設定...", - "newAgent": "新しいエージェント", + "layoutInitializing": "レイアウトを読み込んでいます...", "noDescription": "説明はありません", "ok": "OK", "password": "パスワード", @@ -54,51 +50,21 @@ "rename": "名前の変更", "reset": "リセット", "retry": "再試行", - "roleAndArchive": "役割とアーカイブ", - "searchAgentPlaceholder": "エージェントとチャットを検索...", "send": "送信", - "sendPlaceholder": "チャット内容を入力...", "sessionList": "エージェントリスト", "setting": "設定", "share": "共有", - "shareModal": { - "download": "ダウンロード", - "imageType": "画像形式", - "screenshot": "スクリーンショット", - "settings": "設定をエクスポート", - "shareToShareGPT": "ShareGPT共有リンクを生成", - "withBackground": "背景画像を含む", - "withFooter": "フッターを含む", - "withPluginInfo": "プラグイン情報を含む", - "withSystemRole": "アシスタントの役割設定を含む" - }, "stop": "停止", - "switchMobileLayout": "モバイルレイアウトに切り替え中...", "tab": { "chat": "チャット", "market": "発見", "setting": "設定" }, "temp": "一時的な", - "tokenDetail": "役割設定: {{systemRoleToken}} · チャット履歴: {{chatsToken}}", - "tokenTag": { - "overload": "制限を超える", - "remained": "残り", - "used": "使用済み" - }, - "topic": { - "confirmRemoveTopic": "このトピックを削除しますか?削除後は元に戻せませんので、注意して操作してください。", - "defaultTitle": "デフォルトトピック", - "saveCurrentMessages": "現在のチャットをトピックとして保存", - "searchPlaceholder": "トピックを検索...", - "title": "トピック" - }, - "updateAgent": "アシスタント情報を更新", - "updatePrompt": "プロンプトの更新", + "updateAgent": "エージェント情報の更新", "upgradeVersion": { "action": "今すぐアップグレード", "hasNew": "利用可能な更新があります", "newVersion": "新しいバージョンが利用可能です:{{version}}" - }, - "warp": "改行" + } } diff --git a/locales/ko_KR/chat.json b/locales/ko_KR/chat.json new file mode 100644 index 000000000000..d17be8298dfe --- /dev/null +++ b/locales/ko_KR/chat.json @@ -0,0 +1,55 @@ +{ + "agentDefaultMessage": "안녕하세요, 저는 **{{name}}**입니다. 바로 대화를 시작하거나 [도우미 설정](/chat/settings#session={{id}})으로 이동하여 제 정보를 완성할 수 있습니다.", + "agentDefaultMessageWithSystemRole": "안녕하세요, 저는 **{{name}}**입니다. {{systemRole}}입니다. 대화를 시작해보세요!", + "backToBottom": "최신 메시지 보기", + "clearCurrentMessages": "현재 대화 지우기", + "confirmClearCurrentMessages": "현재 대화를 지우시겠습니까? 지우면 복구할 수 없습니다. 작업을 확인하세요.", + "confirmRemoveSessionItemAlert": "도우미를 삭제하시겠습니까? 삭제하면 복구할 수 없습니다. 작업을 확인하세요.", + "defaultAgent": "사용자 정의 도우미", + "defaultSession": "사용자 정의 도우미", + "historyRange": "기록 범위", + "inbox": { + "defaultMessage": "안녕하세요, 저는 여러분의 인공지능 도우미입니다. 궁금한 점이 있으면 물어보세요. 더 전문적이거나 맞춤화된 도우미가 필요하다면 `+`를 클릭하여 사용자 정의 도우미를 생성할 수 있습니다.", + "desc": "뇌 클러스터를 활성화하여 창의적인 생각을 이끌어내는 인공지능 도우미입니다. 모든 것에 대해 여기에서 대화하세요.", + "title": "잡담하기" + }, + "newAgent": "새 도우미 만들기", + "noDescription": "설명 없음", + "regenerate": "재생성", + "roleAndArchive": "역할 및 아카이브", + "searchAgentPlaceholder": "도우미 및 대화 검색...", + "send": "보내기", + "sendPlaceholder": "대화 내용 입력...", + "shareModal": { + "download": "스크린샷 다운로드", + "imageType": "이미지 형식", + "screenshot": "스크린샷", + "settings": "내보내기 설정", + "shareToShareGPT": "ShareGPT 공유 링크 생성", + "withBackground": "배경 이미지 포함", + "withFooter": "푸터 포함", + "withPluginInfo": "플러그인 정보 포함", + "withSystemRole": "도우미 역할 포함" + }, + "stop": "정지", + "temp": "임시", + "tokenDetail": "역할 설정: {{systemRoleToken}} · 대화 기록: {{chatsToken}}", + "tokenTag": { + "overload": "한도 초과", + "remained": "남음", + "used": "사용" + }, + "topic": { + "confirmRemoveTopic": "해당 주제를 삭제하시겠습니까? 삭제하면 복구할 수 없습니다. 신중하게 작업하세요.", + "defaultTitle": "기본 주제", + "saveCurrentMessages": "현재 대화를 주제로 저장", + "searchPlaceholder": "주제 검색...", + "title": "주제" + }, + "translate": { + "clear": "번역 지우기" + }, + "translateTo": "번역", + "updateAgent": "도우미 정보 업데이트", + "warp": "줄바꿈" +} diff --git a/locales/ko_KR/common.json b/locales/ko_KR/common.json index d0e584f09658..f8676a482a7e 100644 --- a/locales/ko_KR/common.json +++ b/locales/ko_KR/common.json @@ -1,50 +1,46 @@ { "about": "소개", "advanceSettings": "고급 설정", - "agentDefaultMessage": "안녕하세요, 저는 **{{name}}**입니다. 바로 대화를 시작하거나 [도우미 설정](/chat/settings#session={{id}})으로 이동하여 제 정보를 완성할 수 있습니다.", - "agentDefaultMessageWithSystemRole": "안녕하세요, 저는 **{{name}}**입니다. {{systemRole}}입니다. 대화를 시작해봅시다!", "agentMaxToken": "세션 최대 길이", "agentModel": "모델", - "agentProfile": "도우미 정보", - "appInitializing": "LobeChat을 시작하는 중입니다. 잠시 기다려주세요...", - "archive": "보관함", + "agentProfile": "에이전트 정보", + "appInitializing": "LobeChat이 시작 중입니다. 잠시 기다려주세요...", + "archive": "보관", "autoGenerate": "자동 생성", - "autoGenerateTooltip": "도우미 설명을 자동으로 완성합니다.", - "backToBottom": "최신 메시지 보기", + "autoGenerateTooltip": "힌트 단어를 기반으로 에이전트 설명을 자동으로 생성합니다.", "cancel": "취소", "changelog": "변경 내역", - "clearCurrentMessages": "현재 대화 메시지 지우기", "close": "닫기", - "confirmClearCurrentMessages": "현재 대화 메시지를 지우시겠습니까? 지운 후에는 복구할 수 없습니다. 작업을 확인하세요.", - "confirmRemoveSessionItemAlert": "도우미를 삭제하시겠습니까? 삭제한 후에는 복구할 수 없습니다. 작업을 확인하세요.", + "confirmRemoveSessionItemAlert": "에이전트를 삭제하려고 합니다. 삭제 후에는 복구할 수 없습니다. 작업을 확인하세요.", "copy": "복사", "copySuccess": "복사 완료", - "defaultAgent": "기본 도우미", - "defaultSession": "기본 도우미", + "defaultAgent": "기본 에이전트", + "defaultSession": "기본 세션", "delete": "삭제", "edit": "편집", "export": "설정 내보내기", "exportType": { - "agent": "도우미 설정 내보내기", - "agentWithMessage": "도우미와 메시지 내보내기", - "all": "전역 설정과 모든 도우미 데이터 내보내기", - "allAgent": "모든 도우미 설정 내보내기", - "allAgentWithMessage": "모든 도우미와 메시지 내보내기", + "agent": "에이전트 설정 내보내기", + "agentWithMessage": "에이전트 및 메시지 내보내기", + "all": "전역 설정 및 모든 에이전트 데이터 내보내기", + "allAgent": "모든 에이전트 설정 내보내기", + "allAgentWithMessage": "모든 에이전트 및 메시지 내보내기", "globalSetting": "전역 설정 내보내기" }, "feedback": "피드백", "historyRange": "기록 범위", "import": "설정 가져오기", - "inbox": { - "defaultMessage": "안녕하세요, 저는 인공지능 도우미입니다. 궁금한 점이 있으면 물어보세요. 가능한 한 답변해드리겠습니다. 더 전문적이거나 맞춤화된 도우미가 필요하다면 `+`를 클릭하여 사용자 정의 도우미를 만들 수 있습니다.", - "desc": "뇌 클러스터를 활성화하여 창의적인 아이디어를 끄집어내세요. 여기에서 모든 것을 대화하는 인공지능 도우미와 소통하세요.", - "title": "무작위 대화" + "lang": { + "en": "영어", + "en-US": "영어", + "ja-JP": "일본어", + "ko-KR": "한국어", + "ru-RU": "러시아어", + "zh": "중국어 간체", + "zh-CN": "중국어 간체", + "zh-TW": "중국어 번체" }, - "message": { - "function_loading": "플러그인 요청 중..." - }, - "moreSetting": "추가 설정...", - "newAgent": "새 도우미", + "layoutInitializing": "레이아웃을 로드 중입니다...", "noDescription": "설명 없음", "ok": "확인", "password": "비밀번호", @@ -54,51 +50,21 @@ "rename": "이름 변경", "reset": "재설정", "retry": "재시도", - "roleAndArchive": "역할 및 기록", - "searchAgentPlaceholder": "도우미와 대화 검색...", "send": "보내기", - "sendPlaceholder": "대화 내용 입력...", - "sessionList": "도우미 목록", + "sessionList": "에이전트 목록", "setting": "설정", "share": "공유", - "shareModal": { - "download": "스크린샷 다운로드", - "imageType": "이미지 형식", - "screenshot": "스크린샷", - "settings": "내보내기 설정", - "shareToShareGPT": "ShareGPT 공유 링크 생성", - "withBackground": "배경 이미지 포함", - "withFooter": "푸터 포함", - "withPluginInfo": "플러그인 정보 포함", - "withSystemRole": "어시스턴트 역할 포함" - }, "stop": "중지", - "switchMobileLayout": "모바일 레이아웃으로 전환 중...", "tab": { "chat": "채팅", "market": "탐색", "setting": "설정" }, "temp": "임시", - "tokenDetail": "역할 설정: {{systemRoleToken}} · 이전 메시지: {{chatsToken}}", - "tokenTag": { - "overload": "제한 초과", - "remained": "남음", - "used": "사용됨" - }, - "topic": { - "confirmRemoveTopic": "이 주제를 삭제하려고 합니다. 삭제 후에는 복구할 수 없으니 주의하세요.", - "defaultTitle": "기본 주제", - "saveCurrentMessages": "현재 대화를 주제로 저장", - "searchPlaceholder": "주제 검색...", - "title": "주제" - }, - "updateAgent": "어시스턴트 정보 업데이트", - "updatePrompt": "프롬프트 문구 업데이트", + "updateAgent": "에이전트 정보 업데이트", "upgradeVersion": { "action": "지금 업그레이드", "hasNew": "사용 가능한 업데이트가 있습니다", "newVersion": "새 버전 사용 가능: {{version}}" - }, - "warp": "줄바꿈" + } } diff --git a/locales/ru_RU/chat.json b/locales/ru_RU/chat.json new file mode 100644 index 000000000000..a629dad9b57f --- /dev/null +++ b/locales/ru_RU/chat.json @@ -0,0 +1,55 @@ +{ + "agentDefaultMessage": "Привет, я **{{name}}**, ты можешь начать разговор со мной прямо сейчас или перейти к [настройкам помощника](/chat/settings#session={{id}}), чтобы улучшить мою информацию.", + "agentDefaultMessageWithSystemRole": "Привет, я **{{name}}**, {{systemRole}}, давай начнем разговор!", + "backToBottom": "К последнему сообщению", + "clearCurrentMessages": "Очистить текущий разговор", + "confirmClearCurrentMessages": "Вы собираетесь очистить текущий разговор, после этого его нельзя будет восстановить. Подтвердите свое действие.", + "confirmRemoveSessionItemAlert": "Вы собираетесь удалить этого помощника, после этого его нельзя будет восстановить. Подтвердите свое действие.", + "defaultAgent": "Пользовательский помощник", + "defaultSession": "Пользовательский помощник", + "historyRange": "История сообщений", + "inbox": { + "defaultMessage": "Привет, я твой интеллектуальный помощник. Ты можешь задать мне любой вопрос, и я постараюсь ответить на него. Если тебе нужен более профессиональный или настроенный помощник, нажми на `+`, чтобы создать пользовательского помощника.", + "desc": "Включи кластер мозгов и разгори искру мысли. Твой интеллектуальный помощник, готовый общаться о всем здесь", + "title": "Просто поболтаем" + }, + "newAgent": "Создать помощника", + "noDescription": "Нет описания", + "regenerate": "Сгенерировать заново", + "roleAndArchive": "Роль и архив", + "searchAgentPlaceholder": "Поиск помощников и разговоров...", + "send": "Отправить", + "sendPlaceholder": "Введите текст сообщения...", + "shareModal": { + "download": "Скачать скриншот", + "imageType": "Тип изображения", + "screenshot": "Скриншот", + "settings": "Настройки экспорта", + "shareToShareGPT": "Создать ссылку ShareGPT для обмена", + "withBackground": "С фоновым изображением", + "withFooter": "С нижним колонтитулом", + "withPluginInfo": "С информацией о плагине", + "withSystemRole": "С указанием роли помощника" + }, + "stop": "Остановить", + "temp": "Временный", + "tokenDetail": "Роль помощника: {{systemRoleToken}} · История сообщений: {{chatsToken}}", + "tokenTag": { + "overload": "Превышение лимита", + "remained": "Осталось", + "used": "Использовано" + }, + "topic": { + "confirmRemoveTopic": "Вы собираетесь удалить эту тему, после этого ее нельзя будет восстановить. Подтвердите свое действие.", + "defaultTitle": "Стандартная тема", + "saveCurrentMessages": "Сохранить текущий разговор как тему", + "searchPlaceholder": "Поиск темы...", + "title": "Тема" + }, + "translate": { + "clear": "Очистить перевод" + }, + "translateTo": "Перевести на", + "updateAgent": "Обновить информацию о помощнике", + "warp": "Перенос строки" +} diff --git a/locales/ru_RU/common.json b/locales/ru_RU/common.json index bd54fedaca74..c843f5ee2ab7 100644 --- a/locales/ru_RU/common.json +++ b/locales/ru_RU/common.json @@ -2,20 +2,15 @@ "about": "Наш Github", "advanceSettings": "Дополнительные настройки", "agentDefaultMessage": "Здравствуйте, я **{{name}}**. Вы можете начать общаться со мной прямо сейчас или перейти на [Assistant Settings](/chat/settings#session={{id}}) для моей настройки.", - "agentDefaultMessageWithSystemRole": "Здравствуйте, Я **{{name}}**, {{systemRole}}. Давайте начнем общаться!", - "agentMaxToken": "Максимальная длина запроса", "agentModel": "Модель", "agentProfile": "Информация о помощнике", "appInitializing": "LobeChat запускается, пожалуйста, подождите...", "archive": "Архив", "autoGenerate": "Автогенерация", "autoGenerateTooltip": "Автогенерация описания помощника на основе подсказок", - "backToBottom": "Перейти к последним сообщениям", "cancel": "Отмена", "changelog": "Журнал изменений", - "clearCurrentMessages": "Очистить сообщения текущего сеанса", "close": "Закрывать", - "confirmClearCurrentMessages": "Вы собираетесь удалить сообщения текущего сеанса? После очистки их невозможно восстановить. Пожалуйста, подтвердите вашу операцию.", "confirmRemoveSessionItemAlert": "Вы собираетесь удалить этого помощника? После удаления его невозможно восстановить. Пожалуйста, подтвердите вашу операцию.", "copy": "Копировать", "copySuccess": "Скопировано", @@ -35,16 +30,17 @@ "feedback": "Обратная связь", "historyRange": "Исторический диапазон", "import": "Импорт конфига", - "inbox": { - "defaultMessage": "Hello, I'm your intelligent assistant. You can ask me any questions and I will do my best to answer you. If you need a more professional or customized assistant, you can click `+` to create a custom assistant.", - "desc": "Activate the brain cluster and spark your thinking. Your intelligent assistant is here to communicate with you about everything.", - "title": "Chat Freely" + "lang": { + "en": "Английский", + "en-US": "Английский", + "ja-JP": "Японский", + "ko-KR": "Корейский", + "ru-RU": "Русский", + "zh": "Китайский (упрощенный)", + "zh-CN": "Китайский (упрощенный)", + "zh-TW": "Китайский (традиционный)" }, - "message": { - "function_loading": "Запрос плагина в процессе..." - }, - "moreSetting": "Больше настроек...", - "newAgent": "Новый ассистент", + "layoutInitializing": "Идет загрузка макета...", "noDescription": "Нет описания", "ok": "ОК", "password": "пароль", @@ -54,51 +50,21 @@ "rename": "Переименовать", "reset": "Сброс", "retry": "Повторить", - "roleAndArchive": "Роли и архивы", - "searchAgentPlaceholder": "Поисковые помощники и беседы...", "send": "Отправить", - "sendPlaceholder": "Введите ваше сообщение...", "sessionList": "Список помощников", "setting": "Настройки", "share": "Поделиться", - "shareModal": { - "download": "Скачать скриншот", - "imageType": "Тип изображения", - "screenshot": "Скриншот", - "settings": "Настройки экспорта", - "withBackground": "С фоновым изображением", - "withPluginInfo": "С информацией о плагине", - "withSystemRole": "С настройками роли помощника", - "withFooter": "с подвалом", - "shareToShareGPT": "Создать ссылку для обмена ShareGPT" - }, "stop": "Остановить", - "switchMobileLayout": "Переключение на мобильный макет...", "tab": { "chat": "Чат", "market": "Магазин ассистентов", "setting": "Настройки" }, "temp": "Временный", - "tokenDetail": "Установление ролей: {{systemRoleToken}} · История сообщений: {{chatsToken}}", - "tokenTag": { - "overload": "Превышение лимита", - "remained": "Осталось", - "used": "Использовано" - }, - "topic": { - "confirmRemoveTopic": "Вы собираетесь удалить эту тему? После удаления он не может быть восстановлен. Пожалуйста, действуйте с осторожностью.", - "defaultTitle": "Default", - "saveCurrentMessages": "Сохранить текущую сессию в качестве темы", - "searchPlaceholder": "Поиск тем...", - "title": "Тема" - }, "updateAgent": "Обновление информации о помощнике", - "updatePrompt": "Обновление подсказок", "upgradeVersion": { "action": "Обновить сейчас", "hasNew": "Доступно обновление", "newVersion": "Доступна новая версия: {{version}}" - }, - "warp": "Разрыв строки" + } } diff --git a/locales/zh_CN/chat.json b/locales/zh_CN/chat.json new file mode 100644 index 000000000000..e599f8ca5f76 --- /dev/null +++ b/locales/zh_CN/chat.json @@ -0,0 +1,55 @@ +{ + "agentDefaultMessage": "你好,我是 **{{name}}**,你可以立即与我开始对话,也可以前往 [助手设置](/chat/settings#session={{id}}) 完善我的信息。", + "agentDefaultMessageWithSystemRole": "你好,我是 **{{name}}**,{{systemRole}},让我们开始对话吧!", + "backToBottom": "查看最新消息", + "clearCurrentMessages": "清空当前会话消息", + "confirmClearCurrentMessages": "即将清空当前会话消息,清空后将无法找回,请确认你的操作", + "confirmRemoveSessionItemAlert": "即将删除该助手,删除后该将无法找回,请确认你的操作", + "defaultAgent": "自定义助手", + "defaultSession": "自定义助手", + "historyRange": "历史范围", + "inbox": { + "defaultMessage": "你好,我是你的智能助手,你可以问我任何问题,我会尽力回答你。如果需要获得更加专业或定制的助手,可以点击`+`创建自定义助手", + "desc": "开启大脑集群,激发思维火花。你的智能助理,在这里与你交流一切", + "title": "随便聊聊" + }, + "newAgent": "新建助手", + "noDescription": "暂无描述", + "regenerate": "重新生成", + "roleAndArchive": "角色与记录", + "searchAgentPlaceholder": "搜索助手和对话...", + "send": "发送", + "sendPlaceholder": "输入聊天内容...", + "shareModal": { + "download": "下载截图", + "imageType": "图片格式", + "screenshot": "截图", + "settings": "导出设置", + "shareToShareGPT": "生成 ShareGPT 分享链接", + "withBackground": "包含背景图片", + "withFooter": "包含页脚", + "withPluginInfo": "包含插件信息", + "withSystemRole": "包含助手角色设定" + }, + "stop": "停止", + "temp": "临时", + "tokenDetail": "角色设定: {{systemRoleToken}} · 历史消息: {{chatsToken}}", + "tokenTag": { + "overload": "超过限制", + "remained": "剩余", + "used": "使用" + }, + "topic": { + "confirmRemoveTopic": "即将删除该话题,删除后将不可恢复,请谨慎操作。", + "defaultTitle": "默认话题", + "saveCurrentMessages": "将当前会话保存为话题", + "searchPlaceholder": "搜索话题...", + "title": "话题" + }, + "translate": { + "clear": "删除翻译" + }, + "translateTo": "翻译", + "updateAgent": "更新助理信息", + "warp": "换行" +} diff --git a/locales/zh_CN/common.json b/locales/zh_CN/common.json index bcb0f2445d2c..b5d36accfd85 100644 --- a/locales/zh_CN/common.json +++ b/locales/zh_CN/common.json @@ -1,8 +1,6 @@ { "about": "关于", "advanceSettings": "高级设置", - "agentDefaultMessage": "你好,我是 **{{name}}**,你可以立即与我开始对话,也可以前往 [助手设置](/chat/settings#session={{id}}) 完善我的信息。", - "agentDefaultMessageWithSystemRole": "你好,我是 **{{name}}**,{{systemRole}},让我们开始对话吧!", "agentMaxToken": "会话最大长度", "agentModel": "模型", "agentProfile": "助手信息", @@ -10,12 +8,9 @@ "archive": "归档", "autoGenerate": "自动补全", "autoGenerateTooltip": "基于提示词自动补全助手描述", - "backToBottom": "查看最新消息", "cancel": "取消", "changelog": "更新日志", - "clearCurrentMessages": "清空当前会话消息", "close": "关闭", - "confirmClearCurrentMessages": "即将清空当前会话消息,清空后将无法找回,请确认你的操作", "confirmRemoveSessionItemAlert": "即将删除该助手,删除后该将无法找回,请确认你的操作", "copy": "复制", "copySuccess": "复制成功", @@ -35,16 +30,17 @@ "feedback": "反馈与建议", "historyRange": "历史范围", "import": "导入配置", - "inbox": { - "defaultMessage": "你好,我是你的智能助手,你可以问我任何问题,我会尽力回答你。如果需要获得更加专业或定制的助手,可以点击`+`创建自定义助手", - "desc": "开启大脑集群,激发思维火花。你的智能助理,在这里与你交流一切", - "title": "随便聊聊" + "lang": { + "en": "英语", + "en-US": "英语", + "ja-JP": "日语", + "ko-KR": "韩语", + "ru-RU": "俄语", + "zh": "简体中文", + "zh-CN": "简体中文", + "zh-TW": "繁体中文" }, - "message": { - "function_loading": "插件请求中..." - }, - "moreSetting": "更多设置...", - "newAgent": "新建助手", + "layoutInitializing": "正在加载布局...", "noDescription": "暂无描述", "ok": "确定", "password": "密码", @@ -54,51 +50,21 @@ "rename": "重命名", "reset": "重置", "retry": "重试", - "roleAndArchive": "角色与记录", - "searchAgentPlaceholder": "搜索助手和对话...", "send": "发送", - "sendPlaceholder": "输入聊天内容...", "sessionList": "助手列表", "setting": "设置", "share": "分享", - "shareModal": { - "download": "下载截图", - "imageType": "图片格式", - "screenshot": "截图", - "settings": "导出设置", - "shareToShareGPT": "生成 ShareGPT 分享链接", - "withBackground": "包含背景图片", - "withFooter": "包含页脚", - "withPluginInfo": "包含插件信息", - "withSystemRole": "包含助手角色设定" - }, "stop": "停止", - "switchMobileLayout": "正在切换到移动端布局...", "tab": { "chat": "会话", "market": "发现", "setting": "设置" }, "temp": "临时", - "tokenDetail": "角色设定: {{systemRoleToken}} · 历史消息: {{chatsToken}}", - "tokenTag": { - "overload": "超过限制", - "remained": "剩余", - "used": "使用" - }, - "topic": { - "confirmRemoveTopic": "即将删除该话题,删除后将不可恢复,请谨慎操作。", - "defaultTitle": "默认话题", - "saveCurrentMessages": "将当前会话保存为话题", - "searchPlaceholder": "搜索话题...", - "title": "话题" - }, "updateAgent": "更新助理信息", - "updatePrompt": "更新提示词", "upgradeVersion": { "action": "立即升级", "hasNew": "有可用更新", "newVersion": "有新版本可用:{{version}}" - }, - "warp": "换行" + } } diff --git a/locales/zh_TW/chat.json b/locales/zh_TW/chat.json new file mode 100644 index 000000000000..9bc4029d452d --- /dev/null +++ b/locales/zh_TW/chat.json @@ -0,0 +1,55 @@ +{ + "agentDefaultMessage": "妳好,我是 **{{name}}**,妳可以立即與我開始對話,也可以前往 [助手設定](/chat/settings#session={{id}}) 完善我的資訊。", + "agentDefaultMessageWithSystemRole": "妳好,我是 **{{name}}**,{{systemRole}},讓我們開始對話吧!", + "backToBottom": "查看最新訊息", + "clearCurrentMessages": "清空當前會話訊息", + "confirmClearCurrentMessages": "即將清空當前會話訊息,清空後將無法找回,請確認妳的操作", + "confirmRemoveSessionItemAlert": "即將刪除該助手,刪除後該將無法找回,請確認妳的操作", + "defaultAgent": "自定義助手", + "defaultSession": "自定義助手", + "historyRange": "歷史範圍", + "inbox": { + "defaultMessage": "妳好,我是妳的智能助手,妳可以問我任何問題,我會盡力回答妳。如果需要獲得更加專業或定制的助手,可以點擊`+`創建自定義助手", + "desc": "開啟大腦集群,激發思維火花。妳的智能助理,在這裡與妳交流一切", + "title": "隨便聊聊" + }, + "newAgent": "新建助手", + "noDescription": "暫無描述", + "regenerate": "重新生成", + "roleAndArchive": "角色與記錄", + "searchAgentPlaceholder": "搜索助手和對話...", + "send": "發送", + "sendPlaceholder": "輸入聊天內容...", + "shareModal": { + "download": "下載截圖", + "imageType": "圖片格式", + "screenshot": "截圖", + "settings": "導出設定", + "shareToShareGPT": "生成 ShareGPT 分享鏈接", + "withBackground": "包含背景圖片", + "withFooter": "包含頁腳", + "withPluginInfo": "包含插件信息", + "withSystemRole": "包含助手角色設定" + }, + "stop": "停止", + "temp": "臨時", + "tokenDetail": "角色設定: {{systemRoleToken}} · 歷史訊息: {{chatsToken}}", + "tokenTag": { + "overload": "超過限制", + "remained": "剩餘", + "used": "使用" + }, + "topic": { + "confirmRemoveTopic": "即將刪除該話題,刪除後將不可恢復,請謹慎操作。", + "defaultTitle": "默認話題", + "saveCurrentMessages": "將當前會話保存為話題", + "searchPlaceholder": "搜索話題...", + "title": "話題" + }, + "translate": { + "clear": "刪除翻譯" + }, + "translateTo": "翻譯", + "updateAgent": "更新助理資訊", + "warp": "換行" +} diff --git a/locales/zh_TW/common.json b/locales/zh_TW/common.json index 8006b5a2f102..9ba13c9d832c 100644 --- a/locales/zh_TW/common.json +++ b/locales/zh_TW/common.json @@ -1,104 +1,70 @@ { "about": "關於", "advanceSettings": "進階設定", - "agentDefaultMessage": "嗨,我是 **{{name}}**。您可以立即與我開始對話,或是前往 [助理設定](/chat/settings#session={{id}}) 完善我的資訊。", - "agentDefaultMessageWithSystemRole": "嗨,我是 **{{name}}**,{{systemRole}}。讓我們開始對話吧!", "agentMaxToken": "最大對話長度", "agentModel": "模型", - "agentProfile": "助理資訊", - "appInitializing": "LobeChat 正在初始化,請稍候...", + "agentProfile": "助手資訊", + "appInitializing": "LobeChat 正在啟動,請稍候...", "archive": "歸檔", - "autoGenerate": "自動產生", - "autoGenerateTooltip": "根據提示自動產生助理描述", - "backToBottom": "回到最新訊息", + "autoGenerate": "自動生成", + "autoGenerateTooltip": "基於提示詞自動生成助手描述", "cancel": "取消", "changelog": "更新日誌", - "clearCurrentMessages": "清除目前的對話訊息", "close": "關閉", - "confirmClearCurrentMessages": "您將清除目前的對話訊息。一旦清除,將無法恢復。請確認您的操作。", - "confirmRemoveSessionItemAlert": "您將刪除此助理。一旦刪除,將無法恢復。請確認您的操作。", + "confirmRemoveSessionItemAlert": "即將刪除該助手,刪除後將無法找回,請確認您的操作", "copy": "複製", "copySuccess": "複製成功", - "defaultAgent": "自訂助理", - "defaultSession": "自訂助理", + "defaultAgent": "自定義助手", + "defaultSession": "自定義助手", "delete": "刪除", "edit": "編輯", "export": "匯出設定", "exportType": { - "agent": "匯出助理設定", - "agentWithMessage": "匯出助理與訊息", - "all": "匯出全域設定與所有助理資料", - "allAgent": "匯出所有助理設定", - "allAgentWithMessage": "匯出所有助理與訊息", + "agent": "匯出助手設定", + "agentWithMessage": "匯出助手和訊息", + "all": "匯出全域設定和所有助手資料", + "allAgent": "匯出所有助手設定", + "allAgentWithMessage": "匯出所有助手和訊息", "globalSetting": "匯出全域設定" }, - "feedback": "意見回饋", + "feedback": "回饋與建議", "historyRange": "歷史範圍", "import": "匯入設定", - "inbox": { - "defaultMessage": "您好,我是您的智慧助理。您可以問我任何問題,我會盡力回答您。如果您需要更專業或自訂的助理,您可以點選 `+` 來建立一個自訂助理。", - "desc": "啟動思維並激發你的創意。你的智慧助理已經準備好與你討論所有事情。", - "title": "隨便聊聊" + "lang": { + "en": "英語", + "en-US": "英語", + "ja-JP": "日語", + "ko-KR": "韓語", + "ru-RU": "俄語", + "zh": "簡體中文", + "zh-CN": "簡體中文", + "zh-TW": "繁體中文" }, - "message": { - "function_loading": "外掛請求進行中..." - }, - "moreSetting": "更多設定...", - "newAgent": "新助理", - "noDescription": "無描述", + "layoutInitializing": "正在載入佈局...", + "noDescription": "暫無描述", "ok": "確定", "password": "密碼", "pin": "置頂", "pinOff": "取消置頂", - "regenerate": "重新產生", - "rename": "重新命名", - "reset": "重設", + "regenerate": "重新生成", + "rename": "重命名", + "reset": "重置", "retry": "重試", - "roleAndArchive": "角色與歸檔", - "searchAgentPlaceholder": "搜尋助理與對話...", - "send": "傳送", - "sendPlaceholder": "輸入聊天內容...", - "sessionList": "助理列表", + "send": "發送", + "sessionList": "助手列表", "setting": "設定", "share": "分享", - "shareModal": { - "download": "下載截圖", - "imageType": "圖片格式", - "screenshot": "截圖", - "settings": "匯出設定", - "withBackground": "包含背景圖片", - "withPluginInfo": "包含插件資訊", - "withSystemRole": "包含助手角色設定", - "withFooter": "包含頁腳", - "shareToShareGPT": "生成 ShareGPT 分享連結" - }, "stop": "停止", - "switchMobileLayout": "正在切換到行動端佈局...", "tab": { "chat": "聊天", "market": "探索", "setting": "設定" }, "temp": "臨時", - "tokenDetail": "角色設定:{{systemRoleToken}} · 訊息歷史:{{chatsToken}}", - "tokenTag": { - "overload": "超過限制", - "remained": "剩餘", - "used": "已使用" - }, - "topic": { - "confirmRemoveTopic": "您將刪除此主題。一旦刪除,將無法恢復。請小心操作。", - "defaultTitle": "預設主題", - "saveCurrentMessages": "將目前的對話儲存為主題", - "searchPlaceholder": "搜尋主題...", - "title": "主題" - }, "updateAgent": "更新助理資訊", - "updatePrompt": "更新提示", "upgradeVersion": { "action": "立即升級", "hasNew": "有可用更新", "newVersion": "有新版本可用:{{version}}" - }, - "warp": "換行" + } } diff --git a/package.json b/package.json index 86c3c7c6763f..cd1789e340cb 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,7 @@ "antd-style": "^3.5", "brotli-wasm": "^1", "chroma-js": "^2", + "copy-to-clipboard": "^3.3.3", "dayjs": "^1", "emoji-mart": "^5", "fast-deep-equal": "^3", diff --git a/src/app/chat/(desktop)/features/ChatHeader.tsx b/src/app/chat/(desktop)/features/ChatHeader.tsx index b1a1bbc0f3f6..bd4a870c113e 100644 --- a/src/app/chat/(desktop)/features/ChatHeader.tsx +++ b/src/app/chat/(desktop)/features/ChatHeader.tsx @@ -19,7 +19,7 @@ const Header = memo(() => { const init = useSessionChatInit(); const router = useRouter(); - const { t } = useTranslation('common'); + const { t } = useTranslation('chat'); const [isInbox, title, description, avatar, backgroundColor, model, plugins] = useSessionStore( (s) => [ diff --git a/src/app/chat/(desktop)/features/SessionHeader.tsx b/src/app/chat/(desktop)/features/SessionHeader.tsx index 3d949efdc40a..9789f00582ca 100644 --- a/src/app/chat/(desktop)/features/SessionHeader.tsx +++ b/src/app/chat/(desktop)/features/SessionHeader.tsx @@ -21,7 +21,7 @@ export const useStyles = createStyles(({ css, token }) => ({ const Header = memo(() => { const { styles } = useStyles(); - const { t } = useTranslation('common'); + const { t } = useTranslation('chat'); const [createSession] = useSessionStore((s) => [s.createSession]); return ( diff --git a/src/app/chat/(mobile)/features/ChatHeader.tsx b/src/app/chat/(mobile)/features/ChatHeader.tsx index 73096884e534..3f7ac442ba13 100644 --- a/src/app/chat/(mobile)/features/ChatHeader.tsx +++ b/src/app/chat/(mobile)/features/ChatHeader.tsx @@ -13,7 +13,7 @@ import { pathString } from '@/utils/url'; import ShareButton from '../../features/ChatHeader/ShareButton'; const MobileHeader = memo(() => { - const { t } = useTranslation('common'); + const { t } = useTranslation('chat'); const router = useRouter(); const [isInbox, title] = useSessionStore((s) => [ diff --git a/src/app/chat/(mobile)/features/TopicList.tsx b/src/app/chat/(mobile)/features/TopicList.tsx index 407acb8773d8..05d5dd406d51 100644 --- a/src/app/chat/(mobile)/features/TopicList.tsx +++ b/src/app/chat/(mobile)/features/TopicList.tsx @@ -12,7 +12,7 @@ const Topics = memo(() => { s.toggleMobileTopic, ]); - const { t } = useTranslation('common'); + const { t } = useTranslation('chat'); return ( toggleConfig(false)} open={showAgentSettings} title={t('topic.title')}> diff --git a/src/app/chat/features/ChatHeader/ShareButton/Inner.tsx b/src/app/chat/features/ChatHeader/ShareButton/Inner.tsx index 093900f02a91..13b447b6c1f6 100644 --- a/src/app/chat/features/ChatHeader/ShareButton/Inner.tsx +++ b/src/app/chat/features/ChatHeader/ShareButton/Inner.tsx @@ -24,7 +24,7 @@ const Inner = memo(() => { const [withFooter, setWithFooter] = useState(false); const [imageType, setImageType] = useState(ImageType.JPG); const [tab, setTab] = useState(Tab.Screenshot); - const { t } = useTranslation('common'); + const { t } = useTranslation('chat'); const avatar = useGlobalStore((s) => s.settings.avatar); const [shareLoading, shareToShareGPT] = useSessionStore((s) => [ diff --git a/src/app/chat/features/ChatHeader/ShareButton/Preview.tsx b/src/app/chat/features/ChatHeader/ShareButton/Preview.tsx index ce8a70fc503a..202ffe987375 100644 --- a/src/app/chat/features/ChatHeader/ShareButton/Preview.tsx +++ b/src/app/chat/features/ChatHeader/ShareButton/Preview.tsx @@ -62,7 +62,7 @@ const Preview = memo(({ withSystemRole, imageType, withBackground, agentSelectors.currentAgentPlugins(s), agentSelectors.currentAgentSystemRole(s), ]); - const { t } = useTranslation('common'); + const { t } = useTranslation('chat'); const { styles } = useStyles(withBackground); const displayTitle = isInbox ? t('inbox.title') : title; diff --git a/src/app/chat/features/ChatInputContent/ActionBar/ActionRight.tsx b/src/app/chat/features/ChatInputContent/ActionBar/ActionRight.tsx index 5ac9549680ae..a211847f94c7 100644 --- a/src/app/chat/features/ChatInputContent/ActionBar/ActionRight.tsx +++ b/src/app/chat/features/ChatInputContent/ActionBar/ActionRight.tsx @@ -29,15 +29,15 @@ const ActionsRight = memo(() => { cancelText={t('cancel', { ns: 'common' })} okButtonProps={{ danger: true }} okText={t('ok', { ns: 'common' })} - onConfirm={clearMessage} + onConfirm={() => clearMessage()} placement={'topRight'} - title={t('confirmClearCurrentMessages', { ns: 'common' })} + title={t('confirmClearCurrentMessages', { ns: 'chat' })} > ) as any + () as any } /> diff --git a/src/app/chat/features/ChatInputContent/ActionBar/Token.tsx b/src/app/chat/features/ChatInputContent/ActionBar/Token.tsx index f284d7f9e592..184176fcc980 100644 --- a/src/app/chat/features/ChatInputContent/ActionBar/Token.tsx +++ b/src/app/chat/features/ChatInputContent/ActionBar/Token.tsx @@ -9,7 +9,7 @@ import { agentSelectors, chatSelectors } from '@/store/session/selectors'; import { LanguageModel } from '@/types/llm'; const Token = memo<{ input: string }>(({ input }) => { - const { t } = useTranslation('common'); + const { t } = useTranslation('chat'); const inputTokenCount = useTokenCount(input); diff --git a/src/app/chat/features/ChatInputContent/Footer/SaveTopic.tsx b/src/app/chat/features/ChatInputContent/Footer/SaveTopic.tsx index f3ee422e26fa..9d5205fca01d 100644 --- a/src/app/chat/features/ChatInputContent/Footer/SaveTopic.tsx +++ b/src/app/chat/features/ChatInputContent/Footer/SaveTopic.tsx @@ -11,7 +11,7 @@ import { PREFIX_KEY, SAVE_TOPIC_KEY } from '@/const/hotkeys'; import { useSessionStore } from '@/store/session'; const SaveTopic = memo(() => { - const { t } = useTranslation('common'); + const { t } = useTranslation('chat'); const [hasTopic, saveToTopic] = useSessionStore((s) => [!!s.activeTopicId, s.saveToTopic]); const { mobile } = useResponsive(); diff --git a/src/app/chat/features/ChatInputContent/Footer/index.tsx b/src/app/chat/features/ChatInputContent/Footer/index.tsx index e6fa3dc60ece..3db39302af84 100644 --- a/src/app/chat/features/ChatInputContent/Footer/index.tsx +++ b/src/app/chat/features/ChatInputContent/Footer/index.tsx @@ -9,7 +9,7 @@ import SaveTopic from './SaveTopic'; const Footer = memo(() => { const theme = useTheme(); - const { t } = useTranslation('common'); + const { t } = useTranslation('chat'); return ( <> diff --git a/src/app/chat/features/ChatInputContent/index.tsx b/src/app/chat/features/ChatInputContent/index.tsx index 8d00fe936bc8..ae672189e8df 100644 --- a/src/app/chat/features/ChatInputContent/index.tsx +++ b/src/app/chat/features/ChatInputContent/index.tsx @@ -57,7 +57,7 @@ const ChatInputContent = memo( onInputChange={setMessage} onSend={sendMessage} onStop={stopGenerateMessage} - placeholder={t('sendPlaceholder')} + placeholder={t('sendPlaceholder', { ns: 'chat' })} text={{ send: t('send'), stop: t('stop'), diff --git a/src/app/chat/features/Conversation/ChatList/Actions/Assistant.tsx b/src/app/chat/features/Conversation/ChatList/Actions/Assistant.tsx new file mode 100644 index 000000000000..01367c0fdb15 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Actions/Assistant.tsx @@ -0,0 +1,22 @@ +import { ActionIconGroup, RenderAction, useChatListActionsBar } from '@lobehub/ui'; +import { memo } from 'react'; + +import { ErrorActionsBar } from './Error'; +import { useCustomActions } from './customAction'; + +export const AssistantActionsBar: RenderAction = memo(({ text, id, onActionClick, error }) => { + const { regenerate, edit, copy, divider, del } = useChatListActionsBar(text); + const { translate } = useCustomActions(); + if (id === 'default') return; + + if (error) return ; + + return ( + + ); +}); diff --git a/src/app/chat/features/Conversation/ChatList/Actions/Error.tsx b/src/app/chat/features/Conversation/ChatList/Actions/Error.tsx new file mode 100644 index 000000000000..a31fa0c84be6 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Actions/Error.tsx @@ -0,0 +1,15 @@ +import { ActionIconGroup, useChatListActionsBar } from '@lobehub/ui'; +import { ActionsBarProps } from '@lobehub/ui/es/ChatList/ActionsBar'; +import { memo } from 'react'; + +export const ErrorActionsBar = memo(({ text, onActionClick }) => { + const { regenerate, del } = useChatListActionsBar(text); + + return ( + + ); +}); diff --git a/src/app/chat/features/Conversation/ChatList/Messages/System.tsx b/src/app/chat/features/Conversation/ChatList/Actions/Fallback.tsx similarity index 77% rename from src/app/chat/features/Conversation/ChatList/Messages/System.tsx rename to src/app/chat/features/Conversation/ChatList/Actions/Fallback.tsx index 9cd4cb9edb04..33f15c4bb3ea 100644 --- a/src/app/chat/features/Conversation/ChatList/Messages/System.tsx +++ b/src/app/chat/features/Conversation/ChatList/Actions/Fallback.tsx @@ -1,7 +1,7 @@ import { ActionIconGroup, RenderAction, useChatListActionsBar } from '@lobehub/ui'; import { memo } from 'react'; -export const SystemActionsBar: RenderAction = memo(({ text, onActionClick }) => { +export const DefaultActionsBar: RenderAction = memo(({ text, onActionClick }) => { const { del } = useChatListActionsBar(text); return ( diff --git a/src/app/chat/features/Conversation/ChatList/Actions/Function.tsx b/src/app/chat/features/Conversation/ChatList/Actions/Function.tsx new file mode 100644 index 000000000000..e05f3fe28881 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Actions/Function.tsx @@ -0,0 +1,14 @@ +import { ActionIconGroup, RenderAction, useChatListActionsBar } from '@lobehub/ui'; +import { memo } from 'react'; + +export const FunctionActionsBar: RenderAction = memo(({ text, onActionClick }) => { + const { regenerate, divider, del } = useChatListActionsBar(text); + return ( + + ); +}); diff --git a/src/app/chat/features/Conversation/ChatList/Messages/User.tsx b/src/app/chat/features/Conversation/ChatList/Actions/User.tsx similarity index 69% rename from src/app/chat/features/Conversation/ChatList/Messages/User.tsx rename to src/app/chat/features/Conversation/ChatList/Actions/User.tsx index 3084bf3dc2d3..74e2b736f2e9 100644 --- a/src/app/chat/features/Conversation/ChatList/Messages/User.tsx +++ b/src/app/chat/features/Conversation/ChatList/Actions/User.tsx @@ -1,11 +1,16 @@ import { ActionIconGroup, RenderAction, useChatListActionsBar } from '@lobehub/ui'; import { memo } from 'react'; +import { useCustomActions } from './customAction'; + export const UserActionsBar: RenderAction = memo(({ text, onActionClick }) => { const { regenerate, edit, copy, divider, del } = useChatListActionsBar(text); + const { translate } = useCustomActions(); + + return ( { + const { t } = useTranslation('chat'); + + const translate = { + // children: localeOptions.map((i) => ({ + // key: i.value, + // label: t(`lang.${i.value}`, { ns: 'common' }), + // })), + icon: LanguagesIcon, + key: 'translate', + label: t('translateTo'), + } as ActionIconGroupItems; + + return { + translate, + }; +}; diff --git a/src/app/chat/features/Conversation/ChatList/Actions/index.ts b/src/app/chat/features/Conversation/ChatList/Actions/index.ts new file mode 100644 index 000000000000..a87084cfc5e2 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Actions/index.ts @@ -0,0 +1,13 @@ +import { ChatListProps } from '@lobehub/ui'; + +import { AssistantActionsBar } from './Assistant'; +import { DefaultActionsBar } from './Fallback'; +import { FunctionActionsBar } from './Function'; +import { UserActionsBar } from './User'; + +export const renderActions: ChatListProps['renderActions'] = { + assistant: AssistantActionsBar, + function: FunctionActionsBar, + system: DefaultActionsBar, + user: UserActionsBar, +}; diff --git a/src/app/chat/features/Conversation/ChatList/Extras/Assistant.tsx b/src/app/chat/features/Conversation/ChatList/Extras/Assistant.tsx new file mode 100644 index 000000000000..c416dfedfe61 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Extras/Assistant.tsx @@ -0,0 +1,39 @@ +import { SiOpenai } from '@icons-pack/react-simple-icons'; +import { RenderMessageExtra, Tag } from '@lobehub/ui'; +import { Divider } from 'antd'; +import { memo } from 'react'; +import { Flexbox } from 'react-layout-kit'; + +import { useSessionStore } from '@/store/session'; +import { agentSelectors } from '@/store/session/selectors'; + +import Translate from './Translate'; + +export const AssistantMessageExtra: RenderMessageExtra = memo(({ extra, id }) => { + const model = useSessionStore(agentSelectors.currentAgentModel); + + const showModelTag = extra?.fromModel && model !== extra?.fromModel; + const hasTranslate = !!extra?.translate; + + const showExtra = showModelTag || hasTranslate; + + const loading = useSessionStore((s) => s.chatLoadingId === id); + + if (!showExtra) return; + + return ( + + {showModelTag && ( +
+ }>{extra?.fromModel as string} +
+ )} + {extra.translate && ( +
+ + +
+ )} +
+ ); +}); diff --git a/src/app/chat/features/Conversation/ChatList/Extras/Translate.tsx b/src/app/chat/features/Conversation/ChatList/Extras/Translate.tsx new file mode 100644 index 000000000000..93553c5e3e05 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Extras/Translate.tsx @@ -0,0 +1,75 @@ +import { ActionIcon, Icon, Markdown, Tag } from '@lobehub/ui'; +import { App } from 'antd'; +import { createStyles } from 'antd-style'; +import copy from 'copy-to-clipboard'; +import { ChevronDown, ChevronUp, ChevronsRight, CopyIcon, TrashIcon } from 'lucide-react'; +import { memo, useState } from 'react'; +import { useTranslation } from 'react-i18next'; +import { Flexbox } from 'react-layout-kit'; + +import { useSessionStore } from '@/store/session'; +import { ChatTranslate } from '@/types/chatMessage'; + +import BubblesLoading from '../Loading'; + +const useStyles = createStyles(({ css }) => ({ + container: css` + margin-top: 8px; + `, +})); + +interface TranslateProps extends ChatTranslate { + id: string; + loading?: boolean; +} + +const Translate = memo(({ content = '', from, to, id, loading }) => { + const { theme } = useStyles(); + const { t } = useTranslation('common'); + const [show, setShow] = useState(true); + const clearTranslate = useSessionStore((s) => s.clearTranslate); + + const { message } = App.useApp(); + return ( + + +
+ + {from ? t(`lang.${from}` as any) : '...'} + + {t(`lang.${to}` as any)} + +
+ + { + copy(content); + message.success(t('copySuccess')); + }} + size={'small'} + title={t('copy')} + /> + { + clearTranslate(id); + }} + size={'small'} + title={t('translate.clear', { ns: 'chat' })} + /> + { + setShow(!show); + }} + size={'small'} + /> + +
+ {!show ? null : loading && !content ? : {content}} +
+ ); +}); + +export default Translate; diff --git a/src/app/chat/features/Conversation/ChatList/Extras/User.tsx b/src/app/chat/features/Conversation/ChatList/Extras/User.tsx new file mode 100644 index 000000000000..420e2b6b11fa --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Extras/User.tsx @@ -0,0 +1,24 @@ +import { RenderMessageExtra } from '@lobehub/ui'; +import { Divider } from 'antd'; +import { memo } from 'react'; +import { Flexbox } from 'react-layout-kit'; + +import { useSessionStore } from '@/store/session'; + +import Translate from './Translate'; + +export const UserMessageExtra: RenderMessageExtra = memo(({ extra, id }) => { + const hasTranslate = !!extra?.translate; + + const loading = useSessionStore((s) => s.chatLoadingId === id); + return ( + + {extra?.translate && ( +
+ + +
+ )} +
+ ); +}); diff --git a/src/app/chat/features/Conversation/ChatList/Extras/index.ts b/src/app/chat/features/Conversation/ChatList/Extras/index.ts new file mode 100644 index 000000000000..2b7fc63ab899 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Extras/index.ts @@ -0,0 +1,9 @@ +import { ChatListProps } from '@lobehub/ui'; + +import { AssistantMessageExtra } from './Assistant'; +import { UserMessageExtra } from './User'; + +export const renderMessagesExtra: ChatListProps['renderMessagesExtra'] = { + assistant: AssistantMessageExtra, + user: UserMessageExtra, +}; diff --git a/src/app/chat/features/Conversation/ChatList/Loading.tsx b/src/app/chat/features/Conversation/ChatList/Loading.tsx new file mode 100644 index 000000000000..adbc08b25533 --- /dev/null +++ b/src/app/chat/features/Conversation/ChatList/Loading.tsx @@ -0,0 +1,53 @@ +import { useTheme } from 'antd-style'; + +const Svg = () => ( + + + + + + + + + + + +); + +const BubblesLoading = () => { + const { colorTextTertiary } = useTheme(); + return ( +
+ +
+ ); +}; + +export default BubblesLoading; diff --git a/src/app/chat/features/Conversation/ChatList/Messages/Assistant.tsx b/src/app/chat/features/Conversation/ChatList/Messages/Assistant.tsx index 70b996fa20d5..943e2f91759e 100644 --- a/src/app/chat/features/Conversation/ChatList/Messages/Assistant.tsx +++ b/src/app/chat/features/Conversation/ChatList/Messages/Assistant.tsx @@ -1,41 +1,18 @@ -import { SiOpenai } from '@icons-pack/react-simple-icons'; -import { - ActionIconGroup, - RenderAction, - RenderMessage, - RenderMessageExtra, - Tag, - useChatListActionsBar, -} from '@lobehub/ui'; -import { createStyles } from 'antd-style'; +import { RenderMessage } from '@lobehub/ui'; import { memo } from 'react'; -import { Flexbox } from 'react-layout-kit'; import { useSessionStore } from '@/store/session'; -import { agentSelectors } from '@/store/session/slices/agentConfig'; -import { chatSelectors } from '@/store/session/slices/chat/selectors'; +import { chatSelectors } from '@/store/session/selectors'; import { isFunctionMessage } from '@/utils/message'; import FunctionCall from '../Plugins/FunctionCall'; -import { DefautMessage } from './Default'; - -const useStyles = createStyles(({ css }) => ({ - container: css` - margin-top: 8px; - `, - plugin: css` - display: flex; - gap: 4px; - align-items: center; - width: fit-content; - `, -})); +import { DefaultMessage } from './Default'; export const AssistantMessage: RenderMessage = memo( ({ id, plugin, function_call, content, ...props }) => { - const genFunctionCallProps = useSessionStore(chatSelectors.currentFunctionCallProps); + const genFunctionCallProps = useSessionStore(chatSelectors.getFunctionMessageParams); - if (!isFunctionMessage(content)) return ; + if (!isFunctionMessage(content)) return ; const fcProps = genFunctionCallProps({ content, function_call, id, plugin }); @@ -46,33 +23,3 @@ export const AssistantMessage: RenderMessage = memo( ); }, ); - -export const AssistantMessageExtra: RenderMessageExtra = memo(({ extra, function_call }) => { - const { styles } = useStyles(); - const model = useSessionStore(agentSelectors.currentAgentModel); - - const hasModelTag = extra?.fromModel && model !== extra?.fromModel; - const hasFuncTag = !!function_call; - if (!(hasModelTag || hasFuncTag)) return; - - return ( - -
- }>{extra?.fromModel as string} -
-
- ); -}); - -export const AssistantActionsBar: RenderAction = memo(({ text, error, id, onActionClick }) => { - const { regenerate, edit, copy, divider, del } = useChatListActionsBar(text); - if (id === 'default') return; - return ( - - ); -}); diff --git a/src/app/chat/features/Conversation/ChatList/Messages/Default.tsx b/src/app/chat/features/Conversation/ChatList/Messages/Default.tsx index 695e4591d0d0..b5d71bbe72c8 100644 --- a/src/app/chat/features/Conversation/ChatList/Messages/Default.tsx +++ b/src/app/chat/features/Conversation/ChatList/Messages/Default.tsx @@ -1,6 +1,12 @@ import { RenderMessage } from '@lobehub/ui'; import { memo } from 'react'; -export const DefautMessage: RenderMessage = memo(({ id, editableContent }) => { +import { LOADING_FLAT } from '@/const/message'; + +import BubblesLoading from '../Loading'; + +export const DefaultMessage: RenderMessage = memo(({ id, editableContent, content }) => { + if (content === LOADING_FLAT) return ; + return
{editableContent}
; }); diff --git a/src/app/chat/features/Conversation/ChatList/Messages/Function.tsx b/src/app/chat/features/Conversation/ChatList/Messages/Function.tsx index 7e61e855454b..2274227000c5 100644 --- a/src/app/chat/features/Conversation/ChatList/Messages/Function.tsx +++ b/src/app/chat/features/Conversation/ChatList/Messages/Function.tsx @@ -1,4 +1,4 @@ -import { ActionIconGroup, RenderAction, RenderMessage, useChatListActionsBar } from '@lobehub/ui'; +import { RenderMessage } from '@lobehub/ui'; import { memo } from 'react'; import { Flexbox } from 'react-layout-kit'; @@ -9,34 +9,15 @@ import FunctionCall from '../Plugins/FunctionCall'; import PluginMessage from '../Plugins/PluginMessage'; export const FunctionMessage: RenderMessage = memo( - ({ id, content, plugin, function_call, ...props }) => { - const genFunctionCallProps = useSessionStore(chatSelectors.currentFunctionCallProps); + ({ id, content, plugin, function_call, name }) => { + const genFunctionCallProps = useSessionStore(chatSelectors.getFunctionMessageParams); const fcProps = genFunctionCallProps({ content, function_call, id, plugin }); return ( - + ); }, ); - -export const FunctionActionsBar: RenderAction = memo(({ text, onActionClick }) => { - const { regenerate, divider, del } = useChatListActionsBar(text); - return ( - - ); -}); diff --git a/src/app/chat/features/Conversation/ChatList/Messages/index.ts b/src/app/chat/features/Conversation/ChatList/Messages/index.ts index 144973820186..8644d239ddde 100644 --- a/src/app/chat/features/Conversation/ChatList/Messages/index.ts +++ b/src/app/chat/features/Conversation/ChatList/Messages/index.ts @@ -1,24 +1,11 @@ import { ChatListProps } from '@lobehub/ui'; -import { AssistantActionsBar, AssistantMessage, AssistantMessageExtra } from './Assistant'; -import { DefautMessage } from './Default'; -import { FunctionActionsBar, FunctionMessage } from './Function'; -import { SystemActionsBar } from './System'; -import { UserActionsBar } from './User'; +import { AssistantMessage } from './Assistant'; +import { DefaultMessage } from './Default'; +import { FunctionMessage } from './Function'; export const renderMessages: ChatListProps['renderMessages'] = { assistant: AssistantMessage, - default: DefautMessage, + default: DefaultMessage, function: FunctionMessage, }; - -export const renderMessagesExtra: ChatListProps['renderMessagesExtra'] = { - assistant: AssistantMessageExtra, -}; - -export const renderActions: ChatListProps['renderActions'] = { - assistant: AssistantActionsBar, - function: FunctionActionsBar, - system: SystemActionsBar, - user: UserActionsBar, -}; diff --git a/src/app/chat/features/Conversation/ChatList/Plugins/FunctionCall.tsx b/src/app/chat/features/Conversation/ChatList/Plugins/FunctionCall.tsx index f116856b340f..77794295b740 100644 --- a/src/app/chat/features/Conversation/ChatList/Plugins/FunctionCall.tsx +++ b/src/app/chat/features/Conversation/ChatList/Plugins/FunctionCall.tsx @@ -30,8 +30,6 @@ const FunctionCall = memo( const pluginAvatar = pluginHelpers.getPluginAvatar(item?.meta); const pluginTitle = pluginHelpers.getPluginTitle(item?.meta); - console.log(item?.meta); - const avatar = pluginAvatar ? ( ) : ( diff --git a/src/app/chat/features/Conversation/ChatList/Plugins/PluginMessage.tsx b/src/app/chat/features/Conversation/ChatList/Plugins/PluginMessage.tsx index ce4a8d96493a..7862983533d1 100644 --- a/src/app/chat/features/Conversation/ChatList/Plugins/PluginMessage.tsx +++ b/src/app/chat/features/Conversation/ChatList/Plugins/PluginMessage.tsx @@ -6,14 +6,15 @@ import { useTranslation } from 'react-i18next'; import { Flexbox } from 'react-layout-kit'; import { usePluginStore } from '@/store/plugin'; -import { ChatMessage } from '@/types/chatMessage'; import IFrameRender from './IFrameRender'; const SystemJsRender = dynamic(() => import('./SystemJsRender'), { ssr: false }); -export interface FunctionMessageProps extends ChatMessage { +export interface FunctionMessageProps { + content: string; loading?: boolean; + name?: string; } const PluginMessage = memo(({ content, name }) => { @@ -29,8 +30,6 @@ const PluginMessage = memo(({ content, name }) => { const contentObj = useMemo(() => (isJSON ? JSON.parse(content) : content), [content]); - // if (!loading) - if (!isJSON) { return ( diff --git a/src/app/chat/features/Conversation/ChatList/index.tsx b/src/app/chat/features/Conversation/ChatList/index.tsx index 502d17f0e07d..ffbbfeba5436 100644 --- a/src/app/chat/features/Conversation/ChatList/index.tsx +++ b/src/app/chat/features/Conversation/ChatList/index.tsx @@ -5,11 +5,14 @@ import { useHotkeys } from 'react-hotkeys-hook'; import { useTranslation } from 'react-i18next'; import { PREFIX_KEY, REGENERATE_KEY } from '@/const/hotkeys'; +import { settingsSelectors, useGlobalStore } from '@/store/global'; import { useSessionChatInit, useSessionStore } from '@/store/session'; import { agentSelectors, chatSelectors } from '@/store/session/selectors'; +import { renderActions } from './Actions'; import { renderErrorMessages } from './Error'; -import { renderActions, renderMessages, renderMessagesExtra } from './Messages'; +import { renderMessagesExtra } from './Extras'; +import { renderMessages } from './Messages'; import SkeletonList from './SkeletonList'; const List = memo(() => { @@ -25,6 +28,7 @@ const List = memo(() => { deleteMessage, resendMessage, dispatchMessage, + translateMessage, ] = useSessionStore((s) => { const config = agentSelectors.currentAgentConfig(s); return [ @@ -35,9 +39,12 @@ const List = memo(() => { s.deleteMessage, s.resendMessage, s.dispatchMessage, + s.translateMessage, ]; }); + const targetLang = useGlobalStore(settingsSelectors.currentLanguage); + const hotkeys = [PREFIX_KEY, REGENERATE_KEY].join('+'); useHotkeys( @@ -63,7 +70,15 @@ const List = memo(() => { loadingId={chatLoadingId} onActionsClick={{ del: ({ id }) => deleteMessage(id), - regenerate: ({ id }) => resendMessage(id), + regenerate: ({ id, error }) => { + resendMessage(id); + + // if this message is an error message, we need to delete it + if (error) deleteMessage(id); + }, + translate: ({ id }) => { + translateMessage(id, targetLang); + }, }} onMessageChange={(id, content) => dispatchMessage({ id, key: 'content', type: 'updateMessage', value: content }) diff --git a/src/app/chat/features/Conversation/index.tsx b/src/app/chat/features/Conversation/index.tsx index 371f71e813c4..560f3d857778 100644 --- a/src/app/chat/features/Conversation/index.tsx +++ b/src/app/chat/features/Conversation/index.tsx @@ -12,8 +12,7 @@ import ChatScrollAnchor from './ScrollAnchor'; const useStyles = createStyles( ({ css, responsive, stylish }) => css` - overflow-x: hidden; - overflow-y: scroll; + overflow: hidden scroll; height: 100%; ${responsive.mobile} { ${stylish.noScrollbar} @@ -29,7 +28,7 @@ interface ConversationProps { const Conversation = memo(({ mobile, chatInput }) => { const ref = useRef(null); - const { t } = useTranslation('common'); + const { t } = useTranslation('chat'); const { styles } = useStyles(); const useFetchPluginList = usePluginStore((s) => s.useFetchPluginList); diff --git a/src/app/chat/features/SessionListContent/Inbox/index.tsx b/src/app/chat/features/SessionListContent/Inbox/index.tsx index d0984261d7af..aa4823326994 100644 --- a/src/app/chat/features/SessionListContent/Inbox/index.tsx +++ b/src/app/chat/features/SessionListContent/Inbox/index.tsx @@ -15,7 +15,7 @@ const { Item } = List; const Inbox = memo(() => { const ref = useRef(null); const isHovering = useHover(ref); - const { t } = useTranslation('common'); + const { t } = useTranslation('chat'); const { mobile } = useResponsive(); const [activeId, activeSession, switchSession] = useSessionStore((s) => [ s.activeId, diff --git a/src/app/chat/features/SessionListContent/List/AddButton.tsx b/src/app/chat/features/SessionListContent/List/AddButton.tsx index 086500399382..d94d3e5848c8 100644 --- a/src/app/chat/features/SessionListContent/List/AddButton.tsx +++ b/src/app/chat/features/SessionListContent/List/AddButton.tsx @@ -8,7 +8,7 @@ import { Flexbox } from 'react-layout-kit'; import { useSessionStore } from '@/store/session'; const AddButton = memo((props) => { - const { t } = useTranslation('common'); + const { t } = useTranslation('chat'); const createSession = useSessionStore((s) => s.createSession); return ( diff --git a/src/app/chat/features/SessionSearchBar/index.tsx b/src/app/chat/features/SessionSearchBar/index.tsx index 5c855bece0c7..0b40fd611173 100644 --- a/src/app/chat/features/SessionSearchBar/index.tsx +++ b/src/app/chat/features/SessionSearchBar/index.tsx @@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next'; import { useSessionStore } from '@/store/session'; const SessionSearchBar = memo(() => { - const { t } = useTranslation('common'); + const { t } = useTranslation('chat'); const [keywords] = useSessionStore((s) => [s.searchKeywords]); const { mobile } = useResponsive(); return ( diff --git a/src/app/chat/features/TopicListContent/Topic/DefaultContent.tsx b/src/app/chat/features/TopicListContent/Topic/DefaultContent.tsx index fea4b31fda32..e6e54151a5a0 100644 --- a/src/app/chat/features/TopicListContent/Topic/DefaultContent.tsx +++ b/src/app/chat/features/TopicListContent/Topic/DefaultContent.tsx @@ -19,7 +19,7 @@ const DefaultContent = memo(() => { - {t('topic.defaultTitle')} + {t('topic.defaultTitle', { ns: 'chat' })} {t('temp')} diff --git a/src/app/chat/features/TopicListContent/Topic/TopicContent.tsx b/src/app/chat/features/TopicListContent/Topic/TopicContent.tsx index 312fd5b63d40..846936ec60a1 100644 --- a/src/app/chat/features/TopicListContent/Topic/TopicContent.tsx +++ b/src/app/chat/features/TopicListContent/Topic/TopicContent.tsx @@ -74,7 +74,7 @@ const TopicContent = memo(({ id, title, fav }) => { onOk: () => { removeTopic(id); }, - title: t('topic.confirmRemoveTopic'), + title: t('topic.confirmRemoveTopic', { ns: 'chat' }), }); }, }, diff --git a/src/app/chat/features/TopicListContent/Topic/index.tsx b/src/app/chat/features/TopicListContent/Topic/index.tsx index 53248204e9b8..b65a7548d52a 100644 --- a/src/app/chat/features/TopicListContent/Topic/index.tsx +++ b/src/app/chat/features/TopicListContent/Topic/index.tsx @@ -54,7 +54,7 @@ export const Topic = () => { {topicsData.map(({ id, favorite, title }) => ( diff --git a/src/app/chat/features/TopicListContent/TopicSearchBar/index.tsx b/src/app/chat/features/TopicListContent/TopicSearchBar/index.tsx index 7d8e7feb9fe6..adced2b7da99 100644 --- a/src/app/chat/features/TopicListContent/TopicSearchBar/index.tsx +++ b/src/app/chat/features/TopicListContent/TopicSearchBar/index.tsx @@ -6,7 +6,7 @@ import { useTranslation } from 'react-i18next'; import { useSessionStore } from '@/store/session'; const TopicSearchBar = memo(() => { - const { t } = useTranslation('common'); + const { t } = useTranslation('chat'); const [keywords] = useSessionStore((s) => [s.topicSearchKeywords]); const { mobile } = useResponsive(); return ( diff --git a/src/app/home/index.tsx b/src/app/home/index.tsx index 6a96275a337f..d06ee4332cf4 100644 --- a/src/app/home/index.tsx +++ b/src/app/home/index.tsx @@ -5,9 +5,9 @@ import { useTranslation } from 'react-i18next'; import FullscreenLoading from '@/components/FullscreenLoading'; const Loading = () => { - const { t } = useTranslation(); + const { t } = useTranslation('common'); - return ; + return ; }; export default Loading; diff --git a/src/prompts/agent.ts b/src/chains/agent.ts similarity index 100% rename from src/prompts/agent.ts rename to src/chains/agent.ts diff --git a/src/chains/chat.ts b/src/chains/chat.ts new file mode 100644 index 000000000000..b1a0a6e9f947 --- /dev/null +++ b/src/chains/chat.ts @@ -0,0 +1,77 @@ +import { chatHelpers } from '@/store/session/helpers'; +import { LanguageModel } from '@/types/llm'; +import { OpenAIChatMessage, OpenAIChatStreamPayload } from '@/types/openai/chat'; + +export const chainSummaryTitle = async ( + messages: OpenAIChatMessage[], +): Promise> => { + const finalMessages: OpenAIChatMessage[] = [ + { + content: + '你是一名擅长会话的助理,你需要将用户的会话总结为 10 个字以内的标题,不需要包含标点符号', + role: 'system', + }, + { + content: `${messages.map((message) => `${message.role}: ${message.content}`).join('\n')} + +请总结上述对话为10个字以内的标题,不需要包含标点符号`, + role: 'user', + }, + ]; + // 如果超过 4k,则使用 GPT3.5 16K 模型 + const tokens = await chatHelpers.getMessagesTokenCount(finalMessages); + let model: LanguageModel | undefined = undefined; + if (tokens > 4000) { + model = LanguageModel.GPT3_5_16K; + } + + return { + messages: finalMessages, + model, + }; +}; + +export const chainTranslate = ( + content: string, + targetLang: string, +): Partial => ({ + messages: [ + { + content: '你是一名擅长翻译的助理,你需要将输入的语言翻译为目标语言', + role: 'system', + }, + { + content: `请将以下内容 ${content},翻译为 ${targetLang} `, + role: 'user', + }, + ], +}); +export const chainLangDetect = (content: string): Partial => ({ + messages: [ + { + content: + '你是一名精通全世界语言的语言专家,你需要识别用户输入的内容,以国际标准 locale 进行输出', + role: 'system', + }, + { + content: '{你好}', + role: 'user', + }, + { + content: 'zh-CN', + role: 'assistant', + }, + { + content: '{hello}', + role: 'user', + }, + { + content: 'en-US', + role: 'assistant', + }, + { + content: `{${content}}`, + role: 'user', + }, + ], +}); diff --git a/src/features/AgentSetting/AgentPrompt/index.tsx b/src/features/AgentSetting/AgentPrompt/index.tsx index 92fb271ce67d..f06921696db6 100644 --- a/src/features/AgentSetting/AgentPrompt/index.tsx +++ b/src/features/AgentSetting/AgentPrompt/index.tsx @@ -42,9 +42,9 @@ const AgentPrompt = memo(() => { maxValue={ModelTokens[model as LanguageModel]} shape={'square'} text={{ - overload: t('tokenTag.overload', { ns: 'common' }), - remained: t('tokenTag.remained', { ns: 'common' }), - used: t('tokenTag.used', { ns: 'common' }), + overload: t('tokenTag.overload', { ns: 'chat' }), + remained: t('tokenTag.remained', { ns: 'chat' }), + used: t('tokenTag.used', { ns: 'chat' }), }} value={systemTokenCount} /> diff --git a/src/features/AgentSetting/store/action.ts b/src/features/AgentSetting/store/action.ts index c8925e392b33..d0c3e6fcc2f2 100644 --- a/src/features/AgentSetting/store/action.ts +++ b/src/features/AgentSetting/store/action.ts @@ -1,6 +1,6 @@ import { StateCreator } from 'zustand/vanilla'; -import { promptPickEmoji, promptSummaryAgentName, promptSummaryDescription } from '@/prompts/agent'; +import { promptPickEmoji, promptSummaryAgentName, promptSummaryDescription } from '@/chains/agent'; import { MetaData } from '@/types/meta'; import { LobeAgentConfig } from '@/types/session'; import { fetchPresetTaskResult } from '@/utils/fetch'; diff --git a/src/layout/ResponsiveLayout.client.tsx b/src/layout/ResponsiveLayout.client.tsx index 6cbb76e35b5b..c9c4b9175cbf 100644 --- a/src/layout/ResponsiveLayout.client.tsx +++ b/src/layout/ResponsiveLayout.client.tsx @@ -15,10 +15,12 @@ const ResponsiveLayout = ({ children, Desktop, Mobile }: ServerResponsiveLayoutP const { t } = useTranslation(); const mobile = useIsMobile(); - return ( + return mobile ? ( }> - {mobile ? {children} : {children}} + {children} + ) : ( + {children} ); }; diff --git a/src/locales/create.ts b/src/locales/create.ts index 83c85dc2e382..58be9b721040 100644 --- a/src/locales/create.ts +++ b/src/locales/create.ts @@ -4,10 +4,11 @@ import { initReactI18next } from 'react-i18next'; import { getClientConfig } from '@/config/client'; import { DEFAULT_LANG, LOBE_LOCALE_COOKIE } from '@/const/locale'; -import resources from '@/locales/resources'; import type { Namespaces } from '@/types/locale'; import { isOnServerSide } from '@/utils/env'; +import { resources } from './options'; + const { I18N_DEBUG, I18N_DEBUG_BROWSER, I18N_DEBUG_SERVER } = getClientConfig(); const debugMode = I18N_DEBUG ?? isOnServerSide ? I18N_DEBUG_SERVER : I18N_DEBUG_BROWSER; diff --git a/src/locales/default/chat.ts b/src/locales/default/chat.ts new file mode 100644 index 000000000000..a98d233666fa --- /dev/null +++ b/src/locales/default/chat.ts @@ -0,0 +1,60 @@ +export default { + agentDefaultMessage: + '你好,我是 **{{name}}**,你可以立即与我开始对话,也可以前往 [助手设置](/chat/settings#session={{id}}) 完善我的信息。', + agentDefaultMessageWithSystemRole: '你好,我是 **{{name}}**,{{systemRole}},让我们开始对话吧!', + backToBottom: '查看最新消息', + clearCurrentMessages: '清空当前会话消息', + confirmClearCurrentMessages: '即将清空当前会话消息,清空后将无法找回,请确认你的操作', + confirmRemoveSessionItemAlert: '即将删除该助手,删除后该将无法找回,请确认你的操作', + defaultAgent: '自定义助手', + defaultSession: '自定义助手', + historyRange: '历史范围', + inbox: { + defaultMessage: + '你好,我是你的智能助手,你可以问我任何问题,我会尽力回答你。如果需要获得更加专业或定制的助手,可以点击`+`创建自定义助手', + desc: '开启大脑集群,激发思维火花。你的智能助理,在这里与你交流一切', + title: '随便聊聊', + }, + newAgent: '新建助手', + noDescription: '暂无描述', + + regenerate: '重新生成', + + roleAndArchive: '角色与记录', + searchAgentPlaceholder: '搜索助手和对话...', + send: '发送', + sendPlaceholder: '输入聊天内容...', + shareModal: { + download: '下载截图', + imageType: '图片格式', + screenshot: '截图', + settings: '导出设置', + shareToShareGPT: '生成 ShareGPT 分享链接', + withBackground: '包含背景图片', + withFooter: '包含页脚', + withPluginInfo: '包含插件信息', + withSystemRole: '包含助手角色设定', + }, + stop: '停止', + + temp: '临时', + tokenDetail: '角色设定: {{systemRoleToken}} · 历史消息: {{chatsToken}}', + tokenTag: { + overload: '超过限制', + remained: '剩余', + used: '使用', + }, + topic: { + confirmRemoveTopic: '即将删除该话题,删除后将不可恢复,请谨慎操作。', + defaultTitle: '默认话题', + saveCurrentMessages: '将当前会话保存为话题', + searchPlaceholder: '搜索话题...', + title: '话题', + }, + translate: { + clear: '删除翻译', + }, + translateTo: '翻译', + updateAgent: '更新助理信息', + warp: '换行', +}; diff --git a/src/locales/default/common.ts b/src/locales/default/common.ts index 4283ffb434b4..1391f4a1497e 100644 --- a/src/locales/default/common.ts +++ b/src/locales/default/common.ts @@ -1,9 +1,6 @@ export default { about: '关于', advanceSettings: '高级设置', - agentDefaultMessage: - '你好,我是 **{{name}}**,你可以立即与我开始对话,也可以前往 [助手设置](/chat/settings#session={{id}}) 完善我的信息。', - agentDefaultMessageWithSystemRole: '你好,我是 **{{name}}**,{{systemRole}},让我们开始对话吧!', agentMaxToken: '会话最大长度', agentModel: '模型', agentProfile: '助手信息', @@ -11,12 +8,9 @@ export default { archive: '归档', autoGenerate: '自动补全', autoGenerateTooltip: '基于提示词自动补全助手描述', - backToBottom: '查看最新消息', cancel: '取消', changelog: '更新日志', - clearCurrentMessages: '清空当前会话消息', close: '关闭', - confirmClearCurrentMessages: '即将清空当前会话消息,清空后将无法找回,请确认你的操作', confirmRemoveSessionItemAlert: '即将删除该助手,删除后该将无法找回,请确认你的操作', copy: '复制', copySuccess: '复制成功', @@ -37,18 +31,17 @@ export default { historyRange: '历史范围', import: '导入配置', - inbox: { - defaultMessage: - '你好,我是你的智能助手,你可以问我任何问题,我会尽力回答你。如果需要获得更加专业或定制的助手,可以点击`+`创建自定义助手', - desc: '开启大脑集群,激发思维火花。你的智能助理,在这里与你交流一切', - title: '随便聊聊', + lang: { + 'en': '英语', + 'en-US': '英语', + 'ja-JP': '日语', + 'ko-KR': '韩语', + 'ru-RU': '俄语', + 'zh': '简体中文', + 'zh-CN': '简体中文', + 'zh-TW': '繁体中文', }, layoutInitializing: '正在加载布局...', - message: { - function_loading: '插件请求中...', - }, - moreSetting: '更多设置...', - newAgent: '新建助手', noDescription: '暂无描述', ok: '确定', password: '密码', @@ -58,24 +51,10 @@ export default { rename: '重命名', reset: '重置', retry: '重试', - roleAndArchive: '角色与记录', - searchAgentPlaceholder: '搜索助手和对话...', send: '发送', - sendPlaceholder: '输入聊天内容...', sessionList: '助手列表', setting: '设置', share: '分享', - shareModal: { - download: '下载截图', - imageType: '图片格式', - screenshot: '截图', - settings: '导出设置', - shareToShareGPT: '生成 ShareGPT 分享链接', - withBackground: '包含背景图片', - withFooter: '包含页脚', - withPluginInfo: '包含插件信息', - withSystemRole: '包含助手角色设定', - }, stop: '停止', tab: { chat: '会话', @@ -83,25 +62,11 @@ export default { setting: '设置', }, temp: '临时', - tokenDetail: '角色设定: {{systemRoleToken}} · 历史消息: {{chatsToken}}', - tokenTag: { - overload: '超过限制', - remained: '剩余', - used: '使用', - }, - topic: { - confirmRemoveTopic: '即将删除该话题,删除后将不可恢复,请谨慎操作。', - defaultTitle: '默认话题', - saveCurrentMessages: '将当前会话保存为话题', - searchPlaceholder: '搜索话题...', - title: '话题', - }, + updateAgent: '更新助理信息', - updatePrompt: '更新提示词', upgradeVersion: { action: '立即升级', hasNew: '有可用更新', newVersion: '有新版本可用:{{version}}', }, - warp: '换行', }; diff --git a/src/locales/options.ts b/src/locales/options.ts index b3801d9b825d..10e11054fb32 100644 --- a/src/locales/options.ts +++ b/src/locales/options.ts @@ -1,5 +1,7 @@ import type { Locales } from '@/types/locale'; +import _resources from './resources'; + type LocaleOptions = { label: string; value: Locales; @@ -33,3 +35,11 @@ export const localeOptions: LocaleOptions = [ ] as LocaleOptions; export const supportLangs: string[] = localeOptions.map((i) => i.value); + +export const resources = { + ..._resources, + en: _resources['en-US'], + zh: _resources['zh-CN'], +}; + +export const supportLocales = Object.keys(resources); diff --git a/src/locales/resources/en_US.ts b/src/locales/resources/en_US.ts index 23fa31b56adf..5179d8ab99ec 100644 --- a/src/locales/resources/en_US.ts +++ b/src/locales/resources/en_US.ts @@ -1,3 +1,4 @@ +import chat from '../../../locales/en_US/chat.json'; import common from '../../../locales/en_US/common.json'; import empty from '../../../locales/en_US/empty.json'; import error from '../../../locales/en_US/error.json'; @@ -7,6 +8,7 @@ import setting from '../../../locales/en_US/setting.json'; import welcome from '../../../locales/en_US/welcome.json'; const resources = { + chat, common, empty, error, diff --git a/src/locales/resources/index.ts b/src/locales/resources/index.ts index 04866ac558b6..8c088c89ad44 100644 --- a/src/locales/resources/index.ts +++ b/src/locales/resources/index.ts @@ -10,10 +10,10 @@ const resources = { 'ja-JP': ja_JP, 'ko-KR': ko_KR, 'ru-RU': ru_RU, - 'zh': zh_CN, 'zh-CN': zh_CN, 'zh-TW': zh_TW, } as const; + export default resources; export const defaultResources = zh_CN; export type Resources = typeof resources; diff --git a/src/locales/resources/ja_JP.ts b/src/locales/resources/ja_JP.ts index 77c08eee3327..39c4351db6f1 100644 --- a/src/locales/resources/ja_JP.ts +++ b/src/locales/resources/ja_JP.ts @@ -1,3 +1,4 @@ +import chat from '../../../locales/ja_JP/chat.json'; import common from '../../../locales/ja_JP/common.json'; import empty from '../../../locales/ja_JP/empty.json'; import error from '../../../locales/ja_JP/error.json'; @@ -7,6 +8,7 @@ import setting from '../../../locales/ja_JP/setting.json'; import welcome from '../../../locales/ja_JP/welcome.json'; const resources = { + chat, common, empty, error, diff --git a/src/locales/resources/ko_KR.ts b/src/locales/resources/ko_KR.ts index b5f10be2b12b..10aa01249aa1 100644 --- a/src/locales/resources/ko_KR.ts +++ b/src/locales/resources/ko_KR.ts @@ -1,3 +1,4 @@ +import chat from '../../../locales/ko_KR/chat.json'; import common from '../../../locales/ko_KR/common.json'; import empty from '../../../locales/ko_KR/empty.json'; import error from '../../../locales/ko_KR/error.json'; @@ -7,6 +8,7 @@ import setting from '../../../locales/ko_KR/setting.json'; import welcome from '../../../locales/ko_KR/welcome.json'; const resources = { + chat, common, empty, error, diff --git a/src/locales/resources/ru_RU.ts b/src/locales/resources/ru_RU.ts index d653c65d122e..7452fad88a79 100644 --- a/src/locales/resources/ru_RU.ts +++ b/src/locales/resources/ru_RU.ts @@ -1,3 +1,4 @@ +import chat from '../../../locales/ru_RU/chat.json'; import common from '../../../locales/ru_RU/common.json'; import empty from '../../../locales/ru_RU/empty.json'; import error from '../../../locales/ru_RU/error.json'; @@ -7,6 +8,7 @@ import setting from '../../../locales/ru_RU/setting.json'; import welcome from '../../../locales/ru_RU/welcome.json'; const resources = { + chat, common, empty, error, diff --git a/src/locales/resources/zh_CN.ts b/src/locales/resources/zh_CN.ts index 51308f02ec36..9a05fb9243a6 100644 --- a/src/locales/resources/zh_CN.ts +++ b/src/locales/resources/zh_CN.ts @@ -1,3 +1,4 @@ +import chat from '../default/chat'; import common from '../default/common'; import empty from '../default/empty'; import error from '../default/error'; @@ -7,6 +8,7 @@ import setting from '../default/setting'; import welcome from '../default/welcome'; const resources = { + chat, common, empty, error, diff --git a/src/locales/resources/zh_TW.ts b/src/locales/resources/zh_TW.ts index 2e2c5a08b926..0add1fdbf626 100644 --- a/src/locales/resources/zh_TW.ts +++ b/src/locales/resources/zh_TW.ts @@ -1,3 +1,4 @@ +import chat from '../../../locales/zh_TW/chat.json'; import common from '../../../locales/zh_TW/common.json'; import empty from '../../../locales/zh_TW/empty.json'; import error from '../../../locales/zh_TW/error.json'; @@ -7,6 +8,7 @@ import setting from '../../../locales/zh_TW/setting.json'; import welcome from '../../../locales/zh_TW/welcome.json'; const resources = { + chat, common, empty, error, diff --git a/src/prompts/chat.ts b/src/prompts/chat.ts deleted file mode 100644 index 77a779c69acc..000000000000 --- a/src/prompts/chat.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { chatHelpers } from '@/store/session/helpers'; -import { LanguageModel } from '@/types/llm'; -import { OpenAIChatMessage, OpenAIChatStreamPayload } from '@/types/openai/chat'; - -export const promptSummaryTitle = async ( - messages: OpenAIChatMessage[], -): Promise> => { - const finalMessages: OpenAIChatMessage[] = [ - { - content: - '你是一名擅长会话的助理,你需要将用户的会话总结为 10 个字以内的标题,不需要包含标点符号', - role: 'system', - }, - { - content: `${messages.map((message) => `${message.role}: ${message.content}`).join('\n')} - -请总结上述对话为10个字以内的标题,不需要包含标点符号`, - role: 'user', - }, - ]; - // 如果超过 4k,则使用 GPT3.5 16K 模型 - const tokens = await chatHelpers.getMessagesTokenCount(finalMessages); - let model: LanguageModel | undefined = undefined; - if (tokens > 4000) { - model = LanguageModel.GPT3_5_16K; - } - - return { - messages: finalMessages, - model, - }; -}; diff --git a/src/store/global/selectors/settings.ts b/src/store/global/selectors/settings.ts index f61b0d15301b..d87f5c035571 100644 --- a/src/store/global/selectors/settings.ts +++ b/src/store/global/selectors/settings.ts @@ -1,8 +1,10 @@ import { DEFAULT_OPENAI_MODEL_LIST } from '@/const/llm'; +import { DEFAULT_LANG } from '@/const/locale'; import { DEFAULT_AGENT_META } from '@/const/meta'; import { DEFAULT_AGENT, DEFAULT_AGENT_CONFIG, DEFAULT_SETTINGS } from '@/const/settings'; import { Locales } from '@/locales/resources'; import { GlobalSettings } from '@/types/settings'; +import { isOnServerSide } from '@/utils/env'; import { merge } from '@/utils/merge'; import { GlobalStore } from '../store'; @@ -35,6 +37,8 @@ export const exportSettings = (s: GlobalStore) => { const currentLanguage = (s: GlobalStore) => { const locale = s.settings.language; if (locale === 'auto') { + if (isOnServerSide) return DEFAULT_LANG; + return navigator.language as Locales; } diff --git a/src/store/session/slices/chat/actions/index.ts b/src/store/session/slices/chat/actions/index.ts index cc989d232933..9dfa9eacd652 100644 --- a/src/store/session/slices/chat/actions/index.ts +++ b/src/store/session/slices/chat/actions/index.ts @@ -5,11 +5,16 @@ import { SessionStore } from '@/store/session'; import { ChatMessageAction, chatMessage } from './message'; import { ShareAction, chatShare } from './share'; import { ChatTopicAction, chatTopic } from './topic'; +import { ChatTranslateAction, chatTranslate } from './translate'; /** * 聊天操作 */ -export interface ChatAction extends ChatTopicAction, ChatMessageAction, ShareAction {} +export interface ChatAction + extends ChatTopicAction, + ChatMessageAction, + ShareAction, + ChatTranslateAction {} export const createChatSlice: StateCreator< SessionStore, @@ -20,4 +25,5 @@ export const createChatSlice: StateCreator< ...chatTopic(...params), ...chatMessage(...params), ...chatShare(...params), + ...chatTranslate(...params), }); diff --git a/src/store/session/slices/chat/actions/message.ts b/src/store/session/slices/chat/actions/message.ts index 340cd15a6ea7..2e3a777dc355 100644 --- a/src/store/session/slices/chat/actions/message.ts +++ b/src/store/session/slices/chat/actions/message.ts @@ -66,13 +66,14 @@ export interface ChatMessageAction { * @param text - 消息文本 */ sendMessage: (text: string) => Promise; - stopGenerateMessage: () => void; + toggleChatLoading: ( loading: boolean, id?: string, action?: string, ) => AbortController | undefined; + triggerFunctionCall: (id: string) => Promise; } @@ -298,7 +299,6 @@ export const chatMessage: StateCreator< toggleChatLoading(false); }, - toggleChatLoading: (loading, id, action) => { if (loading) { const abortController = new AbortController(); diff --git a/src/store/session/slices/chat/actions/topic.ts b/src/store/session/slices/chat/actions/topic.ts index 9de2c250cf70..4e3f7bb16ecc 100644 --- a/src/store/session/slices/chat/actions/topic.ts +++ b/src/store/session/slices/chat/actions/topic.ts @@ -1,7 +1,7 @@ import { StateCreator } from 'zustand/vanilla'; +import { chainSummaryTitle } from '@/chains/chat'; import { LOADING_FLAT } from '@/const/message'; -import { promptSummaryTitle } from '@/prompts/chat'; import { SessionStore } from '@/store/session'; import { fetchPresetTaskResult } from '@/utils/fetch'; import { setNamespace } from '@/utils/storeDebug'; @@ -116,7 +116,7 @@ export const chatTopic: StateCreator< output += x; dispatchTopic({ id: topicId, key: 'title', type: 'updateChatTopic', value: output }); }, - params: await promptSummaryTitle(messages), + params: await chainSummaryTitle(messages), }); return topicId; diff --git a/src/store/session/slices/chat/actions/translate.ts b/src/store/session/slices/chat/actions/translate.ts new file mode 100644 index 000000000000..0dabb044252e --- /dev/null +++ b/src/store/session/slices/chat/actions/translate.ts @@ -0,0 +1,87 @@ +import { produce } from 'immer'; +import { StateCreator } from 'zustand/vanilla'; + +import { chainLangDetect, chainTranslate } from '@/chains/chat'; +import { supportLocales } from '@/locales/options'; +import { SessionStore } from '@/store/session'; +import { fetchPresetTaskResult } from '@/utils/fetch'; +import { setNamespace } from '@/utils/storeDebug'; + +import { sessionSelectors } from '../../session/selectors'; + +const t = setNamespace('chat/translate'); + +/** + * 翻译事件 + */ +export interface ChatTranslateAction { + clearTranslate: (id: string) => void; + + /** + * 翻译消息 + * @param id + */ + translateMessage: (id: string, targetLang: string) => Promise; +} + +export const chatTranslate: StateCreator< + SessionStore, + [['zustand/devtools', never]], + [], + ChatTranslateAction +> = (set, get) => ({ + clearTranslate: (id) => { + get().dispatchMessage({ + id, + key: 'translate', + type: 'updateMessageExtra', + value: null, + }); + }, + + translateMessage: async (id, targetLang) => { + const { toggleChatLoading, dispatchMessage } = get(); + const session = sessionSelectors.currentSession(get()); + if (!session || !id) return; + + const message = session.chats[id]; + if (!message) return; + + let content = ''; + let from = ''; + + dispatchMessage({ + id, + key: 'translate', + type: 'updateMessageExtra', + value: { content: '', to: targetLang }, + }); + + toggleChatLoading(true, id, t('translateMessage(start)', { id }) as string); + + // detect from language + fetchPresetTaskResult({ + params: chainLangDetect(message.content), + }).then((data) => { + if (data && supportLocales.includes(data)) from = data; + }); + + // translate to target language + await fetchPresetTaskResult({ + onMessageHandle: (text) => { + dispatchMessage({ + id, + key: 'translate', + type: 'updateMessageExtra', + value: produce({ content: '', from, to: targetLang }, (draft) => { + content += text; + draft.content += content; + }), + }); + }, + params: chainTranslate(message.content, targetLang), + }); + + toggleChatLoading(false); + }, +}); diff --git a/src/store/session/slices/chat/selectors/chat.ts b/src/store/session/slices/chat/selectors/chat.ts index 8f1fed6ad4f2..aef599b6ba7d 100644 --- a/src/store/session/slices/chat/selectors/chat.ts +++ b/src/store/session/slices/chat/selectors/chat.ts @@ -52,15 +52,21 @@ export const currentChatsWithGuideMessage = (s: SessionStore): ChatMessage[] => const [activeId, isInbox] = [s.activeId, s.activeId === INBOX_SESSION_ID]; const meta = agentSelectors.currentAgentMeta(s); + + const inboxMsg = t('inbox.defaultMessage', { ns: 'chat' }); + const agentSystemRoleMsg = t('agentDefaultMessageWithSystemRole', { + name: meta.title || t('defaultAgent'), + ns: 'chat', + systemRole: meta.description, + }); + const agentMsg = t('agentDefaultMessage', { + id: activeId, + name: meta.title || t('defaultAgent'), + ns: 'chat', + }); + const emptyInboxGuideMessage = { - content: isInbox - ? t('inbox.defaultMessage') - : !!meta.description - ? t('agentDefaultMessageWithSystemRole', { - name: meta.title || t('defaultAgent'), - systemRole: meta.description, - }) - : t('agentDefaultMessage', { id: activeId, name: meta.title || t('defaultAgent') }), + content: isInbox ? inboxMsg : !!meta.description ? agentSystemRoleMsg : agentMsg, createAt: Date.now(), extra: {}, id: 'default', @@ -86,22 +92,22 @@ export const chatsMessageString = (s: SessionStore): string => { return chats.map((m) => m.content).join(''); }; -export const currentFunctionCallProps = ( - s: SessionStore, -): (( - props: Pick, -) => FunctionCallProps) => { - const chatLoadingId = s.chatLoadingId; - return ({ plugin, function_call, content, id }) => { +export const getFunctionMessageParams = + ( + s: SessionStore, + ): (( + props: Pick, + ) => FunctionCallProps) => + ({ plugin, function_call, content, id }) => { const itemId = plugin?.identifier || function_call?.name; const command = plugin ?? function_call; const args = command?.arguments; + return { arguments: args, command, content, id: itemId, - loading: id === chatLoadingId, + loading: id === s.chatLoadingId, }; }; -}; diff --git a/src/store/session/slices/chat/selectors/index.ts b/src/store/session/slices/chat/selectors/index.ts index b180412a0188..89260404d1bc 100644 --- a/src/store/session/slices/chat/selectors/index.ts +++ b/src/store/session/slices/chat/selectors/index.ts @@ -3,8 +3,8 @@ import { currentChats, currentChatsWithGuideMessage, currentChatsWithHistoryConfig, - currentFunctionCallProps, getChatsById, + getFunctionMessageParams, } from './chat'; import { currentTopics, getTopicMessages } from './topic'; @@ -13,8 +13,8 @@ export const chatSelectors = { currentChats, currentChatsWithGuideMessage, currentChatsWithHistoryConfig, - currentFunctionCallProps, getChatsById, + getFunctionMessageParams, }; export const topicSelectors = { diff --git a/src/types/chatMessage.ts b/src/types/chatMessage.ts index 3cf66b21d457..b4ad09226923 100644 --- a/src/types/chatMessage.ts +++ b/src/types/chatMessage.ts @@ -1,6 +1,7 @@ import { PluginRequestPayload } from '@lobehub/chat-plugin-sdk'; import { ErrorType } from '@/types/fetch'; +import { Translate } from '@/types/translate'; import { LLMRoleType } from './llm'; import { BaseDataModel } from './meta'; @@ -18,6 +19,9 @@ export interface OpenAIFunctionCall { name: string; } +export interface ChatTranslate extends Translate { + content?: string; +} export interface ChatMessage extends BaseDataModel { /** * @title 内容 @@ -29,10 +33,7 @@ export interface ChatMessage extends BaseDataModel { extra?: { fromModel?: string; // 翻译 - translate?: { - target: string; - to: string; - }; + translate?: ChatTranslate; } & Record; /** diff --git a/src/types/translate.ts b/src/types/translate.ts new file mode 100644 index 000000000000..da18f79c8554 --- /dev/null +++ b/src/types/translate.ts @@ -0,0 +1,4 @@ +export interface Translate { + from: string; + to: string; +}