mirror of
https://github.com/lobehub/lobe-chat.git
synced 2026-06-21 14:39:34 +00:00
Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| df0886ebf3 | |||
| f284c25606 | |||
| 23a26a9563 | |||
| 8039186493 | |||
| 5c6b8eaf8a | |||
| dde299312e | |||
| 0aa47d024c | |||
| b86d86782a | |||
| 6006175c5d |
@@ -2,6 +2,83 @@
|
||||
|
||||
# Changelog
|
||||
|
||||
## [Version 1.70.0](https://github.com/lobehub/lobe-chat/compare/v1.69.6...v1.70.0)
|
||||
|
||||
<sup>Released on **2025-03-09**</sup>
|
||||
|
||||
#### ✨ Features
|
||||
|
||||
- **misc**: Support no-fc models like deepseek r1 with online search.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### What's improved
|
||||
|
||||
- **misc**: Support no-fc models like deepseek r1 with online search, closes [#6842](https://github.com/lobehub/lobe-chat/issues/6842) ([f284c25](https://github.com/lobehub/lobe-chat/commit/f284c25))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 1.69.6](https://github.com/lobehub/lobe-chat/compare/v1.69.5...v1.69.6)
|
||||
|
||||
<sup>Released on **2025-03-09**</sup>
|
||||
|
||||
#### 🐛 Bug Fixes
|
||||
|
||||
- **misc**: Fix context cache control and model builtin search switch.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### What's fixed
|
||||
|
||||
- **misc**: Fix context cache control and model builtin search switch, closes [#6831](https://github.com/lobehub/lobe-chat/issues/6831) ([5c6b8ea](https://github.com/lobehub/lobe-chat/commit/5c6b8ea))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 1.69.5](https://github.com/lobehub/lobe-chat/compare/v1.69.4...v1.69.5)
|
||||
|
||||
<sup>Released on **2025-03-09**</sup>
|
||||
|
||||
#### 💄 Styles
|
||||
|
||||
- **chat**: Auto send message from URL.
|
||||
- **misc**: Support openrouter claude 3.7 sonnet reasoning.
|
||||
|
||||
<br/>
|
||||
|
||||
<details>
|
||||
<summary><kbd>Improvements and Fixes</kbd></summary>
|
||||
|
||||
#### Styles
|
||||
|
||||
- **chat**: Auto send message from URL, closes [#6497](https://github.com/lobehub/lobe-chat/issues/6497) ([30b2639](https://github.com/lobehub/lobe-chat/commit/30b2639))
|
||||
- **misc**: Support openrouter claude 3.7 sonnet reasoning, closes [#6806](https://github.com/lobehub/lobe-chat/issues/6806) ([f1ffc2c](https://github.com/lobehub/lobe-chat/commit/f1ffc2c))
|
||||
|
||||
</details>
|
||||
|
||||
<div align="right">
|
||||
|
||||
[](#readme-top)
|
||||
|
||||
</div>
|
||||
|
||||
### [Version 1.69.4](https://github.com/lobehub/lobe-chat/compare/v1.69.3...v1.69.4)
|
||||
|
||||
<sup>Released on **2025-03-09**</sup>
|
||||
|
||||
@@ -1,4 +1,18 @@
|
||||
[
|
||||
{
|
||||
"children": {
|
||||
"fixes": ["Fix context cache control and model builtin search switch."]
|
||||
},
|
||||
"date": "2025-03-09",
|
||||
"version": "1.69.6"
|
||||
},
|
||||
{
|
||||
"children": {
|
||||
"improvements": ["Support openrouter claude 3.7 sonnet reasoning."]
|
||||
},
|
||||
"date": "2025-03-09",
|
||||
"version": "1.69.5"
|
||||
},
|
||||
{
|
||||
"children": {
|
||||
"fixes": ["Fix mistral can not chat."]
|
||||
|
||||
@@ -36,7 +36,7 @@ tags:
|
||||
|
||||
<Image alt={'Clerk 添加 Webhooks 端点'} src={'https://github.com/lobehub/lobe-chat/assets/28616219/f50f47fb-5e8e-4930-bf4e-8cf6f5b8afb9'} />
|
||||
|
||||
在 endppint 中填写你的项目 URL,如 `https://your-project.com/api/webhooks/clerk`。然后在订阅事件(Subscribe to events)中,勾选 user 的三个事件(`user.created` 、`user.deleted`、`user.updated`),然后点击创建。
|
||||
在 endpoint 中填写你的项目 URL,如 `https://your-project.com/api/webhooks/clerk`。然后在订阅事件(Subscribe to events)中,勾选 user 的三个事件(`user.created` 、`user.deleted`、`user.updated`),然后点击创建。
|
||||
|
||||
<Callout type={'warning'}>URL 的`https://`不可缺失,须保持 URL 的完整性</Callout>
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ tags:
|
||||
|
||||
<Image alt={'Clerk 添加 Webhooks 端点'} src={'https://github.com/lobehub/lobe-chat/assets/28616219/f50f47fb-5e8e-4930-bf4e-8cf6f5b8afb9'} />
|
||||
|
||||
在 endppint 中填写你的 Vercel 项目的 URL,如 `https://your-project.vercel.app/api/webhooks/clerk`。然后在订阅事件(Subscribe to events)中,勾选 user 的三个事件(`user.created` 、`user.deleted`、`user.updated`),然后点击创建。
|
||||
在 endpoint 中填写你的 Vercel 项目的 URL,如 `https://your-project.vercel.app/api/webhooks/clerk`。然后在订阅事件(Subscribe to events)中,勾选 user 的三个事件(`user.created` 、`user.deleted`、`user.updated`),然后点击创建。
|
||||
|
||||
<Callout type={'warning'}>URL 的`https://`不可缺失,须保持 URL 的完整性</Callout>
|
||||
|
||||
|
||||
@@ -64,6 +64,9 @@
|
||||
"stop": "توقف",
|
||||
"warp": "تغيير السطر"
|
||||
},
|
||||
"intentUnderstanding": {
|
||||
"title": "جارٍ تحليل وفهم نواياك..."
|
||||
},
|
||||
"knowledgeBase": {
|
||||
"all": "جميع المحتويات",
|
||||
"allFiles": "جميع الملفات",
|
||||
@@ -144,7 +147,6 @@
|
||||
"desc": "تحديد ما إذا كان من الضروري البحث بناءً على محتوى المحادثة",
|
||||
"title": "الاتصال الذكي"
|
||||
},
|
||||
"disable": "النموذج الحالي لا يدعم استدعاء الوظائف، لذا لا يمكن استخدام وظيفة الاتصال الذكي",
|
||||
"off": {
|
||||
"desc": "استخدام المعرفة الأساسية للنموذج فقط، دون إجراء بحث عبر الإنترنت",
|
||||
"title": "إيقاف الاتصال"
|
||||
@@ -155,6 +157,10 @@
|
||||
},
|
||||
"useModelBuiltin": "استخدام محرك البحث المدمج في النموذج"
|
||||
},
|
||||
"searchModel": {
|
||||
"desc": "النموذج الحالي لا يدعم استدعاء الدوال، لذا يجب استخدام نموذج يدعم استدعاء الدوال للبحث عبر الإنترنت",
|
||||
"title": "نموذج البحث المساعد"
|
||||
},
|
||||
"title": "بحث عبر الإنترنت"
|
||||
},
|
||||
"searchAgentPlaceholder": "مساعد البحث...",
|
||||
|
||||
@@ -85,6 +85,8 @@
|
||||
},
|
||||
"ModelSwitchPanel": {
|
||||
"emptyModel": "لا توجد نماذج ممكن تمكينها، يرجى الانتقال إلى الإعدادات لتمكينها",
|
||||
"emptyProvider": "لا توجد مزودات مفعلة، يرجى الذهاب إلى الإعدادات لتفعيلها",
|
||||
"goToSettings": "اذهب إلى الإعدادات",
|
||||
"provider": "مزود"
|
||||
},
|
||||
"OllamaSetupGuide": {
|
||||
|
||||
@@ -506,6 +506,9 @@
|
||||
"anthropic/claude-3.5-sonnet": {
|
||||
"description": "Claude 3.5 Sonnet يقدم قدرات تتجاوز Opus وسرعة أكبر من Sonnet، مع الحفاظ على نفس السعر. يتميز Sonnet بمهارات خاصة في البرمجة وعلوم البيانات ومعالجة الصور والمهام الوكيلة."
|
||||
},
|
||||
"anthropic/claude-3.7-sonnet": {
|
||||
"description": "Claude 3.7 Sonnet هو أكثر النماذج ذكاءً من Anthropic حتى الآن، وهو أيضًا أول نموذج مختلط للتفكير في السوق. يمكن لـ Claude 3.7 Sonnet إنتاج استجابات شبه فورية أو تفكير تدريجي ممتد، حيث يمكن للمستخدمين رؤية هذه العمليات بوضوح. يتميز Sonnet بشكل خاص في البرمجة، وعلوم البيانات، ومعالجة الصور، والمهام الوكيلة."
|
||||
},
|
||||
"aya": {
|
||||
"description": "Aya 23 هو نموذج متعدد اللغات أطلقته Cohere، يدعم 23 لغة، مما يسهل التطبيقات اللغوية المتنوعة."
|
||||
},
|
||||
|
||||
@@ -64,6 +64,9 @@
|
||||
"stop": "Спри",
|
||||
"warp": "Нов ред"
|
||||
},
|
||||
"intentUnderstanding": {
|
||||
"title": "Анализирам и разбирам вашето намерение..."
|
||||
},
|
||||
"knowledgeBase": {
|
||||
"all": "Всички съдържания",
|
||||
"allFiles": "Всички файлове",
|
||||
@@ -144,7 +147,6 @@
|
||||
"desc": "Интелигентно определяне на необходимостта от търсене въз основа на съдържанието на разговора",
|
||||
"title": "Интелигентно свързване"
|
||||
},
|
||||
"disable": "Текущият модел не поддържа извикване на функции, затова не може да се използва интелигентно свързване",
|
||||
"off": {
|
||||
"desc": "Използва само основните знания на модела, без интернет търсене",
|
||||
"title": "Изключване на свързването"
|
||||
@@ -155,6 +157,10 @@
|
||||
},
|
||||
"useModelBuiltin": "Използване на вградената търсачка на модела"
|
||||
},
|
||||
"searchModel": {
|
||||
"desc": "Текущият модел не поддържа извикване на функции, затова е необходимо да се комбинира с модел, който поддържа извикване на функции, за да се извърши търсене в интернет",
|
||||
"title": "Модел за търсене на помощ"
|
||||
},
|
||||
"title": "Търсене в интернет"
|
||||
},
|
||||
"searchAgentPlaceholder": "Търсач на помощ...",
|
||||
|
||||
@@ -85,6 +85,8 @@
|
||||
},
|
||||
"ModelSwitchPanel": {
|
||||
"emptyModel": "Няма активирани модели, моля, посетете настройките и ги активирайте",
|
||||
"emptyProvider": "Няма активиран доставчик на услуги, моля, отидете в настройките, за да го активирате",
|
||||
"goToSettings": "Отидете в настройките",
|
||||
"provider": "Доставчик"
|
||||
},
|
||||
"OllamaSetupGuide": {
|
||||
|
||||
@@ -506,6 +506,9 @@
|
||||
"anthropic/claude-3.5-sonnet": {
|
||||
"description": "Claude 3.5 Sonnet предлага способности, надхвърлящи Opus, и по-бърза скорост в сравнение с Sonnet, като същевременно запазва същата цена. Sonnet е особено силен в програмирането, науката за данни, визуалната обработка и агентските задачи."
|
||||
},
|
||||
"anthropic/claude-3.7-sonnet": {
|
||||
"description": "Claude 3.7 Sonnet е най-интелигентният модел на Anthropic до момента и е първият хибриден модел за разсъждение на пазара. Claude 3.7 Sonnet може да генерира почти мигновени отговори или удължено стъпково мислене, което позволява на потребителите ясно да видят тези процеси. Sonnet е особено добър в програмирането, науката за данни, визуалната обработка и агентските задачи."
|
||||
},
|
||||
"aya": {
|
||||
"description": "Aya 23 е многозначен модел, представен от Cohere, поддържащ 23 езика, предоставяйки удобство за многоезични приложения."
|
||||
},
|
||||
|
||||
@@ -64,6 +64,9 @@
|
||||
"stop": "Stoppen",
|
||||
"warp": "Zeilenumbruch"
|
||||
},
|
||||
"intentUnderstanding": {
|
||||
"title": "Analysiere und verstehe Ihre Absicht..."
|
||||
},
|
||||
"knowledgeBase": {
|
||||
"all": "Alle Inhalte",
|
||||
"allFiles": "Alle Dateien",
|
||||
@@ -144,7 +147,6 @@
|
||||
"desc": "Intelligente Beurteilung, ob eine Suche basierend auf dem Gesprächsinhalt erforderlich ist",
|
||||
"title": "Intelligente Vernetzung"
|
||||
},
|
||||
"disable": "Das aktuelle Modell unterstützt keine Funktionsaufrufe, daher kann die intelligente Vernetzungsfunktion nicht verwendet werden",
|
||||
"off": {
|
||||
"desc": "Verwendet nur das Grundwissen des Modells, ohne Netzsuche",
|
||||
"title": "Vernetzung deaktivieren"
|
||||
@@ -155,6 +157,10 @@
|
||||
},
|
||||
"useModelBuiltin": "Verwenden Sie die integrierte Suchmaschine des Modells"
|
||||
},
|
||||
"searchModel": {
|
||||
"desc": "Das aktuelle Modell unterstützt keine Funktionsaufrufe, daher muss es mit einem Modell kombiniert werden, das Funktionsaufrufe unterstützt, um online zu suchen",
|
||||
"title": "Suchunterstützungsmodell"
|
||||
},
|
||||
"title": "Netzwerksuche"
|
||||
},
|
||||
"searchAgentPlaceholder": "Suchassistent...",
|
||||
|
||||
@@ -85,6 +85,8 @@
|
||||
},
|
||||
"ModelSwitchPanel": {
|
||||
"emptyModel": "Kein aktiviertes Modell. Bitte gehen Sie zu den Einstellungen, um es zu aktivieren.",
|
||||
"emptyProvider": "Es sind keine aktiven Anbieter vorhanden, bitte gehen Sie zu den Einstellungen, um sie zu aktivieren",
|
||||
"goToSettings": "Zu den Einstellungen gehen",
|
||||
"provider": "Anbieter"
|
||||
},
|
||||
"OllamaSetupGuide": {
|
||||
|
||||
@@ -506,6 +506,9 @@
|
||||
"anthropic/claude-3.5-sonnet": {
|
||||
"description": "Claude 3.5 Sonnet bietet Fähigkeiten, die über Opus hinausgehen, und eine schnellere Geschwindigkeit als Sonnet, während es den gleichen Preis wie Sonnet beibehält. Sonnet ist besonders gut in Programmierung, Datenwissenschaft, visueller Verarbeitung und Agentenaufgaben."
|
||||
},
|
||||
"anthropic/claude-3.7-sonnet": {
|
||||
"description": "Claude 3.7 Sonnet ist das intelligenteste Modell von Anthropic bis heute und das erste hybride Inferenzmodell auf dem Markt. Claude 3.7 Sonnet kann nahezu sofortige Antworten oder verlängerte, schrittweise Überlegungen erzeugen, wobei die Benutzer diesen Prozess klar nachvollziehen können. Sonnet ist besonders gut in den Bereichen Programmierung, Datenwissenschaft, visuelle Verarbeitung und Agentenaufgaben."
|
||||
},
|
||||
"aya": {
|
||||
"description": "Aya 23 ist ein mehrsprachiges Modell von Cohere, das 23 Sprachen unterstützt und die Anwendung in einer Vielzahl von Sprachen erleichtert."
|
||||
},
|
||||
|
||||
@@ -64,6 +64,9 @@
|
||||
"stop": "Stop",
|
||||
"warp": "New Line"
|
||||
},
|
||||
"intentUnderstanding": {
|
||||
"title": "Analyzing and understanding your intent..."
|
||||
},
|
||||
"knowledgeBase": {
|
||||
"all": "All Content",
|
||||
"allFiles": "All Files",
|
||||
@@ -144,7 +147,6 @@
|
||||
"desc": "Intelligently determine whether a search is needed based on the conversation content",
|
||||
"title": "Smart Online Search"
|
||||
},
|
||||
"disable": "The current model does not support function calls, so the smart online search feature is unavailable",
|
||||
"off": {
|
||||
"desc": "Use only the model's basic knowledge without performing a web search",
|
||||
"title": "Disable Online Search"
|
||||
@@ -155,6 +157,10 @@
|
||||
},
|
||||
"useModelBuiltin": "Use the model's built-in search engine"
|
||||
},
|
||||
"searchModel": {
|
||||
"desc": "The current model does not support function calls, so it needs to be paired with a model that does support function calls for online searching.",
|
||||
"title": "Search Assistant Model"
|
||||
},
|
||||
"title": "Online Search"
|
||||
},
|
||||
"searchAgentPlaceholder": "Search assistants...",
|
||||
|
||||
@@ -85,6 +85,8 @@
|
||||
},
|
||||
"ModelSwitchPanel": {
|
||||
"emptyModel": "No enabled model. Please go to settings to enable.",
|
||||
"emptyProvider": "No enabled providers. Please go to settings to enable one.",
|
||||
"goToSettings": "Go to settings",
|
||||
"provider": "Provider"
|
||||
},
|
||||
"OllamaSetupGuide": {
|
||||
|
||||
@@ -506,6 +506,9 @@
|
||||
"anthropic/claude-3.5-sonnet": {
|
||||
"description": "Claude 3.5 Sonnet offers capabilities that surpass Opus and faster speeds than Sonnet, while maintaining the same pricing as Sonnet. Sonnet excels particularly in programming, data science, visual processing, and agent tasks."
|
||||
},
|
||||
"anthropic/claude-3.7-sonnet": {
|
||||
"description": "Claude 3.7 Sonnet is Anthropic's most advanced model to date and the first hybrid reasoning model on the market. Claude 3.7 Sonnet can generate near-instant responses or extended step-by-step reasoning, allowing users to clearly observe these processes. Sonnet excels particularly in programming, data science, visual processing, and agent tasks."
|
||||
},
|
||||
"aya": {
|
||||
"description": "Aya 23 is a multilingual model launched by Cohere, supporting 23 languages, facilitating diverse language applications."
|
||||
},
|
||||
|
||||
@@ -64,6 +64,9 @@
|
||||
"stop": "Detener",
|
||||
"warp": "Salto de línea"
|
||||
},
|
||||
"intentUnderstanding": {
|
||||
"title": "Analizando y comprendiendo su intención..."
|
||||
},
|
||||
"knowledgeBase": {
|
||||
"all": "Todo el contenido",
|
||||
"allFiles": "Todos los archivos",
|
||||
@@ -144,7 +147,6 @@
|
||||
"desc": "Determina inteligentemente si se necesita buscar según el contenido de la conversación",
|
||||
"title": "Conexión inteligente"
|
||||
},
|
||||
"disable": "El modelo actual no admite llamadas a funciones, por lo que no se puede utilizar la función de conexión inteligente",
|
||||
"off": {
|
||||
"desc": "Utiliza solo el conocimiento básico del modelo, sin realizar búsquedas en línea",
|
||||
"title": "Desactivar conexión"
|
||||
@@ -155,6 +157,10 @@
|
||||
},
|
||||
"useModelBuiltin": "Utilizar el motor de búsqueda integrado del modelo"
|
||||
},
|
||||
"searchModel": {
|
||||
"desc": "El modelo actual no admite llamadas a funciones, por lo que se necesita combinarlo con un modelo que admita llamadas a funciones para realizar búsquedas en línea",
|
||||
"title": "Modelo de búsqueda auxiliar"
|
||||
},
|
||||
"title": "Búsqueda en línea"
|
||||
},
|
||||
"searchAgentPlaceholder": "Asistente de búsqueda...",
|
||||
|
||||
@@ -85,6 +85,8 @@
|
||||
},
|
||||
"ModelSwitchPanel": {
|
||||
"emptyModel": "No hay modelos habilitados. Vaya a la configuración para habilitarlos.",
|
||||
"emptyProvider": "No hay proveedores habilitados, por favor ve a la configuración para activarlos",
|
||||
"goToSettings": "Ir a la configuración",
|
||||
"provider": "Proveedor"
|
||||
},
|
||||
"OllamaSetupGuide": {
|
||||
|
||||
@@ -506,6 +506,9 @@
|
||||
"anthropic/claude-3.5-sonnet": {
|
||||
"description": "Claude 3.5 Sonnet ofrece capacidades que superan a Opus y una velocidad más rápida que Sonnet, manteniendo el mismo precio que Sonnet. Sonnet es especialmente hábil en programación, ciencia de datos, procesamiento visual y tareas de agente."
|
||||
},
|
||||
"anthropic/claude-3.7-sonnet": {
|
||||
"description": "Claude 3.7 Sonnet es el modelo más inteligente de Anthropic hasta la fecha y el primer modelo de razonamiento híbrido en el mercado. Claude 3.7 Sonnet puede generar respuestas casi instantáneas o un pensamiento prolongado y gradual, permitiendo a los usuarios observar claramente estos procesos. Sonnet es especialmente hábil en programación, ciencia de datos, procesamiento visual y tareas de agente."
|
||||
},
|
||||
"aya": {
|
||||
"description": "Aya 23 es un modelo multilingüe lanzado por Cohere, que admite 23 idiomas, facilitando aplicaciones de lenguaje diversas."
|
||||
},
|
||||
|
||||
@@ -64,6 +64,9 @@
|
||||
"stop": "توقف",
|
||||
"warp": "خط جدید"
|
||||
},
|
||||
"intentUnderstanding": {
|
||||
"title": "در حال تحلیل و درک نیت شما..."
|
||||
},
|
||||
"knowledgeBase": {
|
||||
"all": "همه محتوا",
|
||||
"allFiles": "همه فایلها",
|
||||
@@ -144,7 +147,6 @@
|
||||
"desc": "به طور هوشمندانه بر اساس محتوای گفتگو تشخیص میدهد که آیا نیاز به جستجو است",
|
||||
"title": "اتصال هوشمند"
|
||||
},
|
||||
"disable": "مدل فعلی از فراخوانی توابع پشتیبانی نمیکند، بنابراین نمیتوان از ویژگی اتصال هوشمند استفاده کرد",
|
||||
"off": {
|
||||
"desc": "فقط از دانش پایه مدل استفاده میکند و جستجوی اینترنتی انجام نمیدهد",
|
||||
"title": "قطع اتصال"
|
||||
@@ -155,6 +157,10 @@
|
||||
},
|
||||
"useModelBuiltin": "استفاده از موتور جستجوی داخلی مدل"
|
||||
},
|
||||
"searchModel": {
|
||||
"desc": "مدل فعلی از فراخوانی توابع پشتیبانی نمیکند، بنابراین نیاز است که با مدلی که از فراخوانی توابع پشتیبانی میکند، برای جستجوی آنلاین ترکیب شود",
|
||||
"title": "مدل جستجوی کمکی"
|
||||
},
|
||||
"title": "جستجوی متصل"
|
||||
},
|
||||
"searchAgentPlaceholder": "جستجوی دستیار...",
|
||||
|
||||
@@ -85,6 +85,8 @@
|
||||
},
|
||||
"ModelSwitchPanel": {
|
||||
"emptyModel": "هیچ مدلی فعال نیست، لطفاً به تنظیمات بروید و آن را فعال کنید",
|
||||
"emptyProvider": "هیچ ارائهدهندهای فعال نیست، لطفاً به تنظیمات بروید و آن را فعال کنید",
|
||||
"goToSettings": "به تنظیمات بروید",
|
||||
"provider": "ارائهدهنده"
|
||||
},
|
||||
"OllamaSetupGuide": {
|
||||
|
||||
@@ -506,6 +506,9 @@
|
||||
"anthropic/claude-3.5-sonnet": {
|
||||
"description": "Claude 3.5 Sonnet تواناییهایی فراتر از Opus ارائه میدهد و سرعتی سریعتر از Sonnet دارد، در حالی که قیمت آن با Sonnet یکسان است. Sonnet بهویژه در برنامهنویسی، علم داده، پردازش بصری و وظایف نمایندگی مهارت دارد."
|
||||
},
|
||||
"anthropic/claude-3.7-sonnet": {
|
||||
"description": "Claude 3.7 Sonnet هو هوش مصنوعی پیشرفتهترین مدل Anthropic است و همچنین اولین مدل استدلال ترکیبی در بازار به شمار میرود. Claude 3.7 Sonnet میتواند پاسخهای تقریباً آنی یا تفکر تدریجی و طولانیتری تولید کند که کاربران میتوانند این فرآیندها را به وضوح مشاهده کنند. Sonnet بهویژه در برنامهنویسی، علم داده، پردازش بصری و وظایف نمایندگی مهارت دارد."
|
||||
},
|
||||
"aya": {
|
||||
"description": "Aya 23 یک مدل چندزبانه است که توسط Cohere ارائه شده و از 23 زبان پشتیبانی میکند و برای برنامههای چندزبانه تسهیلات فراهم میآورد."
|
||||
},
|
||||
|
||||
@@ -64,6 +64,9 @@
|
||||
"stop": "Arrêter",
|
||||
"warp": "Saut de ligne"
|
||||
},
|
||||
"intentUnderstanding": {
|
||||
"title": "Analyse et comprend votre intention..."
|
||||
},
|
||||
"knowledgeBase": {
|
||||
"all": "Tout le contenu",
|
||||
"allFiles": "Tous les fichiers",
|
||||
@@ -144,7 +147,6 @@
|
||||
"desc": "Détermine intelligemment si une recherche est nécessaire en fonction du contenu de la conversation",
|
||||
"title": "Connexion intelligente"
|
||||
},
|
||||
"disable": "Le modèle actuel ne prend pas en charge l'appel de fonctions, donc la fonctionnalité de connexion intelligente est indisponible",
|
||||
"off": {
|
||||
"desc": "Utilise uniquement les connaissances de base du modèle, sans recherche en ligne",
|
||||
"title": "Déconnexion"
|
||||
@@ -155,6 +157,10 @@
|
||||
},
|
||||
"useModelBuiltin": "Utiliser le moteur de recherche intégré du modèle"
|
||||
},
|
||||
"searchModel": {
|
||||
"desc": "Le modèle actuel ne prend pas en charge les appels de fonction, il doit donc être associé à un modèle prenant en charge les appels de fonction pour effectuer une recherche en ligne",
|
||||
"title": "Modèle d'assistance à la recherche"
|
||||
},
|
||||
"title": "Recherche en ligne"
|
||||
},
|
||||
"searchAgentPlaceholder": "Assistant de recherche...",
|
||||
|
||||
@@ -85,6 +85,8 @@
|
||||
},
|
||||
"ModelSwitchPanel": {
|
||||
"emptyModel": "Aucun modèle activé. Veuillez vous rendre dans les paramètres pour l'activer.",
|
||||
"emptyProvider": "Aucun fournisseur activé, veuillez aller dans les paramètres pour l'activer",
|
||||
"goToSettings": "Aller aux paramètres",
|
||||
"provider": "Fournisseur"
|
||||
},
|
||||
"OllamaSetupGuide": {
|
||||
|
||||
@@ -506,6 +506,9 @@
|
||||
"anthropic/claude-3.5-sonnet": {
|
||||
"description": "Claude 3.5 Sonnet offre des capacités supérieures à celles d'Opus et une vitesse plus rapide que Sonnet, tout en maintenant le même prix que Sonnet. Sonnet excelle particulièrement dans la programmation, la science des données, le traitement visuel et les tâches d'agent."
|
||||
},
|
||||
"anthropic/claude-3.7-sonnet": {
|
||||
"description": "Claude 3.7 Sonnet est le modèle le plus intelligent d'Anthropic à ce jour, et le premier modèle de raisonnement hybride sur le marché. Claude 3.7 Sonnet peut produire des réponses quasi instantanées ou un raisonnement prolongé, permettant aux utilisateurs de voir clairement ces processus. Sonnet excelle particulièrement dans la programmation, la science des données, le traitement visuel et les tâches d'agent."
|
||||
},
|
||||
"aya": {
|
||||
"description": "Aya 23 est un modèle multilingue lancé par Cohere, prenant en charge 23 langues, facilitant les applications linguistiques diversifiées."
|
||||
},
|
||||
|
||||
@@ -64,6 +64,9 @@
|
||||
"stop": "Ferma",
|
||||
"warp": "A capo"
|
||||
},
|
||||
"intentUnderstanding": {
|
||||
"title": "Analizzando e comprendendo le tue intenzioni..."
|
||||
},
|
||||
"knowledgeBase": {
|
||||
"all": "Tutti i contenuti",
|
||||
"allFiles": "Tutti i file",
|
||||
@@ -144,7 +147,6 @@
|
||||
"desc": "Determina intelligentemente se è necessario cercare in base al contenuto della conversazione",
|
||||
"title": "Collegamento intelligente"
|
||||
},
|
||||
"disable": "Il modello attuale non supporta le chiamate di funzione, quindi non è possibile utilizzare la funzionalità di collegamento intelligente",
|
||||
"off": {
|
||||
"desc": "Utilizza solo la conoscenza di base del modello, senza effettuare ricerche online",
|
||||
"title": "Disattiva collegamento"
|
||||
@@ -155,6 +157,10 @@
|
||||
},
|
||||
"useModelBuiltin": "Utilizza il motore di ricerca integrato del modello"
|
||||
},
|
||||
"searchModel": {
|
||||
"desc": "Il modello attuale non supporta le chiamate di funzione, quindi è necessario utilizzarlo insieme a un modello che supporti le chiamate di funzione per cercare online",
|
||||
"title": "Modello di ricerca assistita"
|
||||
},
|
||||
"title": "Ricerca online"
|
||||
},
|
||||
"searchAgentPlaceholder": "Assistente di ricerca...",
|
||||
|
||||
@@ -85,6 +85,8 @@
|
||||
},
|
||||
"ModelSwitchPanel": {
|
||||
"emptyModel": "Nessun modello attivo. Vai alle impostazioni per attivarne uno.",
|
||||
"emptyProvider": "Nessun fornitore attivo, vai alle impostazioni per attivarlo",
|
||||
"goToSettings": "Vai alle impostazioni",
|
||||
"provider": "Provider"
|
||||
},
|
||||
"OllamaSetupGuide": {
|
||||
|
||||
@@ -506,6 +506,9 @@
|
||||
"anthropic/claude-3.5-sonnet": {
|
||||
"description": "Claude 3.5 Sonnet offre capacità superiori rispetto a Opus e una velocità maggiore rispetto a Sonnet, mantenendo lo stesso prezzo di Sonnet. Sonnet è particolarmente abile in programmazione, scienza dei dati, elaborazione visiva e compiti di agenzia."
|
||||
},
|
||||
"anthropic/claude-3.7-sonnet": {
|
||||
"description": "Claude 3.7 Sonnet è il modello più intelligente di Anthropic fino ad oggi ed è il primo modello di ragionamento ibrido sul mercato. Claude 3.7 Sonnet può generare risposte quasi istantanee o pensieri prolungati e graduali, consentendo agli utenti di vedere chiaramente questi processi. Sonnet è particolarmente abile nella programmazione, nella scienza dei dati, nell'elaborazione visiva e nei compiti di agenzia."
|
||||
},
|
||||
"aya": {
|
||||
"description": "Aya 23 è un modello multilingue lanciato da Cohere, supporta 23 lingue, facilitando applicazioni linguistiche diversificate."
|
||||
},
|
||||
|
||||
@@ -64,6 +64,9 @@
|
||||
"stop": "停止",
|
||||
"warp": "改行"
|
||||
},
|
||||
"intentUnderstanding": {
|
||||
"title": "あなたの意図を分析し理解しています..."
|
||||
},
|
||||
"knowledgeBase": {
|
||||
"all": "すべてのコンテンツ",
|
||||
"allFiles": "すべてのファイル",
|
||||
@@ -144,7 +147,6 @@
|
||||
"desc": "会話の内容に基づいて、検索が必要かどうかを自動的に判断します",
|
||||
"title": "インテリジェント接続"
|
||||
},
|
||||
"disable": "現在のモデルは関数呼び出しをサポートしていないため、インテリジェント接続機能は使用できません",
|
||||
"off": {
|
||||
"desc": "モデルの基本知識のみを使用し、ネット検索は行いません",
|
||||
"title": "接続をオフ"
|
||||
@@ -155,6 +157,10 @@
|
||||
},
|
||||
"useModelBuiltin": "モデル内蔵の検索エンジンを使用"
|
||||
},
|
||||
"searchModel": {
|
||||
"desc": "現在のモデルは関数呼び出しをサポートしていないため、関数呼び出しをサポートするモデルと組み合わせてネット検索を行う必要があります",
|
||||
"title": "検索補助モデル"
|
||||
},
|
||||
"title": "ネット接続検索"
|
||||
},
|
||||
"searchAgentPlaceholder": "検索アシスタント...",
|
||||
|
||||
@@ -85,6 +85,8 @@
|
||||
},
|
||||
"ModelSwitchPanel": {
|
||||
"emptyModel": "有効なモデルがありません。設定に移動して有効にしてください。",
|
||||
"emptyProvider": "有効なサービスプロバイダーがありません。設定に移動して有効にしてください。",
|
||||
"goToSettings": "設定に移動",
|
||||
"provider": "プロバイダー"
|
||||
},
|
||||
"OllamaSetupGuide": {
|
||||
|
||||
@@ -506,6 +506,9 @@
|
||||
"anthropic/claude-3.5-sonnet": {
|
||||
"description": "Claude 3.5 SonnetはOpusを超える能力を提供し、Sonnetよりも速い速度を持ちながら、Sonnetと同じ価格を維持します。Sonnetは特にプログラミング、データサイエンス、視覚処理、代理タスクに優れています。"
|
||||
},
|
||||
"anthropic/claude-3.7-sonnet": {
|
||||
"description": "Claude 3.7 Sonnetは、Anthropicがこれまでに開発した最も知能の高いモデルであり、市場で初めての混合推論モデルです。Claude 3.7 Sonnetは、ほぼ瞬時の応答や段階的な思考を生成することができ、ユーザーはこれらのプロセスを明確に見ることができます。Sonnetは特にプログラミング、データサイエンス、視覚処理、代理タスクに優れています。"
|
||||
},
|
||||
"aya": {
|
||||
"description": "Aya 23は、Cohereが提供する多言語モデルであり、23の言語をサポートし、多様な言語アプリケーションを便利にします。"
|
||||
},
|
||||
|
||||
@@ -64,6 +64,9 @@
|
||||
"stop": "중지",
|
||||
"warp": "줄바꿈"
|
||||
},
|
||||
"intentUnderstanding": {
|
||||
"title": "귀하의 의도를 분석하고 이해하는 중입니다..."
|
||||
},
|
||||
"knowledgeBase": {
|
||||
"all": "모든 내용",
|
||||
"allFiles": "모든 파일",
|
||||
@@ -144,7 +147,6 @@
|
||||
"desc": "대화 내용을 기반으로 검색 필요성을 스마트하게 판단",
|
||||
"title": "스마트 연결"
|
||||
},
|
||||
"disable": "현재 모델은 함수 호출을 지원하지 않으므로 스마트 연결 기능을 사용할 수 없습니다",
|
||||
"off": {
|
||||
"desc": "모델의 기본 지식만 사용하고 네트워크 검색을 수행하지 않음",
|
||||
"title": "연결 끄기"
|
||||
@@ -155,6 +157,10 @@
|
||||
},
|
||||
"useModelBuiltin": "모델 내장 검색 엔진 사용"
|
||||
},
|
||||
"searchModel": {
|
||||
"desc": "현재 모델은 함수 호출을 지원하지 않으므로 함수 호출을 지원하는 모델과 함께 사용해야 인터넷 검색이 가능합니다.",
|
||||
"title": "검색 보조 모델"
|
||||
},
|
||||
"title": "연결 검색"
|
||||
},
|
||||
"searchAgentPlaceholder": "검색 도우미...",
|
||||
|
||||
@@ -85,6 +85,8 @@
|
||||
},
|
||||
"ModelSwitchPanel": {
|
||||
"emptyModel": "활성화된 모델이 없습니다. 설정으로 이동하여 활성화하세요",
|
||||
"emptyProvider": "활성화된 서비스 제공자가 없습니다. 설정으로 가서 활성화하세요.",
|
||||
"goToSettings": "설정으로 가기",
|
||||
"provider": "제공자"
|
||||
},
|
||||
"OllamaSetupGuide": {
|
||||
|
||||
@@ -506,6 +506,9 @@
|
||||
"anthropic/claude-3.5-sonnet": {
|
||||
"description": "Claude 3.5 Sonnet은 Opus를 초월하는 능력과 Sonnet보다 더 빠른 속도를 제공하며, Sonnet과 동일한 가격을 유지합니다. Sonnet은 프로그래밍, 데이터 과학, 비주얼 처리 및 에이전트 작업에 특히 강합니다."
|
||||
},
|
||||
"anthropic/claude-3.7-sonnet": {
|
||||
"description": "Claude 3.7 Sonnet은 Anthropic이 지금까지 개발한 가장 지능적인 모델로, 시장에서 최초의 혼합 추론 모델입니다. Claude 3.7 Sonnet은 거의 즉각적인 응답이나 연장된 단계적 사고를 생성할 수 있으며, 사용자는 이러한 과정을 명확하게 볼 수 있습니다. Sonnet은 프로그래밍, 데이터 과학, 시각 처리, 대리 작업에 특히 뛰어납니다."
|
||||
},
|
||||
"aya": {
|
||||
"description": "Aya 23은 Cohere에서 출시한 다국어 모델로, 23개 언어를 지원하여 다양한 언어 응용에 편리함을 제공합니다."
|
||||
},
|
||||
|
||||
@@ -64,6 +64,9 @@
|
||||
"stop": "Stoppen",
|
||||
"warp": "Nieuwe regel"
|
||||
},
|
||||
"intentUnderstanding": {
|
||||
"title": "Bezig met het analyseren en begrijpen van uw intentie..."
|
||||
},
|
||||
"knowledgeBase": {
|
||||
"all": "Alle inhoud",
|
||||
"allFiles": "Alle bestanden",
|
||||
@@ -144,7 +147,6 @@
|
||||
"desc": "Intelligente beoordeling of er gezocht moet worden op basis van de gesprekinhoud",
|
||||
"title": "Slimme verbinding"
|
||||
},
|
||||
"disable": "Het huidige model ondersteunt geen functieaanroepen, dus de slimme verbindingsfunctie kan niet worden gebruikt",
|
||||
"off": {
|
||||
"desc": "Gebruik alleen de basiskennis van het model, zonder online zoekopdrachten",
|
||||
"title": "Verbinding uitschakelen"
|
||||
@@ -155,6 +157,10 @@
|
||||
},
|
||||
"useModelBuiltin": "Gebruik de ingebouwde zoekmachine van het model"
|
||||
},
|
||||
"searchModel": {
|
||||
"desc": "Het huidige model ondersteunt geen functieaanroepen, dus het moet worden gecombineerd met een model dat functieaanroepen ondersteunt om online te zoeken",
|
||||
"title": "Zoekhulpmiddel model"
|
||||
},
|
||||
"title": "Online zoeken"
|
||||
},
|
||||
"searchAgentPlaceholder": "Zoekassistent...",
|
||||
|
||||
@@ -85,6 +85,8 @@
|
||||
},
|
||||
"ModelSwitchPanel": {
|
||||
"emptyModel": "No enabled model, please go to settings to enable.",
|
||||
"emptyProvider": "Geen ingeschakelde provider, ga naar instellingen om deze in te schakelen",
|
||||
"goToSettings": "Ga naar instellingen",
|
||||
"provider": "Provider"
|
||||
},
|
||||
"OllamaSetupGuide": {
|
||||
|
||||
@@ -506,6 +506,9 @@
|
||||
"anthropic/claude-3.5-sonnet": {
|
||||
"description": "Claude 3.5 Sonnet biedt mogelijkheden die verder gaan dan Opus en een snellere snelheid dan Sonnet, terwijl het dezelfde prijs als Sonnet behoudt. Sonnet is bijzonder goed in programmeren, datawetenschap, visuele verwerking en agenttaken."
|
||||
},
|
||||
"anthropic/claude-3.7-sonnet": {
|
||||
"description": "Claude 3.7 Sonnet is het meest geavanceerde model van Anthropic tot nu toe en het eerste hybride redeneermodel op de markt. Claude 3.7 Sonnet kan bijna onmiddellijke reacties of uitgebreide stapsgewijze overpeinzingen genereren, waarbij gebruikers deze processen duidelijk kunnen volgen. Sonnet is bijzonder goed in programmeren, datawetenschap, visuele verwerking en agenttaken."
|
||||
},
|
||||
"aya": {
|
||||
"description": "Aya 23 is een meertalig model van Cohere, ondersteunt 23 talen en biedt gemak voor diverse taaltoepassingen."
|
||||
},
|
||||
|
||||
@@ -64,6 +64,9 @@
|
||||
"stop": "Zatrzymaj",
|
||||
"warp": "Złamanie wiersza"
|
||||
},
|
||||
"intentUnderstanding": {
|
||||
"title": "Analizuję i rozumiem Twoje intencje..."
|
||||
},
|
||||
"knowledgeBase": {
|
||||
"all": "Wszystkie treści",
|
||||
"allFiles": "Wszystkie pliki",
|
||||
@@ -144,7 +147,6 @@
|
||||
"desc": "Inteligentne określenie, czy potrzebne jest wyszukiwanie na podstawie treści rozmowy",
|
||||
"title": "Inteligentne połączenie"
|
||||
},
|
||||
"disable": "Aktualny model nie obsługuje wywołań funkcji, więc nie można korzystać z inteligentnego połączenia",
|
||||
"off": {
|
||||
"desc": "Używaj tylko podstawowej wiedzy modelu, bez wyszukiwania w sieci",
|
||||
"title": "Wyłącz połączenie"
|
||||
@@ -155,6 +157,10 @@
|
||||
},
|
||||
"useModelBuiltin": "Użyj wbudowanej wyszukiwarki modelu"
|
||||
},
|
||||
"searchModel": {
|
||||
"desc": "Aktualny model nie obsługuje wywołań funkcji, dlatego wymaga współpracy z modelem obsługującym wywołania funkcji, aby móc przeszukiwać sieć",
|
||||
"title": "Model wspomagający wyszukiwanie"
|
||||
},
|
||||
"title": "Wyszukiwanie w sieci"
|
||||
},
|
||||
"searchAgentPlaceholder": "Wyszukaj pomocnika...",
|
||||
|
||||
@@ -85,6 +85,8 @@
|
||||
},
|
||||
"ModelSwitchPanel": {
|
||||
"emptyModel": "Brak włączonych modeli, przejdź do ustawień i włącz je",
|
||||
"emptyProvider": "Nie ma aktywnego dostawcy usług, przejdź do ustawień, aby go włączyć",
|
||||
"goToSettings": "Przejdź do ustawień",
|
||||
"provider": "Dostawca"
|
||||
},
|
||||
"OllamaSetupGuide": {
|
||||
|
||||
@@ -506,6 +506,9 @@
|
||||
"anthropic/claude-3.5-sonnet": {
|
||||
"description": "Claude 3.5 Sonnet oferuje możliwości przewyższające Opus oraz szybsze tempo niż Sonnet, zachowując tę samą cenę. Sonnet szczególnie dobrze radzi sobie z programowaniem, nauką o danych, przetwarzaniem wizualnym i zadaniami agenta."
|
||||
},
|
||||
"anthropic/claude-3.7-sonnet": {
|
||||
"description": "Claude 3.7 Sonnet to najinteligentniejszy model stworzony przez Anthropic, a także pierwszy na rynku model mieszanej dedukcji. Claude 3.7 Sonnet potrafi generować niemal natychmiastowe odpowiedzi lub wydłużone, krok po kroku myślenie, które użytkownicy mogą wyraźnie obserwować. Sonnet szczególnie dobrze radzi sobie z programowaniem, nauką o danych, przetwarzaniem wizualnym oraz zadaniami agenta."
|
||||
},
|
||||
"aya": {
|
||||
"description": "Aya 23 to model wielojęzyczny wydany przez Cohere, wspierający 23 języki, ułatwiający różnorodne zastosowania językowe."
|
||||
},
|
||||
|
||||
@@ -64,6 +64,9 @@
|
||||
"stop": "Parar",
|
||||
"warp": "Quebrar linha"
|
||||
},
|
||||
"intentUnderstanding": {
|
||||
"title": "Analisando e compreendendo sua intenção..."
|
||||
},
|
||||
"knowledgeBase": {
|
||||
"all": "Todo conteúdo",
|
||||
"allFiles": "Todos os arquivos",
|
||||
@@ -144,7 +147,6 @@
|
||||
"desc": "Determina inteligentemente se é necessário pesquisar com base no conteúdo da conversa",
|
||||
"title": "Conexão Inteligente"
|
||||
},
|
||||
"disable": "O modelo atual não suporta chamadas de função, portanto, a funcionalidade de conexão inteligente não está disponível",
|
||||
"off": {
|
||||
"desc": "Usa apenas o conhecimento básico do modelo, sem realizar pesquisas na web",
|
||||
"title": "Desativar Conexão"
|
||||
@@ -155,6 +157,10 @@
|
||||
},
|
||||
"useModelBuiltin": "Usar o mecanismo de busca embutido no modelo"
|
||||
},
|
||||
"searchModel": {
|
||||
"desc": "O modelo atual não suporta chamadas de função, portanto, é necessário combiná-lo com um modelo que suporte chamadas de função para realizar buscas na internet",
|
||||
"title": "Modelo de busca auxiliar"
|
||||
},
|
||||
"title": "Pesquisa Conectada"
|
||||
},
|
||||
"searchAgentPlaceholder": "Assistente de busca...",
|
||||
|
||||
@@ -85,6 +85,8 @@
|
||||
},
|
||||
"ModelSwitchPanel": {
|
||||
"emptyModel": "Nenhum modelo habilitado. Por favor, vá para as configurações e habilite um.",
|
||||
"emptyProvider": "Nenhum provedor ativado, por favor vá para as configurações para ativar",
|
||||
"goToSettings": "Ir para as configurações",
|
||||
"provider": "Fornecedor"
|
||||
},
|
||||
"OllamaSetupGuide": {
|
||||
|
||||
@@ -506,6 +506,9 @@
|
||||
"anthropic/claude-3.5-sonnet": {
|
||||
"description": "Claude 3.5 Sonnet oferece capacidades que vão além do Opus e uma velocidade superior ao Sonnet, mantendo o mesmo preço do Sonnet. O Sonnet é especialmente habilidoso em programação, ciência de dados, processamento visual e tarefas de agente."
|
||||
},
|
||||
"anthropic/claude-3.7-sonnet": {
|
||||
"description": "Claude 3.7 Sonnet é o modelo mais inteligente da Anthropic até agora e é o primeiro modelo de raciocínio misto do mercado. Claude 3.7 Sonnet pode gerar respostas quase instantâneas ou um pensamento gradual prolongado, permitindo que os usuários vejam claramente esses processos. Sonnet é especialmente habilidoso em programação, ciência de dados, processamento visual e tarefas de agente."
|
||||
},
|
||||
"aya": {
|
||||
"description": "Aya 23 é um modelo multilíngue lançado pela Cohere, suportando 23 idiomas, facilitando aplicações linguísticas diversificadas."
|
||||
},
|
||||
|
||||
@@ -64,6 +64,9 @@
|
||||
"stop": "Остановить",
|
||||
"warp": "Перенос строки"
|
||||
},
|
||||
"intentUnderstanding": {
|
||||
"title": "Анализ и понимание вашего намерения..."
|
||||
},
|
||||
"knowledgeBase": {
|
||||
"all": "Все содержимое",
|
||||
"allFiles": "Все файлы",
|
||||
@@ -144,7 +147,6 @@
|
||||
"desc": "Интеллектуально определяет необходимость поиска на основе содержания диалога",
|
||||
"title": "Интеллектуальное подключение к сети"
|
||||
},
|
||||
"disable": "Текущая модель не поддерживает вызовы функций, поэтому функция интеллектуального подключения к сети недоступна",
|
||||
"off": {
|
||||
"desc": "Использует только базовые знания модели, без сетевого поиска",
|
||||
"title": "Отключить подключение к сети"
|
||||
@@ -155,6 +157,10 @@
|
||||
},
|
||||
"useModelBuiltin": "Использовать встроенный поисковый движок модели"
|
||||
},
|
||||
"searchModel": {
|
||||
"desc": "Текущая модель не поддерживает вызов функций, поэтому необходимо использовать модель, поддерживающую вызов функций, для поиска в интернете",
|
||||
"title": "Модель поиска"
|
||||
},
|
||||
"title": "Поиск в сети"
|
||||
},
|
||||
"searchAgentPlaceholder": "Поиск помощника...",
|
||||
|
||||
@@ -85,6 +85,8 @@
|
||||
},
|
||||
"ModelSwitchPanel": {
|
||||
"emptyModel": "Нет активированных моделей. Пожалуйста, перейдите в настройки и включите модель",
|
||||
"emptyProvider": "Нет активных провайдеров, пожалуйста, перейдите в настройки для их включения",
|
||||
"goToSettings": "Перейти в настройки",
|
||||
"provider": "Поставщик"
|
||||
},
|
||||
"OllamaSetupGuide": {
|
||||
|
||||
@@ -506,6 +506,9 @@
|
||||
"anthropic/claude-3.5-sonnet": {
|
||||
"description": "Claude 3.5 Sonnet предлагает возможности, превосходящие Opus, и скорость, превышающую Sonnet, при этом сохраняя ту же цену. Sonnet особенно хорошо справляется с программированием, наукой о данных, визуальной обработкой и агентскими задачами."
|
||||
},
|
||||
"anthropic/claude-3.7-sonnet": {
|
||||
"description": "Claude 3.7 Sonnet — это самая умная модель от Anthropic на сегодняшний день и первая в мире смешанная модель вывода. Claude 3.7 Sonnet может генерировать почти мгновенные ответы или длительные пошаговые размышления, позволяя пользователям четко видеть эти процессы. Sonnet особенно хорошо справляется с программированием, научными данными, визуальной обработкой и агентскими задачами."
|
||||
},
|
||||
"aya": {
|
||||
"description": "Aya 23 — это многоязычная модель, выпущенная Cohere, поддерживающая 23 языка, обеспечивая удобство для многоязычных приложений."
|
||||
},
|
||||
|
||||
@@ -64,6 +64,9 @@
|
||||
"stop": "Dur",
|
||||
"warp": "Satır atla"
|
||||
},
|
||||
"intentUnderstanding": {
|
||||
"title": "Niyetinizi analiz ediyor ve anlıyor..."
|
||||
},
|
||||
"knowledgeBase": {
|
||||
"all": "Tüm İçerik",
|
||||
"allFiles": "Tüm Dosyalar",
|
||||
@@ -144,7 +147,6 @@
|
||||
"desc": "Sohbet içeriğine göre akıllıca arama gerekip gerekmediğini belirler",
|
||||
"title": "Akıllı Bağlantı"
|
||||
},
|
||||
"disable": "Mevcut model fonksiyon çağrısını desteklemediği için akıllı bağlantı özelliği kullanılamaz",
|
||||
"off": {
|
||||
"desc": "Sadece modelin temel bilgilerini kullanır, ağ araması yapmaz",
|
||||
"title": "Bağlantıyı Kapat"
|
||||
@@ -155,6 +157,10 @@
|
||||
},
|
||||
"useModelBuiltin": "Modelin yerleşik arama motorunu kullan"
|
||||
},
|
||||
"searchModel": {
|
||||
"desc": "Mevcut model fonksiyon çağrısını desteklemiyor, bu nedenle çevrimiçi arama yapmak için fonksiyon çağrısını destekleyen bir model ile birlikte kullanılması gerekiyor",
|
||||
"title": "Arama Yardımcı Modeli"
|
||||
},
|
||||
"title": "Ağ Araması"
|
||||
},
|
||||
"searchAgentPlaceholder": "Arama Asistanı...",
|
||||
|
||||
@@ -85,6 +85,8 @@
|
||||
},
|
||||
"ModelSwitchPanel": {
|
||||
"emptyModel": "Etkinleştirilmiş model bulunmamaktadır, lütfen ayarlara giderek açın",
|
||||
"emptyProvider": "Etkinleştirilmiş bir sağlayıcı yok, lütfen ayarlara gidin",
|
||||
"goToSettings": "Ayrıntılara git",
|
||||
"provider": "Sağlayıcı"
|
||||
},
|
||||
"OllamaSetupGuide": {
|
||||
|
||||
@@ -506,6 +506,9 @@
|
||||
"anthropic/claude-3.5-sonnet": {
|
||||
"description": "Claude 3.5 Sonnet, Opus'tan daha fazla yetenek ve Sonnet'ten daha hızlı bir hız sunar; aynı zamanda Sonnet ile aynı fiyatı korur. Sonnet, programlama, veri bilimi, görsel işleme ve ajan görevlerinde özellikle başarılıdır."
|
||||
},
|
||||
"anthropic/claude-3.7-sonnet": {
|
||||
"description": "Claude 3.7 Sonnet, Anthropic'in şimdiye kadarki en akıllı modeli ve piyasadaki ilk karma akıl yürütme modelidir. Claude 3.7 Sonnet, neredeyse anlık yanıtlar veya uzatılmış adım adım düşünme süreçleri üretebilir; kullanıcılar bu süreçleri net bir şekilde görebilir. Sonnet, programlama, veri bilimi, görsel işleme ve temsilci görevlerde özellikle yeteneklidir."
|
||||
},
|
||||
"aya": {
|
||||
"description": "Aya 23, Cohere tarafından sunulan çok dilli bir modeldir, 23 dili destekler ve çok dilli uygulamalar için kolaylık sağlar."
|
||||
},
|
||||
|
||||
@@ -64,6 +64,9 @@
|
||||
"stop": "Dừng",
|
||||
"warp": "Xuống dòng"
|
||||
},
|
||||
"intentUnderstanding": {
|
||||
"title": "Đang phân tích và hiểu ý định của bạn..."
|
||||
},
|
||||
"knowledgeBase": {
|
||||
"all": "Tất cả nội dung",
|
||||
"allFiles": "Tất cả tệp",
|
||||
@@ -144,7 +147,6 @@
|
||||
"desc": "Thông minh xác định xem có cần tìm kiếm dựa trên nội dung cuộc trò chuyện",
|
||||
"title": "Kết nối thông minh"
|
||||
},
|
||||
"disable": "Mô hình hiện tại không hỗ trợ gọi hàm, do đó không thể sử dụng chức năng kết nối thông minh",
|
||||
"off": {
|
||||
"desc": "Chỉ sử dụng kiến thức cơ bản của mô hình, không thực hiện tìm kiếm trên mạng",
|
||||
"title": "Tắt kết nối"
|
||||
@@ -155,6 +157,10 @@
|
||||
},
|
||||
"useModelBuiltin": "Sử dụng công cụ tìm kiếm tích hợp của mô hình"
|
||||
},
|
||||
"searchModel": {
|
||||
"desc": "Mô hình hiện tại không hỗ trợ gọi hàm, vì vậy cần kết hợp với mô hình hỗ trợ gọi hàm để tìm kiếm trực tuyến",
|
||||
"title": "Mô hình hỗ trợ tìm kiếm"
|
||||
},
|
||||
"title": "Tìm kiếm trực tuyến"
|
||||
},
|
||||
"searchAgentPlaceholder": "Trợ lý tìm kiếm...",
|
||||
|
||||
@@ -85,6 +85,8 @@
|
||||
},
|
||||
"ModelSwitchPanel": {
|
||||
"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",
|
||||
"emptyProvider": "Không có nhà cung cấp nào được kích hoạt, vui lòng vào cài đặt để bật",
|
||||
"goToSettings": "Đi đến cài đặt",
|
||||
"provider": "Nhà cung cấp"
|
||||
},
|
||||
"OllamaSetupGuide": {
|
||||
|
||||
@@ -506,6 +506,9 @@
|
||||
"anthropic/claude-3.5-sonnet": {
|
||||
"description": "Claude 3.5 Sonnet cung cấp khả năng vượt trội hơn Opus và tốc độ nhanh hơn Sonnet, trong khi vẫn giữ giá tương tự. Sonnet đặc biệt xuất sắc trong lập trình, khoa học dữ liệu, xử lý hình ảnh và các nhiệm vụ đại lý."
|
||||
},
|
||||
"anthropic/claude-3.7-sonnet": {
|
||||
"description": "Claude 3.7 Sonnet là mô hình thông minh nhất của Anthropic cho đến nay, và cũng là mô hình suy luận hỗn hợp đầu tiên trên thị trường. Claude 3.7 Sonnet có khả năng tạo ra phản hồi gần như ngay lập tức hoặc suy nghĩ từng bước kéo dài, cho phép người dùng thấy rõ những quá trình này. Sonnet đặc biệt xuất sắc trong lập trình, khoa học dữ liệu, xử lý hình ảnh và các nhiệm vụ đại diện."
|
||||
},
|
||||
"aya": {
|
||||
"description": "Aya 23 là mô hình đa ngôn ngữ do Cohere phát hành, hỗ trợ 23 ngôn ngữ, tạo điều kiện thuận lợi cho các ứng dụng ngôn ngữ đa dạng."
|
||||
},
|
||||
|
||||
@@ -64,6 +64,9 @@
|
||||
"stop": "停止",
|
||||
"warp": "换行"
|
||||
},
|
||||
"intentUnderstanding": {
|
||||
"title": "正在分析并理解意图您的意图..."
|
||||
},
|
||||
"knowledgeBase": {
|
||||
"all": "所有内容",
|
||||
"allFiles": "所有文件",
|
||||
@@ -144,7 +147,6 @@
|
||||
"desc": "根据对话内容智能判断是否需要搜索",
|
||||
"title": "智能联网"
|
||||
},
|
||||
"disable": "当前模型不支持函数调用,因此无法使用智能联网功能",
|
||||
"off": {
|
||||
"desc": "仅使用模型的基础知识,不进行网络搜索",
|
||||
"title": "关闭联网"
|
||||
@@ -155,6 +157,10 @@
|
||||
},
|
||||
"useModelBuiltin": "使用模型内置搜索引擎"
|
||||
},
|
||||
"searchModel": {
|
||||
"desc": "当前模型不支持函数调用,因此需要搭配支持函数调用的模型才能联网搜索",
|
||||
"title": "搜索辅助模型"
|
||||
},
|
||||
"title": "联网搜索"
|
||||
},
|
||||
"searchAgentPlaceholder": "搜索助手...",
|
||||
|
||||
@@ -85,7 +85,9 @@
|
||||
},
|
||||
"ModelSwitchPanel": {
|
||||
"emptyModel": "没有启用的模型,请前往设置开启",
|
||||
"provider": "提供商"
|
||||
"emptyProvider": "没有启用的服务商,请前往设置开启",
|
||||
"goToSettings": "前往设置",
|
||||
"provider": "服务商"
|
||||
},
|
||||
"OllamaSetupGuide": {
|
||||
"cors": {
|
||||
|
||||
@@ -506,6 +506,9 @@
|
||||
"anthropic/claude-3.5-sonnet": {
|
||||
"description": "Claude 3.5 Sonnet 提供了超越 Opus 的能力和比 Sonnet 更快的速度,同时保持与 Sonnet 相同的价格。Sonnet 特别擅长编程、数据科学、视觉处理、代理任务。"
|
||||
},
|
||||
"anthropic/claude-3.7-sonnet": {
|
||||
"description": "Claude 3.7 Sonnet 是 Anthropic 迄今为止最智能的模型,也是市场上首个混合推理模型。Claude 3.7 Sonnet 可以产生近乎即时的响应或延长的逐步思考,用户可以清晰地看到这些过程。Sonnet 特别擅长编程、数据科学、视觉处理、代理任务。"
|
||||
},
|
||||
"aya": {
|
||||
"description": "Aya 23 是 Cohere 推出的多语言模型,支持 23 种语言,为多元化语言应用提供便利。"
|
||||
},
|
||||
|
||||
@@ -64,6 +64,9 @@
|
||||
"stop": "停止",
|
||||
"warp": "換行"
|
||||
},
|
||||
"intentUnderstanding": {
|
||||
"title": "正在分析並理解您的意圖..."
|
||||
},
|
||||
"knowledgeBase": {
|
||||
"all": "所有內容",
|
||||
"allFiles": "所有檔案",
|
||||
@@ -144,7 +147,6 @@
|
||||
"desc": "根據對話內容智能判斷是否需要搜尋",
|
||||
"title": "智能連網"
|
||||
},
|
||||
"disable": "當前模型不支持函數調用,因此無法使用智能連網功能",
|
||||
"off": {
|
||||
"desc": "僅使用模型的基礎知識,不進行網路搜尋",
|
||||
"title": "關閉連網"
|
||||
@@ -155,6 +157,10 @@
|
||||
},
|
||||
"useModelBuiltin": "使用模型內建搜尋引擎"
|
||||
},
|
||||
"searchModel": {
|
||||
"desc": "當前模型不支持函數調用,因此需要搭配支持函數調用的模型才能聯網搜索",
|
||||
"title": "搜索輔助模型"
|
||||
},
|
||||
"title": "連網搜尋"
|
||||
},
|
||||
"searchAgentPlaceholder": "搜尋助手...",
|
||||
|
||||
@@ -85,6 +85,8 @@
|
||||
},
|
||||
"ModelSwitchPanel": {
|
||||
"emptyModel": "沒有啟用的模型,請前往設定開啟",
|
||||
"emptyProvider": "沒有啟用的服務商,請前往設定開啟",
|
||||
"goToSettings": "前往設定",
|
||||
"provider": "提供商"
|
||||
},
|
||||
"OllamaSetupGuide": {
|
||||
|
||||
@@ -506,6 +506,9 @@
|
||||
"anthropic/claude-3.5-sonnet": {
|
||||
"description": "Claude 3.5 Sonnet 提供了超越 Opus 的能力和比 Sonnet 更快的速度,同時保持與 Sonnet 相同的價格。Sonnet 特別擅長程式設計、數據科學、視覺處理、代理任務。"
|
||||
},
|
||||
"anthropic/claude-3.7-sonnet": {
|
||||
"description": "Claude 3.7 Sonnet 是 Anthropic 迄今為止最智能的模型,也是市場上首個混合推理模型。Claude 3.7 Sonnet 可以產生近乎即時的回應或延長的逐步思考,使用者可以清晰地看到這些過程。Sonnet 特別擅長程式設計、數據科學、視覺處理、代理任務。"
|
||||
},
|
||||
"aya": {
|
||||
"description": "Aya 23 是 Cohere 推出的多語言模型,支持 23 種語言,為多元化語言應用提供便利。"
|
||||
},
|
||||
|
||||
+3
-3
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@lobehub/chat",
|
||||
"version": "1.69.4",
|
||||
"version": "1.70.0",
|
||||
"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.",
|
||||
"keywords": [
|
||||
"framework",
|
||||
@@ -120,7 +120,7 @@
|
||||
"@clerk/themes": "^2.2.4",
|
||||
"@codesandbox/sandpack-react": "^2.19.10",
|
||||
"@cyntler/react-doc-viewer": "^1.17.0",
|
||||
"@electric-sql/pglite": "0.2.13",
|
||||
"@electric-sql/pglite": "0.2.17",
|
||||
"@google-cloud/vertexai": "^1.9.2",
|
||||
"@google/generative-ai": "^0.24.0",
|
||||
"@huggingface/inference": "^2.8.1",
|
||||
@@ -326,7 +326,7 @@
|
||||
"vitest": "~1.2.2",
|
||||
"vitest-canvas-mock": "^0.3.3"
|
||||
},
|
||||
"packageManager": "pnpm@9.15.6",
|
||||
"packageManager": "pnpm@9.15.7",
|
||||
"publishConfig": {
|
||||
"access": "public",
|
||||
"registry": "https://registry.npmjs.org"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"main": "src/index.ts",
|
||||
"types": "src/index.ts",
|
||||
"dependencies": {
|
||||
"@mozilla/readability": "^0.5.0",
|
||||
"@mozilla/readability": "^0.6.0",
|
||||
"happy-dom": "^17.0.0",
|
||||
"node-html-markdown": "^1.3.0",
|
||||
"query-string": "^9.1.1",
|
||||
|
||||
@@ -67,7 +67,7 @@ describe('browserless', () => {
|
||||
contentType: 'text',
|
||||
description: expect.any(String),
|
||||
length: expect.any(Number),
|
||||
siteName: null,
|
||||
siteName: undefined,
|
||||
title: 'Test Title',
|
||||
url: 'https://example.com',
|
||||
});
|
||||
|
||||
@@ -48,7 +48,7 @@ export const browserless: CrawlImpl = async (url, { filterOptions }) => {
|
||||
return {
|
||||
content: result.content,
|
||||
contentType: 'text',
|
||||
description: result?.excerpt,
|
||||
description: result?.description,
|
||||
length: result.length,
|
||||
siteName: result?.siteName,
|
||||
title: result?.title,
|
||||
|
||||
@@ -103,7 +103,7 @@ export const naive: CrawlImpl = async (url, { filterOptions }) => {
|
||||
return {
|
||||
content: result.content,
|
||||
contentType: 'text',
|
||||
description: result?.excerpt,
|
||||
description: result?.description,
|
||||
length: result.length,
|
||||
siteName: result?.siteName,
|
||||
title: result?.title,
|
||||
|
||||
@@ -3,8 +3,18 @@ import { CrawlUrlRule } from './type';
|
||||
import { crawUrlRules } from './urlRules';
|
||||
import { applyUrlRules } from './utils/appUrlRules';
|
||||
|
||||
interface CrawlOptions {
|
||||
impls?: string[];
|
||||
}
|
||||
|
||||
export class Crawler {
|
||||
impls = ['naive', 'jina', 'browserless'] as const;
|
||||
impls: CrawlImplType[];
|
||||
|
||||
constructor(options: CrawlOptions = {}) {
|
||||
this.impls = !!options.impls?.length
|
||||
? (options.impls.filter((impl) => Object.keys(crawlImpls).includes(impl)) as CrawlImplType[])
|
||||
: (['naive', 'jina', 'browserless'] as const);
|
||||
}
|
||||
|
||||
/**
|
||||
* 爬取网页内容
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
exports[`htmlToMarkdown > should transform terms.html to markdown 1`] = `
|
||||
{
|
||||
"byline": null,
|
||||
"content": " Lasted Updated at
|
||||
|
||||
2024-03-01
|
||||
@@ -111,378 +110,14 @@ Examples of prohibited activities include but are not limited to:
|
||||
This agreement represents the entire agreement between You and LobeHub regarding the use of the Services. It supersedes any prior agreements or understandings. The failure of LobeHub to enforce any provision of this agreement does not constitute a waiver of its rights.
|
||||
|
||||
By accessing or using the LobeHub Services, You acknowledge that You have read, understood, and agreed to be bound by this agreement. If You have any questions regarding this agreement, please contact us at[support@lobehub.com](mailto:support@lobehub.com).",
|
||||
"dir": null,
|
||||
"excerpt": "Lasted Updated at",
|
||||
"lang": null,
|
||||
"description": "Lasted Updated at",
|
||||
"length": 18284,
|
||||
"publishedTime": null,
|
||||
"siteName": null,
|
||||
"textContent": "
|
||||
|
||||
|
||||
Lasted Updated at
|
||||
2024-03-01
|
||||
|
||||
|
||||
|
||||
Welcome to LobeHub! Please carefully read the following Terms of Use (hereinafter
|
||||
referred to as the "Agreement"). This Agreement constitutes a legally binding
|
||||
agreement between You and LobeHub regarding the access and use of the LobeHub
|
||||
software applications, services, and websites (collectively referred to as the
|
||||
"Services").
|
||||
|
||||
|
||||
By accessing or using the Services in any way, You acknowledge that You have read,
|
||||
understood, and agreed to be bound by all the terms of this Agreement. If You do not
|
||||
agree to any part of this Agreement, You are not permitted to continue accessing or
|
||||
using the Services.
|
||||
|
||||
|
||||
Definitions
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
The words of which the initial letter is capitalized have meanings defined under the
|
||||
following conditions. The following definitions shall have the same meaning
|
||||
regardless of whether they appear in singular or in plural.
|
||||
|
||||
|
||||
|
||||
Affiliate means an entity that controls, is controlled by or is
|
||||
under common control with a party, where "control" means ownership of 50% or more
|
||||
of the shares, equity interest or other securities entitled to vote for election
|
||||
of directors or other managing authority.
|
||||
|
||||
Agreement means this Terms of Use Agreement.
|
||||
|
||||
Company (referred to as either "the Company", "We", "Us" or "Our"
|
||||
in this Agreement) refers to LobeHub LLC.
|
||||
|
||||
|
||||
Service means the LobeHub software applications, services, and
|
||||
website.
|
||||
|
||||
|
||||
You means the individual accessing or using the Services, or the
|
||||
company, or other legal entity on behalf of which such individual is accessing or
|
||||
using the Services, as applicable.
|
||||
|
||||
|
||||
|
||||
Our Services
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
LobeHub provides a platform and interface that enables users to interact with
|
||||
artificial intelligence technologies, including but not limited to natural language
|
||||
processing models or content generation models developed independently or provided
|
||||
by third parties such as Google, Microsoft, OpenAI, and other commercial companies
|
||||
as well as open-source communities. The Service facilitates functions such as
|
||||
information retrieval, content creation, and automation through user interaction
|
||||
with AI systems. Additionally, it utilizes cloud technology to provide capabilities
|
||||
like data synchronization, vector data storage, server-side functionalities, etc.,
|
||||
to enhance the interactive experience with AI models.
|
||||
|
||||
|
||||
Eligibility
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
By accessing or using the Services, You represent and warrant to the Company that
|
||||
You: (1)Are of legal age (18 years and above). (2)Have legal capacity and agree to
|
||||
abide by these terms. (3)Will use the Services in accordance with this Agreement and
|
||||
all applicable laws. (4)Will not use the Services for any illegal, harmful,
|
||||
dangerous, or offensive purposes.
|
||||
|
||||
Examples of prohibited activities include but are not limited to:
|
||||
|
||||
Illegal activities
|
||||
Infringement of intellectual property rights
|
||||
Generating harmful, unsafe, deceptive, or illegal content
|
||||
Impersonation, fraud
|
||||
|
||||
|
||||
If You do not comply with the usage conditions, We reserve the right to suspend or
|
||||
terminate Your account and refuse any and all current or future use of the Services
|
||||
(or any part thereof).
|
||||
|
||||
|
||||
Account Registration
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
To access the Services, You must register an account by providing true, accurate,
|
||||
up-to-date, and complete information. You are solely responsible for all activities
|
||||
that occur under Your account, including maintaining the security of Your account
|
||||
and restricting access. You must immediately notify LobeHub of any unauthorized
|
||||
account use or other security breaches.
|
||||
|
||||
|
||||
Please ensure to keep Your password secure and take responsibility for all use of
|
||||
Your account and password. If We deem the chosen username inappropriate, containing
|
||||
obscene content, or otherwise offensive, We reserve the right to delete, revoke, or
|
||||
modify that username.
|
||||
|
||||
|
||||
Purchases and Payments
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
You agree to provide current, complete, and accurate purchase and account
|
||||
information for all purchases made using the Services. You also agree to promptly
|
||||
update Your account and payment information, including email address, payment
|
||||
method, and payment card expiration date, to allow us to complete Your transactions
|
||||
and contact You when necessary. Sales tax will be added to the purchase price as
|
||||
required by law.
|
||||
|
||||
|
||||
You agree to pay all charges at the current purchase price and authorize us to
|
||||
charge any such amounts to Your chosen payment provider at the time of purchase. If
|
||||
Your order requires recurring charges, You agree that We may charge Your payment
|
||||
method on a recurring basis at the specified intervals without obtaining prior
|
||||
approval for each recurring charge until the relevant order is canceled. We reserve
|
||||
the right to correct any errors or pricing errors even after payment has been
|
||||
requested or accepted.
|
||||
|
||||
|
||||
We may utilize third-party payment processing services (such as Stripe) for payment
|
||||
processing. You may use a valid card (credit or debit card) for payment, subject to
|
||||
verification and authorization by Your card issuer. We will not be liable for any
|
||||
delays or failure to provide Services resulting from payment failures due to
|
||||
authorization issues or any reasons related to third-party payment providers.
|
||||
|
||||
|
||||
We reserve the right to refuse or cancel Your order at any time for certain reasons,
|
||||
including but not limited to: (1) Service availability, (2) errors in Service
|
||||
description or pricing, (3) order errors, (4) suspected fraud or unauthorized or
|
||||
illegal transactions. We reserve the right, at our sole discretion, to limit or
|
||||
prohibit orders placed by dealers, resellers, or distributors.
|
||||
|
||||
|
||||
Fee Changes
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
We reserve the right to adjust the Service fees at our discretion and at any time.
|
||||
Any changes in fees will take effect immediately upon the change. Services that have
|
||||
already been paid for and purchased will not be affected.
|
||||
|
||||
|
||||
If Your order requires recurring automatic billing, the revised price will take
|
||||
effect on the next billing cycle. We will notify You in advance of any fee
|
||||
adjustments so that You have the opportunity to cancel the order before the
|
||||
adjustment takes effect. If You do not cancel the order and continue to use the
|
||||
Services, You agree to pay the revised fee amount.
|
||||
|
||||
|
||||
Refunds
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
For Services that have been purchased but not used, We support refunds within 30
|
||||
days of payment. However, for Services that have been used or purchased for more
|
||||
than 30 days, We will not accept refund requests.
|
||||
|
||||
|
||||
For subscription-based Services where partial usage has occurred, Your refund
|
||||
request will be reviewed on a case-by-case basis, and the final decision on
|
||||
approving the refund will be at the Company's discretion.
|
||||
|
||||
|
||||
Content
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Our Services allows You to generate and publish content. You are responsible for the
|
||||
legality, reliability, and appropriateness of the content generated using the AI
|
||||
ability. We do not assume responsibility for user-generated content on the Services.
|
||||
You explicitly understand and agree that You are solely responsible for the content
|
||||
You post and all activities conducted under Your account, whether by Yourself or by
|
||||
third parties using Your account.
|
||||
|
||||
|
||||
By generating and publishing content in the Services, You grant us the rights and
|
||||
licenses necessary to use, modify, publicly perform, publicly display, copy, and
|
||||
distribute such content within the Services. You retain full ownership of all
|
||||
content created, published, or displayed within the Services and are responsible for
|
||||
maintaining these rights. You agree that this license includes the permission for us
|
||||
to provide Your content to other Service users for their use under these terms.
|
||||
Additionally, You declare and warrant that: (1) the content is owned by You or You
|
||||
have the legal right to use and authorize it to us under this agreement. (2) posting
|
||||
the shared information in the Services will not infringe upon the privacy rights,
|
||||
image rights, copyrights, contractual relationships, or other individual rights of
|
||||
others.
|
||||
|
||||
|
||||
All content generated by You is by default stored locally on the client-side, and
|
||||
You are responsible for the storage and backup of Your content.
|
||||
|
||||
|
||||
Additionally, We offer optional cloud sync content functionality. By using this
|
||||
feature, You agree that We may retain complete and accurate copies of any content in
|
||||
locations independent of the Services in our manner. However, We cannot guarantee
|
||||
that data will not be lost or damaged. Data or content loss or damage can occur due
|
||||
to various reasons, such as pre-existing damage before synchronization or changes
|
||||
during synchronization.
|
||||
|
||||
|
||||
We do not assume any responsibility for the security and integrity of content in the
|
||||
event of content damage or loss under any circumstances.
|
||||
|
||||
|
||||
Intellectual Property Rights
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
LobeHub reserves all rights to the technology, software, first-party content, and
|
||||
data within the Services, including but not limited to patents, trademarks, trade
|
||||
secrets, copyrights, and other intellectual property rights. Your permission to use
|
||||
the Services does not grant You any ownership or title. You are not permitted to
|
||||
copy, modify, adapt, translate, create derivative works, reverse engineer,
|
||||
disassemble, or decompile the Services or any part thereof. If You wish to
|
||||
participate in collaborative technical development, please engage through our GitHub
|
||||
open-source community and adhere to the relevant open-source licenses.
|
||||
|
||||
|
||||
Privacy and Security
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
LobeHub employs industry-standard technical, managerial, and physical security
|
||||
measures to protect the security, confidentiality, and integrity of Your data.
|
||||
However, We cannot guarantee that unauthorized access, hacking attacks, data loss,
|
||||
or other breaches will never occur. LobeHub is not liable for any damages or
|
||||
liabilities related to security incidents. Please refer to our Privacy Policy for
|
||||
more detailed information.
|
||||
|
||||
|
||||
Termination of Services
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
You may close Your account and cease using the Services at any time. In the event of
|
||||
a violation of the terms of the agreement, LobeHub may immediately suspend or
|
||||
terminate Your access to the Services. Upon termination, You will immediately lose
|
||||
the right to access or use the Services. LobeHub will not be liable to You or any
|
||||
third party for the termination of the Services.
|
||||
|
||||
|
||||
Disclaimer of Warranties
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
The Services provided by LobeHub are provided on an "as-is" basis, and without any
|
||||
form of guarantee. We explicitly disclaim all warranties, whether express, implied,
|
||||
statutory, or otherwise, including but not limited to warranties of merchantability,
|
||||
fitness for a particular purpose, and non-infringement. Your use of the Services is
|
||||
at Your own risk.
|
||||
|
||||
|
||||
Limitation of Liability
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
In no event shall LobeHub, its Affiliates, directors, employees, or agents be liable
|
||||
for any direct, indirect, punitive, incidental, special, or consequential damages
|
||||
arising from or related to Your use or inability to use the Services. This
|
||||
limitation applies regardless of the basis or form of action.
|
||||
|
||||
|
||||
Modification of Terms
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
We may revise this agreement periodically, and the new version of the agreement will
|
||||
replace the previous version. We will indicate the "last updated" date at the
|
||||
beginning and provide notice within the Services to inform You of significant
|
||||
changes. It is Your responsibility to regularly review these legal terms to stay
|
||||
informed of any updates. By continuing to use the Services after the revised legal
|
||||
terms are posted, You will be deemed to have understood and accepted any changes to
|
||||
the revised legal terms.
|
||||
|
||||
|
||||
Governing Law and Jurisdiction
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
This agreement shall be governed by the laws of the State of Delaware, and You agree
|
||||
to submit to the exclusive jurisdiction of the state and federal courts located in
|
||||
Delaware for the resolution of any disputes related to this agreement or the
|
||||
Services. You may also be required to comply with the laws of Your local
|
||||
jurisdiction, state, country, or international laws when using the Services.
|
||||
|
||||
|
||||
Conclusion
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
This agreement represents the entire agreement between You and LobeHub regarding the
|
||||
use of the Services. It supersedes any prior agreements or understandings. The
|
||||
failure of LobeHub to enforce any provision of this agreement does not constitute a
|
||||
waiver of its rights.
|
||||
|
||||
|
||||
By accessing or using the LobeHub Services, You acknowledge that You have read,
|
||||
understood, and agreed to be bound by this agreement. If You have any questions
|
||||
regarding this agreement, please contact us at
|
||||
support@lobehub.com.
|
||||
|
||||
",
|
||||
"title": "Terms of Service · LobeHub",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`htmlToMarkdown > should transform yingchao.html to markdown 1`] = `
|
||||
{
|
||||
"byline": null,
|
||||
"content": " 资讯
|
||||
|
||||
全部 NBA CBA 英超 法甲 意甲 德甲 西甲 综合 专题 预测
|
||||
@@ -616,23 +251,8 @@ copyright © 2016 - 2025 qiumiwu.com All Rights Reserved
|
||||
温馨提示
|
||||
|
||||
扫描二维码,下载球迷屋App,获得更好的使用体验",
|
||||
"dir": null,
|
||||
"excerpt": "球迷屋为您提供2024-2025赛季英超积分排行榜,包含所有英超球队的全部赛季的排行榜数据,包含了英超球队的排名、场次、胜平负、进球、失球、积分等等详细积分数据,让大家迅速了解英超积分排行榜的数据。",
|
||||
"lang": null,
|
||||
"description": "球迷屋为您提供2024-2025赛季英超积分排行榜,包含所有英超球队的全部赛季的排行榜数据,包含了英超球队的排名、场次、胜平负、进球、失球、积分等等详细积分数据,让大家迅速了解英超积分排行榜的数据。",
|
||||
"length": 201,
|
||||
"publishedTime": null,
|
||||
"siteName": null,
|
||||
"textContent": "
|
||||
copyright © 2016 - 2025 qiumiwu.com All Rights Reserved
|
||||
|
||||
|
||||
|
||||
粤公网安备 44190002004105号
|
||||
粤ICP备16062857号
|
||||
增值电信业务经营许可证粤B2-20210041
|
||||
粤网文[2021]4047-607号
|
||||
|
||||
",
|
||||
"title": "英超排行榜|英超积分榜2024-2025赛季 - 球迷屋",
|
||||
}
|
||||
`;
|
||||
|
||||
@@ -4,10 +4,28 @@ import { NodeHtmlMarkdown, type TranslatorConfigObject } from 'node-html-markdow
|
||||
|
||||
import { FilterOptions } from '../type';
|
||||
|
||||
const cleanObj = <T extends object>(
|
||||
obj: T,
|
||||
): {
|
||||
[K in keyof T as T[K] extends null ? never : K]: T[K];
|
||||
} => Object.fromEntries(Object.entries(obj).filter(([, value]) => value !== null)) as any;
|
||||
|
||||
interface HtmlToMarkdownOutput {
|
||||
author?: string;
|
||||
content: string;
|
||||
description?: string;
|
||||
dir?: string;
|
||||
lang?: string;
|
||||
length?: number;
|
||||
publishedTime?: string;
|
||||
siteName?: string;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
export const htmlToMarkdown = (
|
||||
html: string,
|
||||
{ url, filterOptions }: { filterOptions: FilterOptions; url: string },
|
||||
) => {
|
||||
): HtmlToMarkdownOutput => {
|
||||
const window = new Window({ url });
|
||||
|
||||
const document = window.document;
|
||||
@@ -41,5 +59,17 @@ export const htmlToMarkdown = (
|
||||
|
||||
const content = nodeHtmlMarkdown.translate(htmlNode);
|
||||
|
||||
return { ...parsedContent, content };
|
||||
const result = {
|
||||
author: parsedContent?.byline,
|
||||
content,
|
||||
description: parsedContent?.excerpt,
|
||||
dir: parsedContent?.dir,
|
||||
lang: parsedContent?.lang,
|
||||
length: parsedContent?.length,
|
||||
publishedTime: parsedContent?.publishedTime,
|
||||
siteName: parsedContent?.siteName,
|
||||
title: parsedContent?.title,
|
||||
};
|
||||
|
||||
return cleanObj(result) as HtmlToMarkdownOutput;
|
||||
};
|
||||
|
||||
@@ -181,7 +181,10 @@ describe('POST handler', () => {
|
||||
const response = await POST(request as unknown as Request, { params: mockParams });
|
||||
|
||||
expect(response).toEqual(mockChatResponse);
|
||||
expect(AgentRuntime.prototype.chat).toHaveBeenCalledWith(mockChatPayload, { user: 'abc' });
|
||||
expect(AgentRuntime.prototype.chat).toHaveBeenCalledWith(mockChatPayload, {
|
||||
user: 'abc',
|
||||
signal: expect.anything(),
|
||||
});
|
||||
});
|
||||
|
||||
it('should return an error response when chat completion fails', async () => {
|
||||
|
||||
@@ -39,7 +39,11 @@ export const POST = checkAuth(async (req: Request, { params, jwtPayload, createR
|
||||
});
|
||||
}
|
||||
|
||||
return await agentRuntime.chat(data, { user: jwtPayload.userId, ...traceOptions });
|
||||
return await agentRuntime.chat(data, {
|
||||
user: jwtPayload.userId,
|
||||
...traceOptions,
|
||||
signal: req.signal,
|
||||
});
|
||||
} catch (e) {
|
||||
const {
|
||||
errorType = ChatErrorType.InternalServerError,
|
||||
|
||||
+5
-1
@@ -105,7 +105,11 @@ const AgentsSuggest = memo<{ mobile?: boolean }>(({ mobile }) => {
|
||||
: assistantList
|
||||
.slice(sliceStart, sliceStart + agentLength)
|
||||
.map((item: DiscoverAssistantItem) => (
|
||||
<Link href={urlJoin('/discover/assistant/', item.identifier)} key={item.identifier}>
|
||||
<Link
|
||||
href={urlJoin('/discover/assistant/', item.identifier)}
|
||||
key={item.identifier}
|
||||
prefetch={false}
|
||||
>
|
||||
<Flexbox className={styles.card} gap={8} horizontal>
|
||||
<Avatar avatar={item.meta.avatar} style={{ flex: 'none' }} />
|
||||
<Flexbox gap={mobile ? 2 : 8} style={{ overflow: 'hidden', width: '100%' }}>
|
||||
|
||||
+4
-3
@@ -1,4 +1,5 @@
|
||||
import { createStyles } from 'antd-style';
|
||||
import { memo } from 'react';
|
||||
|
||||
export const useStyles = createStyles(({ css, token }, borderWidth: number = 2.5) => ({
|
||||
background: css`
|
||||
@@ -44,7 +45,7 @@ export const useStyles = createStyles(({ css, token }, borderWidth: number = 2.5
|
||||
`,
|
||||
}));
|
||||
|
||||
const Loader = () => {
|
||||
const CircleLoader = memo(() => {
|
||||
const { styles } = useStyles();
|
||||
|
||||
return (
|
||||
@@ -53,6 +54,6 @@ const Loader = () => {
|
||||
<div className={styles.background} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
});
|
||||
|
||||
export default Loader;
|
||||
export default CircleLoader;
|
||||
@@ -301,6 +301,9 @@ const OpenAI: ModelProviderCard = {
|
||||
name: 'OpenAI',
|
||||
settings: {
|
||||
showModelFetcher: true,
|
||||
smoothing: {
|
||||
text: true,
|
||||
},
|
||||
},
|
||||
url: 'https://openai.com',
|
||||
};
|
||||
|
||||
@@ -4,10 +4,12 @@ import { z } from 'zod';
|
||||
export const getToolsConfig = () => {
|
||||
return createEnv({
|
||||
runtimeEnv: {
|
||||
CRAWLER_IMPLS: process.env.CRAWLER_IMPLS,
|
||||
SEARXNG_URL: process.env.SEARXNG_URL,
|
||||
},
|
||||
|
||||
server: {
|
||||
CRAWLER_IMPLS: z.string().optional(),
|
||||
SEARXNG_URL: z.string().url().optional(),
|
||||
},
|
||||
});
|
||||
|
||||
@@ -13,6 +13,11 @@ export const DEFAUTT_AGENT_TTS_CONFIG: LobeAgentTTSConfig = {
|
||||
},
|
||||
};
|
||||
|
||||
export const DEFAULT_AGENT_SEARCH_FC_MODEL = {
|
||||
model: DEFAULT_MODEL,
|
||||
provider: ModelProvider.OpenAI,
|
||||
};
|
||||
|
||||
export const DEFAULT_AGENT_CHAT_CONFIG: LobeAgentChatConfig = {
|
||||
autoCreateTopicThreshold: 2,
|
||||
displayMode: 'chat',
|
||||
@@ -22,6 +27,7 @@ export const DEFAULT_AGENT_CHAT_CONFIG: LobeAgentChatConfig = {
|
||||
enableReasoning: false,
|
||||
historyCount: 8,
|
||||
reasoningBudgetToken: 1024,
|
||||
searchFCModel: DEFAULT_AGENT_SEARCH_FC_MODEL,
|
||||
searchMode: 'off',
|
||||
};
|
||||
|
||||
|
||||
@@ -26,13 +26,13 @@ export class DatabaseManager {
|
||||
|
||||
// CDN 配置
|
||||
private static WASM_CDN_URL =
|
||||
'https://registry.npmmirror.com/@electric-sql/pglite/0.2.13/files/dist/postgres.wasm';
|
||||
'https://registry.npmmirror.com/@electric-sql/pglite/0.2.17/files/dist/postgres.wasm';
|
||||
|
||||
private static FSBUNDLER_CDN_URL =
|
||||
'https://registry.npmmirror.com/@electric-sql/pglite/0.2.13/files/dist/postgres.data';
|
||||
'https://registry.npmmirror.com/@electric-sql/pglite/0.2.17/files/dist/postgres.data';
|
||||
|
||||
private static VECTOR_CDN_URL =
|
||||
'https://registry.npmmirror.com/@electric-sql/pglite/0.2.13/files/dist/vector.tar.gz';
|
||||
'https://registry.npmmirror.com/@electric-sql/pglite/0.2.17/files/dist/vector.tar.gz';
|
||||
|
||||
private constructor() {}
|
||||
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import { createStyles } from 'antd-style';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Flexbox } from 'react-layout-kit';
|
||||
|
||||
import InfoTooltip from '@/components/InfoTooltip';
|
||||
import { useAgentStore } from '@/store/agent';
|
||||
import { agentChatConfigSelectors } from '@/store/agent/slices/chat';
|
||||
|
||||
import FunctionCallingModelSelect from './FunctionCallingModelSelect';
|
||||
|
||||
const useStyles = createStyles(({ css, token }) => ({
|
||||
check: css`
|
||||
margin-inline-start: 12px;
|
||||
font-size: 16px;
|
||||
color: ${token.colorPrimary};
|
||||
`,
|
||||
content: css`
|
||||
flex: 1;
|
||||
width: 230px;
|
||||
`,
|
||||
description: css`
|
||||
width: 200px;
|
||||
font-size: 12px;
|
||||
color: ${token.colorTextSecondary};
|
||||
`,
|
||||
title: css`
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: ${token.colorText};
|
||||
`,
|
||||
}));
|
||||
|
||||
const FCSearchModel = () => {
|
||||
const { t } = useTranslation('chat');
|
||||
const { styles } = useStyles();
|
||||
const [searchFCModel, updateAgentChatConfig] = useAgentStore((s) => [
|
||||
agentChatConfigSelectors.searchFCModel(s),
|
||||
s.updateAgentChatConfig,
|
||||
]);
|
||||
return (
|
||||
<Flexbox distribution={'space-between'} gap={16} horizontal padding={8}>
|
||||
<Flexbox align={'center'} gap={4} horizontal>
|
||||
<Flexbox className={styles.title}>{t('search.searchModel.title')}</Flexbox>
|
||||
<InfoTooltip title={t('search.searchModel.desc')} />
|
||||
</Flexbox>
|
||||
<FunctionCallingModelSelect
|
||||
onChange={(value) => {
|
||||
updateAgentChatConfig({ searchFCModel: value });
|
||||
}}
|
||||
value={searchFCModel}
|
||||
/>
|
||||
</Flexbox>
|
||||
);
|
||||
};
|
||||
|
||||
export default FCSearchModel;
|
||||
@@ -0,0 +1,85 @@
|
||||
import { Select, SelectProps } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import { memo, useMemo } from 'react';
|
||||
|
||||
import { ModelItemRender, ProviderItemRender } from '@/components/ModelSelect';
|
||||
import { useEnabledChatModels } from '@/hooks/useEnabledChatModels';
|
||||
import { WorkingModel } from '@/types/agent';
|
||||
import { EnabledProviderWithModels } from '@/types/aiProvider';
|
||||
|
||||
const useStyles = createStyles(({ css, prefixCls }) => ({
|
||||
select: css`
|
||||
&.${prefixCls}-select-dropdown .${prefixCls}-select-item-option-grouped {
|
||||
padding-inline-start: 12px;
|
||||
}
|
||||
`,
|
||||
}));
|
||||
|
||||
interface ModelOption {
|
||||
label: any;
|
||||
provider: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
interface ModelSelectProps {
|
||||
onChange?: (props: WorkingModel) => void;
|
||||
showAbility?: boolean;
|
||||
value?: WorkingModel;
|
||||
}
|
||||
|
||||
const ModelSelect = memo<ModelSelectProps>(({ value, onChange }) => {
|
||||
const enabledList = useEnabledChatModels();
|
||||
|
||||
const { styles } = useStyles();
|
||||
|
||||
const options = useMemo<SelectProps['options']>(() => {
|
||||
const getChatModels = (provider: EnabledProviderWithModels) =>
|
||||
provider.children
|
||||
.filter((model) => !!model.abilities.functionCall)
|
||||
.map((model) => ({
|
||||
label: <ModelItemRender {...model} {...model.abilities} showInfoTag={false} />,
|
||||
provider: provider.id,
|
||||
value: `${provider.id}/${model.id}`,
|
||||
}));
|
||||
|
||||
if (enabledList.length === 1) {
|
||||
const provider = enabledList[0];
|
||||
|
||||
return getChatModels(provider);
|
||||
}
|
||||
|
||||
return enabledList
|
||||
.filter((p) => !!getChatModels(p).length)
|
||||
.map((provider) => {
|
||||
const options = getChatModels(provider);
|
||||
|
||||
return {
|
||||
label: (
|
||||
<ProviderItemRender
|
||||
logo={provider.logo}
|
||||
name={provider.name}
|
||||
provider={provider.id}
|
||||
source={provider.source}
|
||||
/>
|
||||
),
|
||||
options,
|
||||
};
|
||||
});
|
||||
}, [enabledList]);
|
||||
|
||||
return (
|
||||
<Select
|
||||
onChange={(value, option) => {
|
||||
const model = value.split('/').slice(1).join('/');
|
||||
onChange?.({ model, provider: (option as unknown as ModelOption).provider });
|
||||
}}
|
||||
options={options}
|
||||
popupClassName={styles.select}
|
||||
popupMatchSelectWidth={false}
|
||||
value={`${value?.provider}/${value?.model}`}
|
||||
variant={'filled'}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
export default ModelSelect;
|
||||
@@ -12,6 +12,7 @@ import { agentChatConfigSelectors, agentSelectors } from '@/store/agent/slices/c
|
||||
import { aiModelSelectors, useAiInfraStore } from '@/store/aiInfra';
|
||||
import { SearchMode } from '@/types/search';
|
||||
|
||||
import FCSearchModel from './FCSearchModel';
|
||||
import ModelBuiltinSearch from './ModelBuiltinSearch';
|
||||
|
||||
const { Text } = Typography;
|
||||
@@ -38,10 +39,6 @@ const useStyles = createStyles(({ css, token }) => ({
|
||||
font-size: 12px;
|
||||
color: ${token.colorTextSecondary};
|
||||
`,
|
||||
disable: css`
|
||||
cursor: not-allowed;
|
||||
opacity: 0.45;
|
||||
`,
|
||||
iconWrapper: css`
|
||||
display: flex;
|
||||
flex-shrink: 0;
|
||||
@@ -80,8 +77,7 @@ const useStyles = createStyles(({ css, token }) => ({
|
||||
`,
|
||||
}));
|
||||
|
||||
const Item = memo<NetworkOption>(({ value, description, icon, label, disable }) => {
|
||||
const { t } = useTranslation('chat');
|
||||
const Item = memo<NetworkOption>(({ value, description, icon, label }) => {
|
||||
const { styles } = useStyles();
|
||||
const [mode, updateAgentChatConfig] = useAgentStore((s) => [
|
||||
agentChatConfigSelectors.agentSearchMode(s),
|
||||
@@ -96,12 +92,12 @@ const Item = memo<NetworkOption>(({ value, description, icon, label, disable })
|
||||
key={value}
|
||||
onClick={() => updateAgentChatConfig({ searchMode: value })}
|
||||
>
|
||||
<Flexbox className={disable ? styles.disable : ''} gap={8} horizontal>
|
||||
<Flexbox gap={8} horizontal>
|
||||
<div className={styles.iconWrapper}>{icon}</div>
|
||||
<div className={styles.content}>
|
||||
<div className={styles.title}>{label}</div>
|
||||
<Text className={styles.description} type="secondary">
|
||||
{disable ? t('search.mode.disable') : description}
|
||||
{description}
|
||||
</Text>
|
||||
</div>
|
||||
</Flexbox>
|
||||
@@ -132,34 +128,24 @@ const AINetworkSettings = memo<AINetworkSettingsProps>(() => {
|
||||
label: t('search.mode.off.title'),
|
||||
value: 'off',
|
||||
},
|
||||
// 等应用层联网功能做好以后再开启
|
||||
// {
|
||||
// description: t('search.mode.on.desc'),
|
||||
// icon: <WifiOutlined />,
|
||||
// label: t('search.mode.on.title'),
|
||||
// value: 'on',
|
||||
// },
|
||||
{
|
||||
description: t('search.mode.auto.desc'),
|
||||
disable: !supportFC,
|
||||
icon: <Icon icon={SparklesIcon} />,
|
||||
label: t('search.mode.auto.title'),
|
||||
value: 'auto',
|
||||
},
|
||||
];
|
||||
|
||||
const showDivider = isModelHasBuiltinSearchConfig || !supportFC;
|
||||
|
||||
return (
|
||||
<Flexbox gap={8}>
|
||||
{options.map((option) => (
|
||||
<Item {...option} key={option.value} />
|
||||
))}
|
||||
|
||||
{isModelHasBuiltinSearchConfig && (
|
||||
<>
|
||||
<Divider style={{ margin: 0, paddingInline: 12 }} />
|
||||
<ModelBuiltinSearch />
|
||||
</>
|
||||
)}
|
||||
{showDivider && <Divider style={{ margin: 0, paddingInline: 12 }} />}
|
||||
{isModelHasBuiltinSearchConfig && <ModelBuiltinSearch />}
|
||||
{!supportFC && <FCSearchModel />}
|
||||
</Flexbox>
|
||||
);
|
||||
});
|
||||
|
||||
@@ -7,11 +7,10 @@ import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Flexbox } from 'react-layout-kit';
|
||||
|
||||
import { getPrice } from '@/features/Conversation/Extras/Usage/UsageDetail/pricing';
|
||||
import { useGlobalStore } from '@/store/global';
|
||||
import { systemStatusSelectors } from '@/store/global/selectors';
|
||||
import { LobeDefaultAiModelListItem } from '@/types/aiModel';
|
||||
import { ModelPriceCurrency } from '@/types/llm';
|
||||
import { formatPriceByCurrency } from '@/utils/format';
|
||||
|
||||
export const useStyles = createStyles(({ css, token }) => {
|
||||
return {
|
||||
@@ -40,19 +39,8 @@ const ModelCard = memo<ModelCardProps>(({ pricing, id, provider, displayName })
|
||||
const isShowCredit = useGlobalStore(systemStatusSelectors.isShowCredit) && !!pricing;
|
||||
const updateSystemStatus = useGlobalStore((s) => s.updateSystemStatus);
|
||||
|
||||
const inputPrice = formatPriceByCurrency(pricing?.input, pricing?.currency as ModelPriceCurrency);
|
||||
const cachedInputPrice = formatPriceByCurrency(
|
||||
pricing?.cachedInput,
|
||||
pricing?.currency as ModelPriceCurrency,
|
||||
);
|
||||
const writeCacheInputPrice = formatPriceByCurrency(
|
||||
pricing?.writeCacheInput,
|
||||
pricing?.currency as ModelPriceCurrency,
|
||||
);
|
||||
const outputPrice = formatPriceByCurrency(
|
||||
pricing?.output,
|
||||
pricing?.currency as ModelPriceCurrency,
|
||||
);
|
||||
const formatPrice = getPrice(pricing || {});
|
||||
|
||||
return (
|
||||
<Flexbox gap={8}>
|
||||
<Flexbox
|
||||
@@ -103,37 +91,41 @@ const ModelCard = memo<ModelCardProps>(({ pricing, id, provider, displayName })
|
||||
{pricing?.cachedInput && (
|
||||
<Tooltip
|
||||
title={t('messages.modelCard.pricing.inputCachedTokens', {
|
||||
amount: cachedInputPrice,
|
||||
amount: formatPrice.cachedInput,
|
||||
})}
|
||||
>
|
||||
<Flexbox gap={2} horizontal>
|
||||
<Icon icon={CircleFadingArrowUp} />
|
||||
{cachedInputPrice}
|
||||
{formatPrice.cachedInput}
|
||||
</Flexbox>
|
||||
</Tooltip>
|
||||
)}
|
||||
{pricing?.writeCacheInput && (
|
||||
<Tooltip
|
||||
title={t('messages.modelCard.pricing.writeCacheInputTokens', {
|
||||
amount: writeCacheInputPrice,
|
||||
amount: formatPrice.writeCacheInput,
|
||||
})}
|
||||
>
|
||||
<Flexbox gap={2} horizontal>
|
||||
<Icon icon={BookUp2Icon} />
|
||||
{writeCacheInputPrice}
|
||||
{formatPrice.writeCacheInput}
|
||||
</Flexbox>
|
||||
</Tooltip>
|
||||
)}
|
||||
<Tooltip title={t('messages.modelCard.pricing.inputTokens', { amount: inputPrice })}>
|
||||
<Tooltip
|
||||
title={t('messages.modelCard.pricing.inputTokens', { amount: formatPrice.input })}
|
||||
>
|
||||
<Flexbox gap={2} horizontal>
|
||||
<Icon icon={ArrowUpFromDot} />
|
||||
{inputPrice}
|
||||
{formatPrice.input}
|
||||
</Flexbox>
|
||||
</Tooltip>
|
||||
<Tooltip title={t('messages.modelCard.pricing.outputTokens', { amount: outputPrice })}>
|
||||
<Tooltip
|
||||
title={t('messages.modelCard.pricing.outputTokens', { amount: formatPrice.output })}
|
||||
>
|
||||
<Flexbox gap={2} horizontal>
|
||||
<Icon icon={ArrowDownToDot} />
|
||||
{outputPrice}
|
||||
{formatPrice.output}
|
||||
</Flexbox>
|
||||
</Tooltip>
|
||||
</Flexbox>
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { ChatModelPricing } from '@/types/aiModel';
|
||||
import { ModelPriceCurrency } from '@/types/llm';
|
||||
import { formatPriceByCurrency } from '@/utils/format';
|
||||
|
||||
export const getPrice = (pricing: ChatModelPricing) => {
|
||||
const inputPrice = formatPriceByCurrency(pricing?.input, pricing?.currency as ModelPriceCurrency);
|
||||
const cachedInputPrice = formatPriceByCurrency(
|
||||
pricing?.cachedInput,
|
||||
pricing?.currency as ModelPriceCurrency,
|
||||
);
|
||||
const writeCacheInputPrice = formatPriceByCurrency(
|
||||
pricing?.writeCacheInput,
|
||||
pricing?.currency as ModelPriceCurrency,
|
||||
);
|
||||
const outputPrice = formatPriceByCurrency(
|
||||
pricing?.output,
|
||||
pricing?.currency as ModelPriceCurrency,
|
||||
);
|
||||
|
||||
return {
|
||||
cachedInput: Number(cachedInputPrice),
|
||||
input: Number(inputPrice),
|
||||
output: Number(outputPrice),
|
||||
writeCacheInput: Number(writeCacheInputPrice),
|
||||
};
|
||||
};
|
||||
@@ -70,7 +70,7 @@ describe('getDetailsToken', () => {
|
||||
const result = getDetailsToken(usage, mockModelCard);
|
||||
|
||||
expect(result.inputCached).toEqual({
|
||||
credit: 0, // 50 * 0.005 = 0.25, rounded to 0
|
||||
credit: 1,
|
||||
token: 50,
|
||||
});
|
||||
|
||||
@@ -165,12 +165,12 @@ describe('getDetailsToken', () => {
|
||||
const result = getDetailsToken(usage, mockModelCard);
|
||||
|
||||
// uncachedInput: (200 - 50) * 0.01 = 1.5 -> 2
|
||||
// cachedInput: 50 * 0.005 = 0.25 -> 0
|
||||
// cachedInput: 50 * 0.005 = 0.25 -> 1
|
||||
// totalOutput: 300 * 0.02 = 6
|
||||
// totalCredit = 2 + 0 + 6 = 8
|
||||
// totalCredit = 2 + 1 + 6 = 9
|
||||
|
||||
expect(result.totalTokens).toEqual({
|
||||
credit: 8,
|
||||
credit: 9,
|
||||
token: 500,
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { LobeDefaultAiModelListItem } from '@/types/aiModel';
|
||||
import { ChatModelPricing, LobeDefaultAiModelListItem } from '@/types/aiModel';
|
||||
import { ModelTokensUsage } from '@/types/message';
|
||||
|
||||
import { getPrice } from './pricing';
|
||||
|
||||
const calcCredit = (token: number, pricing?: number) => {
|
||||
if (!pricing) return '-';
|
||||
|
||||
@@ -29,23 +31,26 @@ export const getDetailsToken = (
|
||||
? usage?.inputCacheMissTokens
|
||||
: totalInputTokens - (inputCacheTokens || 0);
|
||||
|
||||
// Pricing
|
||||
const formatPrice = getPrice(modelCard?.pricing as ChatModelPricing);
|
||||
|
||||
const inputCacheMissCredit = (
|
||||
!!inputCacheMissTokens ? calcCredit(inputCacheMissTokens, modelCard?.pricing?.input) : 0
|
||||
!!inputCacheMissTokens ? calcCredit(inputCacheMissTokens, formatPrice.input) : 0
|
||||
) as number;
|
||||
|
||||
const inputCachedCredit = (
|
||||
!!inputCacheTokens ? calcCredit(inputCacheTokens, modelCard?.pricing?.cachedInput) : 0
|
||||
!!inputCacheTokens ? calcCredit(inputCacheTokens, formatPrice.cachedInput) : 0
|
||||
) as number;
|
||||
|
||||
const inputWriteCachedCredit = !!inputWriteCacheTokens
|
||||
? (calcCredit(inputWriteCacheTokens, modelCard?.pricing?.writeCacheInput) as number)
|
||||
? (calcCredit(inputWriteCacheTokens, formatPrice.writeCacheInput) as number)
|
||||
: 0;
|
||||
|
||||
const totalOutputCredit = (
|
||||
!!totalOutputTokens ? calcCredit(totalOutputTokens, modelCard?.pricing?.output) : 0
|
||||
!!totalOutputTokens ? calcCredit(totalOutputTokens, formatPrice.output) : 0
|
||||
) as number;
|
||||
const totalInputCredit = (
|
||||
!!totalInputTokens ? calcCredit(totalInputTokens, modelCard?.pricing?.output) : 0
|
||||
!!totalInputTokens ? calcCredit(totalInputTokens, formatPrice.output) : 0
|
||||
) as number;
|
||||
|
||||
const totalCredit =
|
||||
@@ -69,13 +74,13 @@ export const getDetailsToken = (
|
||||
: undefined,
|
||||
inputCitation: !!usage.inputCitationTokens
|
||||
? {
|
||||
credit: calcCredit(usage.inputCitationTokens, modelCard?.pricing?.input),
|
||||
credit: calcCredit(usage.inputCitationTokens, formatPrice.input),
|
||||
token: usage.inputCitationTokens,
|
||||
}
|
||||
: undefined,
|
||||
inputText: !!inputTextTokens
|
||||
? {
|
||||
credit: calcCredit(inputTextTokens, modelCard?.pricing?.input),
|
||||
credit: calcCredit(inputTextTokens, formatPrice.input),
|
||||
token: inputTextTokens,
|
||||
}
|
||||
: undefined,
|
||||
@@ -89,13 +94,13 @@ export const getDetailsToken = (
|
||||
: undefined,
|
||||
outputReasoning: !!outputReasoningTokens
|
||||
? {
|
||||
credit: calcCredit(outputReasoningTokens, modelCard?.pricing?.output),
|
||||
credit: calcCredit(outputReasoningTokens, formatPrice.output),
|
||||
token: outputReasoningTokens,
|
||||
}
|
||||
: undefined,
|
||||
outputText: !!outputTextTokens
|
||||
? {
|
||||
credit: calcCredit(outputTextTokens, modelCard?.pricing?.output),
|
||||
credit: calcCredit(outputTextTokens, formatPrice.output),
|
||||
token: outputTextTokens,
|
||||
}
|
||||
: undefined,
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
import { createStyles } from 'antd-style';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Flexbox } from 'react-layout-kit';
|
||||
|
||||
import CircleLoader from '@/components/CircleLoader';
|
||||
import { shinyTextStylish } from '@/styles/loading';
|
||||
|
||||
const useStyles = createStyles(({ token }) => ({
|
||||
shinyText: shinyTextStylish(token),
|
||||
}));
|
||||
|
||||
const IntentUnderstanding = () => {
|
||||
const { styles } = useStyles();
|
||||
const { t } = useTranslation('chat');
|
||||
|
||||
return (
|
||||
<Flexbox align={'center'} gap={8} horizontal>
|
||||
<CircleLoader />
|
||||
<Flexbox className={styles.shinyText} horizontal>
|
||||
{t('intentUnderstanding.title')}
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
);
|
||||
};
|
||||
export default IntentUnderstanding;
|
||||
@@ -6,6 +6,7 @@ import { memo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import { Flexbox } from 'react-layout-kit';
|
||||
|
||||
import Loader from '@/components/CircleLoader';
|
||||
import PluginAvatar from '@/features/PluginAvatar';
|
||||
import { useChatStore } from '@/store/chat';
|
||||
import { chatSelectors } from '@/store/chat/selectors';
|
||||
@@ -14,8 +15,6 @@ import { toolSelectors } from '@/store/tool/selectors';
|
||||
import { shinyTextStylish } from '@/styles/loading';
|
||||
import { WebBrowsingManifest } from '@/tools/web-browsing';
|
||||
|
||||
import Loader from './Loader';
|
||||
|
||||
export const useStyles = createStyles(({ css, token }) => ({
|
||||
apiName: css`
|
||||
overflow: hidden;
|
||||
|
||||
@@ -8,6 +8,7 @@ import { ChatMessage } from '@/types/message';
|
||||
|
||||
import { DefaultMessage } from '../Default';
|
||||
import FileChunks from './FileChunks';
|
||||
import IntentUnderstanding from './IntentUnderstanding';
|
||||
import Reasoning from './Reasoning';
|
||||
import SearchGrounding from './SearchGrounding';
|
||||
import Tool from './Tool';
|
||||
@@ -24,6 +25,8 @@ export const AssistantMessage = memo<
|
||||
|
||||
const isReasoning = useChatStore(aiChatSelectors.isMessageInReasoning(id));
|
||||
|
||||
const isIntentUnderstanding = useChatStore(aiChatSelectors.isIntentUnderstanding(id));
|
||||
|
||||
const showSearch = !!search && !!search.citations?.length;
|
||||
|
||||
// remove \n to avoid empty content
|
||||
@@ -32,6 +35,8 @@ export const AssistantMessage = memo<
|
||||
(!!props.reasoning && props.reasoning.content?.trim() !== '') ||
|
||||
(!props.reasoning && isReasoning);
|
||||
|
||||
const showFileChunks = !!chunksList && chunksList.length > 0;
|
||||
|
||||
return editing ? (
|
||||
<DefaultMessage
|
||||
content={content}
|
||||
@@ -44,16 +49,20 @@ export const AssistantMessage = memo<
|
||||
{showSearch && (
|
||||
<SearchGrounding citations={search?.citations} searchQueries={search?.searchQueries} />
|
||||
)}
|
||||
{!!chunksList && chunksList.length > 0 && <FileChunks data={chunksList} />}
|
||||
{showFileChunks && <FileChunks data={chunksList} />}
|
||||
{showReasoning && <Reasoning {...props.reasoning} id={id} />}
|
||||
{content && (
|
||||
<DefaultMessage
|
||||
addIdOnDOM={false}
|
||||
content={content}
|
||||
id={id}
|
||||
isToolCallGenerating={isToolCallGenerating}
|
||||
{...props}
|
||||
/>
|
||||
{isIntentUnderstanding ? (
|
||||
<IntentUnderstanding />
|
||||
) : (
|
||||
content && (
|
||||
<DefaultMessage
|
||||
addIdOnDOM={false}
|
||||
content={content}
|
||||
id={id}
|
||||
isToolCallGenerating={isToolCallGenerating}
|
||||
{...props}
|
||||
/>
|
||||
)
|
||||
)}
|
||||
{tools && (
|
||||
<Flexbox gap={8}>
|
||||
|
||||
+51
-52
@@ -64,16 +64,14 @@ const Render = memo<ArtifactProps>(({ identifier, title, type, language, childre
|
||||
|
||||
const inThread = useContext(InPortalThreadContext);
|
||||
const { message } = App.useApp();
|
||||
const [isGenerating, isArtifactTagClosed, currentArtifactMessageId, openArtifact, closeArtifact] =
|
||||
useChatStore((s) => {
|
||||
return [
|
||||
chatSelectors.isMessageGenerating(id)(s),
|
||||
chatPortalSelectors.isArtifactTagClosed(id)(s),
|
||||
chatPortalSelectors.artifactMessageId(s),
|
||||
s.openArtifact,
|
||||
s.closeArtifact,
|
||||
];
|
||||
});
|
||||
const [isGenerating, isArtifactTagClosed, openArtifact, closeArtifact] = useChatStore((s) => {
|
||||
return [
|
||||
chatSelectors.isMessageGenerating(id)(s),
|
||||
chatPortalSelectors.isArtifactTagClosed(id)(s),
|
||||
s.openArtifact,
|
||||
s.closeArtifact,
|
||||
];
|
||||
});
|
||||
|
||||
const openArtifactUI = () => {
|
||||
openArtifact({ id, identifier, language, title, type });
|
||||
@@ -86,52 +84,53 @@ const Render = memo<ArtifactProps>(({ identifier, title, type, language, childre
|
||||
}, [isGenerating, hasChildren, str, identifier, title, type, id, language]);
|
||||
|
||||
return (
|
||||
<p>
|
||||
<Flexbox
|
||||
className={styles.container}
|
||||
gap={16}
|
||||
onClick={() => {
|
||||
if (currentArtifactMessageId === id) {
|
||||
closeArtifact();
|
||||
} else {
|
||||
if (inThread) {
|
||||
message.info(t('artifact.inThread'));
|
||||
return;
|
||||
}
|
||||
openArtifactUI();
|
||||
<Flexbox
|
||||
className={styles.container}
|
||||
gap={16}
|
||||
onClick={() => {
|
||||
const currentArtifactMessageId = chatPortalSelectors.artifactMessageId(
|
||||
useChatStore.getState(),
|
||||
);
|
||||
if (currentArtifactMessageId === id) {
|
||||
closeArtifact();
|
||||
} else {
|
||||
if (inThread) {
|
||||
message.info(t('artifact.inThread'));
|
||||
return;
|
||||
}
|
||||
}}
|
||||
width={'100%'}
|
||||
>
|
||||
<Flexbox align={'center'} flex={1} horizontal>
|
||||
<Center className={styles.avatar} height={64} horizontal width={64}>
|
||||
<ArtifactIcon type={type} />
|
||||
</Center>
|
||||
<Flexbox gap={4} paddingBlock={8} paddingInline={12}>
|
||||
{!title && isGenerating ? (
|
||||
<Flexbox className={cx(dotLoading)} horizontal>
|
||||
{t('artifact.generating')}
|
||||
openArtifactUI();
|
||||
}
|
||||
}}
|
||||
width={'100%'}
|
||||
>
|
||||
<Flexbox align={'center'} flex={1} horizontal>
|
||||
<Center className={styles.avatar} height={64} horizontal width={64}>
|
||||
<ArtifactIcon type={type} />
|
||||
</Center>
|
||||
<Flexbox gap={4} paddingBlock={8} paddingInline={12}>
|
||||
{!title && isGenerating ? (
|
||||
<Flexbox className={cx(dotLoading)} horizontal>
|
||||
{t('artifact.generating')}
|
||||
</Flexbox>
|
||||
) : (
|
||||
<Flexbox className={cx(styles.title)}>{title || t('artifact.unknownTitle')}</Flexbox>
|
||||
)}
|
||||
{hasChildren && (
|
||||
<Flexbox className={styles.desc} horizontal>
|
||||
{identifier} ·{' '}
|
||||
<Flexbox gap={2} horizontal>
|
||||
{!isArtifactTagClosed && (
|
||||
<div>
|
||||
<Icon icon={Loader2} spin />
|
||||
</div>
|
||||
)}
|
||||
{str?.length}
|
||||
</Flexbox>
|
||||
) : (
|
||||
<Flexbox className={cx(styles.title)}>{title || t('artifact.unknownTitle')}</Flexbox>
|
||||
)}
|
||||
{hasChildren && (
|
||||
<Flexbox className={styles.desc} horizontal>
|
||||
{identifier} ·{' '}
|
||||
<Flexbox gap={2} horizontal>
|
||||
{!isArtifactTagClosed && (
|
||||
<div>
|
||||
<Icon icon={Loader2} spin />
|
||||
</div>
|
||||
)}
|
||||
{str?.length}
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
)}
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
)}
|
||||
</Flexbox>
|
||||
</Flexbox>
|
||||
</p>
|
||||
</Flexbox>
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import { Icon } from '@lobehub/ui';
|
||||
import { ActionIcon, Icon } from '@lobehub/ui';
|
||||
import { Dropdown } from 'antd';
|
||||
import { createStyles } from 'antd-style';
|
||||
import type { ItemType } from 'antd/es/menu/interface';
|
||||
import { LucideArrowRight } from 'lucide-react';
|
||||
import { LucideArrowRight, LucideBolt } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { PropsWithChildren, memo, useMemo } from 'react';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
@@ -86,17 +87,42 @@ const ModelSwitchPanel = memo<PropsWithChildren>(({ children }) => {
|
||||
return items;
|
||||
};
|
||||
|
||||
if (enabledList.length === 0)
|
||||
return [
|
||||
{
|
||||
key: `no-provider`,
|
||||
label: (
|
||||
<Flexbox gap={8} horizontal style={{ color: theme.colorTextTertiary }}>
|
||||
{t('ModelSwitchPanel.emptyProvider')}
|
||||
<Icon icon={LucideArrowRight} />
|
||||
</Flexbox>
|
||||
),
|
||||
onClick: () => {
|
||||
router.push(isDeprecatedEdition ? '/settings/llm' : `/settings/provider`);
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
// otherwise show with provider group
|
||||
return enabledList.map((provider) => ({
|
||||
children: getModelItems(provider),
|
||||
key: provider.id,
|
||||
label: (
|
||||
<ProviderItemRender
|
||||
logo={provider.logo}
|
||||
name={provider.name}
|
||||
provider={provider.id}
|
||||
source={provider.source}
|
||||
/>
|
||||
<Flexbox horizontal justify="space-between">
|
||||
<ProviderItemRender
|
||||
logo={provider.logo}
|
||||
name={provider.name}
|
||||
provider={provider.id}
|
||||
source={provider.source}
|
||||
/>
|
||||
<Link href={isDeprecatedEdition ? '/settings/llm' : `/settings/provider/${provider.id}`}>
|
||||
<ActionIcon
|
||||
icon={LucideBolt}
|
||||
size={'small'}
|
||||
title={t('ModelSwitchPanel.goToSettings')}
|
||||
/>
|
||||
</Link>
|
||||
</Flexbox>
|
||||
),
|
||||
type: 'group',
|
||||
}));
|
||||
|
||||
@@ -9,19 +9,11 @@ export const useAgentEnableSearch = () => {
|
||||
agentChatConfigSelectors.agentSearchMode(s),
|
||||
]);
|
||||
|
||||
const isModelSupportToolUse = useAiInfraStore(
|
||||
aiModelSelectors.isModelSupportToolUse(model, provider),
|
||||
);
|
||||
const searchImpl = useAiInfraStore(aiModelSelectors.modelBuiltinSearchImpl(model, provider));
|
||||
|
||||
// 只要是内置的搜索实现,一定可以联网搜索
|
||||
if (searchImpl === 'internal') return true;
|
||||
|
||||
// 如果是关闭状态,一定不能联网搜索
|
||||
if (agentSearchMode === 'off') return false;
|
||||
|
||||
// 如果是智能模式,根据是否支持 Tool Calling 判断
|
||||
if (agentSearchMode === 'auto') {
|
||||
return isModelSupportToolUse;
|
||||
}
|
||||
return agentSearchMode !== 'off';
|
||||
};
|
||||
|
||||
@@ -102,7 +102,8 @@ export class LobeAnthropicAI implements LobeRuntimeAI {
|
||||
|
||||
if (!!thinking) {
|
||||
const maxTokens =
|
||||
max_tokens ?? (thinking?.budget_tokens ? thinking?.budget_tokens + 4096 : 4096);
|
||||
// claude 3.7 thinking has max output of 64000 tokens
|
||||
max_tokens ?? (thinking?.budget_tokens ? thinking?.budget_tokens + 64_000 : 8192);
|
||||
|
||||
// `temperature` may only be set to 1 when thinking is enabled.
|
||||
// `top_p` must be unset when thinking is enabled.
|
||||
@@ -117,7 +118,9 @@ export class LobeAnthropicAI implements LobeRuntimeAI {
|
||||
}
|
||||
|
||||
return {
|
||||
max_tokens: max_tokens ?? 4096,
|
||||
// claude 3 series model hax max output token of 4096, 3.x series has 8192
|
||||
// https://docs.anthropic.com/en/docs/about-claude/models/all-models#:~:text=200K-,Max%20output,-Normal%3A
|
||||
max_tokens: max_tokens ?? (model.startsWith('claude-3-') ? 4096 : 8192),
|
||||
messages: postMessages,
|
||||
model,
|
||||
system: systemPrompts,
|
||||
|
||||
@@ -65,6 +65,9 @@ export default {
|
||||
stop: '停止',
|
||||
warp: '换行',
|
||||
},
|
||||
intentUnderstanding: {
|
||||
title: '正在分析并理解意图您的意图...',
|
||||
},
|
||||
knowledgeBase: {
|
||||
all: '所有内容',
|
||||
allFiles: '所有文件',
|
||||
@@ -142,13 +145,11 @@ export default {
|
||||
searchQueries: '搜索关键词',
|
||||
title: '已搜索到 {{count}} 个结果',
|
||||
},
|
||||
|
||||
mode: {
|
||||
auto: {
|
||||
desc: '根据对话内容智能判断是否需要搜索',
|
||||
title: '智能联网',
|
||||
},
|
||||
disable: '当前模型不支持函数调用,因此无法使用智能联网功能',
|
||||
off: {
|
||||
desc: '仅使用模型的基础知识,不进行网络搜索',
|
||||
title: '关闭联网',
|
||||
@@ -159,7 +160,10 @@ export default {
|
||||
},
|
||||
useModelBuiltin: '使用模型内置搜索引擎',
|
||||
},
|
||||
|
||||
searchModel: {
|
||||
desc: '当前模型不支持函数调用,因此需要搭配支持函数调用的模型才能联网搜索',
|
||||
title: '搜索辅助模型',
|
||||
},
|
||||
title: '联网搜索',
|
||||
},
|
||||
searchAgentPlaceholder: '搜索助手...',
|
||||
|
||||
@@ -87,7 +87,9 @@ export default {
|
||||
},
|
||||
ModelSwitchPanel: {
|
||||
emptyModel: '没有启用的模型,请前往设置开启',
|
||||
provider: '提供商',
|
||||
emptyProvider: '没有启用的服务商,请前往设置开启',
|
||||
goToSettings: '前往设置',
|
||||
provider: '服务商',
|
||||
},
|
||||
OllamaSetupGuide: {
|
||||
cors: {
|
||||
|
||||
@@ -20,7 +20,14 @@ export const searchRouter = router({
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ input }) => {
|
||||
const crawler = new Crawler();
|
||||
const envString = toolsEnv.CRAWLER_IMPLS || '';
|
||||
|
||||
// 处理全角逗号和多余空格
|
||||
let envValue = envString.replaceAll(',', ',').trim();
|
||||
|
||||
const impls = envValue.split(',').filter(Boolean);
|
||||
|
||||
const crawler = new Crawler({ impls });
|
||||
|
||||
const results = await pMap(
|
||||
input.urls,
|
||||
|
||||
@@ -26,12 +26,16 @@ import {
|
||||
ModelProvider,
|
||||
} from '@/libs/agent-runtime';
|
||||
import { AgentRuntime } from '@/libs/agent-runtime';
|
||||
import { agentChatConfigSelectors } from '@/store/agent/selectors';
|
||||
import { aiModelSelectors } from '@/store/aiInfra';
|
||||
import { useToolStore } from '@/store/tool';
|
||||
import { toolSelectors } from '@/store/tool/selectors';
|
||||
import { UserStore } from '@/store/user';
|
||||
import { useUserStore } from '@/store/user';
|
||||
import { modelConfigSelectors } from '@/store/user/selectors';
|
||||
import { UserSettingsState, initialSettingsState } from '@/store/user/slices/settings/initialState';
|
||||
import { DalleManifest } from '@/tools/dalle';
|
||||
import { WebBrowsingManifest } from '@/tools/web-browsing';
|
||||
import { ChatMessage } from '@/types/message';
|
||||
import { ChatStreamPayload, type OpenAIChatMessage } from '@/types/openai/chat';
|
||||
import { LobeTool } from '@/types/tool';
|
||||
@@ -480,6 +484,125 @@ describe('ChatService', () => {
|
||||
expect(calls![1]).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe('search functionality', () => {
|
||||
it('should add WebBrowsingManifest when search is enabled and not using model built-in search', async () => {
|
||||
const getChatCompletionSpy = vi.spyOn(chatService, 'getChatCompletion');
|
||||
|
||||
const messages = [{ content: 'Search for something', role: 'user' }] as ChatMessage[];
|
||||
|
||||
// Mock agent store state with search enabled
|
||||
vi.spyOn(agentChatConfigSelectors, 'currentChatConfig').mockReturnValueOnce({
|
||||
searchMode: 'auto', // not 'off'
|
||||
useModelBuiltinSearch: false,
|
||||
} as any);
|
||||
|
||||
// Mock AI infra store state
|
||||
vi.spyOn(aiModelSelectors, 'isModelHasBuiltinSearch').mockReturnValueOnce(() => false);
|
||||
vi.spyOn(aiModelSelectors, 'isModelHasExtendParams').mockReturnValueOnce(() => false);
|
||||
|
||||
// Mock tool selectors
|
||||
vi.spyOn(toolSelectors, 'enabledSchema').mockReturnValueOnce(() => [
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: WebBrowsingManifest.identifier + '____search',
|
||||
description: 'Search the web',
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
await chatService.createAssistantMessage({ messages, plugins: [] });
|
||||
|
||||
// Verify tools were passed to getChatCompletion
|
||||
expect(getChatCompletionSpy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
tools: expect.arrayContaining([
|
||||
expect.objectContaining({
|
||||
function: expect.objectContaining({
|
||||
name: expect.stringContaining(WebBrowsingManifest.identifier),
|
||||
}),
|
||||
}),
|
||||
]),
|
||||
}),
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
|
||||
it('should enable built-in search when model supports it and useModelBuiltinSearch is true', async () => {
|
||||
const getChatCompletionSpy = vi.spyOn(chatService, 'getChatCompletion');
|
||||
|
||||
const messages = [{ content: 'Search for something', role: 'user' }] as ChatMessage[];
|
||||
|
||||
// Mock agent store state with search enabled and useModelBuiltinSearch enabled
|
||||
vi.spyOn(agentChatConfigSelectors, 'currentChatConfig').mockReturnValueOnce({
|
||||
searchMode: 'auto', // not 'off'
|
||||
useModelBuiltinSearch: true,
|
||||
} as any);
|
||||
|
||||
// Mock AI infra store state - model has built-in search
|
||||
vi.spyOn(aiModelSelectors, 'isModelHasBuiltinSearch').mockReturnValueOnce(() => true);
|
||||
vi.spyOn(aiModelSelectors, 'isModelHasExtendParams').mockReturnValueOnce(() => false);
|
||||
|
||||
// Mock tool selectors
|
||||
vi.spyOn(toolSelectors, 'enabledSchema').mockReturnValueOnce(() => [
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: WebBrowsingManifest.identifier + '____search',
|
||||
description: 'Search the web',
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
await chatService.createAssistantMessage({ messages, plugins: [] });
|
||||
|
||||
// Verify enabledSearch was set to true
|
||||
expect(getChatCompletionSpy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
enabledSearch: true,
|
||||
}),
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
|
||||
it('should not enable search when searchMode is off', async () => {
|
||||
const getChatCompletionSpy = vi.spyOn(chatService, 'getChatCompletion');
|
||||
|
||||
const messages = [{ content: 'Search for something', role: 'user' }] as ChatMessage[];
|
||||
|
||||
// Mock agent store state with search disabled
|
||||
vi.spyOn(agentChatConfigSelectors, 'currentChatConfig').mockReturnValueOnce({
|
||||
searchMode: 'off',
|
||||
useModelBuiltinSearch: true,
|
||||
} as any);
|
||||
|
||||
// Mock AI infra store state
|
||||
vi.spyOn(aiModelSelectors, 'isModelHasBuiltinSearch').mockReturnValueOnce(() => true);
|
||||
vi.spyOn(aiModelSelectors, 'isModelHasExtendParams').mockReturnValueOnce(() => false);
|
||||
|
||||
// Mock tool selectors
|
||||
vi.spyOn(toolSelectors, 'enabledSchema').mockReturnValueOnce(() => [
|
||||
{
|
||||
type: 'function',
|
||||
function: {
|
||||
name: WebBrowsingManifest.identifier + '____search',
|
||||
description: 'Search the web',
|
||||
},
|
||||
},
|
||||
]);
|
||||
|
||||
await chatService.createAssistantMessage({ messages, plugins: [] });
|
||||
|
||||
// Verify enabledSearch was not set
|
||||
expect(getChatCompletionSpy).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
enabledSearch: undefined,
|
||||
}),
|
||||
undefined,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getChatCompletion', () => {
|
||||
@@ -754,6 +877,7 @@ describe('ChatService', () => {
|
||||
// 重新模拟模块,设置 isServerMode 为 true
|
||||
vi.doMock('@/const/version', () => ({
|
||||
isServerMode: true,
|
||||
isDeprecatedEdition: false,
|
||||
}));
|
||||
|
||||
// 需要在修改模拟后重新导入相关模块
|
||||
|
||||
+82
-49
@@ -19,12 +19,7 @@ import { filesPrompts } from '@/prompts/files';
|
||||
import { BuiltinSystemRolePrompts } from '@/prompts/systemRole';
|
||||
import { getAgentStoreState } from '@/store/agent';
|
||||
import { agentChatConfigSelectors } from '@/store/agent/selectors';
|
||||
import {
|
||||
aiModelSelectors,
|
||||
aiProviderSelectors,
|
||||
getAiInfraStoreState,
|
||||
useAiInfraStore,
|
||||
} from '@/store/aiInfra';
|
||||
import { aiModelSelectors, aiProviderSelectors, getAiInfraStoreState } from '@/store/aiInfra';
|
||||
import { getSessionStoreState } from '@/store/session';
|
||||
import { sessionMetaSelectors } from '@/store/session/selectors';
|
||||
import { getToolStoreState } from '@/store/tool';
|
||||
@@ -37,6 +32,7 @@ import {
|
||||
userProfileSelectors,
|
||||
} from '@/store/user/selectors';
|
||||
import { WebBrowsingManifest } from '@/tools/web-browsing';
|
||||
import { WorkingModel } from '@/types/agent';
|
||||
import { ChatErrorType } from '@/types/fetch';
|
||||
import { ChatMessage, MessageToolCall } from '@/types/message';
|
||||
import type { ChatStreamPayload, OpenAIChatMessage } from '@/types/openai/chat';
|
||||
@@ -74,9 +70,9 @@ const findDeploymentName = (model: string, provider: string) => {
|
||||
if (deploymentName) deploymentId = deploymentName;
|
||||
} else {
|
||||
// find the model by id
|
||||
const modelItem = useAiInfraStore
|
||||
.getState()
|
||||
.enabledAiModels?.find((i) => i.id === model && i.providerId === provider);
|
||||
const modelItem = getAiInfraStoreState().enabledAiModels?.find(
|
||||
(i) => i.id === model && i.providerId === provider,
|
||||
);
|
||||
|
||||
if (modelItem && modelItem.config?.deploymentName) {
|
||||
deploymentId = modelItem.config?.deploymentName;
|
||||
@@ -91,7 +87,7 @@ const isEnableFetchOnClient = (provider: string) => {
|
||||
if (isDeprecatedEdition) {
|
||||
return modelConfigSelectors.isProviderFetchOnClient(provider)(useUserStore.getState());
|
||||
} else {
|
||||
return aiProviderSelectors.isProviderFetchOnClient(provider)(useAiInfraStore.getState());
|
||||
return aiProviderSelectors.isProviderFetchOnClient(provider)(getAiInfraStoreState());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -181,10 +177,10 @@ class ChatService {
|
||||
const isModelHasBuiltinSearch = aiModelSelectors.isModelHasBuiltinSearch(
|
||||
payload.model,
|
||||
payload.provider!,
|
||||
)(useAiInfraStore.getState());
|
||||
)(getAiInfraStoreState());
|
||||
|
||||
const useApplicationBuiltinSearchTool =
|
||||
enabledSearch && !(isModelHasBuiltinSearch && chatConfig.useModelBuiltinSearch);
|
||||
const useModelSearch = isModelHasBuiltinSearch && chatConfig.useModelBuiltinSearch;
|
||||
const useApplicationBuiltinSearchTool = enabledSearch && !useModelSearch;
|
||||
|
||||
const pluginIds = [...(enabledPlugins || [])];
|
||||
|
||||
@@ -206,17 +202,10 @@ class ChatService {
|
||||
|
||||
// ============ 2. preprocess tools ============ //
|
||||
|
||||
let filterTools = toolSelectors.enabledSchema(pluginIds)(getToolStoreState());
|
||||
|
||||
// check this model can use function call
|
||||
const canUseFC = isCanUseFC(payload.model, payload.provider!);
|
||||
|
||||
// the rule that model can use tools:
|
||||
// 1. tools is not empty
|
||||
// 2. model can use function call
|
||||
const shouldUseTools = filterTools.length > 0 && canUseFC;
|
||||
|
||||
const tools = shouldUseTools ? filterTools : undefined;
|
||||
const tools = this.prepareTools(pluginIds, {
|
||||
model: payload.model,
|
||||
provider: payload.provider!,
|
||||
});
|
||||
|
||||
// ============ 3. process extend params ============ //
|
||||
|
||||
@@ -225,14 +214,14 @@ class ChatService {
|
||||
const isModelHasExtendParams = aiModelSelectors.isModelHasExtendParams(
|
||||
payload.model,
|
||||
payload.provider!,
|
||||
)(useAiInfraStore.getState());
|
||||
)(getAiInfraStoreState());
|
||||
|
||||
// model
|
||||
if (isModelHasExtendParams) {
|
||||
const modelExtendParams = aiModelSelectors.modelExtendParams(
|
||||
payload.model,
|
||||
payload.provider!,
|
||||
)(useAiInfraStore.getState());
|
||||
)(getAiInfraStoreState());
|
||||
// if model has extended params, then we need to check if the model can use reasoning
|
||||
|
||||
if (modelExtendParams!.includes('enableReasoning') && chatConfig.enableReasoning) {
|
||||
@@ -241,13 +230,19 @@ class ChatService {
|
||||
type: 'enabled',
|
||||
};
|
||||
}
|
||||
if (
|
||||
modelExtendParams!.includes('disableContextCaching') &&
|
||||
chatConfig.disableContextCaching
|
||||
) {
|
||||
extendParams.enabledContextCaching = false;
|
||||
}
|
||||
}
|
||||
|
||||
return this.getChatCompletion(
|
||||
{
|
||||
...params,
|
||||
...extendParams,
|
||||
enabledSearch: enabledSearch && isModelHasBuiltinSearch ? true : undefined,
|
||||
enabledSearch: enabledSearch && useModelSearch ? true : undefined,
|
||||
messages: oaiMessages,
|
||||
tools,
|
||||
},
|
||||
@@ -351,9 +346,8 @@ class ChatService {
|
||||
|
||||
// TODO: remove `!isDeprecatedEdition` condition in V2.0
|
||||
if (!isDeprecatedEdition && !isBuiltin) {
|
||||
const providerConfig = aiProviderSelectors.providerConfigById(provider)(
|
||||
useAiInfraStore.getState(),
|
||||
);
|
||||
const providerConfig =
|
||||
aiProviderSelectors.providerConfigById(provider)(getAiInfraStoreState());
|
||||
|
||||
sdkType = providerConfig?.settings.sdkType || 'openai';
|
||||
}
|
||||
@@ -433,15 +427,29 @@ class ChatService {
|
||||
onLoadingChange?.(true);
|
||||
|
||||
try {
|
||||
await this.getChatCompletion(params, {
|
||||
onErrorHandle: (error) => {
|
||||
errorHandle(new Error(error.message), error);
|
||||
},
|
||||
onFinish,
|
||||
onMessageHandle,
|
||||
signal: abortController?.signal,
|
||||
trace: this.mapTrace(trace, TraceTagMap.SystemChain),
|
||||
const oaiMessages = this.processMessages({
|
||||
messages: params.messages as any,
|
||||
model: params.model!,
|
||||
provider: params.provider!,
|
||||
tools: params.plugins,
|
||||
});
|
||||
const tools = this.prepareTools(params.plugins || [], {
|
||||
model: params.model!,
|
||||
provider: params.provider!,
|
||||
});
|
||||
|
||||
await this.getChatCompletion(
|
||||
{ ...params, messages: oaiMessages, tools },
|
||||
{
|
||||
onErrorHandle: (error) => {
|
||||
errorHandle(new Error(error.message), error);
|
||||
},
|
||||
onFinish,
|
||||
onMessageHandle,
|
||||
signal: abortController?.signal,
|
||||
trace: this.mapTrace(trace, TraceTagMap.SystemChain),
|
||||
},
|
||||
);
|
||||
|
||||
onLoadingChange?.(false);
|
||||
} catch (e) {
|
||||
@@ -451,7 +459,7 @@ class ChatService {
|
||||
|
||||
private processMessages = (
|
||||
{
|
||||
messages,
|
||||
messages = [],
|
||||
tools,
|
||||
model,
|
||||
provider,
|
||||
@@ -483,6 +491,7 @@ class ChatService {
|
||||
};
|
||||
|
||||
let postMessages = messages.map((m): OpenAIChatMessage => {
|
||||
const supportTools = isCanUseFC(model, provider);
|
||||
switch (m.role) {
|
||||
case 'user': {
|
||||
return { content: getContent(m), role: m.role };
|
||||
@@ -492,17 +501,23 @@ class ChatService {
|
||||
// signature is a signal of anthropic thinking mode
|
||||
const shouldIncludeThinking = m.reasoning && !!m.reasoning?.signature;
|
||||
|
||||
const content = shouldIncludeThinking
|
||||
? [
|
||||
{
|
||||
signature: m.reasoning!.signature,
|
||||
thinking: m.reasoning!.content,
|
||||
type: 'thinking',
|
||||
} as any,
|
||||
{ text: m.content, type: 'text' },
|
||||
]
|
||||
: m.content;
|
||||
|
||||
if (!supportTools) {
|
||||
return { content, role: m.role };
|
||||
}
|
||||
|
||||
return {
|
||||
content: shouldIncludeThinking
|
||||
? [
|
||||
{
|
||||
signature: m.reasoning!.signature,
|
||||
thinking: m.reasoning!.content,
|
||||
type: 'thinking',
|
||||
} as any,
|
||||
{ text: m.content, type: 'text' },
|
||||
]
|
||||
: m.content,
|
||||
content,
|
||||
role: m.role,
|
||||
tool_calls: m.tools?.map(
|
||||
(tool): MessageToolCall => ({
|
||||
@@ -518,6 +533,10 @@ class ChatService {
|
||||
}
|
||||
|
||||
case 'tool': {
|
||||
if (!supportTools) {
|
||||
return { content: m.content, role: 'user' };
|
||||
}
|
||||
|
||||
return {
|
||||
content: m.content,
|
||||
name: genToolCallingName(m.plugin!.identifier, m.plugin!.apiName, m.plugin?.type),
|
||||
@@ -669,6 +688,20 @@ class ChatService {
|
||||
|
||||
return reorderedMessages;
|
||||
};
|
||||
|
||||
private prepareTools = (pluginIds: string[], { model, provider }: WorkingModel) => {
|
||||
let filterTools = toolSelectors.enabledSchema(pluginIds)(getToolStoreState());
|
||||
|
||||
// check this model can use function call
|
||||
const canUseFC = isCanUseFC(model, provider!);
|
||||
|
||||
// the rule that model can use tools:
|
||||
// 1. tools is not empty
|
||||
// 2. model can use function call
|
||||
const shouldUseTools = filterTools.length > 0 && canUseFC;
|
||||
|
||||
return shouldUseTools ? filterTools : undefined;
|
||||
};
|
||||
}
|
||||
|
||||
export const chatService = new ChatService();
|
||||
|
||||
@@ -53,7 +53,7 @@ export interface ISessionService {
|
||||
|
||||
updateSessionChatConfig(
|
||||
id: string,
|
||||
config: DeepPartial<LobeAgentChatConfig>,
|
||||
config: Partial<LobeAgentChatConfig>,
|
||||
signal?: AbortSignal,
|
||||
): Promise<any>;
|
||||
|
||||
|
||||
@@ -11,6 +11,10 @@ exports[`agentSelectors > defaultAgentConfig > should merge DEFAULT_AGENT_CONFIG
|
||||
"enableReasoning": false,
|
||||
"historyCount": 8,
|
||||
"reasoningBudgetToken": 1024,
|
||||
"searchFCModel": {
|
||||
"model": "gpt-4o-mini",
|
||||
"provider": "openai",
|
||||
},
|
||||
"searchMode": "off",
|
||||
},
|
||||
"model": "gpt-3.5-turbo",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { contextCachingModels, thinkingWithToolClaudeModels } from '@/const/models';
|
||||
import { DEFAULT_AGENT_CHAT_CONFIG } from '@/const/settings';
|
||||
import { DEFAULT_AGENT_CHAT_CONFIG, DEFAULT_AGENT_SEARCH_FC_MODEL } from '@/const/settings';
|
||||
import { AgentStoreState } from '@/store/agent/initialState';
|
||||
import { LobeAgentChatConfig } from '@/types/agent';
|
||||
|
||||
@@ -14,6 +14,9 @@ const isAgentEnableSearch = (s: AgentStoreState) => agentSearchMode(s) !== 'off'
|
||||
const useModelBuiltinSearch = (s: AgentStoreState) =>
|
||||
currentAgentChatConfig(s).useModelBuiltinSearch;
|
||||
|
||||
const searchFCModel = (s: AgentStoreState) =>
|
||||
currentAgentChatConfig(s).searchFCModel || DEFAULT_AGENT_SEARCH_FC_MODEL;
|
||||
|
||||
const enableHistoryCount = (s: AgentStoreState) => {
|
||||
const config = currentAgentConfig(s);
|
||||
const chatConfig = currentAgentChatConfig(s);
|
||||
@@ -62,5 +65,6 @@ export const agentChatConfigSelectors = {
|
||||
enableHistoryDivider,
|
||||
historyCount,
|
||||
isAgentEnableSearch,
|
||||
searchFCModel,
|
||||
useModelBuiltinSearch,
|
||||
};
|
||||
|
||||
@@ -765,10 +765,12 @@ describe('chatMessage actions', () => {
|
||||
(fetch as Mock).mockResolvedValueOnce(new Response(aiResponse));
|
||||
|
||||
await act(async () => {
|
||||
const response = await result.current.internal_fetchAIChatMessage(
|
||||
const response = await result.current.internal_fetchAIChatMessage({
|
||||
messages,
|
||||
assistantMessageId,
|
||||
);
|
||||
messageId: assistantMessageId,
|
||||
model: 'gpt-4o-mini',
|
||||
provider: 'openai',
|
||||
});
|
||||
expect(response.isFunctionCall).toEqual(false);
|
||||
});
|
||||
});
|
||||
@@ -784,7 +786,13 @@ describe('chatMessage actions', () => {
|
||||
|
||||
await act(async () => {
|
||||
expect(
|
||||
await result.current.internal_fetchAIChatMessage(messages, assistantMessageId),
|
||||
await result.current.internal_fetchAIChatMessage({
|
||||
model: 'gpt-4o-mini',
|
||||
provider: 'openai',
|
||||
|
||||
messages,
|
||||
messageId: assistantMessageId,
|
||||
}),
|
||||
).toEqual({
|
||||
isFunctionCall: false,
|
||||
});
|
||||
|
||||
@@ -13,10 +13,13 @@ import { messageService } from '@/services/message';
|
||||
import { useAgentStore } from '@/store/agent';
|
||||
import { agentChatConfigSelectors, agentSelectors } from '@/store/agent/selectors';
|
||||
import { getAgentStoreState } from '@/store/agent/store';
|
||||
import { aiModelSelectors } from '@/store/aiInfra';
|
||||
import { getAiInfraStoreState } from '@/store/aiInfra/store';
|
||||
import { chatHelpers } from '@/store/chat/helpers';
|
||||
import { ChatStore } from '@/store/chat/store';
|
||||
import { messageMapKey } from '@/store/chat/utils/messageMapKey';
|
||||
import { useSessionStore } from '@/store/session';
|
||||
import { WebBrowsingManifest } from '@/tools/web-browsing';
|
||||
import { ChatMessage, CreateMessageParams, SendMessageParams } from '@/types/message';
|
||||
import { MessageSemanticSearchChunk } from '@/types/rag';
|
||||
import { setNamespace } from '@/utils/storeDebug';
|
||||
@@ -28,6 +31,7 @@ const n = setNamespace('ai');
|
||||
interface ProcessMessageParams {
|
||||
traceId?: string;
|
||||
isWelcomeQuestion?: boolean;
|
||||
inSearchWorkflow?: boolean;
|
||||
/**
|
||||
* the RAG query content, should be embedding and used in the semantic search
|
||||
*/
|
||||
@@ -70,11 +74,13 @@ export interface AIGenerateAction {
|
||||
/**
|
||||
* Retrieves an AI-generated chat message from the backend service
|
||||
*/
|
||||
internal_fetchAIChatMessage: (
|
||||
messages: ChatMessage[],
|
||||
messageId: string,
|
||||
params?: ProcessMessageParams,
|
||||
) => Promise<{
|
||||
internal_fetchAIChatMessage: (input: {
|
||||
messages: ChatMessage[];
|
||||
messageId: string;
|
||||
params?: ProcessMessageParams;
|
||||
model: string;
|
||||
provider: string;
|
||||
}) => Promise<{
|
||||
isFunctionCall: boolean;
|
||||
traceId?: string;
|
||||
}>;
|
||||
@@ -110,6 +116,8 @@ export interface AIGenerateAction {
|
||||
id?: string,
|
||||
action?: string,
|
||||
) => AbortController | undefined;
|
||||
|
||||
internal_toggleSearchWorkflow: (loading: boolean, id?: string) => void;
|
||||
}
|
||||
|
||||
export const generateAIChat: StateCreator<
|
||||
@@ -336,10 +344,97 @@ export const generateAIChat: StateCreator<
|
||||
|
||||
const assistantId = await get().internal_createMessage(assistantMessage);
|
||||
|
||||
// 3. fetch the AI response
|
||||
const { isFunctionCall } = await internal_fetchAIChatMessage(messages, assistantId, params);
|
||||
// 3. place a search with the search working model if this model is not support tool use
|
||||
const isModelSupportToolUse = aiModelSelectors.isModelSupportToolUse(
|
||||
model,
|
||||
provider!,
|
||||
)(getAiInfraStoreState());
|
||||
const isAgentEnableSearch = agentChatConfigSelectors.isAgentEnableSearch(getAgentStoreState());
|
||||
|
||||
// 4. if it's the function call message, trigger the function method
|
||||
if (isAgentEnableSearch && !isModelSupportToolUse) {
|
||||
const { model, provider } = agentChatConfigSelectors.searchFCModel(getAgentStoreState());
|
||||
|
||||
let isToolsCalling = false;
|
||||
let isError = false;
|
||||
|
||||
const abortController = get().internal_toggleChatLoading(
|
||||
true,
|
||||
assistantId,
|
||||
n('generateMessage(start)', { messageId: assistantId, messages }) as string,
|
||||
);
|
||||
|
||||
get().internal_toggleSearchWorkflow(true, assistantId);
|
||||
await chatService.fetchPresetTaskResult({
|
||||
params: { messages, model, provider, plugins: [WebBrowsingManifest.identifier] },
|
||||
onFinish: async (_, { toolCalls, usage }) => {
|
||||
if (toolCalls && toolCalls.length > 0) {
|
||||
get().internal_toggleToolCallingStreaming(assistantId, undefined);
|
||||
// update tools calling
|
||||
await get().internal_updateMessageContent(assistantId, '', {
|
||||
toolCalls,
|
||||
metadata: usage,
|
||||
model,
|
||||
provider,
|
||||
});
|
||||
}
|
||||
},
|
||||
abortController,
|
||||
onMessageHandle: async (chunk) => {
|
||||
if (chunk.type === 'tool_calls') {
|
||||
get().internal_toggleSearchWorkflow(false, assistantId);
|
||||
get().internal_toggleToolCallingStreaming(assistantId, chunk.isAnimationActives);
|
||||
get().internal_dispatchMessage({
|
||||
id: assistantId,
|
||||
type: 'updateMessage',
|
||||
value: { tools: get().internal_transformToolCalls(chunk.tool_calls) },
|
||||
});
|
||||
isToolsCalling = true;
|
||||
}
|
||||
|
||||
if (chunk.type === 'text') {
|
||||
abortController!.abort('not fc');
|
||||
}
|
||||
},
|
||||
onErrorHandle: async (error) => {
|
||||
isError = true;
|
||||
await messageService.updateMessageError(assistantId, error);
|
||||
await refreshMessages();
|
||||
},
|
||||
});
|
||||
|
||||
get().internal_toggleChatLoading(
|
||||
false,
|
||||
assistantId,
|
||||
n('generateMessage(start)', { messageId: assistantId, messages }) as string,
|
||||
);
|
||||
get().internal_toggleSearchWorkflow(false, assistantId);
|
||||
|
||||
// if there is error, then stop
|
||||
if (isError) return;
|
||||
|
||||
// if it's the function call message, trigger the function method
|
||||
if (isToolsCalling) {
|
||||
await refreshMessages();
|
||||
await triggerToolCalls(assistantId, {
|
||||
threadId: params?.threadId,
|
||||
inPortalThread: params?.inPortalThread,
|
||||
});
|
||||
|
||||
// then story the workflow
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// 4. fetch the AI response
|
||||
const { isFunctionCall } = await internal_fetchAIChatMessage({
|
||||
messages,
|
||||
messageId: assistantId,
|
||||
params,
|
||||
model,
|
||||
provider: provider!,
|
||||
});
|
||||
|
||||
// 5. if it's the function call message, trigger the function method
|
||||
if (isFunctionCall) {
|
||||
await refreshMessages();
|
||||
await triggerToolCalls(assistantId, {
|
||||
@@ -348,7 +443,7 @@ export const generateAIChat: StateCreator<
|
||||
});
|
||||
}
|
||||
|
||||
// 5. summary history if context messages is larger than historyCount
|
||||
// 6. summary history if context messages is larger than historyCount
|
||||
const historyCount = agentChatConfigSelectors.historyCount(getAgentStoreState());
|
||||
|
||||
if (
|
||||
@@ -365,7 +460,7 @@ export const generateAIChat: StateCreator<
|
||||
await get().internal_summaryHistory(historyMessages);
|
||||
}
|
||||
},
|
||||
internal_fetchAIChatMessage: async (messages, messageId, params) => {
|
||||
internal_fetchAIChatMessage: async ({ messages, messageId, params, provider, model }) => {
|
||||
const {
|
||||
internal_toggleChatLoading,
|
||||
refreshMessages,
|
||||
@@ -382,7 +477,7 @@ export const generateAIChat: StateCreator<
|
||||
);
|
||||
|
||||
const agentConfig = agentSelectors.currentAgentConfig(getAgentStoreState());
|
||||
const chatConfig = agentConfig.chatConfig;
|
||||
const chatConfig = agentChatConfigSelectors.currentChatConfig(getAgentStoreState());
|
||||
|
||||
const compiler = template(chatConfig.inputTemplate, { interpolate: /{{([\S\s]+?)}}/g });
|
||||
|
||||
@@ -444,8 +539,8 @@ export const generateAIChat: StateCreator<
|
||||
abortController,
|
||||
params: {
|
||||
messages: preprocessMsgs,
|
||||
model: agentConfig.model,
|
||||
provider: agentConfig.provider,
|
||||
model,
|
||||
provider,
|
||||
...agentConfig.params,
|
||||
plugins: agentConfig.plugins,
|
||||
},
|
||||
@@ -529,6 +624,7 @@ export const generateAIChat: StateCreator<
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
case 'reasoning': {
|
||||
// if there is no thinkingStartAt, it means the start of reasoning
|
||||
if (!thinkingStartAt) {
|
||||
@@ -639,4 +735,8 @@ export const generateAIChat: StateCreator<
|
||||
`toggleToolCallingStreaming/${!!streaming ? 'start' : 'end'}`,
|
||||
);
|
||||
},
|
||||
|
||||
internal_toggleSearchWorkflow: (loading, id) => {
|
||||
return get().internal_toggleLoadingArrays('searchWorkflowLoadingIds', loading, id);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -15,6 +15,7 @@ export interface ChatAIChatState {
|
||||
* is the AI message is reasoning
|
||||
*/
|
||||
reasoningLoadingIds: string[];
|
||||
searchWorkflowLoadingIds: string[];
|
||||
/**
|
||||
* the tool calling stream ids
|
||||
*/
|
||||
@@ -28,5 +29,6 @@ export const initialAiChatState: ChatAIChatState = {
|
||||
messageRAGLoadingIds: [],
|
||||
pluginApiLoadingIds: [],
|
||||
reasoningLoadingIds: [],
|
||||
searchWorkflowLoadingIds: [],
|
||||
toolCallingStreamIds: {},
|
||||
};
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
|
||||
import type { ChatStoreState } from '../../initialState';
|
||||
|
||||
const isMessageInReasoning = (id: string) => (s: ChatStoreState) =>
|
||||
s.reasoningLoadingIds.includes(id);
|
||||
|
||||
const isMessageInSearchWorkflow = (id: string) => (s: ChatStoreState) =>
|
||||
s.searchWorkflowLoadingIds.includes(id);
|
||||
|
||||
const isIntentUnderstanding = (id: string) => (s: ChatStoreState) =>
|
||||
isMessageInSearchWorkflow(id)(s);
|
||||
|
||||
export const aiChatSelectors = {
|
||||
isIntentUnderstanding,
|
||||
isMessageInReasoning,
|
||||
isMessageInSearchWorkflow,
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user