@lobehub/chat 1.48.3 → 1.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/changelog/v1.json +18 -0
  3. package/docker-compose/local/setup.sh +16 -6
  4. package/docs/self-hosting/server-database/docker-compose.zh-CN.mdx +197 -194
  5. package/locales/ar/chat.json +0 -4
  6. package/locales/ar/components.json +5 -0
  7. package/locales/bg-BG/chat.json +0 -4
  8. package/locales/bg-BG/components.json +5 -0
  9. package/locales/de-DE/chat.json +0 -4
  10. package/locales/de-DE/components.json +5 -0
  11. package/locales/en-US/chat.json +0 -4
  12. package/locales/en-US/components.json +5 -0
  13. package/locales/es-ES/chat.json +0 -4
  14. package/locales/es-ES/components.json +5 -0
  15. package/locales/fa-IR/chat.json +0 -4
  16. package/locales/fa-IR/components.json +5 -0
  17. package/locales/fr-FR/chat.json +0 -4
  18. package/locales/fr-FR/components.json +5 -0
  19. package/locales/it-IT/chat.json +0 -4
  20. package/locales/it-IT/components.json +5 -0
  21. package/locales/ja-JP/chat.json +0 -4
  22. package/locales/ja-JP/components.json +5 -0
  23. package/locales/ko-KR/chat.json +0 -4
  24. package/locales/ko-KR/components.json +5 -0
  25. package/locales/nl-NL/chat.json +0 -4
  26. package/locales/nl-NL/components.json +5 -0
  27. package/locales/pl-PL/chat.json +0 -4
  28. package/locales/pl-PL/components.json +5 -0
  29. package/locales/pt-BR/chat.json +0 -4
  30. package/locales/pt-BR/components.json +5 -0
  31. package/locales/ru-RU/chat.json +0 -4
  32. package/locales/ru-RU/components.json +5 -0
  33. package/locales/tr-TR/chat.json +0 -4
  34. package/locales/tr-TR/components.json +5 -0
  35. package/locales/vi-VN/chat.json +0 -4
  36. package/locales/vi-VN/components.json +5 -0
  37. package/locales/zh-CN/chat.json +0 -4
  38. package/locales/zh-CN/components.json +5 -0
  39. package/locales/zh-TW/chat.json +0 -4
  40. package/locales/zh-TW/components.json +5 -0
  41. package/package.json +1 -1
  42. package/src/app/(main)/settings/provider/(detail)/doubao/page.tsx +40 -0
  43. package/src/app/(main)/settings/provider/features/ModelList/ModelConfigModal/index.tsx +1 -1
  44. package/src/components/Thinking/index.tsx +137 -0
  45. package/src/config/aiModels/doubao.ts +65 -0
  46. package/src/config/aiModels/index.ts +3 -0
  47. package/src/config/llm.ts +6 -0
  48. package/src/config/modelProviders/doubao.ts +23 -0
  49. package/src/config/modelProviders/index.ts +3 -0
  50. package/src/features/Conversation/Messages/Assistant/Reasoning/index.tsx +6 -110
  51. package/src/libs/agent-runtime/AgentRuntime.ts +7 -0
  52. package/src/libs/agent-runtime/doubao/index.ts +10 -0
  53. package/src/libs/agent-runtime/index.ts +1 -0
  54. package/src/libs/agent-runtime/types/type.ts +1 -0
  55. package/src/locales/default/chat.ts +0 -4
  56. package/src/locales/default/components.ts +5 -0
  57. package/src/server/globalConfig/index.ts +3 -0
  58. package/src/services/chat.ts +1 -1
  59. package/src/types/aiProvider.ts +1 -0
  60. package/src/types/user/settings/keyVaults.ts +1 -0
@@ -85,5 +85,10 @@
85
85
  "ModelSwitchPanel": {
86
86
  "emptyModel": "لا توجد نماذج ممكن تمكينها، يرجى الانتقال إلى الإعدادات لتمكينها",
87
87
  "provider": "مزود"
88
+ },
89
+ "Thinking": {
90
+ "thinking": "في حالة تفكير عميق...",
91
+ "thought": "تم التفكير بعمق",
92
+ "thoughtWithDuration": "تم التفكير بعمق (استغرق {{duration}} ثانية)"
88
93
  }
89
94
  }
@@ -82,10 +82,6 @@
82
82
  }
83
83
  }
84
84
  },
85
- "reasoning": {
86
- "thinking": "В дълбочинно размисъл",
87
- "thought": "Дълбоко помислих (отне ми {{duration}} секунди)"
88
- },
89
85
  "regenerate": "Прегенерирай",
90
86
  "roleAndArchive": "Роля и архив",
91
87
  "searchAgentPlaceholder": "Търсач на помощ...",
@@ -85,5 +85,10 @@
85
85
  "ModelSwitchPanel": {
86
86
  "emptyModel": "Няма активирани модели, моля, посетете настройките и ги активирайте",
87
87
  "provider": "Доставчик"
88
+ },
89
+ "Thinking": {
90
+ "thinking": "В процес на дълбочинно размисъл...",
91
+ "thought": "Дълбочинно размислено",
92
+ "thoughtWithDuration": "Дълбочинно размислено (време: {{duration}} секунди)"
88
93
  }
89
94
  }
@@ -82,10 +82,6 @@
82
82
  }
83
83
  }
84
84
  },
85
- "reasoning": {
86
- "thinking": "Tiefes Nachdenken",
87
- "thought": "Tiefgründig nachgedacht (Dauer: {{duration}} Sekunden)"
88
- },
89
85
  "regenerate": "Neu generieren",
90
86
  "roleAndArchive": "Rolle und Archiv",
91
87
  "searchAgentPlaceholder": "Suchassistent...",
@@ -85,5 +85,10 @@
85
85
  "ModelSwitchPanel": {
86
86
  "emptyModel": "Kein aktiviertes Modell. Bitte gehen Sie zu den Einstellungen, um es zu aktivieren.",
87
87
  "provider": "Anbieter"
88
+ },
89
+ "Thinking": {
90
+ "thinking": "Tiefes Nachdenken...",
91
+ "thought": "Tief nachgedacht",
92
+ "thoughtWithDuration": "Tief nachgedacht (Dauer: {{duration}} Sekunden)"
88
93
  }
89
94
  }
@@ -82,10 +82,6 @@
82
82
  }
83
83
  }
84
84
  },
85
- "reasoning": {
86
- "thinking": "Deep in thought",
87
- "thought": "Deeply thought (took {{duration}} seconds)"
88
- },
89
85
  "regenerate": "Regenerate",
90
86
  "roleAndArchive": "Role and Archive",
91
87
  "searchAgentPlaceholder": "Search assistants...",
@@ -85,5 +85,10 @@
85
85
  "ModelSwitchPanel": {
86
86
  "emptyModel": "No enabled model. Please go to settings to enable.",
87
87
  "provider": "Provider"
88
+ },
89
+ "Thinking": {
90
+ "thinking": "Deep in thought...",
91
+ "thought": "Thought deeply",
92
+ "thoughtWithDuration": "Thought deeply (took {{duration}} seconds)"
88
93
  }
89
94
  }
@@ -82,10 +82,6 @@
82
82
  }
83
83
  }
84
84
  },
85
- "reasoning": {
86
- "thinking": "Pensando profundamente",
87
- "thought": "He reflexionado profundamente (durante {{duration}} segundos)"
88
- },
89
85
  "regenerate": "Regenerar",
90
86
  "roleAndArchive": "Rol y archivo",
91
87
  "searchAgentPlaceholder": "Asistente de búsqueda...",
@@ -85,5 +85,10 @@
85
85
  "ModelSwitchPanel": {
86
86
  "emptyModel": "No hay modelos habilitados. Vaya a la configuración para habilitarlos.",
87
87
  "provider": "Proveedor"
88
+ },
89
+ "Thinking": {
90
+ "thinking": "Pensando profundamente...",
91
+ "thought": "He pensado profundamente",
92
+ "thoughtWithDuration": "He pensado profundamente (durante {{duration}} segundos)"
88
93
  }
89
94
  }
@@ -82,10 +82,6 @@
82
82
  }
83
83
  }
84
84
  },
85
- "reasoning": {
86
- "thinking": "در حال تفکر عمیق",
87
- "thought": "به طور عمیق فکر شده است (زمان صرف شده: {{duration}} ثانیه)"
88
- },
89
85
  "regenerate": "بازتولید",
90
86
  "roleAndArchive": "نقش‌ها و بایگانی",
91
87
  "searchAgentPlaceholder": "جستجوی دستیار...",
@@ -85,5 +85,10 @@
85
85
  "ModelSwitchPanel": {
86
86
  "emptyModel": "هیچ مدلی فعال نیست، لطفاً به تنظیمات بروید و آن را فعال کنید",
87
87
  "provider": "ارائه‌دهنده"
88
+ },
89
+ "Thinking": {
90
+ "thinking": "در حال تفکر عمیق...",
91
+ "thought": "تفکر عمیق انجام شد",
92
+ "thoughtWithDuration": "تفکر عمیق انجام شد (مدت زمان {{duration}} ثانیه)"
88
93
  }
89
94
  }
@@ -82,10 +82,6 @@
82
82
  }
83
83
  }
84
84
  },
85
- "reasoning": {
86
- "thinking": "En pleine réflexion profonde",
87
- "thought": "J'ai réfléchi en profondeur (durée : {{duration}} secondes)"
88
- },
89
85
  "regenerate": "Regénérer",
90
86
  "roleAndArchive": "Rôle et archivage",
91
87
  "searchAgentPlaceholder": "Assistant de recherche...",
@@ -85,5 +85,10 @@
85
85
  "ModelSwitchPanel": {
86
86
  "emptyModel": "Aucun modèle activé. Veuillez vous rendre dans les paramètres pour l'activer.",
87
87
  "provider": "Fournisseur"
88
+ },
89
+ "Thinking": {
90
+ "thinking": "En pleine réflexion...",
91
+ "thought": "Réflexion terminée",
92
+ "thoughtWithDuration": "Réflexion terminée (durée : {{duration}} secondes)"
88
93
  }
89
94
  }
@@ -82,10 +82,6 @@
82
82
  }
83
83
  }
84
84
  },
85
- "reasoning": {
86
- "thinking": "In profonda riflessione",
87
- "thought": "Pensato in profondità (tempo impiegato {{duration}} secondi)"
88
- },
89
85
  "regenerate": "Rigenera",
90
86
  "roleAndArchive": "Ruolo e archivio",
91
87
  "searchAgentPlaceholder": "Assistente di ricerca...",
@@ -85,5 +85,10 @@
85
85
  "ModelSwitchPanel": {
86
86
  "emptyModel": "Nessun modello attivo. Vai alle impostazioni per attivarne uno.",
87
87
  "provider": "Provider"
88
+ },
89
+ "Thinking": {
90
+ "thinking": "Pensando profondamente...",
91
+ "thought": "Pensato profondamente",
92
+ "thoughtWithDuration": "Pensato profondamente (tempo impiegato {{duration}} secondi)"
88
93
  }
89
94
  }
@@ -82,10 +82,6 @@
82
82
  }
83
83
  }
84
84
  },
85
- "reasoning": {
86
- "thinking": "深く考えています",
87
- "thought": "深く考えました(所要時間 {{duration}} 秒)"
88
- },
89
85
  "regenerate": "再生成",
90
86
  "roleAndArchive": "役割とアーカイブ",
91
87
  "searchAgentPlaceholder": "検索アシスタント...",
@@ -85,5 +85,10 @@
85
85
  "ModelSwitchPanel": {
86
86
  "emptyModel": "有効なモデルがありません。設定に移動して有効にしてください。",
87
87
  "provider": "プロバイダー"
88
+ },
89
+ "Thinking": {
90
+ "thinking": "深く考えています...",
91
+ "thought": "深く考えました",
92
+ "thoughtWithDuration": "深く考えました(所要時間 {{duration}} 秒)"
88
93
  }
89
94
  }
@@ -82,10 +82,6 @@
82
82
  }
83
83
  }
84
84
  },
85
- "reasoning": {
86
- "thinking": "심층 사고 중",
87
- "thought": "심층적으로 생각했습니다 (소요 시간: {{duration}} 초)"
88
- },
89
85
  "regenerate": "재생성",
90
86
  "roleAndArchive": "역할 및 아카이브",
91
87
  "searchAgentPlaceholder": "검색 도우미...",
@@ -85,5 +85,10 @@
85
85
  "ModelSwitchPanel": {
86
86
  "emptyModel": "활성화된 모델이 없습니다. 설정으로 이동하여 활성화하세요",
87
87
  "provider": "제공자"
88
+ },
89
+ "Thinking": {
90
+ "thinking": "심층적으로 생각 중...",
91
+ "thought": "심층적으로 생각했습니다",
92
+ "thoughtWithDuration": "심층적으로 생각했습니다 (소요 시간: {{duration}} 초)"
88
93
  }
89
94
  }
@@ -82,10 +82,6 @@
82
82
  }
83
83
  }
84
84
  },
85
- "reasoning": {
86
- "thinking": "Diep aan het denken",
87
- "thought": "Diep nagedacht (tijd: {{duration}} seconden)"
88
- },
89
85
  "regenerate": "Opnieuw genereren",
90
86
  "roleAndArchive": "Rol en archief",
91
87
  "searchAgentPlaceholder": "Zoekassistent...",
@@ -85,5 +85,10 @@
85
85
  "ModelSwitchPanel": {
86
86
  "emptyModel": "No enabled model, please go to settings to enable.",
87
87
  "provider": "Provider"
88
+ },
89
+ "Thinking": {
90
+ "thinking": "Diep in gedachten...",
91
+ "thought": "Diep nagedacht",
92
+ "thoughtWithDuration": "Diep nagedacht (geduurd {{duration}} seconden)"
88
93
  }
89
94
  }
@@ -82,10 +82,6 @@
82
82
  }
83
83
  }
84
84
  },
85
- "reasoning": {
86
- "thinking": "Głęboko myślę",
87
- "thought": "Głęboko myślałem (czas: {{duration}} sekund)"
88
- },
89
85
  "regenerate": "Wygeneruj ponownie",
90
86
  "roleAndArchive": "Rola i archiwum",
91
87
  "searchAgentPlaceholder": "Wyszukaj pomocnika...",
@@ -85,5 +85,10 @@
85
85
  "ModelSwitchPanel": {
86
86
  "emptyModel": "Brak włączonych modeli, przejdź do ustawień i włącz je",
87
87
  "provider": "Dostawca"
88
+ },
89
+ "Thinking": {
90
+ "thinking": "Głęboko myślę...",
91
+ "thought": "Już głęboko myślałem",
92
+ "thoughtWithDuration": "Już głęboko myślałem (czas: {{duration}} sekund)"
88
93
  }
89
94
  }
@@ -82,10 +82,6 @@
82
82
  }
83
83
  }
84
84
  },
85
- "reasoning": {
86
- "thinking": "Pensando profundamente",
87
- "thought": "Pensou profundamente (tempo gasto: {{duration}} segundos)"
88
- },
89
85
  "regenerate": "Regenerar",
90
86
  "roleAndArchive": "Função e Arquivo",
91
87
  "searchAgentPlaceholder": "Assistente de busca...",
@@ -85,5 +85,10 @@
85
85
  "ModelSwitchPanel": {
86
86
  "emptyModel": "Nenhum modelo habilitado. Por favor, vá para as configurações e habilite um.",
87
87
  "provider": "Fornecedor"
88
+ },
89
+ "Thinking": {
90
+ "thinking": "Pensando profundamente...",
91
+ "thought": "Pensamento profundo concluído",
92
+ "thoughtWithDuration": "Pensamento profundo concluído (durante {{duration}} segundos)"
88
93
  }
89
94
  }
@@ -82,10 +82,6 @@
82
82
  }
83
83
  }
84
84
  },
85
- "reasoning": {
86
- "thinking": "Глубокое размышление",
87
- "thought": "Глубоко размышлял (время: {{duration}} секунд)"
88
- },
89
85
  "regenerate": "Сгенерировать заново",
90
86
  "roleAndArchive": "Роль и архив",
91
87
  "searchAgentPlaceholder": "Поиск помощника...",
@@ -85,5 +85,10 @@
85
85
  "ModelSwitchPanel": {
86
86
  "emptyModel": "Нет активированных моделей. Пожалуйста, перейдите в настройки и включите модель",
87
87
  "provider": "Поставщик"
88
+ },
89
+ "Thinking": {
90
+ "thinking": "Глубокое размышление...",
91
+ "thought": "Глубоко размышлено",
92
+ "thoughtWithDuration": "Глубоко размышлено (время: {{duration}} секунд)"
88
93
  }
89
94
  }
@@ -82,10 +82,6 @@
82
82
  }
83
83
  }
84
84
  },
85
- "reasoning": {
86
- "thinking": "Derin düşünme aşamasında",
87
- "thought": "Derinlemesine düşündü (geçen süre {{duration}} saniye)"
88
- },
89
85
  "regenerate": "Tekrarla",
90
86
  "roleAndArchive": "Rol ve Arşiv",
91
87
  "searchAgentPlaceholder": "Arama Asistanı...",
@@ -85,5 +85,10 @@
85
85
  "ModelSwitchPanel": {
86
86
  "emptyModel": "Etkinleştirilmiş model bulunmamaktadır, lütfen ayarlara giderek açın",
87
87
  "provider": "Sağlayıcı"
88
+ },
89
+ "Thinking": {
90
+ "thinking": "Derin düşünme aşamasında...",
91
+ "thought": "Derin düşünme tamamlandı",
92
+ "thoughtWithDuration": "Derin düşünme tamamlandı (geçen süre {{duration}} saniye)"
88
93
  }
89
94
  }
@@ -82,10 +82,6 @@
82
82
  }
83
83
  }
84
84
  },
85
- "reasoning": {
86
- "thinking": "Đang suy nghĩ sâu sắc",
87
- "thought": "Đã suy nghĩ sâu sắc (thời gian: {{duration}} giây)"
88
- },
89
85
  "regenerate": "Tạo lại",
90
86
  "roleAndArchive": "Vai trò và lưu trữ",
91
87
  "searchAgentPlaceholder": "Trợ lý tìm kiếm...",
@@ -85,5 +85,10 @@
85
85
  "ModelSwitchPanel": {
86
86
  "emptyModel": "Không có mô hình nào được kích hoạt, vui lòng điều chỉnh trong cài đặt",
87
87
  "provider": "Nhà cung cấp"
88
+ },
89
+ "Thinking": {
90
+ "thinking": "Đang suy nghĩ sâu sắc...",
91
+ "thought": "Đã suy nghĩ sâu sắc",
92
+ "thoughtWithDuration": "Đã suy nghĩ sâu sắc (thời gian: {{duration}} giây)"
88
93
  }
89
94
  }
@@ -82,10 +82,6 @@
82
82
  }
83
83
  }
84
84
  },
85
- "reasoning": {
86
- "thinking": "深度思考中",
87
- "thought": "已深度思考(用时 {{duration}} 秒)"
88
- },
89
85
  "regenerate": "重新生成",
90
86
  "roleAndArchive": "角色与记录",
91
87
  "searchAgentPlaceholder": "搜索助手...",
@@ -85,5 +85,10 @@
85
85
  "ModelSwitchPanel": {
86
86
  "emptyModel": "没有启用的模型,请前往设置开启",
87
87
  "provider": "提供商"
88
+ },
89
+ "Thinking": {
90
+ "thinking": "深度思考中...",
91
+ "thought": "已深度思考",
92
+ "thoughtWithDuration": "已深度思考(用时 {{duration}} 秒)"
88
93
  }
89
94
  }
@@ -82,10 +82,6 @@
82
82
  }
83
83
  }
84
84
  },
85
- "reasoning": {
86
- "thinking": "深入思考中",
87
- "thought": "已深度思考(用時 {{duration}} 秒)"
88
- },
89
85
  "regenerate": "重新生成",
90
86
  "roleAndArchive": "角色與記錄",
91
87
  "searchAgentPlaceholder": "搜尋助手...",
@@ -85,5 +85,10 @@
85
85
  "ModelSwitchPanel": {
86
86
  "emptyModel": "沒有啟用的模型,請前往設定開啟",
87
87
  "provider": "提供商"
88
+ },
89
+ "Thinking": {
90
+ "thinking": "深度思考中...",
91
+ "thought": "已深度思考",
92
+ "thoughtWithDuration": "已深度思考(用時 {{duration}} 秒)"
88
93
  }
89
94
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/chat",
3
- "version": "1.48.3",
3
+ "version": "1.49.0",
4
4
  "description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
5
5
  "keywords": [
6
6
  "framework",
@@ -0,0 +1,40 @@
1
+ 'use client';
2
+
3
+ import { DoubaoProviderCard } from '@/config/modelProviders';
4
+ import { ModelProvider } from '@/libs/agent-runtime';
5
+ import { useUserStore } from '@/store/user';
6
+ import { modelProviderSelectors } from '@/store/user/selectors';
7
+
8
+ import { ProviderItem } from '../../type';
9
+ import ProviderDetail from '../[id]';
10
+
11
+ const providerKey = ModelProvider.Doubao;
12
+
13
+ const useProviderCard = (): ProviderItem => {
14
+
15
+ // Get the first model card's deployment name as the check model
16
+ const checkModel = useUserStore((s) => {
17
+ const chatModelCards = modelProviderSelectors.getModelCardsById(providerKey)(s);
18
+
19
+ if (chatModelCards.length > 0) {
20
+ return chatModelCards[0].deploymentName;
21
+ }
22
+
23
+ return 'Doubao-lite-4k';
24
+ });
25
+ return {
26
+ ...DoubaoProviderCard,
27
+ checkModel,
28
+ modelList: {
29
+ azureDeployName: true,
30
+ },
31
+ };
32
+ };
33
+
34
+ const Page = () => {
35
+ const card = useProviderCard();
36
+
37
+ return <ProviderDetail {...card} />;
38
+ };
39
+
40
+ export default Page;
@@ -66,7 +66,7 @@ const ModelConfigModal = memo<ModelConfigModalProps>(({ id, open, setOpen }) =>
66
66
  idEditable={false}
67
67
  initialValues={model}
68
68
  onFormInstanceReady={setFormInstance}
69
- showAzureDeployName={editingProvider === ModelProvider.Azure}
69
+ showAzureDeployName={editingProvider === ModelProvider.Azure || editingProvider === ModelProvider.Doubao}
70
70
  type={model?.type}
71
71
  />
72
72
  </Modal>
@@ -0,0 +1,137 @@
1
+ import { Icon, Markdown } from '@lobehub/ui';
2
+ import { createStyles } from 'antd-style';
3
+ import { AnimatePresence, motion } from 'framer-motion';
4
+ import { AtomIcon, ChevronDown, ChevronRight } from 'lucide-react';
5
+ import { rgba } from 'polished';
6
+ import { memo, useEffect, useState } from 'react';
7
+ import { useTranslation } from 'react-i18next';
8
+ import { Flexbox } from 'react-layout-kit';
9
+
10
+ const useStyles = createStyles(({ css, token, isDarkMode }) => ({
11
+ container: css`
12
+ cursor: pointer;
13
+
14
+ width: fit-content;
15
+ padding-block: 4px;
16
+ padding-inline: 8px;
17
+ border-radius: 6px;
18
+
19
+ color: ${token.colorTextTertiary};
20
+
21
+ &:hover {
22
+ background: ${isDarkMode ? token.colorFillQuaternary : token.colorFillTertiary};
23
+ }
24
+ `,
25
+ expand: css`
26
+ background: ${isDarkMode ? token.colorFillQuaternary : token.colorFillTertiary} !important;
27
+ `,
28
+ shinyText: css`
29
+ color: ${rgba(token.colorText, 0.45)};
30
+
31
+ background: linear-gradient(
32
+ 120deg,
33
+ ${rgba(token.colorTextBase, 0)} 40%,
34
+ ${token.colorTextSecondary} 50%,
35
+ ${rgba(token.colorTextBase, 0)} 60%
36
+ );
37
+ background-clip: text;
38
+ background-size: 200% 100%;
39
+
40
+ animation: shine 1.5s linear infinite;
41
+
42
+ @keyframes shine {
43
+ 0% {
44
+ background-position: 100%;
45
+ }
46
+
47
+ 100% {
48
+ background-position: -100%;
49
+ }
50
+ }
51
+ `,
52
+ title: css`
53
+ overflow: hidden;
54
+ display: -webkit-box;
55
+ -webkit-box-orient: vertical;
56
+ -webkit-line-clamp: 1;
57
+
58
+ font-size: 12px;
59
+ text-overflow: ellipsis;
60
+ `,
61
+ }));
62
+
63
+ interface ThinkingProps {
64
+ content?: string;
65
+ duration?: number;
66
+ thinking?: boolean;
67
+ }
68
+
69
+ const Thinking = memo<ThinkingProps>(({ content = '', duration, thinking }) => {
70
+ const { t } = useTranslation('components');
71
+ const { styles, cx } = useStyles();
72
+
73
+ const [showDetail, setShowDetail] = useState(false);
74
+
75
+ useEffect(() => {
76
+ if (thinking && !content) {
77
+ setShowDetail(true);
78
+ }
79
+
80
+ if (!thinking) {
81
+ setShowDetail(false);
82
+ }
83
+ }, [thinking, content]);
84
+
85
+ return (
86
+ <Flexbox
87
+ className={cx(styles.container, showDetail && styles.expand)}
88
+ gap={16}
89
+ onClick={() => {
90
+ setShowDetail(!showDetail);
91
+ }}
92
+ >
93
+ <Flexbox distribution={'space-between'} flex={1} horizontal>
94
+ {thinking ? (
95
+ <Flexbox gap={8} horizontal>
96
+ <Icon icon={AtomIcon} />
97
+ <Flexbox className={styles.shinyText} horizontal>
98
+ {t('Thinking.thinking')}
99
+ </Flexbox>
100
+ </Flexbox>
101
+ ) : (
102
+ <Flexbox gap={8} horizontal>
103
+ <Icon icon={AtomIcon} />
104
+ {typeof duration === 'undefined'
105
+ ? t('Thinking.thoughtWithDuration')
106
+ : t('Thinking.thought', { duration: ((duration || 0) / 1000).toFixed(1) })}
107
+ </Flexbox>
108
+ )}
109
+ <Icon icon={showDetail ? ChevronDown : ChevronRight} />
110
+ </Flexbox>
111
+
112
+ <AnimatePresence initial={false}>
113
+ {showDetail && (
114
+ <motion.div
115
+ animate="open"
116
+ exit="collapsed"
117
+ initial="collapsed"
118
+ style={{ overflow: 'hidden' }}
119
+ transition={{
120
+ duration: 0.2,
121
+ ease: [0.4, 0, 0.2, 1], // 使用 ease-out 缓动函数
122
+ }}
123
+ variants={{
124
+ collapsed: { height: 0, opacity: 0, width: 'auto' },
125
+ open: { height: 'auto', opacity: 1, width: 'auto' },
126
+ }}
127
+ >
128
+ <Markdown variant={'chat'}>{content}</Markdown>
129
+ </motion.div>
130
+ )}
131
+ {/*<Flexbox></Flexbox>*/}
132
+ </AnimatePresence>
133
+ </Flexbox>
134
+ );
135
+ });
136
+
137
+ export default Thinking;