Compare commits

...

29 Commits

Author SHA1 Message Date
semantic-release-bot 5fe229c600 🔖 chore(release): v1.124.4 [skip ci]
### [Version 1.124.4](https://github.com/lobehub/lobe-chat/compare/v1.124.3...v1.124.4)
<sup>Released on **2025-09-06**</sup>

#### 🐛 Bug Fixes

- **misc**: Revert V1 Mobile.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Revert V1 Mobile, closes [#9143](https://github.com/lobehub/lobe-chat/issues/9143) ([b385602](https://github.com/lobehub/lobe-chat/commit/b385602))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2025-09-06 16:31:26 +00:00
bbbugg 6b9337b8ae 🐛fix: Qwen 3 Max Preview model with search capability (#9132)
fix: Qwen 3 Max Preview with search capability
2025-09-07 00:21:17 +08:00
Arvin Xu b3856026d2 🐛 fix: revert V1 Mobile (#9143)
revert V1 Mobile
2025-09-07 00:20:24 +08:00
bbbugg 8dbcbd8c4b 🐛fix: update back navigation logic for provider settings in mobile view (#9141)
🐛 fix: update back navigation logic for provider settings in mobile view
2025-09-06 23:57:02 +08:00
lobehubbot a5b6aadc1f 📝 docs(bot): Auto sync agents & plugin to readme 2025-09-06 10:55:25 +00:00
semantic-release-bot 3690724751 🔖 chore(release): v1.124.3 [skip ci]
### [Version&nbsp;1.124.3](https://github.com/lobehub/lobe-chat/compare/v1.124.2...v1.124.3)
<sup>Released on **2025-09-06**</sup>

#### ♻ Code Refactoring

- **misc**: Refactor to remove edge runtime and add more tests.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### Code refactoring

* **misc**: Refactor to remove edge runtime and add more tests, closes [#9133](https://github.com/lobehub/lobe-chat/issues/9133) ([6f87034](https://github.com/lobehub/lobe-chat/commit/6f87034))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2025-09-06 10:54:26 +00:00
Arvin Xu 6f87034303 ♻️ refactor: refactor to remove edge runtime and add more tests (#9133)
* refactor to add more tests

* refactor the add

* update

* remove edge runtime

* improve types

* remove edge runtime

* fix

* revert auth part

* revert auth part

* revert auth part
2025-09-06 18:44:19 +08:00
Arvin Xu ae28f1794c ️ build : Revert "support mac intel chip" (#9134)
Revert "feat(desktop): support mac intel chip (#9084)"

This reverts commit 1a75f4a6b5.
2025-09-06 16:14:42 +08:00
lobehubbot 68783fd2f7 📝 docs(bot): Auto sync agents & plugin to readme 2025-09-06 07:10:23 +00:00
semantic-release-bot 9e43c1d6e0 🔖 chore(release): v1.124.2 [skip ci]
### [Version&nbsp;1.124.2](https://github.com/lobehub/lobe-chat/compare/v1.124.1...v1.124.2)
<sup>Released on **2025-09-06**</sup>

#### 🐛 Bug Fixes

- **misc**: Fix ChatInput send command switch.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Fix ChatInput send command switch, closes [#9131](https://github.com/lobehub/lobe-chat/issues/9131) ([4d5246a](https://github.com/lobehub/lobe-chat/commit/4d5246a))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2025-09-06 07:09:17 +00:00
Arvin Xu 4d5246acd8 🐛 fix: fix ChatInput send command switch (#9131)
fix command enter switch
2025-09-06 14:59:26 +08:00
Arvin Xu f813d0c429 test: add model runtime tests (#9128)
* fix

* refactor to remove model runtime alias in tests
2025-09-06 14:57:14 +08:00
YuTengjing 1a75f4a6b5 feat(desktop): support mac intel chip (#9084) 2025-09-06 14:03:16 +08:00
Arvin Xu f4c3002b55 test: refactor to improve utils tests and add more tests (#9124)
* refactor to improve utils code

* refactor to improve const code

* refactor to improve types code

* add web crawler tests

* refactor citation item

* add electron server ipc tests

* fix tests

* add more tests

* add timeout
2025-09-06 12:21:58 +08:00
lobehubbot e3aacfcdce 📝 docs(bot): Auto sync agents & plugin to readme 2025-09-06 03:42:14 +00:00
semantic-release-bot 67ad3c42cc 🔖 chore(release): v1.124.1 [skip ci]
### [Version&nbsp;1.124.1](https://github.com/lobehub/lobe-chat/compare/v1.124.0...v1.124.1)
<sup>Released on **2025-09-06**</sup>

#### 🐛 Bug Fixes

- **misc**: Enhance NewAPI with environment variables and fix routers compatibility.

#### 💄 Styles

- **misc**: Update doubao-seed-1.6-vision models.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Enhance NewAPI with environment variables and fix routers compatibility, closes [#9110](https://github.com/lobehub/lobe-chat/issues/9110) ([a66856d](https://github.com/lobehub/lobe-chat/commit/a66856d))

#### Styles

* **misc**: Update doubao-seed-1.6-vision models, closes [#9052](https://github.com/lobehub/lobe-chat/issues/9052) ([df2d001](https://github.com/lobehub/lobe-chat/commit/df2d001))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2025-09-06 03:41:13 +00:00
sxjeru df2d001336 💄 style: Update doubao-seed-1.6-vision models (#9052)
*  feat: 更新 Hunyuan、Novita 和 VolcEngine 模型的参数和描述

*  feat: 添加 DeepSeek V3.1 的思考模式和非思考模式模型,更新描述和显示名称

*  feat: 更新 Groq 模型的描述和显示名称,调整 ID 格式

*  feat: 更新 Novita 模型的上下文窗口令牌和定价策略

*  feat: 添加 Gemma 3 12B 和 Seed OSS 36B Instruct 模型,更新描述、定价和上下文窗口令牌

*  feat: 更新 Novita 模型的定价策略,调整输入和输出的费率

*  feat: 移除 Gemini 2.5 Flash 实验模型,更新模型列表

*  feat: 添加 Kimi K2 0905 模型,更新上下文窗口令牌和定价策略

* update groq

*  feat: 添加 Kimi K2 0905 模型,更新上下文窗口令牌和定价策略

*  feat: 更新 Doubao Seed 模型的部署名称和最大输出,调整上下文窗口令牌

*  feat: 添加 Qwen3 Max Preview 模型,更新上下文窗口令牌和定价策略
2025-09-06 11:30:46 +08:00
Maple Gao a66856dc83 🐛 fix: enhance NewAPI with environment variables and fix routers compatibility (#9110)
 feat: enhance NewAPI with environment variables and fix routers compatibility

- Add NEWAPI_API_KEY and NEWAPI_PROXY_URL environment variable support
- Update documentation for NewAPI configuration options
- Fix routers baseURL handling to prevent duplicate version paths
- Remove /v1 baseURL requirement to avoid SDK compatibility issues
- Auto-detect model capabilities based on provider detection
- Support dynamic routing to correct provider endpoints

This resolves URL duplication issues like /v1beta/v1beta/ and ensures
proper routing to Anthropic, Google, OpenAI, and XAI endpoints.
2025-09-06 11:30:12 +08:00
Arvin Xu e7036af61e test: add test for v2 genai (#9123)
* add more tests

* update tests

* improve
2025-09-06 11:16:30 +08:00
lobehubbot 86ff95ff15 📝 docs(bot): Auto sync agents & plugin to readme 2025-09-06 02:03:08 +00:00
semantic-release-bot 926577302e 🔖 chore(release): v1.124.0 [skip ci]
## [Version&nbsp;1.124.0](https://github.com/lobehub/lobe-chat/compare/v1.123.4...v1.124.0)
<sup>Released on **2025-09-06**</sup>

####  Features

- **misc**: ChatInput support rich text and support parallel send.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's improved

* **misc**: ChatInput support rich text and support parallel send, closes [#8964](https://github.com/lobehub/lobe-chat/issues/8964) ([38d9d98](https://github.com/lobehub/lobe-chat/commit/38d9d98))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2025-09-06 02:02:12 +00:00
CanisMinor 38d9d98b97 feat: ChatInput support rich text and support parallel send (#8964)
*  feat: Add LobeEditor

* fix tests

* fix mobile

---------

Co-authored-by: arvinxx <arvinx@foxmail.com>
2025-09-06 09:51:52 +08:00
lobehubbot e2448eb091 📝 docs(bot): Auto sync agents & plugin to readme 2025-09-05 14:23:34 +00:00
semantic-release-bot 5747239625 🔖 chore(release): v1.123.4 [skip ci]
### [Version&nbsp;1.123.4](https://github.com/lobehub/lobe-chat/compare/v1.123.3...v1.123.4)
<sup>Released on **2025-09-05**</sup>

#### ♻ Code Refactoring

- **misc**: Remove edge runtime.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### Code refactoring

* **misc**: Remove edge runtime, closes [#9085](https://github.com/lobehub/lobe-chat/issues/9085) ([d3544f9](https://github.com/lobehub/lobe-chat/commit/d3544f9))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2025-09-05 14:22:34 +00:00
Arvin Xu d3544f90d3 ♻️ refactor: remove edge runtime (#9085)
* remove edge runtime

* refactor
2025-09-05 22:12:34 +08:00
Arvin Xu 3e537cd01d ♻️ refactor: refactor to use trpc client link chain (#9107)
* refactor

* Update lambda.ts
2025-09-05 21:53:31 +08:00
lobehubbot 72e77b497c 📝 docs(bot): Auto sync agents & plugin to readme 2025-09-05 09:58:40 +00:00
semantic-release-bot 285e2f35f7 🔖 chore(release): v1.123.3 [skip ci]
### [Version&nbsp;1.123.3](https://github.com/lobehub/lobe-chat/compare/v1.123.2...v1.123.3)
<sup>Released on **2025-09-05**</sup>

#### 🐛 Bug Fixes

- **misc**: Fix mobile header title to loog not ellipsis.

<br/>

<details>
<summary><kbd>Improvements and Fixes</kbd></summary>

#### What's fixed

* **misc**: Fix mobile header title to loog not ellipsis, closes [#9109](https://github.com/lobehub/lobe-chat/issues/9109) ([9b8435b](https://github.com/lobehub/lobe-chat/commit/9b8435b))

</details>

<div align="right">

[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)

</div>
2025-09-05 09:57:45 +00:00
Shinji-Li 9b8435b024 🐛 fix: fix mobile header title to loog not ellipsis (#9109)
fix: fix mobile header title to loog not ellipsis
2025-09-05 17:47:37 +08:00
278 changed files with 7618 additions and 2457 deletions
+5
View File
@@ -173,6 +173,11 @@ OPENAI_API_KEY=sk-xxxxxxxxx
# NEBIUS_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
### NewAPI Service ###
# NEWAPI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
# NEWAPI_PROXY_URL=https://your-newapi-server.com
########################################
############ Market Service ############
########################################
+183
View File
@@ -2,6 +2,189 @@
# Changelog
### [Version 1.124.4](https://github.com/lobehub/lobe-chat/compare/v1.124.3...v1.124.4)
<sup>Released on **2025-09-06**</sup>
#### 🐛 Bug Fixes
- **misc**: Revert V1 Mobile.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### What's fixed
- **misc**: Revert V1 Mobile, closes [#9143](https://github.com/lobehub/lobe-chat/issues/9143) ([b385602](https://github.com/lobehub/lobe-chat/commit/b385602))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
### [Version 1.124.3](https://github.com/lobehub/lobe-chat/compare/v1.124.2...v1.124.3)
<sup>Released on **2025-09-06**</sup>
#### ♻ Code Refactoring
- **misc**: Refactor to remove edge runtime and add more tests.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### Code refactoring
- **misc**: Refactor to remove edge runtime and add more tests, closes [#9133](https://github.com/lobehub/lobe-chat/issues/9133) ([6f87034](https://github.com/lobehub/lobe-chat/commit/6f87034))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
### [Version 1.124.2](https://github.com/lobehub/lobe-chat/compare/v1.124.1...v1.124.2)
<sup>Released on **2025-09-06**</sup>
#### 🐛 Bug Fixes
- **misc**: Fix ChatInput send command switch.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### What's fixed
- **misc**: Fix ChatInput send command switch, closes [#9131](https://github.com/lobehub/lobe-chat/issues/9131) ([4d5246a](https://github.com/lobehub/lobe-chat/commit/4d5246a))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
### [Version 1.124.1](https://github.com/lobehub/lobe-chat/compare/v1.124.0...v1.124.1)
<sup>Released on **2025-09-06**</sup>
#### 🐛 Bug Fixes
- **misc**: Enhance NewAPI with environment variables and fix routers compatibility.
#### 💄 Styles
- **misc**: Update doubao-seed-1.6-vision models.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### What's fixed
- **misc**: Enhance NewAPI with environment variables and fix routers compatibility, closes [#9110](https://github.com/lobehub/lobe-chat/issues/9110) ([a66856d](https://github.com/lobehub/lobe-chat/commit/a66856d))
#### Styles
- **misc**: Update doubao-seed-1.6-vision models, closes [#9052](https://github.com/lobehub/lobe-chat/issues/9052) ([df2d001](https://github.com/lobehub/lobe-chat/commit/df2d001))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
## [Version 1.124.0](https://github.com/lobehub/lobe-chat/compare/v1.123.4...v1.124.0)
<sup>Released on **2025-09-06**</sup>
#### ✨ Features
- **misc**: ChatInput support rich text and support parallel send.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### What's improved
- **misc**: ChatInput support rich text and support parallel send, closes [#8964](https://github.com/lobehub/lobe-chat/issues/8964) ([38d9d98](https://github.com/lobehub/lobe-chat/commit/38d9d98))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
### [Version 1.123.4](https://github.com/lobehub/lobe-chat/compare/v1.123.3...v1.123.4)
<sup>Released on **2025-09-05**</sup>
#### ♻ Code Refactoring
- **misc**: Remove edge runtime.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### Code refactoring
- **misc**: Remove edge runtime, closes [#9085](https://github.com/lobehub/lobe-chat/issues/9085) ([d3544f9](https://github.com/lobehub/lobe-chat/commit/d3544f9))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
### [Version 1.123.3](https://github.com/lobehub/lobe-chat/compare/v1.123.2...v1.123.3)
<sup>Released on **2025-09-05**</sup>
#### 🐛 Bug Fixes
- **misc**: Fix mobile header title to loog not ellipsis.
<br/>
<details>
<summary><kbd>Improvements and Fixes</kbd></summary>
#### What's fixed
- **misc**: Fix mobile header title to loog not ellipsis, closes [#9109](https://github.com/lobehub/lobe-chat/issues/9109) ([9b8435b](https://github.com/lobehub/lobe-chat/commit/9b8435b))
</details>
<div align="right">
[![](https://img.shields.io/badge/-BACK_TO_TOP-151515?style=flat-square)](#readme-top)
</div>
### [Version 1.123.2](https://github.com/lobehub/lobe-chat/compare/v1.123.1...v1.123.2)
<sup>Released on **2025-09-05**</sup>
+2
View File
@@ -196,6 +196,8 @@ ENV \
MOONSHOT_API_KEY="" MOONSHOT_MODEL_LIST="" MOONSHOT_PROXY_URL="" \
# Nebius
NEBIUS_API_KEY="" NEBIUS_MODEL_LIST="" NEBIUS_PROXY_URL="" \
# NewAPI
NEWAPI_API_KEY="" NEWAPI_PROXY_URL="" \
# Novita
NOVITA_API_KEY="" NOVITA_MODEL_LIST="" \
# Nvidia NIM
+2
View File
@@ -238,6 +238,8 @@ ENV \
MOONSHOT_API_KEY="" MOONSHOT_MODEL_LIST="" MOONSHOT_PROXY_URL="" \
# Nebius
NEBIUS_API_KEY="" NEBIUS_MODEL_LIST="" NEBIUS_PROXY_URL="" \
# NewAPI
NEWAPI_API_KEY="" NEWAPI_PROXY_URL="" \
# Novita
NOVITA_API_KEY="" NOVITA_MODEL_LIST="" \
# Nvidia NIM
+2
View File
@@ -198,6 +198,8 @@ ENV \
MOONSHOT_API_KEY="" MOONSHOT_MODEL_LIST="" MOONSHOT_PROXY_URL="" \
# Nebius
NEBIUS_API_KEY="" NEBIUS_MODEL_LIST="" NEBIUS_PROXY_URL="" \
# NewAPI
NEWAPI_API_KEY="" NEWAPI_PROXY_URL="" \
# Novita
NOVITA_API_KEY="" NOVITA_MODEL_LIST="" \
# Nvidia NIM
+43
View File
@@ -1,4 +1,47 @@
[
{
"children": {
"improvements": ["Refactor to remove edge runtime and add more tests."]
},
"date": "2025-09-06",
"version": "1.124.3"
},
{
"children": {
"fixes": ["Fix ChatInput send command switch."]
},
"date": "2025-09-06",
"version": "1.124.2"
},
{
"children": {
"fixes": ["Enhance NewAPI with environment variables and fix routers compatibility."],
"improvements": ["Update doubao-seed-1.6-vision models."]
},
"date": "2025-09-06",
"version": "1.124.1"
},
{
"children": {
"features": ["ChatInput support rich text and support parallel send."]
},
"date": "2025-09-06",
"version": "1.124.0"
},
{
"children": {
"improvements": ["Remove edge runtime."]
},
"date": "2025-09-05",
"version": "1.123.4"
},
{
"children": {
"fixes": ["Fix mobile header title to loog not ellipsis."]
},
"date": "2025-09-05",
"version": "1.123.3"
},
{
"children": {
"fixes": ["Not use branch topic when this topic is not save."]
@@ -675,4 +675,22 @@ The above example disables all models first, then enables `flux/schnell` and `fl
The above example disables all models first, then enables `flux-pro-1.1` and `flux-kontext-pro` (displayed as `FLUX.1 Kontext [pro]`).
## NewAPI
### `NEWAPI_API_KEY`
- Type: Optional
- Description: This is the API key for your NewAPI service instance. NewAPI is a multi-provider model aggregation service that provides unified access to various AI model APIs.
- Default: -
- Example: `sk-xxxxxx...xxxxxx`
### `NEWAPI_PROXY_URL`
- Type: Optional
- Description: The base URL for your NewAPI server instance. This should point to your deployed NewAPI service endpoint.
- Default: -
- Example: `https://your-newapi-server.com/`
NewAPI is a multi-provider model aggregation service that supports automatic model routing based on provider detection. It offers cost management features and provides a single endpoint for accessing models from multiple providers including OpenAI, Anthropic, Google, and more. Learn more about NewAPI at [https://github.com/Calcium-Ion/new-api](https://github.com/Calcium-Ion/new-api).
[model-list]: /docs/self-hosting/advanced/model-list
@@ -674,4 +674,24 @@ LobeChat 在部署时提供了丰富的模型服务商相关的环境变量,
上述示例表示先禁用所有模型,再启用 `flux-pro-1.1` 和 `flux-kontext-pro`(显示名为 `FLUX.1 Kontext [pro]`)。
## NewAPI
### `NEWAPI_API_KEY`
- 类型:可选
- 描述:这是你的 NewAPI 服务实例的 API 密钥。NewAPI 是一个多供应商模型聚合服务,提供对各种 AI 模型 API 的统一访问。
- 默认值:-
- 示例:`sk-xxxxxx...xxxxxx`
### `NEWAPI_PROXY_URL`
- 类型:可选
- 描述:你的 NewAPI 服务器实例的基础 URL。这应该指向你部署的 NewAPI 服务端点。
- 默认值:-
- 示例:`https://your-newapi-server.com`
<Callout type={'info'}>
NewAPI 是一个多供应商模型聚合服务,支持基于供应商检测的自动模型路由。它提供成本管理功能,并为访问包括 OpenAI、Anthropic、Google 等多个供应商的模型提供单一端点。了解更多关于 NewAPI 的信息请访问 [https://github.com/Calcium-Ion/new-api](https://github.com/Calcium-Ion/new-api)。
</Callout>
[model-list]: /zh/docs/self-hosting/advanced/model-list
+8 -2
View File
@@ -70,10 +70,12 @@
"input": {
"addAi": "إضافة رسالة AI",
"addUser": "إضافة رسالة مستخدم",
"disclaimer": "قد يرتكب الذكاء الاصطناعي أخطاءً أيضًا، يرجى التحقق من المعلومات الهامة",
"errorMsg": "فشل إرسال الرسالة، يرجى التحقق من الشبكة والمحاولة مرة أخرى: {{errorMsg}}",
"more": "المزيد",
"send": "إرسال",
"sendWithCmdEnter": "اضغط {{meta}} + Enter للإرسال",
"sendWithEnter": "اضغط Enter للإرسال",
"sendWithCmdEnter": "اضغط <key/> للإرسال",
"sendWithEnter": "اضغط <key/> للإرسال",
"stop": "توقف",
"warp": "تغيير السطر"
},
@@ -232,6 +234,10 @@
"threadMessageCount": "{{messageCount}} رسالة",
"title": "موضوع فرعي"
},
"toggleWideScreen": {
"off": "إيقاف وضع الشاشة العريضة",
"on": "تشغيل وضع الشاشة العريضة"
},
"tokenDetails": {
"chats": "رسائل المحادثة",
"historySummary": "ملخص التاريخ",
+47
View File
@@ -0,0 +1,47 @@
{
"actions": {
"expand": {
"off": "طي",
"on": "توسيع"
},
"typobar": {
"off": "إخفاء شريط أدوات التنسيق",
"on": "إظهار شريط أدوات التنسيق"
}
},
"file": {
"error": "خطأ: {{message}}",
"uploading": "جاري رفع الملف..."
},
"image": {
"broken": "الصورة تالفة"
},
"link": {
"edit": "تعديل الرابط",
"open": "فتح الرابط",
"placeholder": "أدخل عنوان URL للرابط",
"unlink": "إزالة الرابط"
},
"table": {
"delete": "حذف الجدول",
"deleteColumn": "حذف العمود",
"deleteRow": "حذف الصف",
"insertColumnLeft": "إدراج {{count}} عمودًا إلى اليسار",
"insertColumnRight": "إدراج {{count}} عمودًا إلى اليمين",
"insertRowAbove": "إدراج {{count}} صفًا في الأعلى",
"insertRowBelow": "إدراج {{count}} صفًا في الأسفل"
},
"typobar": {
"blockquote": "اقتباس",
"bold": "غامق",
"bulletList": "قائمة نقطية",
"code": "كود مضمن",
"codeblock": "كتلة كود",
"italic": "مائل",
"link": "رابط",
"numberList": "قائمة مرقمة",
"strikethrough": "شطب",
"table": "إدراج جدول",
"underline": "تسطير"
}
}
+8 -2
View File
@@ -70,10 +70,12 @@
"input": {
"addAi": "Добави AI съобщение",
"addUser": "Добави потребителско съобщение",
"disclaimer": "Изкуственият интелект също може да греши, моля проверете важната информация",
"errorMsg": "Неуспешно изпращане на съобщението, моля, проверете мрежата и опитайте отново: {{errorMsg}}",
"more": "още",
"send": "Изпрати",
"sendWithCmdEnter": "Натисни {{meta}} + Enter за да изпратиш",
"sendWithEnter": "Натисни Enter за да изпратиш",
"sendWithCmdEnter": "Натиснете <key/> за изпращане",
"sendWithEnter": "Натиснете <key/> за изпращане",
"stop": "Спри",
"warp": "Нов ред"
},
@@ -232,6 +234,10 @@
"threadMessageCount": "{{messageCount}} съобщения",
"title": "Подтема"
},
"toggleWideScreen": {
"off": "Изключване на широк екран",
"on": "Включване на широк екран"
},
"tokenDetails": {
"chats": "Чат съобщения",
"historySummary": "Историческо резюме",
+47
View File
@@ -0,0 +1,47 @@
{
"actions": {
"expand": {
"off": "Сгъни",
"on": "Разгъни"
},
"typobar": {
"off": "Скрий лентата за форматиране",
"on": "Покажи лентата за форматиране"
}
},
"file": {
"error": "Грешка: {{message}}",
"uploading": "Качване на файл..."
},
"image": {
"broken": "Изображението е повредено"
},
"link": {
"edit": "Редактирай връзката",
"open": "Отвори връзката",
"placeholder": "Въведете URL адрес на връзката",
"unlink": "Премахни връзката"
},
"table": {
"delete": "Премахни таблицата",
"deleteColumn": "Премахни колоната",
"deleteRow": "Премахни реда",
"insertColumnLeft": "Вмъкни {{count}} колони отляво",
"insertColumnRight": "Вмъкни {{count}} колони отдясно",
"insertRowAbove": "Вмъкни {{count}} реда отгоре",
"insertRowBelow": "Вмъкни {{count}} реда отдолу"
},
"typobar": {
"blockquote": "Цитат",
"bold": "Удебели",
"bulletList": "Маркиран списък",
"code": "Код в реда",
"codeblock": "Блок с код",
"italic": "Курсив",
"link": "Връзка",
"numberList": "Номериран списък",
"strikethrough": "Зачеркване",
"table": "Вмъкване на таблица",
"underline": "Подчертаване"
}
}
+8 -2
View File
@@ -70,10 +70,12 @@
"input": {
"addAi": "Fügen Sie eine AI-Nachricht hinzu",
"addUser": "Fügen Sie eine Benutzer-Nachricht hinzu",
"disclaimer": "KI kann auch Fehler machen, bitte überprüfen Sie wichtige Informationen",
"errorMsg": "Nachricht konnte nicht gesendet werden, bitte überprüfen Sie Ihre Netzwerkverbindung und versuchen Sie es erneut: {{errorMsg}}",
"more": "Mehr",
"send": "Senden",
"sendWithCmdEnter": "Mit {{meta}} + Eingabetaste senden",
"sendWithEnter": "Mit Eingabetaste senden",
"sendWithCmdEnter": "Drücken Sie <key/>, um zu senden",
"sendWithEnter": "Drücken Sie <key/>, um zu senden",
"stop": "Stoppen",
"warp": "Zeilenumbruch"
},
@@ -232,6 +234,10 @@
"threadMessageCount": "{{messageCount}} Nachrichten",
"title": "Unterthema"
},
"toggleWideScreen": {
"off": "Breitbildmodus deaktivieren",
"on": "Breitbildmodus aktivieren"
},
"tokenDetails": {
"chats": "Chats",
"historySummary": "Historische Zusammenfassung",
+47
View File
@@ -0,0 +1,47 @@
{
"actions": {
"expand": {
"off": "Einklappen",
"on": "Ausklappen"
},
"typobar": {
"off": "Formatierungsleiste ausblenden",
"on": "Formatierungsleiste anzeigen"
}
},
"file": {
"error": "Fehler: {{message}}",
"uploading": "Datei wird hochgeladen..."
},
"image": {
"broken": "Bild beschädigt"
},
"link": {
"edit": "Link bearbeiten",
"open": "Link öffnen",
"placeholder": "Link-URL eingeben",
"unlink": "Link entfernen"
},
"table": {
"delete": "Tabelle löschen",
"deleteColumn": "Spalte löschen",
"deleteRow": "Zeile löschen",
"insertColumnLeft": "Links {{count}} Spalten einfügen",
"insertColumnRight": "Rechts {{count}} Spalten einfügen",
"insertRowAbove": "Oben {{count}} Zeilen einfügen",
"insertRowBelow": "Unten {{count}} Zeilen einfügen"
},
"typobar": {
"blockquote": "Zitat",
"bold": "Fett",
"bulletList": "Ungeordnete Liste",
"code": "Inline-Code",
"codeblock": "Codeblock",
"italic": "Kursiv",
"link": "Link",
"numberList": "Nummerierte Liste",
"strikethrough": "Durchgestrichen",
"table": "Tabelle einfügen",
"underline": "Unterstrichen"
}
}
+8 -2
View File
@@ -70,10 +70,12 @@
"input": {
"addAi": "Add an AI message",
"addUser": "Add a user message",
"disclaimer": "AI may also make mistakes, please verify important information",
"errorMsg": "Message sending failed, please check your network and try again: {{errorMsg}}",
"more": "more",
"send": "Send",
"sendWithCmdEnter": "Press {{meta}} + Enter to send",
"sendWithEnter": "Press Enter to send",
"sendWithCmdEnter": "Press <key/> to send",
"sendWithEnter": "Press <key/> to send",
"stop": "Stop",
"warp": "New Line"
},
@@ -232,6 +234,10 @@
"threadMessageCount": "{{messageCount}} messages",
"title": "Subtopic"
},
"toggleWideScreen": {
"off": "Turn off widescreen mode",
"on": "Turn on widescreen mode"
},
"tokenDetails": {
"chats": "Chat Messages",
"historySummary": "History Summary",
+47
View File
@@ -0,0 +1,47 @@
{
"actions": {
"expand": {
"off": "Collapse",
"on": "Expand"
},
"typobar": {
"off": "Hide formatting toolbar",
"on": "Show formatting toolbar"
}
},
"file": {
"error": "Error: {{message}}",
"uploading": "Uploading file..."
},
"image": {
"broken": "Image is corrupted"
},
"link": {
"edit": "Edit link",
"open": "Open link",
"placeholder": "Enter link URL",
"unlink": "Unlink"
},
"table": {
"delete": "Delete table",
"deleteColumn": "Delete column",
"deleteRow": "Delete row",
"insertColumnLeft": "Insert {{count}} column(s) to the left",
"insertColumnRight": "Insert {{count}} column(s) to the right",
"insertRowAbove": "Insert {{count}} row(s) above",
"insertRowBelow": "Insert {{count}} row(s) below"
},
"typobar": {
"blockquote": "Blockquote",
"bold": "Bold",
"bulletList": "Bulleted list",
"code": "Inline code",
"codeblock": "Code block",
"italic": "Italic",
"link": "Link",
"numberList": "Numbered list",
"strikethrough": "Strikethrough",
"table": "Insert table",
"underline": "Underline"
}
}
+8 -2
View File
@@ -70,10 +70,12 @@
"input": {
"addAi": "Agregar un mensaje de IA",
"addUser": "Agregar un mensaje de usuario",
"disclaimer": "La IA también puede cometer errores, por favor verifique la información importante",
"errorMsg": "Error al enviar el mensaje, por favor revise la conexión y vuelva a intentarlo: {{errorMsg}}",
"more": "más",
"send": "Enviar",
"sendWithCmdEnter": "Enviar con {{meta}} + Enter",
"sendWithEnter": "Enviar con Enter",
"sendWithCmdEnter": "Presiona <key/> para enviar",
"sendWithEnter": "Presiona <key/> para enviar",
"stop": "Detener",
"warp": "Salto de línea"
},
@@ -232,6 +234,10 @@
"threadMessageCount": "{{messageCount}} mensajes",
"title": "Subtema"
},
"toggleWideScreen": {
"off": "Desactivar modo de pantalla ancha",
"on": "Activar modo de pantalla ancha"
},
"tokenDetails": {
"chats": "Mensajes de chat",
"historySummary": "Resumen histórico",
+47
View File
@@ -0,0 +1,47 @@
{
"actions": {
"expand": {
"off": "Contraer",
"on": "Expandir"
},
"typobar": {
"off": "Ocultar barra de herramientas de formato",
"on": "Mostrar barra de herramientas de formato"
}
},
"file": {
"error": "Error: {{message}}",
"uploading": "Subiendo archivo..."
},
"image": {
"broken": "Imagen dañada"
},
"link": {
"edit": "Editar enlace",
"open": "Abrir enlace",
"placeholder": "Introduce la URL del enlace",
"unlink": "Quitar enlace"
},
"table": {
"delete": "Eliminar tabla",
"deleteColumn": "Eliminar columna",
"deleteRow": "Eliminar fila",
"insertColumnLeft": "Insertar {{count}} columna(s) a la izquierda",
"insertColumnRight": "Insertar {{count}} columna(s) a la derecha",
"insertRowAbove": "Insertar {{count}} fila(s) encima",
"insertRowBelow": "Insertar {{count}} fila(s) debajo"
},
"typobar": {
"blockquote": "Cita",
"bold": "Negrita",
"bulletList": "Lista desordenada",
"code": "Código en línea",
"codeblock": "Bloque de código",
"italic": "Cursiva",
"link": "Enlace",
"numberList": "Lista ordenada",
"strikethrough": "Tachado",
"table": "Insertar tabla",
"underline": "Subrayado"
}
}
+3 -1
View File
@@ -1505,7 +1505,9 @@
"gpt-4.1-nano": {
"description": "GPT-4.1 mini ofrece un equilibrio entre inteligencia, velocidad y costo, lo que lo convierte en un modelo atractivo para muchos casos de uso."
},
"gpt-4.5-preview": "GPT-4.5-preview es el modelo de propósito general más reciente, con un profundo conocimiento del mundo y una mejor comprensión de las intenciones de los usuarios; destaca en tareas creativas y en la planificación de agentes. El conocimiento de este modelo está actualizado hasta octubre de 2023.",
"gpt-4.5-preview": {
"description": "GPT-4.5-preview es el modelo de propósito general más reciente, con un profundo conocimiento del mundo y una mejor comprensión de las intenciones de los usuarios; destaca en tareas creativas y en la planificación de agentes. El conocimiento de este modelo está actualizado hasta octubre de 2023."
},
"gpt-4o": {
"description": "ChatGPT-4o es un modelo dinámico que se actualiza en tiempo real para mantener la versión más actual. Combina una poderosa comprensión y generación de lenguaje, adecuado para aplicaciones a gran escala, incluyendo servicio al cliente, educación y soporte técnico."
},
+8 -2
View File
@@ -70,10 +70,12 @@
"input": {
"addAi": "افزودن یک پیام AI",
"addUser": "افزودن یک پیام کاربر",
"disclaimer": "هوش مصنوعی نیز ممکن است اشتباه کند، لطفاً اطلاعات مهم را بررسی کنید",
"errorMsg": "ارسال پیام ناموفق بود، لطفاً پس از بررسی شبکه دوباره تلاش کنید: {{errorMsg}}",
"more": "بیشتر",
"send": "ارسال",
"sendWithCmdEnter": "فشار دهید {{meta}} + Enter برای ارسال",
"sendWithEnter": "فشار دهید Enter برای ارسال",
"sendWithCmdEnter": "برای ارسال، کلید <key/> را فشار دهید",
"sendWithEnter": "برای ارسال، کلید <key/> را فشار دهید",
"stop": "توقف",
"warp": "خط جدید"
},
@@ -232,6 +234,10 @@
"threadMessageCount": "{{messageCount}} پیام",
"title": "زیرموضوع"
},
"toggleWideScreen": {
"off": "حالت صفحه‌نمایش عریض را غیرفعال کنید",
"on": "حالت صفحه‌نمایش عریض را فعال کنید"
},
"tokenDetails": {
"chats": "پیام‌های گفتگو",
"historySummary": "خلاصه تاریخ",
+47
View File
@@ -0,0 +1,47 @@
{
"actions": {
"expand": {
"off": "جمع کردن",
"on": "باز کردن"
},
"typobar": {
"off": "مخفی کردن نوار ابزار قالب‌بندی",
"on": "نمایش نوار ابزار قالب‌بندی"
}
},
"file": {
"error": "خطا: {{message}}",
"uploading": "در حال بارگذاری فایل..."
},
"image": {
"broken": "تصویر خراب است"
},
"link": {
"edit": "ویرایش پیوند",
"open": "باز کردن پیوند",
"placeholder": "آدرس URL پیوند را وارد کنید",
"unlink": "حذف پیوند"
},
"table": {
"delete": "حذف جدول",
"deleteColumn": "حذف ستون",
"deleteRow": "حذف ردیف",
"insertColumnLeft": "درج {{count}} ستون در سمت چپ",
"insertColumnRight": "درج {{count}} ستون در سمت راست",
"insertRowAbove": "درج {{count}} ردیف در بالا",
"insertRowBelow": "درج {{count}} ردیف در پایین"
},
"typobar": {
"blockquote": "نقل قول",
"bold": "پررنگ",
"bulletList": "فهرست نشانه‌دار",
"code": "کد درون‌خطی",
"codeblock": "بلوک کد",
"italic": "ایتالیک",
"link": "پیوند",
"numberList": "فهرست شماره‌دار",
"strikethrough": "خط خورده",
"table": "درج جدول",
"underline": "زیرخط"
}
}
+8 -2
View File
@@ -70,10 +70,12 @@
"input": {
"addAi": "Ajouter un message AI",
"addUser": "Ajouter un message utilisateur",
"disclaimer": "L'IA peut également faire des erreurs, veuillez vérifier les informations importantes",
"errorMsg": "Échec de l'envoi du message, veuillez vérifier votre connexion réseau et réessayer : {{errorMsg}}",
"more": "Plus",
"send": "Envoyer",
"sendWithCmdEnter": "Envoyer avec {{meta}} + Entrée",
"sendWithEnter": "Envoyer avec Entrée",
"sendWithCmdEnter": "Appuyez sur <key/> pour envoyer",
"sendWithEnter": "Appuyez sur <key/> pour envoyer",
"stop": "Arrêter",
"warp": "Saut de ligne"
},
@@ -232,6 +234,10 @@
"threadMessageCount": "{{messageCount}} messages",
"title": "Sous-sujet"
},
"toggleWideScreen": {
"off": "Désactiver le mode écran large",
"on": "Activer le mode écran large"
},
"tokenDetails": {
"chats": "Messages de discussion",
"historySummary": "Résumé historique",
+47
View File
@@ -0,0 +1,47 @@
{
"actions": {
"expand": {
"off": "Réduire",
"on": "Développer"
},
"typobar": {
"off": "Masquer la barre d'outils de formatage",
"on": "Afficher la barre d'outils de formatage"
}
},
"file": {
"error": "Erreur : {{message}}",
"uploading": "Téléversement du fichier en cours..."
},
"image": {
"broken": "Image endommagée"
},
"link": {
"edit": "Modifier le lien",
"open": "Ouvrir le lien",
"placeholder": "Entrez l'URL du lien",
"unlink": "Supprimer le lien"
},
"table": {
"delete": "Supprimer le tableau",
"deleteColumn": "Supprimer la colonne",
"deleteRow": "Supprimer la ligne",
"insertColumnLeft": "Insérer {{count}} colonne(s) à gauche",
"insertColumnRight": "Insérer {{count}} colonne(s) à droite",
"insertRowAbove": "Insérer {{count}} ligne(s) au-dessus",
"insertRowBelow": "Insérer {{count}} ligne(s) en dessous"
},
"typobar": {
"blockquote": "Citation",
"bold": "Gras",
"bulletList": "Liste à puces",
"code": "Code en ligne",
"codeblock": "Bloc de code",
"italic": "Italique",
"link": "Lien",
"numberList": "Liste numérotée",
"strikethrough": "Barré",
"table": "Insérer un tableau",
"underline": "Souligné"
}
}
+8 -2
View File
@@ -70,10 +70,12 @@
"input": {
"addAi": "Aggiungi un messaggio AI",
"addUser": "Aggiungi un messaggio utente",
"disclaimer": "L'IA può anche commettere errori, si prega di verificare le informazioni importanti",
"errorMsg": "Invio del messaggio fallito, controlla la rete e riprova: {{errorMsg}}",
"more": "Ulteriori",
"send": "Invia",
"sendWithCmdEnter": "Invia premendo {{meta}} + Invio",
"sendWithEnter": "Invia premendo Invio",
"sendWithCmdEnter": "Premi <key/> per inviare",
"sendWithEnter": "Premi <key/> per inviare",
"stop": "Ferma",
"warp": "A capo"
},
@@ -232,6 +234,10 @@
"threadMessageCount": "{{messageCount}} messaggi",
"title": "Sottoargomento"
},
"toggleWideScreen": {
"off": "Disattiva modalità schermo ampio",
"on": "Attiva modalità schermo ampio"
},
"tokenDetails": {
"chats": "Chat",
"historySummary": "Riepilogo storico",
+47
View File
@@ -0,0 +1,47 @@
{
"actions": {
"expand": {
"off": "Comprimi",
"on": "Espandi"
},
"typobar": {
"off": "Nascondi barra degli strumenti di formattazione",
"on": "Mostra barra degli strumenti di formattazione"
}
},
"file": {
"error": "Errore: {{message}}",
"uploading": "Caricamento file in corso..."
},
"image": {
"broken": "Immagine danneggiata"
},
"link": {
"edit": "Modifica link",
"open": "Apri link",
"placeholder": "Inserisci URL del link",
"unlink": "Rimuovi link"
},
"table": {
"delete": "Elimina tabella",
"deleteColumn": "Elimina colonna",
"deleteRow": "Elimina riga",
"insertColumnLeft": "Inserisci {{count}} colonne a sinistra",
"insertColumnRight": "Inserisci {{count}} colonne a destra",
"insertRowAbove": "Inserisci {{count}} righe sopra",
"insertRowBelow": "Inserisci {{count}} righe sotto"
},
"typobar": {
"blockquote": "Citazione",
"bold": "Grassetto",
"bulletList": "Elenco puntato",
"code": "Codice in linea",
"codeblock": "Blocco di codice",
"italic": "Corsivo",
"link": "Collegamento",
"numberList": "Elenco numerato",
"strikethrough": "Testo barrato",
"table": "Inserisci tabella",
"underline": "Sottolineato"
}
}
+8 -2
View File
@@ -70,10 +70,12 @@
"input": {
"addAi": "AIメッセージを追加",
"addUser": "ユーザーメッセージを追加",
"disclaimer": "AIも誤りを犯すことがありますので、重要な情報はご確認ください",
"errorMsg": "メッセージの送信に失敗しました。ネットワークを確認してから再試行してください: {{errorMsg}}",
"more": "もっと",
"send": "送信",
"sendWithCmdEnter": "{{meta}} + Enter キーで送信",
"sendWithEnter": "Enter キーで送信",
"sendWithCmdEnter": "<key/> キーを押して送信",
"sendWithEnter": "<key/> キーを押して送信",
"stop": "停止",
"warp": "改行"
},
@@ -232,6 +234,10 @@
"threadMessageCount": "{{messageCount}} 件のメッセージ",
"title": "サブトピック"
},
"toggleWideScreen": {
"off": "ワイドスクリーンモードをオフにする",
"on": "ワイドスクリーンモードをオンにする"
},
"tokenDetails": {
"chats": "チャットメッセージ",
"historySummary": "履歴の要約",
+47
View File
@@ -0,0 +1,47 @@
{
"actions": {
"expand": {
"off": "折りたたむ",
"on": "展開する"
},
"typobar": {
"off": "書式ツールバーを非表示",
"on": "書式ツールバーを表示"
}
},
"file": {
"error": "エラー:{{message}}",
"uploading": "ファイルをアップロードしています..."
},
"image": {
"broken": "画像が破損しています"
},
"link": {
"edit": "リンクを編集",
"open": "リンクを開く",
"placeholder": "リンクの URL を入力",
"unlink": "リンクを解除"
},
"table": {
"delete": "表を削除",
"deleteColumn": "列を削除",
"deleteRow": "行を削除",
"insertColumnLeft": "左側に {{count}} 列を挿入",
"insertColumnRight": "右側に {{count}} 列を挿入",
"insertRowAbove": "上に {{count}} 行を挿入",
"insertRowBelow": "下に {{count}} 行を挿入"
},
"typobar": {
"blockquote": "引用",
"bold": "太字",
"bulletList": "番号なしリスト",
"code": "インラインコード",
"codeblock": "コードブロック",
"italic": "斜体",
"link": "リンク",
"numberList": "番号付きリスト",
"strikethrough": "取り消し線",
"table": "表を挿入",
"underline": "下線"
}
}
+8 -2
View File
@@ -70,10 +70,12 @@
"input": {
"addAi": "AI 메시지 추가",
"addUser": "사용자 메시지 추가",
"disclaimer": "AI도 실수를 할 수 있으니 중요한 정보는 꼭 확인하세요",
"errorMsg": "메시지 전송에 실패했습니다. 네트워크를 확인한 후 다시 시도해 주세요: {{errorMsg}}",
"more": "더 많은",
"send": "전송",
"sendWithCmdEnter": "{{meta}} + Enter 키로 전송",
"sendWithEnter": "Enter 키로 전송",
"sendWithCmdEnter": "<key/> 키를 눌러 전송",
"sendWithEnter": "<key/> 키를 눌러 전송",
"stop": "중지",
"warp": "줄바꿈"
},
@@ -232,6 +234,10 @@
"threadMessageCount": "{{messageCount}}개의 메시지",
"title": "하위 주제"
},
"toggleWideScreen": {
"off": "와이드 스크린 모드 끄기",
"on": "와이드 스크린 모드 켜기"
},
"tokenDetails": {
"chats": "채팅 메시지",
"historySummary": "역사 요약",
+47
View File
@@ -0,0 +1,47 @@
{
"actions": {
"expand": {
"off": "접기",
"on": "펼치기"
},
"typobar": {
"off": "서식 도구 모음 숨기기",
"on": "서식 도구 모음 표시"
}
},
"file": {
"error": "오류: {{message}}",
"uploading": "파일 업로드 중..."
},
"image": {
"broken": "이미지가 손상되었습니다"
},
"link": {
"edit": "링크 편집",
"open": "링크 열기",
"placeholder": "링크 URL 입력",
"unlink": "링크 제거"
},
"table": {
"delete": "테이블 삭제",
"deleteColumn": "열 삭제",
"deleteRow": "행 삭제",
"insertColumnLeft": "왼쪽에 {{count}}개의 열 삽입",
"insertColumnRight": "오른쪽에 {{count}}개의 열 삽입",
"insertRowAbove": "위에 {{count}}개의 행 삽입",
"insertRowBelow": "아래에 {{count}}개의 행 삽입"
},
"typobar": {
"blockquote": "인용",
"bold": "굵게",
"bulletList": "순서 없는 목록",
"code": "인라인 코드",
"codeblock": "코드 블록",
"italic": "기울임꼴",
"link": "링크",
"numberList": "번호 매긴 목록",
"strikethrough": "취소선",
"table": "표 삽입",
"underline": "밑줄"
}
}
+3 -1
View File
@@ -1505,7 +1505,9 @@
"gpt-4.1-nano": {
"description": "GPT-4.1 mini는 지능, 속도 및 비용 간의 균형을 제공하여 많은 사용 사례에서 매력적인 모델이 됩니다."
},
"gpt-4.5-preview": "GPT-4.5-preview는 최신 범용 모델로, 폭넓은 세계 지식과 사용자 의도에 대한 향상된 이해를 갖추고 있어 창의적 과제와 에이전트 계획에 능숙합니다. 이 모델의 지식은 2023년 10월까지입니다.",
"gpt-4.5-preview": {
"description": "GPT-4.5-preview는 최신 범용 모델로, 폭넓은 세계 지식과 사용자 의도에 대한 향상된 이해를 갖추고 있어 창의적 과제와 에이전트 계획에 능숙합니다. 이 모델의 지식은 2023년 10월까지입니다."
},
"gpt-4o": {
"description": "ChatGPT-4o는 동적 모델로, 최신 버전을 유지하기 위해 실시간으로 업데이트됩니다. 강력한 언어 이해 및 생성 능력을 결합하여 고객 서비스, 교육 및 기술 지원을 포함한 대규모 응용 프로그램에 적합합니다."
},
+8 -2
View File
@@ -70,10 +70,12 @@
"input": {
"addAi": "Voeg een AI-bericht toe",
"addUser": "Voeg een gebruikersbericht toe",
"disclaimer": "AI kan ook fouten maken, controleer belangrijke informatie alstublieft",
"errorMsg": "Bericht verzenden mislukt, controleer uw netwerk en probeer het opnieuw: {{errorMsg}}",
"more": "Meer",
"send": "Verzenden",
"sendWithCmdEnter": "Verzenden met {{meta}} + Enter",
"sendWithEnter": "Verzenden met Enter",
"sendWithCmdEnter": "Druk op <key/> om te verzenden",
"sendWithEnter": "Druk op <key/> om te verzenden",
"stop": "Stoppen",
"warp": "Nieuwe regel"
},
@@ -232,6 +234,10 @@
"threadMessageCount": "{{messageCount}} berichten",
"title": "Subonderwerp"
},
"toggleWideScreen": {
"off": "Schakel breedbeeldmodus uit",
"on": "Schakel breedbeeldmodus in"
},
"tokenDetails": {
"chats": "Chats",
"historySummary": "Geschiedenis samenvatting",
+47
View File
@@ -0,0 +1,47 @@
{
"actions": {
"expand": {
"off": "Inklappen",
"on": "Uitklappen"
},
"typobar": {
"off": "Verberg opmaakwerkbalk",
"on": "Toon opmaakwerkbalk"
}
},
"file": {
"error": "Fout: {{message}}",
"uploading": "Bestand wordt geüpload..."
},
"image": {
"broken": "Afbeelding beschadigd"
},
"link": {
"edit": "Link bewerken",
"open": "Link openen",
"placeholder": "Voer de URL van de link in",
"unlink": "Link verwijderen"
},
"table": {
"delete": "Tabel verwijderen",
"deleteColumn": "Kolom verwijderen",
"deleteRow": "Rij verwijderen",
"insertColumnLeft": "Voeg {{count}} kolommen links in",
"insertColumnRight": "Voeg {{count}} kolommen rechts in",
"insertRowAbove": "Voeg {{count}} rijen hierboven in",
"insertRowBelow": "Voeg {{count}} rijen hieronder in"
},
"typobar": {
"blockquote": "Citaat",
"bold": "Vet",
"bulletList": "Opsomming",
"code": "Inlinecode",
"codeblock": "Codeblok",
"italic": "Cursief",
"link": "Link",
"numberList": "Genummerde lijst",
"strikethrough": "Doorhalen",
"table": "Tabel invoegen",
"underline": "Onderstrepen"
}
}
+3 -1
View File
@@ -2663,7 +2663,9 @@
"step-r1-v-mini": {
"description": "Dit model is een krachtig redeneringsmodel met sterke beeldbegripcapaciteiten, in staat om beeld- en tekstinformatie te verwerken en tekstinhoud te genereren na diep nadenken. Dit model presteert uitstekend in visuele redenering en heeft eersteklas wiskundige, code- en tekstredeneringscapaciteiten. De contextlengte is 100k."
},
"stepfun-ai/step3": "Step3 is een geavanceerd multimodaal redeneermodel uitgebracht door StepFun (阶跃星辰). Het is gebouwd op een Mixture-of-Experts (MoE)-architectuur met in totaal 321 miljard (321B) parameters en 38 miljard (38B) actieve parameters. Het model heeft een end-to-end ontwerp dat gericht is op het minimaliseren van decodeerkosten, terwijl het topniveau-prestaties levert bij vision-language redenering. Dankzij de synergie tussen Multi-Matrix Factorized Attention (MFA) en Attention-FFN Decoupling (AFD) behoudt Step3 uitstekende efficiëntie zowel op high-end als low-end accelerators. Tijdens de voortraining verwerkte Step3 meer dan 20 biljoen (20T) teksttokens en 4 biljoen (4T) gecombineerde beeld-tekst-tokens, en bestrijkt daarmee meer dan tien talen. Het model behaalt leidende resultaten onder open-sourcemodellen op verschillende benchmarks, waaronder wiskunde, code en multimodaal.",
"stepfun-ai/step3": {
"description": "Step3 is een geavanceerd multimodaal redeneermodel uitgebracht door StepFun (阶跃星辰). Het is gebouwd op een Mixture-of-Experts (MoE)-architectuur met in totaal 321 miljard (321B) parameters en 38 miljard (38B) actieve parameters. Het model heeft een end-to-end ontwerp dat gericht is op het minimaliseren van decodeerkosten, terwijl het topniveau-prestaties levert bij vision-language redenering. Dankzij de synergie tussen Multi-Matrix Factorized Attention (MFA) en Attention-FFN Decoupling (AFD) behoudt Step3 uitstekende efficiëntie zowel op high-end als low-end accelerators. Tijdens de voortraining verwerkte Step3 meer dan 20 biljoen (20T) teksttokens en 4 biljoen (4T) gecombineerde beeld-tekst-tokens, en bestrijkt daarmee meer dan tien talen. Het model behaalt leidende resultaten onder open-sourcemodellen op verschillende benchmarks, waaronder wiskunde, code en multimodaal."
},
"taichu_llm": {
"description": "Het Zido Tai Chu-taalmodel heeft een sterke taalbegripcapaciteit en kan tekstcreatie, kennisvragen, codeprogrammering, wiskundige berekeningen, logische redenering, sentimentanalyse, tekstsamenvattingen en meer aan. Het combineert innovatief grote data voortraining met rijke kennis uit meerdere bronnen, door algoritmische technologie continu te verfijnen en voortdurend nieuwe kennis op te nemen uit enorme tekstdata op het gebied van vocabulaire, structuur, grammatica en semantiek, waardoor de modelprestaties voortdurend evolueren. Het biedt gebruikers gemakkelijkere informatie en diensten en een meer intelligente ervaring."
},
+8 -2
View File
@@ -70,10 +70,12 @@
"input": {
"addAi": "Dodaj wiadomość AI",
"addUser": "Dodaj wiadomość użytkownika",
"disclaimer": "AI również może popełniać błędy, proszę sprawdzić ważne informacje",
"errorMsg": "Wysyłanie wiadomości nie powiodło się, sprawdź połączenie sieciowe i spróbuj ponownie: {{errorMsg}}",
"more": "więcej",
"send": "Wyślij",
"sendWithCmdEnter": "Wyślij za pomocą klawisza {{meta}} + Enter",
"sendWithEnter": "Wyślij za pomocą klawisza Enter",
"sendWithCmdEnter": "Naciśnij <key/>, aby wysłać",
"sendWithEnter": "Naciśnij <key/>, aby wysłać",
"stop": "Zatrzymaj",
"warp": "Złamanie wiersza"
},
@@ -232,6 +234,10 @@
"threadMessageCount": "{{messageCount}} wiadomości",
"title": "Podwątek"
},
"toggleWideScreen": {
"off": "Wyłącz tryb szerokiego ekranu",
"on": "Włącz tryb szerokiego ekranu"
},
"tokenDetails": {
"chats": "Rozmowy",
"historySummary": "Podsumowanie historii",
+47
View File
@@ -0,0 +1,47 @@
{
"actions": {
"expand": {
"off": "Zwiń",
"on": "Rozwiń"
},
"typobar": {
"off": "Ukryj pasek narzędzi formatowania",
"on": "Pokaż pasek narzędzi formatowania"
}
},
"file": {
"error": "Błąd: {{message}}",
"uploading": "Przesyłanie pliku..."
},
"image": {
"broken": "Obraz uszkodzony"
},
"link": {
"edit": "Edytuj link",
"open": "Otwórz link",
"placeholder": "Wpisz adres URL linku",
"unlink": "Usuń link"
},
"table": {
"delete": "Usuń tabelę",
"deleteColumn": "Usuń kolumnę",
"deleteRow": "Usuń wiersz",
"insertColumnLeft": "Wstaw {{count}} kolumn po lewej",
"insertColumnRight": "Wstaw {{count}} kolumn po prawej",
"insertRowAbove": "Wstaw {{count}} wierszy powyżej",
"insertRowBelow": "Wstaw {{count}} wierszy poniżej"
},
"typobar": {
"blockquote": "Cytat",
"bold": "Pogrubienie",
"bulletList": "Lista punktowana",
"code": "Kod w linii",
"codeblock": "Blok kodu",
"italic": "Kursywa",
"link": "Link",
"numberList": "Lista numerowana",
"strikethrough": "Przekreślenie",
"table": "Wstaw tabelę",
"underline": "Podkreślenie"
}
}
+8 -2
View File
@@ -70,10 +70,12 @@
"input": {
"addAi": "Adicionar uma mensagem de IA",
"addUser": "Adicionar uma mensagem de usuário",
"disclaimer": "A IA também pode cometer erros, por favor verifique as informações importantes",
"errorMsg": "Falha ao enviar a mensagem, verifique a rede e tente novamente: {{errorMsg}}",
"more": "mais",
"send": "Enviar",
"sendWithCmdEnter": "Pressione {{meta}} + Enter para enviar",
"sendWithEnter": "Pressione Enter para enviar",
"sendWithCmdEnter": "Pressione <key/> para enviar",
"sendWithEnter": "Pressione <key/> para enviar",
"stop": "Parar",
"warp": "Quebrar linha"
},
@@ -232,6 +234,10 @@
"threadMessageCount": "{{messageCount}} mensagens",
"title": "Subtópico"
},
"toggleWideScreen": {
"off": "Desativar modo de tela ampla",
"on": "Ativar modo de tela ampla"
},
"tokenDetails": {
"chats": "Mensagens de bate-papo",
"historySummary": "Resumo Histórico",
+47
View File
@@ -0,0 +1,47 @@
{
"actions": {
"expand": {
"off": "Recolher",
"on": "Expandir"
},
"typobar": {
"off": "Ocultar barra de formatação",
"on": "Mostrar barra de formatação"
}
},
"file": {
"error": "Erro: {{message}}",
"uploading": "Enviando arquivo..."
},
"image": {
"broken": "Imagem corrompida"
},
"link": {
"edit": "Editar link",
"open": "Abrir link",
"placeholder": "Digite a URL do link",
"unlink": "Remover link"
},
"table": {
"delete": "Excluir tabela",
"deleteColumn": "Excluir coluna",
"deleteRow": "Excluir linha",
"insertColumnLeft": "Inserir {{count}} coluna(s) à esquerda",
"insertColumnRight": "Inserir {{count}} coluna(s) à direita",
"insertRowAbove": "Inserir {{count}} linha(s) acima",
"insertRowBelow": "Inserir {{count}} linha(s) abaixo"
},
"typobar": {
"blockquote": "Citação",
"bold": "Negrito",
"bulletList": "Lista não ordenada",
"code": "Código inline",
"codeblock": "Bloco de código",
"italic": "Itálico",
"link": "Link",
"numberList": "Lista numerada",
"strikethrough": "Tachado",
"table": "Inserir tabela",
"underline": "Sublinhado"
}
}
+8 -2
View File
@@ -70,10 +70,12 @@
"input": {
"addAi": "Добавить сообщение AI",
"addUser": "Добавить сообщение пользователя",
"disclaimer": "ИИ также может ошибаться, пожалуйста, проверяйте важную информацию",
"errorMsg": "Не удалось отправить сообщение, проверьте подключение к сети и попробуйте снова: {{errorMsg}}",
"more": "больше",
"send": "Отправить",
"sendWithCmdEnter": "Отправить с помощью {{meta}} + Enter",
"sendWithEnter": "Отправить с помощью Enter",
"sendWithCmdEnter": "Нажмите <key/> для отправки",
"sendWithEnter": "Нажмите <key/> для отправки",
"stop": "Остановить",
"warp": "Перенос строки"
},
@@ -232,6 +234,10 @@
"threadMessageCount": "{{messageCount}} сообщений",
"title": "Подтема"
},
"toggleWideScreen": {
"off": "Отключить режим широкого экрана",
"on": "Включить режим широкого экрана"
},
"tokenDetails": {
"chats": "Чаты",
"historySummary": "Историческое резюме",
+47
View File
@@ -0,0 +1,47 @@
{
"actions": {
"expand": {
"off": "Свернуть",
"on": "Развернуть"
},
"typobar": {
"off": "Скрыть панель форматирования",
"on": "Показать панель форматирования"
}
},
"file": {
"error": "Ошибка: {{message}}",
"uploading": "Загрузка файла..."
},
"image": {
"broken": "Изображение повреждено"
},
"link": {
"edit": "Редактировать ссылку",
"open": "Открыть ссылку",
"placeholder": "Введите URL ссылки",
"unlink": "Удалить ссылку"
},
"table": {
"delete": "Удалить таблицу",
"deleteColumn": "Удалить столбец",
"deleteRow": "Удалить строку",
"insertColumnLeft": "{count, plural, one {Вставить # столбец слева} few {Вставить # столбца слева} many {Вставить # столбцов слева} other {Вставить # столбца слева}}",
"insertColumnRight": "{count, plural, one {Вставить # столбец справа} few {Вставить # столбца справа} many {Вставить # столбцов справа} other {Вставить # столбца справа}}",
"insertRowAbove": "{count, plural, one {Вставить # строку сверху} few {Вставить # строки сверху} many {Вставить # строк сверху} other {Вставить # строки сверху}}",
"insertRowBelow": "{count, plural, one {Вставить # строку снизу} few {Вставить # строки снизу} many {Вставить # строк снизу} other {Вставить # строки снизу}}"
},
"typobar": {
"blockquote": "Цитата",
"bold": "Жирный",
"bulletList": "Маркированный список",
"code": "Встроенный код",
"codeblock": "Блок кода",
"italic": "Курсив",
"link": "Ссылка",
"numberList": "Нумерованный список",
"strikethrough": "Зачёркнутый",
"table": "Вставить таблицу",
"underline": "Подчёркнутый"
}
}
+8 -2
View File
@@ -70,10 +70,12 @@
"input": {
"addAi": "Bir AI mesajı ekleyin",
"addUser": "Bir kullanıcı mesajı ekleyin",
"disclaimer": "Yapay zeka da hata yapabilir, lütfen önemli bilgileri kontrol edin",
"errorMsg": "Mesaj gönderilemedi, lütfen ağı kontrol edip tekrar deneyin: {{errorMsg}}",
"more": "Daha fazla",
"send": "Gönder",
"sendWithCmdEnter": "{{meta}} + Enter tuşuna basarak gönder",
"sendWithEnter": "Enter tuşuna basarak gönder",
"sendWithCmdEnter": "<key/> tuşuna basarak gönder",
"sendWithEnter": "<key/> tuşuna basarak gönder",
"stop": "Dur",
"warp": "Satır atla"
},
@@ -232,6 +234,10 @@
"threadMessageCount": "{{messageCount}} mesaj",
"title": "Alt konu"
},
"toggleWideScreen": {
"off": "Geniş ekran modunu kapat",
"on": "Geniş ekran modunu aç"
},
"tokenDetails": {
"chats": "Sohbetler",
"historySummary": "Tarih Özeti",
+47
View File
@@ -0,0 +1,47 @@
{
"actions": {
"expand": {
"off": "Daralt",
"on": "Genişlet"
},
"typobar": {
"off": "Biçim araç çubuğunu gizle",
"on": "Biçim araç çubuğunu göster"
}
},
"file": {
"error": "Hata: {{message}}",
"uploading": "Dosya yükleniyor..."
},
"image": {
"broken": "Resim bozuk"
},
"link": {
"edit": "Bağlantıyı düzenle",
"open": "Bağlantıyı aç",
"placeholder": "Bağlantı URL'si girin",
"unlink": "Bağlantıyı kaldır"
},
"table": {
"delete": "Tabloyu sil",
"deleteColumn": "Sütunu sil",
"deleteRow": "Satırı sil",
"insertColumnLeft": "Sol tarafa {{count}} sütun ekle",
"insertColumnRight": "Sağ tarafa {{count}} sütun ekle",
"insertRowAbove": "Üst tarafa {{count}} satır ekle",
"insertRowBelow": "Alt tarafa {{count}} satır ekle"
},
"typobar": {
"blockquote": "Alıntı",
"bold": "Kalın",
"bulletList": "Sırasız liste",
"code": "Satır içi kod",
"codeblock": "Kod bloğu",
"italic": "İtalik",
"link": "Bağlantı",
"numberList": "Numaralı liste",
"strikethrough": "Üstü çizili",
"table": "Tablo ekle",
"underline": "Altı çizili"
}
}
+8 -2
View File
@@ -70,10 +70,12 @@
"input": {
"addAi": "Thêm một tin nhắn AI",
"addUser": "Thêm một tin nhắn người dùng",
"disclaimer": "AI cũng có thể mắc lỗi, vui lòng kiểm tra kỹ thông tin quan trọng",
"errorMsg": "Gửi tin nhắn thất bại, vui lòng kiểm tra mạng và thử lại: {{errorMsg}}",
"more": "Thêm",
"send": "Gửi",
"sendWithCmdEnter": "Nhấn {{meta}} + Enter để gửi",
"sendWithEnter": "Nhấn Enter để gửi",
"sendWithCmdEnter": "Nhấn <key/> để gửi",
"sendWithEnter": "Nhấn <key/> để gửi",
"stop": "Dừng",
"warp": "Xuống dòng"
},
@@ -232,6 +234,10 @@
"threadMessageCount": "{{messageCount}} tin nhắn",
"title": "Chủ đề con"
},
"toggleWideScreen": {
"off": "Tắt chế độ màn hình rộng",
"on": "Bật chế độ màn hình rộng"
},
"tokenDetails": {
"chats": "Tin nhắn trò chuyện",
"historySummary": "Tóm tắt lịch sử",
+47
View File
@@ -0,0 +1,47 @@
{
"actions": {
"expand": {
"off": "Thu gọn",
"on": "Mở rộng"
},
"typobar": {
"off": "Ẩn thanh công cụ định dạng",
"on": "Hiển thị thanh công cụ định dạng"
}
},
"file": {
"error": "Lỗi: {{message}}",
"uploading": "Đang tải tệp lên..."
},
"image": {
"broken": "Hình ảnh bị hỏng"
},
"link": {
"edit": "Chỉnh sửa liên kết",
"open": "Mở liên kết",
"placeholder": "Nhập URL liên kết",
"unlink": "Gỡ liên kết"
},
"table": {
"delete": "Xóa bảng",
"deleteColumn": "Xóa cột",
"deleteRow": "Xóa hàng",
"insertColumnLeft": "Chèn {{count}} cột vào bên trái",
"insertColumnRight": "Chèn {{count}} cột vào bên phải",
"insertRowAbove": "Chèn {{count}} hàng vào phía trên",
"insertRowBelow": "Chèn {{count}} hàng vào phía dưới"
},
"typobar": {
"blockquote": "Trích dẫn",
"bold": "Đậm",
"bulletList": "Danh sách gạch đầu dòng",
"code": "Mã nội tuyến",
"codeblock": "Khối mã",
"italic": "Nghiêng",
"link": "Liên kết",
"numberList": "Danh sách có thứ tự",
"strikethrough": "Gạch ngang",
"table": "Chèn bảng",
"underline": "Gạch chân"
}
}
+8 -2
View File
@@ -70,10 +70,12 @@
"input": {
"addAi": "添加一条 AI 消息",
"addUser": "添加一条用户消息",
"disclaimer": "AI 也可能会犯错,请检查重要信息",
"errorMsg": "消息发送失败,请检查网络后重试: {{errorMsg}}",
"more": "更多",
"send": "发送",
"sendWithCmdEnter": "按 {{meta}} + Enter 键发送",
"sendWithEnter": "按 Enter 键发送",
"sendWithCmdEnter": "按 <key/> 键发送",
"sendWithEnter": "按 <key/> 键发送",
"stop": "停止",
"warp": "换行"
},
@@ -232,6 +234,10 @@
"threadMessageCount": "{{messageCount}} 条消息",
"title": "子话题"
},
"toggleWideScreen": {
"off": "关闭宽屏模式",
"on": "开启宽屏模式"
},
"tokenDetails": {
"chats": "会话消息",
"historySummary": "历史总结",
+47
View File
@@ -0,0 +1,47 @@
{
"actions": {
"expand": {
"off": "收起",
"on": "展开"
},
"typobar": {
"off": "隐藏格式工具栏",
"on": "显示格式工具栏"
}
},
"file": {
"error": "错误:{{message}}",
"uploading": "正在上传文件..."
},
"image": {
"broken": "图片损坏"
},
"link": {
"edit": "编辑链接",
"open": "打开链接",
"placeholder": "输入链接 URL",
"unlink": "取消链接"
},
"table": {
"delete": "删除表格",
"deleteColumn": "删除列",
"deleteRow": "删除行",
"insertColumnLeft": "在左侧插入 {{count}} 列",
"insertColumnRight": "在右侧插入 {{count}} 列",
"insertRowAbove": "在上方插入 {{count}} 行",
"insertRowBelow": "在下方插入 {{count}} 行"
},
"typobar": {
"blockquote": "引用",
"bold": "加粗",
"bulletList": "无序列表",
"code": "行内代码",
"codeblock": "代码块",
"italic": "斜体",
"link": "链接",
"numberList": "有序列表",
"strikethrough": "删除线",
"table": "插入表格",
"underline": "下划线"
}
}
+1 -1
View File
@@ -161,7 +161,7 @@
"title": "API 密钥"
},
"apiUrl": {
"desc": "New API 服务的 API 地址,大部分时候要带 /v1",
"desc": "New API 服务的 API 地址,大部分时候要带 /v1",
"title": "API 地址"
},
"enabled": {
+8 -2
View File
@@ -70,10 +70,12 @@
"input": {
"addAi": "新增一條 AI 訊息",
"addUser": "新增一條使用者訊息",
"disclaimer": "AI 也可能會犯錯,請檢查重要資訊",
"errorMsg": "訊息發送失敗,請檢查網路後重試:{{errorMsg}}",
"more": "更多",
"send": "發送",
"sendWithCmdEnter": "按 {{meta}} + Enter 鍵發送",
"sendWithEnter": "按 Enter 鍵發送",
"sendWithCmdEnter": "按 <key/> 鍵發送",
"sendWithEnter": "按 <key/> 鍵發送",
"stop": "停止",
"warp": "換行"
},
@@ -232,6 +234,10 @@
"threadMessageCount": "{{messageCount}} 條消息",
"title": "子話題"
},
"toggleWideScreen": {
"off": "關閉寬螢幕模式",
"on": "開啟寬螢幕模式"
},
"tokenDetails": {
"chats": "聊天訊息",
"historySummary": "歷史總結",
+47
View File
@@ -0,0 +1,47 @@
{
"actions": {
"expand": {
"off": "收合",
"on": "展開"
},
"typobar": {
"off": "隱藏格式工具列",
"on": "顯示格式工具列"
}
},
"file": {
"error": "錯誤:{{message}}",
"uploading": "正在上傳檔案..."
},
"image": {
"broken": "圖片損毀"
},
"link": {
"edit": "編輯連結",
"open": "開啟連結",
"placeholder": "輸入連結 URL",
"unlink": "取消連結"
},
"table": {
"delete": "刪除表格",
"deleteColumn": "刪除列",
"deleteRow": "刪除行",
"insertColumnLeft": "在左側插入 {{count}} 列",
"insertColumnRight": "在右側插入 {{count}} 列",
"insertRowAbove": "在上方插入 {{count}} 行",
"insertRowBelow": "在下方插入 {{count}} 行"
},
"typobar": {
"blockquote": "引用",
"bold": "粗體",
"bulletList": "無序清單",
"code": "行內程式碼",
"codeblock": "程式碼區塊",
"italic": "斜體",
"link": "連結",
"numberList": "有序清單",
"strikethrough": "刪除線",
"table": "插入表格",
"underline": "底線"
}
}
+3 -1
View File
@@ -1505,7 +1505,9 @@
"gpt-4.1-nano": {
"description": "GPT-4.1 mini 提供了智能、速度和成本之間的平衡,使其成為許多用例中具吸引力的模型。"
},
"gpt-4.5-preview": "GPT-4.5-preview 是最新的通用模型,具備深厚的世界知識並能更好地理解使用者意圖,擅長創意任務與代理規劃。此模型的知識截至 2023 年 10 月。",
"gpt-4.5-preview": {
"description": "GPT-4.5-preview 是最新的通用模型,擁有深厚的世界知識和對使用者意圖的更佳理解,擅長創意任務與代理規劃。該模型的知識截止至2023年10月。"
},
"gpt-4o": {
"description": "ChatGPT-4o是一款動態模型,實時更新以保持當前最新版本。它結合了強大的語言理解與生成能力,適合於大規模應用場景,包括客戶服務、教育和技術支持。"
},
+4
View File
@@ -22,6 +22,9 @@ const standaloneConfig: NextConfig = {
const nextConfig: NextConfig = {
...(isStandaloneMode ? standaloneConfig : {}),
compiler: {
emotion: true,
},
compress: isProd,
experimental: {
optimizePackageImports: [
@@ -30,6 +33,7 @@ const nextConfig: NextConfig = {
'@emoji-mart/data',
'@icons-pack/react-simple-icons',
'@lobehub/ui',
'@lobehub/icons',
'gpt-tokenizer',
],
// oidc provider depend on constructor.name
+4 -2
View File
@@ -1,6 +1,6 @@
{
"name": "@lobehub/chat",
"version": "1.123.2",
"version": "1.124.4",
"description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
"keywords": [
"framework",
@@ -134,6 +134,7 @@
"@codesandbox/sandpack-react": "^2.20.0",
"@cyntler/react-doc-viewer": "^1.17.0",
"@electric-sql/pglite": "0.2.17",
"@emotion/react": "^11.14.0",
"@fal-ai/client": "^1.6.1",
"@formkit/auto-animate": "^0.8.2",
"@google/genai": "^1.13.0",
@@ -154,10 +155,11 @@
"@lobehub/charts": "^2.0.0",
"@lobehub/chat-plugin-sdk": "^1.32.4",
"@lobehub/chat-plugins-gateway": "^1.9.0",
"@lobehub/editor": "^1.4.4",
"@lobehub/icons": "^2.31.0",
"@lobehub/market-sdk": "^0.22.7",
"@lobehub/tts": "^2.0.1",
"@lobehub/ui": "^2.8.3",
"@lobehub/ui": "^2.11.9",
"@modelcontextprotocol/sdk": "^1.17.1",
"@neondatabase/serverless": "^1.0.1",
"@next/third-parties": "^15.4.6",
+3 -1
View File
@@ -4,6 +4,8 @@
"private": true,
"main": "./src/index.ts",
"dependencies": {
"model-bank": "workspace:*"
"model-bank": "workspace:*",
"query-string": "^9.2.2",
"url-join": "^5.0.0"
}
}
+1 -1
View File
@@ -1,3 +1,3 @@
import { isDesktop } from '@/const/version';
import { isDesktop } from './version';
export const BUSINESS_LINE = isDesktop ? 'lobe-chat-desktop' : 'lobe-chat';
+3 -2
View File
@@ -1,5 +1,6 @@
import { DESKTOP_HOTKEYS_REGISTRATION } from '@/const/hotkeys';
import { DesktopHotkeyConfig } from '@/types/hotkey';
import { DesktopHotkeyConfig } from '@lobechat/types';
import { DESKTOP_HOTKEYS_REGISTRATION } from './hotkeys';
export const DESKTOP_USER_ID = 'DEFAULT_DESKTOP_USER';
+3 -2
View File
@@ -1,10 +1,11 @@
import { DEFAULT_AGENT_CONFIG } from '@/const/settings';
import {
DiscoverAssistantDetail,
DiscoverModelDetail,
DiscoverPluginDetail,
DiscoverProviderDetail,
} from '@/types/discover';
} from '@lobechat/types';
import { DEFAULT_AGENT_CONFIG } from './settings';
const DEFAULT_CREATED_AT = new Date().toISOString();
+2 -2
View File
@@ -1,6 +1,6 @@
import urlJoin from 'url-join';
import { BRANDING_EMAIL } from '@/const/branding';
import { BRANDING_EMAIL } from './branding';
import {
BLOG,
DOCKER_IMAGE,
@@ -11,7 +11,7 @@ import {
SELF_HOSTING_DOCUMENTS,
USAGE_DOCUMENTS,
WIKI,
} from '@/const/url';
} from './url';
export const INBOX_GUIDE_SYSTEMROLE = `# Role: LobeChat Support Assistant
+1 -1
View File
@@ -6,7 +6,7 @@ import {
HotkeyItem,
HotkeyScopeEnum,
KeyEnum,
} from '@/types/hotkey';
} from '@lobechat/types';
const combineKeys = (keys: string[]) => keys.join('+');
+2
View File
@@ -1,9 +1,11 @@
export * from './auth';
export * from './branding';
export * from './currency';
export * from './desktop';
export * from './layoutTokens';
export * from './message';
export * from './session';
export * from './settings';
export * from './trace';
export * from './user';
export * from './version';
+1
View File
@@ -7,6 +7,7 @@ export const CHAT_TEXTAREA_MAX_HEIGHT = 800;
export const CHAT_TEXTAREA_HEIGHT = 160;
export const CHAT_TEXTAREA_HEIGHT_MOBILE = 108;
export const CHAT_SIDEBAR_WIDTH = 280;
export const CONVERSATION_MIN_WIDTH = 850;
export const CHAT_PORTAL_WIDTH = 400;
export const CHAT_PORTAL_MAX_WIDTH = 1280;
+1 -1
View File
@@ -1,4 +1,4 @@
import { UserGeneralConfig } from '@/types/user/settings';
import { UserGeneralConfig } from '@lobechat/types';
export const DEFAULT_COMMON_SETTINGS: UserGeneralConfig = {
animationMode: 'agile',
@@ -1,7 +1,6 @@
import { ModelProviderCard } from '@lobechat/types';
import { describe, expect, it, vi } from 'vitest';
import { ModelProviderCard } from '@/types/index';
import { genUserLLMConfig } from './genUserLLMConfig';
// Mock ModelProvider enum
@@ -1,8 +1,7 @@
import { ModelProvider } from '@lobechat/model-runtime';
import { UserModelProviderConfig } from '@lobechat/types';
import { ModelProviderCard, UserModelProviderConfig } from '@lobechat/types';
import * as ProviderCards from '@/config/modelProviders';
import { ModelProviderCard } from '@/types/llm';
export const genUserLLMConfig = (specificConfig: Record<any, any>): UserModelProviderConfig => {
return Object.keys(ModelProvider).reduce((config, providerKey) => {
+3 -2
View File
@@ -1,5 +1,6 @@
import { HOTKEYS_REGISTRATION } from '@/const/hotkeys';
import { UserHotkeyConfig } from '@/types/user/settings';
import { UserHotkeyConfig } from '@lobechat/types';
import { HOTKEYS_REGISTRATION } from '../hotkeys';
export const DEFAULT_HOTKEY_CONFIG: UserHotkeyConfig = HOTKEYS_REGISTRATION.reduce(
(acc: UserHotkeyConfig, item) => {
+1 -3
View File
@@ -1,10 +1,9 @@
import { UserSettings } from '@/types/user/settings';
import { UserSettings } from '@lobechat/types';
import { DEFAULT_AGENT } from './agent';
import { DEFAULT_COMMON_SETTINGS } from './common';
import { DEFAULT_HOTKEY_CONFIG } from './hotkey';
import { DEFAULT_LLM_CONFIG } from './llm';
import { DEFAULT_SYNC_CONFIG } from './sync';
import { DEFAULT_SYSTEM_AGENT_CONFIG } from './systemAgent';
import { DEFAULT_TOOL_CONFIG } from './tool';
import { DEFAULT_TTS_CONFIG } from './tts';
@@ -22,7 +21,6 @@ export const DEFAULT_SETTINGS: UserSettings = {
hotkey: DEFAULT_HOTKEY_CONFIG,
keyVaults: {},
languageModel: DEFAULT_LLM_CONFIG,
sync: DEFAULT_SYNC_CONFIG,
systemAgent: DEFAULT_SYSTEM_AGENT_CONFIG,
tool: DEFAULT_TOOL_CONFIG,
tts: DEFAULT_TTS_CONFIG,
+1 -1
View File
@@ -1,4 +1,4 @@
import { FilesConfig, FilesConfigItem } from '@/types/user/settings/filesConfig';
import { FilesConfig, FilesConfigItem } from '@lobechat/types';
import {
DEFAULT_EMBEDDING_MODEL,
+2 -4
View File
@@ -1,5 +1,3 @@
import { ModelProvider } from '@lobechat/model-runtime';
import { genUserLLMConfig } from './genUserLLMConfig';
export const DEFAULT_LLM_CONFIG = genUserLLMConfig({
@@ -18,10 +16,10 @@ export const DEFAULT_LLM_CONFIG = genUserLLMConfig({
export const DEFAULT_MODEL = 'gpt-5-mini';
export const DEFAULT_EMBEDDING_MODEL = 'text-embedding-3-small';
export const DEFAULT_EMBEDDING_PROVIDER = ModelProvider.OpenAI;
export const DEFAULT_EMBEDDING_PROVIDER = 'openai';
export const DEFAULT_RERANK_MODEL = 'rerank-english-v3.0';
export const DEFAULT_RERANK_PROVIDER = 'cohere';
export const DEFAULT_RERANK_QUERY_MODE = 'full_text';
export const DEFAULT_PROVIDER = ModelProvider.OpenAI;
export const DEFAULT_PROVIDER = 'openai';
-5
View File
@@ -1,5 +0,0 @@
import { UserSyncSettings } from '@/types/user/settings';
export const DEFAULT_SYNC_CONFIG: UserSyncSettings = {
webrtc: { enabled: false },
};
+1 -5
View File
@@ -1,8 +1,4 @@
import {
QueryRewriteSystemAgent,
SystemAgentItem,
UserSystemAgentConfig,
} from '@/types/user/settings';
import { QueryRewriteSystemAgent, SystemAgentItem, UserSystemAgentConfig } from '@lobechat/types';
import { DEFAULT_MODEL, DEFAULT_PROVIDER } from './llm';
+1 -1
View File
@@ -1,4 +1,4 @@
import { UserTTSConfig } from '@/types/user/settings';
import { UserTTSConfig } from '@lobechat/types';
export const DEFAULT_TTS_CONFIG: UserTTSConfig = {
openAI: {
+1 -1
View File
@@ -1,4 +1,4 @@
import { TraceNameMap } from '@/types/trace';
import { TraceNameMap } from '@lobechat/types';
export const LOBE_CHAT_TRACE_HEADER = 'X-lobe-trace';
export const LOBE_CHAT_TRACE_ID = 'X-lobe-chat-trace-id';
+2 -2
View File
@@ -1,10 +1,10 @@
import qs from 'query-string';
import urlJoin from 'url-join';
import { isDev } from '@/utils/env';
import { INBOX_SESSION_ID } from './session';
const isDev = process.env.NODE_ENV === 'development';
export const UTM_SOURCE = 'chat_preview';
export const OFFICIAL_URL = 'https://lobechat.com';
+1 -2
View File
@@ -1,5 +1,4 @@
import { TopicDisplayMode } from '@/types/topic';
import { UserPreference } from '@/types/user';
import { TopicDisplayMode, UserPreference } from '@lobechat/types';
export const DEFAULT_PREFERENCE: UserPreference = {
guide: {
+18 -12
View File
@@ -58,19 +58,25 @@ beforeEach(() => {
describe('DatabaseManager', () => {
describe('Callback Handling', () => {
it('should properly track loading states', async () => {
await manager.initialize(callbacks);
it(
'should properly track loading states',
async () => {
await manager.initialize(callbacks);
// 验证状态转换顺序
expect(stateChanges).toEqual([
DatabaseLoadingState.Initializing,
DatabaseLoadingState.LoadingDependencies,
DatabaseLoadingState.LoadingWasm,
DatabaseLoadingState.Migrating,
DatabaseLoadingState.Finished,
DatabaseLoadingState.Ready,
]);
});
// 验证状态转换顺序
expect(stateChanges).toEqual([
DatabaseLoadingState.Initializing,
DatabaseLoadingState.LoadingDependencies,
DatabaseLoadingState.LoadingWasm,
DatabaseLoadingState.Migrating,
DatabaseLoadingState.Finished,
DatabaseLoadingState.Ready,
]);
},
{
timeout: 15000,
},
);
it('should report dependencies loading progress', async () => {
await manager.initialize(callbacks);
@@ -2,7 +2,7 @@ import fs from 'node:fs';
import net from 'node:net';
import os from 'node:os';
import path from 'node:path';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { afterAll, afterEach, beforeAll, beforeEach, describe, expect, it, vi } from 'vitest';
import { ElectronIpcClient } from './ipcClient';
@@ -14,6 +14,16 @@ vi.mock('node:path');
const appId = 'lobehub';
describe('ElectronIpcClient', () => {
// Swallow unhandledRejection during timeout tests to avoid Vitest global capture
const onUnhandled = (/* reason, promise */) => {};
beforeAll(() => {
process.on('unhandledRejection', onUnhandled);
});
afterAll(() => {
process.off('unhandledRejection', onUnhandled);
});
// Mock data
const mockTempDir = '/mock/temp/dir';
const mockSocketInfoPath = '/mock/temp/dir/lobehub-electron-ipc-info.json';
@@ -41,6 +51,10 @@ describe('ElectronIpcClient', () => {
// Mock console methods
vi.spyOn(console, 'error').mockImplementation(() => {});
vi.spyOn(console, 'log').mockImplementation(() => {});
// Mock timers
vi.spyOn(global, 'setTimeout');
vi.spyOn(global, 'clearTimeout');
});
afterEach(() => {
@@ -155,6 +169,10 @@ describe('ElectronIpcClient', () => {
// Start request
const requestPromise = client.sendRequest('getDatabasePath');
// Prevent unhandled rejection warnings before assertion
void requestPromise.catch(() => {});
// Prevent unhandled rejection warnings before assertion
void requestPromise.catch(() => {});
// Simulate connection established
if (connectionCallback) connectionCallback();
@@ -162,6 +180,729 @@ describe('ElectronIpcClient', () => {
// Now await the promise
await expect(requestPromise).rejects.toThrow('Write error');
});
it('should handle successful request-response cycle', async () => {
// Setup connection callback
let connectionCallback: Function | undefined;
let dataCallback: Function | undefined;
vi.mocked(net.createConnection).mockImplementation((path, callback) => {
connectionCallback = callback as Function;
return mockSocket as unknown as net.Socket;
});
mockSocket.on.mockImplementation((event, callback) => {
if (event === 'data') {
dataCallback = callback as Function;
}
return mockSocket;
});
// Mock write to immediately call success callback
mockSocket.write.mockImplementation((data, callback) => {
if (callback) {
// Call success callback synchronously
setTimeout(() => callback(), 0);
}
return true;
});
// Start request
const requestPromise = client.sendRequest('getDatabasePath', { test: 'param' });
// Immediately resolve connection
if (connectionCallback) connectionCallback();
// Process all pending promises
await new Promise((resolve) => process.nextTick(resolve));
// Verify request was written
expect(mockSocket.write).toHaveBeenCalled();
const writeCall = mockSocket.write.mock.calls[0];
const request = JSON.parse(writeCall[0] as string);
expect(request).toMatchObject({
method: 'getDatabasePath',
params: { test: 'param' },
});
// Simulate server response immediately
const response = {
id: request.id,
result: '/path/to/database',
};
if (dataCallback) {
dataCallback(Buffer.from(JSON.stringify(response) + '\n'));
}
// Verify promise resolves with result
const result = await requestPromise;
expect(result).toBe('/path/to/database');
});
it('should handle server error responses', async () => {
// Setup connection and data callbacks
let connectionCallback: Function | undefined;
let dataCallback: Function | undefined;
vi.mocked(net.createConnection).mockImplementation((path, callback) => {
connectionCallback = callback as Function;
return mockSocket as unknown as net.Socket;
});
mockSocket.on.mockImplementation((event, callback) => {
if (event === 'data') {
dataCallback = callback as Function;
}
return mockSocket;
});
// Mock write to immediately call success callback
mockSocket.write.mockImplementation((data, callback) => {
if (callback) {
setTimeout(() => callback(), 0);
}
return true;
});
// Start request
const requestPromise = client.sendRequest('getDatabasePath');
// Prevent unhandled rejection warnings before assertion
void requestPromise.catch(() => {});
// Prevent unhandled rejection warnings before assertion
void requestPromise.catch(() => {});
// Immediately resolve connection
if (connectionCallback) connectionCallback();
// Process all pending promises
await new Promise((resolve) => process.nextTick(resolve));
const writeCall = mockSocket.write.mock.calls[0];
const request = JSON.parse(writeCall[0] as string);
// Simulate server error response
const errorResponse = {
id: request.id,
error: 'Database not found',
};
if (dataCallback) {
dataCallback(Buffer.from(JSON.stringify(errorResponse) + '\n'));
}
// Verify promise rejects with error
await expect(requestPromise).rejects.toThrow('Database not found');
});
it('should handle multiple messages in single data chunk', async () => {
let connectionCallback: Function | undefined;
let dataCallback: Function | undefined;
vi.mocked(net.createConnection).mockImplementation((path, callback) => {
connectionCallback = callback as Function;
return mockSocket as unknown as net.Socket;
});
mockSocket.on.mockImplementation((event, callback) => {
if (event === 'data') {
dataCallback = callback as Function;
}
return mockSocket;
});
// Mock write to immediately call success callback
mockSocket.write.mockImplementation((data, callback) => {
if (callback) {
setTimeout(() => callback(), 0);
}
return true;
});
// Start multiple requests
const request1Promise = client.sendRequest('getDatabasePath');
// Immediately resolve connection
if (connectionCallback) connectionCallback();
// Process all pending promises
await new Promise((resolve) => process.nextTick(resolve));
const request2Promise = client.sendRequest('getUserDataPath');
// Process second request
await new Promise((resolve) => process.nextTick(resolve));
// Get request IDs
const request1 = JSON.parse(mockSocket.write.mock.calls[0][0] as string);
const request2 = JSON.parse(mockSocket.write.mock.calls[1][0] as string);
// Simulate multiple responses in single data chunk
const response1 = { id: request1.id, result: '/db/path' };
const response2 = { id: request2.id, result: '/user/path' };
const combinedData = JSON.stringify(response1) + '\n' + JSON.stringify(response2) + '\n';
if (dataCallback) {
dataCallback(Buffer.from(combinedData));
}
// Both promises should resolve
const result1 = await request1Promise;
const result2 = await request2Promise;
expect(result1).toBe('/db/path');
expect(result2).toBe('/user/path');
});
it('should handle fragmented messages', async () => {
let connectionCallback: Function | undefined;
let dataCallback: Function | undefined;
vi.mocked(net.createConnection).mockImplementation((path, callback) => {
connectionCallback = callback as Function;
return mockSocket as unknown as net.Socket;
});
mockSocket.on.mockImplementation((event, callback) => {
if (event === 'data') {
dataCallback = callback as Function;
}
return mockSocket;
});
// Mock write to immediately call success callback
mockSocket.write.mockImplementation((data, callback) => {
if (callback) {
setTimeout(() => callback(), 0);
}
return true;
});
// Start request
const requestPromise = client.sendRequest('getDatabasePath');
// Prevent unhandled rejection warnings before assertion
void requestPromise.catch(() => {});
// Prevent unhandled rejection warnings before assertion
void requestPromise.catch(() => {});
// Immediately resolve connection
if (connectionCallback) connectionCallback();
// Process all pending promises
await new Promise((resolve) => process.nextTick(resolve));
const request = JSON.parse(mockSocket.write.mock.calls[0][0] as string);
const response = JSON.stringify({ id: request.id, result: '/database/path' }) + '\n';
// Send response in fragments
const fragment1 = response.slice(0, 20);
const fragment2 = response.slice(20);
if (dataCallback) {
// First fragment - should not resolve yet
dataCallback(Buffer.from(fragment1));
// Second fragment - should complete and resolve
dataCallback(Buffer.from(fragment2));
}
const result = await requestPromise;
expect(result).toBe('/database/path');
});
it('should handle request timeout', async () => {
let connectionCallback: Function | undefined;
vi.mocked(net.createConnection).mockImplementation((path, callback) => {
connectionCallback = callback as Function;
return mockSocket as unknown as net.Socket;
});
// Start request
const requestPromise = client.sendRequest('getDatabasePath');
// Allow promise to start
await vi.runAllTimersAsync();
if (connectionCallback) connectionCallback();
// Allow connection to be processed
await vi.runAllTimersAsync();
// Prepare assertion before advancing timers to avoid late-attached handlers
const expectReject = expect(requestPromise).rejects.toThrow(
'Request timed out, method: getDatabasePath',
);
// Fast-forward time by 5000ms to trigger timeout
vi.advanceTimersByTime(5000);
// Run timer callbacks
await vi.runAllTimersAsync();
// Request should timeout
await expectReject;
}, 10000);
it('should handle socket close event', async () => {
let connectionCallback: Function | undefined;
let closeCallback: Function | undefined;
vi.mocked(net.createConnection).mockImplementation((path, callback) => {
connectionCallback = callback as Function;
return mockSocket as unknown as net.Socket;
});
mockSocket.on.mockImplementation((event, callback) => {
if (event === 'close') {
closeCallback = callback as Function;
}
return mockSocket;
});
// Mock write to immediately call success callback
mockSocket.write.mockImplementation((data, callback) => {
if (callback) {
setTimeout(() => callback(), 0);
}
return true;
});
// Start request
const requestPromise = client.sendRequest('getDatabasePath');
// Immediately resolve connection
if (connectionCallback) connectionCallback();
// Process all pending promises
await new Promise((resolve) => process.nextTick(resolve));
// Simulate socket close
if (closeCallback) closeCallback();
// Request should be rejected due to connection loss
await expect(requestPromise).rejects.toThrow('Connection to Electron IPC server lost');
});
it('should handle malformed JSON responses', async () => {
let connectionCallback: Function | undefined;
let dataCallback: Function | undefined;
vi.mocked(net.createConnection).mockImplementation((path, callback) => {
connectionCallback = callback as Function;
return mockSocket as unknown as net.Socket;
});
mockSocket.on.mockImplementation((event, callback) => {
if (event === 'data') {
dataCallback = callback as Function;
}
return mockSocket;
});
// Start request
const requestPromise = client.sendRequest('getDatabasePath');
// Allow request to start
await vi.runAllTimersAsync();
if (connectionCallback) connectionCallback();
// Allow connection to be processed
await vi.runAllTimersAsync();
// Send malformed JSON
if (dataCallback) {
dataCallback(Buffer.from('invalid json\n'));
}
// Allow malformed data to be processed
await vi.runAllTimersAsync();
// Should log error but not crash
expect(console.error).toHaveBeenCalledWith(
expect.stringContaining('Failed to parse response'),
expect.anything(),
'invalid json',
);
// Original request should still timeout normally
const expectReject = expect(requestPromise).rejects.toThrow('Request timed out');
vi.advanceTimersByTime(5000);
await vi.runAllTimersAsync();
await expectReject;
}, 10000);
it('should handle response for unknown request ID', async () => {
let connectionCallback: Function | undefined;
let dataCallback: Function | undefined;
vi.mocked(net.createConnection).mockImplementation((path, callback) => {
connectionCallback = callback as Function;
return mockSocket as unknown as net.Socket;
});
mockSocket.on.mockImplementation((event, callback) => {
if (event === 'data') {
dataCallback = callback as Function;
}
return mockSocket;
});
// Start request
const requestPromise = client.sendRequest('getDatabasePath');
// Allow request to start
await vi.runAllTimersAsync();
if (connectionCallback) connectionCallback();
// Allow connection to be processed
await vi.runAllTimersAsync();
// Send response with unknown ID
const unknownResponse = {
id: 'unknown-id',
result: 'some result',
};
if (dataCallback) {
dataCallback(Buffer.from(JSON.stringify(unknownResponse) + '\n'));
}
// Allow unknown response to be processed
await vi.runAllTimersAsync();
// Should handle gracefully without crashing
vi.advanceTimersByTime(100); // Small delay
await vi.runAllTimersAsync();
// Original request should still timeout
const expectReject = expect(requestPromise).rejects.toThrow('Request timed out');
vi.advanceTimersByTime(5000);
await vi.runAllTimersAsync();
await expectReject;
}, 10000);
it('should skip empty messages', async () => {
let connectionCallback: Function | undefined;
let dataCallback: Function | undefined;
vi.mocked(net.createConnection).mockImplementation((path, callback) => {
connectionCallback = callback as Function;
return mockSocket as unknown as net.Socket;
});
mockSocket.on.mockImplementation((event, callback) => {
if (event === 'data') {
dataCallback = callback as Function;
}
return mockSocket;
});
// Mock write to immediately call success callback
mockSocket.write.mockImplementation((data, callback) => {
if (callback) {
setTimeout(() => callback(), 0);
}
return true;
});
// Start request
const requestPromise = client.sendRequest('getDatabasePath');
// Immediately resolve connection
if (connectionCallback) connectionCallback();
// Process all pending promises
await new Promise((resolve) => process.nextTick(resolve));
const request = JSON.parse(mockSocket.write.mock.calls[0][0] as string);
// Send data with empty lines and valid response
const dataWithEmptyLines =
'\n\n\n' + JSON.stringify({ id: request.id, result: '/path' }) + '\n';
if (dataCallback) {
dataCallback(Buffer.from(dataWithEmptyLines));
}
const result = await requestPromise;
expect(result).toBe('/path');
});
it('should handle connection attempt on already connected client', async () => {
let connectionCallback: Function | undefined;
vi.mocked(net.createConnection).mockImplementation((path, callback) => {
connectionCallback = callback as Function;
return mockSocket as unknown as net.Socket;
});
// First request - establishes connection
const request1Promise = client.sendRequest('getDatabasePath');
// Prevent unhandled rejection warnings before assertion
void request1Promise.catch(() => {});
// Allow first request to start
await vi.runAllTimersAsync();
if (connectionCallback) connectionCallback();
// Allow connection to be processed
await vi.runAllTimersAsync();
// Second request - should reuse existing connection
const request2Promise = client.sendRequest('getUserDataPath');
// Prevent unhandled rejection warnings before assertion
void request2Promise.catch(() => {});
// Allow second request to be processed
await vi.runAllTimersAsync();
// net.createConnection should only be called once
expect(net.createConnection).toHaveBeenCalledTimes(1);
// Clean up promises
vi.advanceTimersByTime(5000);
await vi.runAllTimersAsync();
await expect(request1Promise).rejects.toThrow('Request timed out');
await expect(request2Promise).rejects.toThrow('Request timed out');
}, 10000);
});
describe('reconnection logic', () => {
let client: ElectronIpcClient;
beforeEach(() => {
// Setup a client with a known socket path
vi.mocked(fs.existsSync).mockReturnValue(true);
vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify(mockSocketInfo));
client = new ElectronIpcClient(appId);
});
it('should attempt reconnection after connection loss', async () => {
let connectionCallback: Function | undefined;
let errorCallback: Function | undefined;
vi.mocked(net.createConnection).mockImplementation((path, callback) => {
connectionCallback = callback as Function;
return mockSocket as unknown as net.Socket;
});
mockSocket.on.mockImplementation((event, callback) => {
if (event === 'error') {
errorCallback = callback as Function;
}
return mockSocket;
});
// Mock write to immediately call success callback
mockSocket.write.mockImplementation((data, callback) => {
if (callback) {
setTimeout(() => callback(), 0);
}
return true;
});
// Start request
const requestPromise = client.sendRequest('getDatabasePath');
// Immediately resolve connection
if (connectionCallback) connectionCallback();
// Process all pending promises
await new Promise((resolve) => process.nextTick(resolve));
// Simulate connection error
if (errorCallback) {
errorCallback(new Error('Connection lost'));
}
// Should schedule reconnection
expect(vi.mocked(setTimeout)).toHaveBeenCalled();
await expect(requestPromise).rejects.toThrow('Connection to Electron IPC server lost');
});
it('should give up after max reconnection attempts', async () => {
let connectionCallback: Function | undefined;
let errorCallback: Function | undefined;
// Mock multiple connection attempts that fail
vi.mocked(net.createConnection).mockImplementation((path, callback) => {
connectionCallback = callback as Function;
return mockSocket as unknown as net.Socket;
});
mockSocket.on.mockImplementation((event, callback) => {
if (event === 'error') {
errorCallback = callback as Function;
}
return mockSocket;
});
// Mock write to immediately call success callback
mockSocket.write.mockImplementation((data, callback) => {
if (callback) {
setTimeout(() => callback(), 0);
}
return true;
});
// Start request
const requestPromise = client.sendRequest('getDatabasePath');
// Immediately resolve connection
if (connectionCallback) connectionCallback();
// Process all pending promises
await new Promise((resolve) => process.nextTick(resolve));
if (errorCallback) {
errorCallback(new Error('Connection failed 1'));
}
await expect(requestPromise).rejects.toThrow('Connection to Electron IPC server lost');
expect(vi.mocked(setTimeout)).toHaveBeenCalled();
});
it('should clear existing reconnect timeout when handling new disconnect', async () => {
// This test verifies that clearTimeout is called during client close
let connectionCallback: Function | undefined;
let errorCallback: Function | undefined;
vi.mocked(net.createConnection).mockImplementation((path, callback) => {
connectionCallback = callback as Function;
return mockSocket as unknown as net.Socket;
});
mockSocket.on.mockImplementation((event, callback) => {
if (event === 'error') {
errorCallback = callback as Function;
}
return mockSocket;
});
// Mock write to immediately call success callback
mockSocket.write.mockImplementation((data, callback) => {
if (callback) {
setTimeout(() => callback(), 0);
}
return true;
});
// Start request
const requestPromise = client.sendRequest('getDatabasePath').catch(() => {});
// Immediately resolve connection
if (connectionCallback) connectionCallback();
// Process setup
await new Promise((resolve) => process.nextTick(resolve));
// Simulate error to trigger reconnection setup
if (errorCallback) {
errorCallback(new Error('First error'));
}
// Close client to trigger clearTimeout
client.close();
// clearTimeout should be called
expect(vi.mocked(clearTimeout)).toHaveBeenCalled();
});
});
describe('error scenarios', () => {
let client: ElectronIpcClient;
beforeEach(() => {
vi.mocked(fs.existsSync).mockReturnValue(true);
vi.mocked(fs.readFileSync).mockReturnValue(JSON.stringify(mockSocketInfo));
client = new ElectronIpcClient(appId);
});
// Note: socketPath null test skipped due to complexity with async error handling
it('should handle connection creation failure', async () => {
vi.mocked(net.createConnection).mockImplementation(() => {
throw new Error('Failed to create connection');
});
const requestPromise = client.sendRequest('getDatabasePath');
await expect(requestPromise).rejects.toThrow('Failed to create connection');
expect(console.error).toHaveBeenCalledWith(
'Failed to connect to IPC server: %o',
expect.any(Error),
);
});
it('should handle JSON stringify error in sendRequest', async () => {
let connectionCallback: Function | undefined;
vi.mocked(net.createConnection).mockImplementation((path, callback) => {
connectionCallback = callback as Function;
return mockSocket as unknown as net.Socket;
});
// Create a circular reference object that will cause JSON.stringify to fail
const circularParams: any = { prop: 'value' };
circularParams.circular = circularParams;
// Start request with circular reference
const requestPromise = client.sendRequest('getDatabasePath', circularParams);
if (connectionCallback) connectionCallback();
await expect(requestPromise).rejects.toThrow();
expect(console.error).toHaveBeenCalledWith(
'Error sending request (during setup/write phase): %o',
expect.any(Error),
);
});
it('should handle write failure without pending request', async () => {
let connectionCallback: Function | undefined;
vi.mocked(net.createConnection).mockImplementation((path, callback) => {
connectionCallback = callback as Function;
return mockSocket as unknown as net.Socket;
});
// Mock write to fail after clearing the request from queue
let writeCallback: Function | undefined;
mockSocket.write.mockImplementation((data, callback) => {
writeCallback = callback as Function;
return true;
});
// Start request
const requestPromise = client.sendRequest('getDatabasePath').catch(() => {});
// Allow request to start
await vi.runAllTimersAsync();
if (connectionCallback) connectionCallback();
// Allow connection to be processed
await vi.runAllTimersAsync();
// Manually clear the request queue to simulate timing issue
(client as any).requestQueue.clear();
// Now trigger write callback with error
if (writeCallback) {
writeCallback(new Error('Write failed'));
}
// Allow error to be processed
await vi.runAllTimersAsync();
// Should handle gracefully - note the error is logged but no exception is thrown
// because the request is no longer in the queue
expect(console.error).toHaveBeenCalledWith(
'Failed to write request to socket: %o',
expect.any(Error),
);
}, 10000);
});
describe('close method', () => {
@@ -207,5 +948,46 @@ describe('ElectronIpcClient', () => {
// Verify no errors
expect(mockSocket.end).not.toHaveBeenCalled();
});
it('should clear reconnect timeout when closing', async () => {
let connectionCallback: Function | undefined;
let errorCallback: Function | undefined;
vi.mocked(net.createConnection).mockImplementation((path, callback) => {
connectionCallback = callback as Function;
return mockSocket as unknown as net.Socket;
});
mockSocket.on.mockImplementation((event, callback) => {
if (event === 'error') {
errorCallback = callback as Function;
}
return mockSocket;
});
// Start request and trigger error to set up reconnection
const requestPromise = client.sendRequest('getDatabasePath').catch(() => {});
// Allow promise to start
await vi.runAllTimersAsync();
if (connectionCallback) connectionCallback();
// Allow connection to be processed
await vi.runAllTimersAsync();
if (errorCallback) {
errorCallback(new Error('Test error'));
}
// Allow error to be processed
await vi.runAllTimersAsync();
// Close the client
client.close();
// Should clear timeout
expect(vi.mocked(clearTimeout)).toHaveBeenCalled();
}, 10000);
});
});
@@ -0,0 +1,61 @@
// @vitest-environment node
import * as fsPromises from 'node:fs/promises';
import path from 'node:path';
import { describe, expect, it, vi } from 'vitest';
import { loadFile } from './loadFile';
const fixtures = path.join(__dirname, '../test/fixtures');
const fp = (name: string) => path.join(fixtures, name);
describe('loadFile', () => {
it('loads text-like files via TextLoader and aggregates', async () => {
const file = fp('test.txt');
const doc = await loadFile(file);
expect(doc.fileType).toBe('txt');
expect(doc.filename).toBe('test.txt');
expect(doc.source).toBe(file);
expect(doc.content).toContain('This is line 1.');
expect(doc.pages?.[0].metadata.lineNumberStart).toBe(1);
expect(doc.totalCharCount).toBeGreaterThan(0);
expect(doc.totalLineCount).toBeGreaterThan(0);
});
it('loads pdf files via PdfLoader and aggregates', async () => {
const file = fp('test.pdf');
const doc = await loadFile(file);
expect(doc.fileType).toBe('pdf');
expect(doc.filename).toBe('test.pdf');
expect(doc.source).toBe(file);
expect(doc.content).toContain('123');
expect(doc.pages && doc.pages.length).toBeGreaterThan(0);
});
it('returns error page when fs.stat fails', async () => {
const doc = await loadFile('/not/exists.xyz');
expect(doc.pages).toHaveLength(1);
expect(doc.pages?.[0].metadata.error).toContain('Failed to access file stats:');
expect(doc.metadata.error).toContain('Failed to access file stats:');
});
it('falls back to TextLoader for unsupported type and warns', async () => {
const warn = vi.spyOn(console, 'warn').mockImplementation(() => {});
const doc = await loadFile(fp('test.epub')); // epub is unsupported in current mapping
expect(warn).toHaveBeenCalled();
expect(doc.content.length).toBeGreaterThanOrEqual(0);
warn.mockRestore();
});
it('allows overriding metadata via second parameter', async () => {
const file = fp('test.txt');
const override = {
source: 's3://bucket/key',
filename: 'override.txt',
fileType: 'custom',
};
const doc = await loadFile(file, override);
expect(doc.source).toBe('s3://bucket/key');
expect(doc.filename).toBe('override.txt');
expect(doc.fileType).toBe('custom');
});
});
@@ -0,0 +1,43 @@
import { describe, expect, it } from 'vitest';
import { isTextReadableFile } from './isTextReadableFile';
describe('isTextReadableFile', () => {
it('should return true for common text-readable types', () => {
const positives = [
'txt',
'md',
'mdx',
'json',
'yaml',
'yml',
'csv',
'html',
'css',
'js',
'ts',
'py',
'log',
'sql',
'patch',
'diff',
];
for (const ext of positives) {
expect(isTextReadableFile(ext)).toBe(true);
}
});
it('should be case-insensitive', () => {
expect(isTextReadableFile('Md')).toBe(true);
expect(isTextReadableFile('JSON')).toBe(true);
expect(isTextReadableFile('YML')).toBe(true);
});
it('should return false for non text-readable or binary types', () => {
const negatives = ['pdf', 'docx', 'xlsx', 'pptx', 'png', 'jpg', 'gif'];
for (const ext of negatives) {
expect(isTextReadableFile(ext)).toBe(false);
}
});
});
@@ -0,0 +1,155 @@
// @vitest-environment node
import { beforeEach, describe, expect, it, vi } from 'vitest';
import { type ExtractedFile, extractFiles, parseString } from './parser-utils';
describe('parser-utils', () => {
describe('parseString', () => {
it('should parse valid XML string into XMLDocument', () => {
const xml = '<root><item id="1">hello</item></root>';
const doc = parseString(xml);
// The parsed document should contain the root and item node
const root = (doc as any).getElementsByTagName('root')[0];
expect(root).toBeDefined();
const item = (doc as any).getElementsByTagName('item')[0];
expect(item).toBeDefined();
expect(item.getAttribute('id')).toBe('1');
expect(item.textContent).toBe('hello');
});
});
describe('extractFiles', () => {
beforeEach(() => {
vi.resetModules();
});
it('should reject on invalid input type', async () => {
// @ts-expect-error intentional wrong type
await expect(extractFiles(123, () => true)).rejects.toThrow(
'[OfficeParser]: Invalid input type',
);
});
it('should read entries via yauzl.fromBuffer and filter matches', async () => {
// Arrange: build a fake zipfile object with two file entries and one directory
const entryHandlers: Record<string, (cb: () => void) => void> = {};
const listeners: Record<string, Function[]> = { entry: [], end: [], error: [] };
let idx = 0;
const sequence = [
{ fileName: 'folder/' },
{ fileName: 'keep.txt' },
{ fileName: 'skip.bin' },
];
const emit = (name: string, payload?: any) =>
(listeners[name] || []).forEach((fn) => fn(payload));
const fakeZipfile = {
readEntry: vi.fn().mockImplementation(() => {
queueMicrotask(() => {
if (idx < sequence.length) {
const entry = sequence[idx++];
emit('entry', entry as any);
} else {
emit('end');
}
});
}),
openReadStream: vi.fn((entry: any, cb: (err: any, stream?: any) => void) => {
if (entry.fileName === 'keep.txt') {
// Provide a minimal readable stream compatible with concat-stream
const chunks: any[] = [];
const stream = {
pipe(destination: any) {
// emulate piping to concat-stream writable
if (typeof destination.end === 'function') {
destination.end(Buffer.from('hello world'));
}
return destination;
},
on: vi.fn(),
};
cb(null, stream);
} else if (entry.fileName === 'skip.bin') {
// This entry should be skipped by filter, so not invoked
cb(null, undefined as any);
}
}),
on: vi.fn((evt: string, handler: Function) => {
listeners[evt] = listeners[evt] || [];
listeners[evt].push(handler);
}),
close: vi.fn(),
} as any;
// Mock yauzl.fromBuffer to pass back our fake zipfile
vi.doMock('yauzl', () => ({
default: {
fromBuffer: (_buf: Buffer, _opts: any, cb: (err: any, zf?: any) => void) =>
cb(null, fakeZipfile),
open: vi.fn(),
},
}));
// Re-import module to use mocked yauzl
const { extractFiles: mockedExtractFiles } = await import('./parser-utils');
const files: ExtractedFile[] = await mockedExtractFiles(Buffer.from('zip'), (name) =>
name.endsWith('.txt'),
);
expect(files).toEqual([{ path: 'keep.txt', content: 'hello world' }]);
});
it('should open zip by file path when input is string', async () => {
const listeners: Record<string, Function[]> = { entry: [], end: [], error: [] };
let idx = 0;
const entries = [{ fileName: 'keep.txt' }];
const emit2 = (name: string, payload?: any) =>
(listeners[name] || []).forEach((fn) => fn(payload));
const fakeZipfile = {
readEntry: vi.fn().mockImplementation(() => {
queueMicrotask(() => {
if (idx < entries.length) {
const entry = entries[idx++];
emit2('entry', entry as any);
} else {
emit2('end');
}
});
}),
openReadStream: vi.fn((entry: any, cb: (err: any, stream?: any) => void) => {
const stream = {
pipe(destination: any) {
if (typeof destination.end === 'function') {
destination.end(Buffer.from('A'));
}
return destination;
},
on: vi.fn(),
};
cb(null, stream);
}),
on: vi.fn((evt: string, handler: Function) => {
listeners[evt] = listeners[evt] || [];
listeners[evt].push(handler);
}),
close: vi.fn(),
} as any;
vi.doMock('yauzl', () => ({
default: {
fromBuffer: vi.fn(),
open: (_path: string, _opts: any, cb: (err: any, zf?: any) => void) =>
cb(null, fakeZipfile),
},
}));
const { extractFiles: mockedExtractFiles } = await import('./parser-utils');
const files = await mockedExtractFiles('/tmp/file.zip', (name) => name === 'keep.txt');
expect(files).toEqual([{ path: 'keep.txt', content: 'A' }]);
});
});
});
+38 -4
View File
@@ -552,13 +552,11 @@ const aihubmixModels: AIChatModelCard[] = [
{
abilities: {
functionCall: true,
reasoning: true,
},
contextWindowTokens: 131_072,
description:
'DeepSeek-V3.1 是深度求索全新推出的混合推理模型,支持思考与非思考2种推理模式,较 DeepSeek-R1-0528 思考效率更高。经 Post-Training 优化,Agent 工具使用与智能体任务表现大幅提升。',
displayName: 'DeepSeek V3.1',
enabled: true,
'DeepSeek-V3.1-非思考模式;DeepSeek-V3.1 是深度求索全新推出的混合推理模型,支持思考与非思考2种推理模式,较 DeepSeek-R1-0528 思考效率更高。经 Post-Training 优化,Agent 工具使用与智能体任务表现大幅提升。',
displayName: 'DeepSeek V3.1 (non-Think)',
id: 'DeepSeek-V3.1',
pricing: {
units: [
@@ -568,6 +566,42 @@ const aihubmixModels: AIChatModelCard[] = [
},
type: 'chat',
},
{
abilities: {
functionCall: true,
reasoning: true,
},
contextWindowTokens: 131_072,
description:
'DeepSeek-V3.1-思考模式;DeepSeek-V3.1 是深度求索全新推出的混合推理模型,支持思考与非思考2种推理模式,较 DeepSeek-R1-0528 思考效率更高。经 Post-Training 优化,Agent 工具使用与智能体任务表现大幅提升。',
displayName: 'DeepSeek V3.1 (Think)',
id: 'DeepSeek-V3.1-Think',
pricing: {
units: [
{ name: 'textInput', rate: 0.56, strategy: 'fixed', unit: 'millionTokens' },
{ name: 'textOutput', rate: 1.68, strategy: 'fixed', unit: 'millionTokens' },
],
},
type: 'chat',
},
{
abilities: {
functionCall: true,
reasoning: true,
},
contextWindowTokens: 131_072,
description:
'DeepSeek V3.1 Fast 是 DeepSeek V3.1版本的高TPS极速版。 混合思考模式:通过更改聊天模板,一个模型可以同时支持思考模式和非思考模式。 更智能的工具调用:通过后训练优化,模型在工具使用和代理任务中的表现显著提升。',
displayName: 'DeepSeek V3.1 (Fast)',
id: 'DeepSeek-V3.1-Fast',
pricing: {
units: [
{ name: 'textInput', rate: 1.096, strategy: 'fixed', unit: 'millionTokens' },
{ name: 'textOutput', rate: 3.288, strategy: 'fixed', unit: 'millionTokens' },
],
},
type: 'chat',
},
{
abilities: {
functionCall: true,
+26 -8
View File
@@ -7,19 +7,19 @@ const groqChatModels: AIChatModelCard[] = [
{
contextWindowTokens: 131_072,
description:
'Compound-beta 是一个复合 AI 系统,由 GroqCloud 中已经支持的多个开放可用的模型提供支持,可以智能地、有选择地使用工具来回答用户查询。',
displayName: 'Compound Beta',
'Compound 是一个复合 AI 系统,由 GroqCloud 中已经支持的多个开放可用的模型提供支持,可以智能地、有选择地使用工具来回答用户查询。',
displayName: 'Compound',
enabled: true,
id: 'compound-beta',
id: 'groq/compound',
maxOutput: 8192,
type: 'chat',
},
{
contextWindowTokens: 131_072,
description:
'Compound-beta-mini 是一个复合 AI 系统,由 GroqCloud 中已经支持的公开可用模型提供支持,可以智能地、有选择地使用工具来回答用户查询。',
displayName: 'Compound Beta Mini',
id: 'compound-beta-mini',
'Compound-mini 是一个复合 AI 系统,由 GroqCloud 中已经支持的公开可用模型提供支持,可以智能地、有选择地使用工具来回答用户查询。',
displayName: 'Compound Mini',
id: 'groq/compound-mini',
maxOutput: 8192,
type: 'chat',
},
@@ -63,6 +63,25 @@ const groqChatModels: AIChatModelCard[] = [
releasedAt: '2025-08-06',
type: 'chat',
},
{
abilities: {
functionCall: true,
},
contextWindowTokens: 262_144,
description:
'kimi-k2-0905-preview 模型上下文长度为 256k,具备更强的 Agentic Coding 能力、更突出的前端代码的美观度和实用性、以及更好的上下文理解能力。',
displayName: 'Kimi K2 0905',
enabled: true,
id: 'moonshotai/kimi-k2-instruct-0905',
pricing: {
units: [
{ name: 'textInput', rate: 1, strategy: 'fixed', unit: 'millionTokens' },
{ name: 'textOutput', rate: 3, strategy: 'fixed', unit: 'millionTokens' },
],
},
releasedAt: '2025-09-05',
type: 'chat',
},
{
abilities: {
functionCall: true,
@@ -70,8 +89,7 @@ const groqChatModels: AIChatModelCard[] = [
contextWindowTokens: 131_072,
description:
'kimi-k2 是一款具备超强代码和 Agent 能力的 MoE 架构基础模型,总参数 1T,激活参数 32B。在通用知识推理、编程、数学、Agent 等主要类别的基准性能测试中,K2 模型的性能超过其他主流开源模型。',
displayName: 'Kimi K2 Instruct',
enabled: true,
displayName: 'Kimi K2 0711',
id: 'moonshotai/kimi-k2-instruct',
maxOutput: 16_384,
pricing: {
+3 -3
View File
@@ -26,9 +26,9 @@ const hunyuanChatModels: AIChatModelCard[] = [
reasoning: true,
search: true,
},
contextWindowTokens: 92_000,
contextWindowTokens: 96_000,
description:
'业内首个超大规模 Hybrid-Transformer-Mamba 推理模型,扩展推理能力,超强解码速度,进一步对齐人类偏好。',
'大幅提升主模型慢思考模型的高难数学、复杂推理、高难代码、指令遵循、文本创作质量等能力。',
displayName: 'Hunyuan T1',
enabled: true,
id: 'hunyuan-t1-latest',
@@ -40,7 +40,7 @@ const hunyuanChatModels: AIChatModelCard[] = [
{ name: 'textOutput', rate: 4, strategy: 'fixed', unit: 'millionTokens' },
],
},
releasedAt: '2025-05-21',
releasedAt: '2025-08-22',
settings: {
searchImpl: 'params',
},
+13 -2
View File
@@ -1,6 +1,19 @@
import { AIChatModelCard } from '../types/aiModel';
const modelscopeChatModels: AIChatModelCard[] = [
{
abilities: {
functionCall: true,
},
contextWindowTokens: 262_144,
description:
'kimi-k2-0905-preview 模型上下文长度为 256k,具备更强的 Agentic Coding 能力、更突出的前端代码的美观度和实用性、以及更好的上下文理解能力。',
displayName: 'Kimi K2 0905',
enabled: true,
id: 'moonshotai/Kimi-K2-Instruct-0905',
releasedAt: '2025-09-05',
type: 'chat',
},
{
abilities: {
functionCall: true,
@@ -53,7 +66,6 @@ const modelscopeChatModels: AIChatModelCard[] = [
contextWindowTokens: 131_072,
description: 'Qwen3-235B-A22B是通义千问3代超大规模模型,提供顶级的AI能力。',
displayName: 'Qwen3-235B-A22B',
enabled: true,
id: 'Qwen/Qwen3-235B-A22B',
type: 'chat',
},
@@ -64,7 +76,6 @@ const modelscopeChatModels: AIChatModelCard[] = [
contextWindowTokens: 131_072,
description: 'Qwen3-32B是通义千问3代模型,具有强大的推理和对话能力。',
displayName: 'Qwen3-32B',
enabled: true,
id: 'Qwen/Qwen3-32B',
type: 'chat',
},
+25 -5
View File
@@ -2,6 +2,27 @@ import { AIChatModelCard } from '../types/aiModel';
// https://platform.moonshot.cn/docs/pricing/chat
const moonshotChatModels: AIChatModelCard[] = [
{
abilities: {
functionCall: true,
},
contextWindowTokens: 262_144,
description:
'kimi-k2-0905-preview 模型上下文长度为 256k,具备更强的 Agentic Coding 能力、更突出的前端代码的美观度和实用性、以及更好的上下文理解能力。',
displayName: 'Kimi K2 0905',
enabled: true,
id: 'kimi-k2-0905-preview',
pricing: {
currency: 'CNY',
units: [
{ name: 'textInput_cacheRead', rate: 1, strategy: 'fixed', unit: 'millionTokens' },
{ name: 'textInput', rate: 4, strategy: 'fixed', unit: 'millionTokens' },
{ name: 'textOutput', rate: 16, strategy: 'fixed', unit: 'millionTokens' },
],
},
releasedAt: '2025-09-05',
type: 'chat',
},
{
abilities: {
functionCall: true,
@@ -9,8 +30,7 @@ const moonshotChatModels: AIChatModelCard[] = [
contextWindowTokens: 131_072,
description:
'kimi-k2 是一款具备超强代码和 Agent 能力的 MoE 架构基础模型,总参数 1T,激活参数 32B。在通用知识推理、编程、数学、Agent 等主要类别的基准性能测试中,K2 模型的性能超过其他主流开源模型。',
displayName: 'Kimi K2',
enabled: true,
displayName: 'Kimi K2 0711',
id: 'kimi-k2-0711-preview',
pricing: {
currency: 'CNY',
@@ -27,10 +47,10 @@ const moonshotChatModels: AIChatModelCard[] = [
abilities: {
functionCall: true,
},
contextWindowTokens: 131_072,
contextWindowTokens: 262_144,
description:
'kimi-k2 是一款具备超强代码和 Agent 能力的 MoE 架构基础模型,总参数 1T,激活参数 32B。在通用知识推理、编程、数学、Agent 等主要类别的基准性能测试中,K2 模型的性能超过其他主流开源模型。',
displayName: 'Kimi K2 Turbo',
displayName: 'Kimi K2 0905 Turbo',
id: 'kimi-k2-turbo-preview',
pricing: {
currency: 'CNY',
@@ -40,7 +60,7 @@ const moonshotChatModels: AIChatModelCard[] = [
{ name: 'textOutput', rate: 64, strategy: 'fixed', unit: 'millionTokens' },
],
},
releasedAt: '2025-07-11',
releasedAt: '2025-09-05',
type: 'chat',
},
{
+40 -9
View File
@@ -2,6 +2,24 @@ import { AIChatModelCard } from '../types/aiModel';
// https://novita.ai/pricing
const novitaChatModels: AIChatModelCard[] = [
{
abilities: {
functionCall: true,
},
contextWindowTokens: 262_144,
description:
'kimi-k2-0905-preview 模型上下文长度为 256k,具备更强的 Agentic Coding 能力、更突出的前端代码的美观度和实用性、以及更好的上下文理解能力。',
displayName: 'Kimi K2 0905',
id: 'moonshotai/kimi-k2-0905',
pricing: {
units: [
{ name: 'textInput', rate: 0.6, strategy: 'fixed', unit: 'millionTokens' },
{ name: 'textOutput', rate: 2.5, strategy: 'fixed', unit: 'millionTokens' },
],
},
releasedAt: '2025-09-05',
type: 'chat',
},
{
abilities: {
functionCall: true,
@@ -9,11 +27,12 @@ const novitaChatModels: AIChatModelCard[] = [
},
contextWindowTokens: 163_840,
displayName: 'DeepSeek V3.1',
enabled: true,
id: 'deepseek/deepseek-v3.1',
pricing: {
units: [
{ name: 'textInput', rate: 0.55, strategy: 'fixed', unit: 'millionTokens' },
{ name: 'textOutput', rate: 1.66, strategy: 'fixed', unit: 'millionTokens' },
{ name: 'textInput', rate: 0.27, strategy: 'fixed', unit: 'millionTokens' },
{ name: 'textOutput', rate: 1, strategy: 'fixed', unit: 'millionTokens' },
],
},
type: 'chat',
@@ -128,10 +147,10 @@ const novitaChatModels: AIChatModelCard[] = [
},
{
abilities: {
reasoning: true,
functionCall: true,
},
contextWindowTokens: 131_072,
displayName: 'Kimi K2 Instruct',
displayName: 'Kimi K2 0711',
id: 'moonshotai/kimi-k2-instruct',
pricing: {
units: [
@@ -286,12 +305,12 @@ const novitaChatModels: AIChatModelCard[] = [
abilities: {
reasoning: true,
},
contextWindowTokens: 40_960,
contextWindowTokens: 32_768,
displayName: 'Qwen3 30B A3B FP8',
id: 'qwen/qwen3-30b-a3b-fp8',
pricing: {
units: [
{ name: 'textInput', rate: 0.1, strategy: 'fixed', unit: 'millionTokens' },
{ name: 'textInput', rate: 0.09, strategy: 'fixed', unit: 'millionTokens' },
{ name: 'textOutput', rate: 0.45, strategy: 'fixed', unit: 'millionTokens' },
],
},
@@ -413,7 +432,7 @@ const novitaChatModels: AIChatModelCard[] = [
type: 'chat',
},
{
contextWindowTokens: 32_000,
contextWindowTokens: 32_768,
description: 'Gemma 3 27B 是谷歌的一款开源语言模型,以其在效率和性能方面设立了新的标准。',
displayName: 'Gemma 3 27B',
id: 'google/gemma-3-27b-it',
@@ -425,6 +444,20 @@ const novitaChatModels: AIChatModelCard[] = [
},
type: 'chat',
},
{
contextWindowTokens: 131_072,
description: 'Gemma 3 12B 是谷歌的一款开源语言模型,以其在效率和性能方面设立了新的标准。',
displayName: 'Gemma 3 12B',
id: 'google/gemma-3-12b-it',
maxOutput: 8192,
pricing: {
units: [
{ name: 'textInput', rate: 0.05, strategy: 'fixed', unit: 'millionTokens' },
{ name: 'textOutput', rate: 0.1, strategy: 'fixed', unit: 'millionTokens' },
],
},
type: 'chat',
},
{
contextWindowTokens: 32_768,
description: 'Gemma 3 1B 是谷歌的一款开源语言模型,以其在效率和性能方面设立了新的标准。',
@@ -549,7 +582,6 @@ const novitaChatModels: AIChatModelCard[] = [
},
contextWindowTokens: 163_840,
displayName: 'Deepseek V3 0324',
enabled: true,
id: 'deepseek/deepseek-v3-0324',
pricing: {
units: [
@@ -566,7 +598,6 @@ const novitaChatModels: AIChatModelCard[] = [
},
contextWindowTokens: 163_840,
displayName: 'Deepseek R1 0528',
enabled: true,
id: 'deepseek/deepseek-r1-0528',
pricing: {
units: [
@@ -50,19 +50,6 @@ const openrouterChatModels: AIChatModelCard[] = [
releasedAt: '2025-08-26',
type: 'chat',
},
{
abilities: {
imageOutput: true,
vision: true,
},
contextWindowTokens: 32_768 + 8192,
description: 'Gemini 2.5 Flash 实验模型,支持图像生成',
displayName: 'Nano Banana (free)',
id: 'google/gemini-2.5-flash-image-preview:free',
maxOutput: 8192,
releasedAt: '2025-08-26',
type: 'chat',
},
{
abilities: {
functionCall: true,
+66 -1
View File
@@ -601,6 +601,72 @@ const qwenChatModels: AIChatModelCard[] = [
},
type: 'chat',
},
{
abilities: {
functionCall: true,
search: true,
},
config: {
deploymentName: 'qwen3-max-preview',
},
contextWindowTokens: 262_144,
description:
'通义千问3系列Max模型Preview版本,相较2.5系列整体通用能力有大幅度提升,中英文通用文本理解能力、复杂指令遵循能力、主观开放任务能力、多语言能力、工具调用能力均显著增强;模型知识幻觉更少。',
displayName: 'Qwen3 Max Preview',
enabled: true,
id: 'qwen3-max-preview',
maxOutput: 32_768,
organization: 'Qwen',
pricing: {
currency: 'CNY',
units: [
{
lookup: {
prices: {
'[0, 32_000]': 6 * 0.2,
'[32_000, 128_000]': 10 * 0.2,
'[128_000, infinity]': 15 * 0.2,
},
pricingParams: ['textInputRange'],
},
name: 'textInput_cacheRead',
strategy: 'lookup',
unit: 'millionTokens',
},
{
lookup: {
prices: {
'[0, 32_000]': 6,
'[32_000, 128_000]': 10,
'[128_000, infinity]': 15,
},
pricingParams: ['textInputRange'],
},
name: 'textInput',
strategy: 'lookup',
unit: 'millionTokens',
},
{
lookup: {
prices: {
'[0, 32_000]': 24,
'[32_000, 128_000]': 40,
'[128_000, infinity]': 60,
},
pricingParams: ['textInputRange'],
},
name: 'textOutput',
strategy: 'lookup',
unit: 'millionTokens',
},
],
},
releasedAt: '2025-09-05',
settings: {
searchImpl: 'params',
},
type: 'chat',
},
{
abilities: {
functionCall: true,
@@ -613,7 +679,6 @@ const qwenChatModels: AIChatModelCard[] = [
description:
'通义千问千亿级别超大规模语言模型,支持中文、英文等不同语言输入,当前通义千问2.5产品版本背后的API模型。',
displayName: 'Qwen Max',
enabled: true,
id: 'qwen-max',
maxOutput: 8192,
organization: 'Qwen',
@@ -47,6 +47,26 @@ const siliconcloudChatModels: AIChatModelCard[] = [
},
type: 'chat',
},
{
abilities: {
functionCall: true,
reasoning: true,
},
contextWindowTokens: 256_000,
description:
'Seed-OSS 是由字节跳动 Seed 团队开发的一系列开源大型语言模型,专为强大的长上下文处理、推理、智能体(agent)和通用能力而设计。该系列中的 Seed-OSS-36B-Instruct 是一个拥有 360 亿参数的指令微调模型,它原生支持超长上下文长度,使其能够一次性处理海量文档或复杂的代码库。该模型在推理、代码生成和智能体任务(如工具使用)方面进行了特别优化,同时保持了平衡且出色的通用能力。此模型的一大特色是“思考预算”(Thinking Budget)功能,允许用户根据需要灵活调整推理长度,从而在实际应用中有效提升推理效率。',
displayName: 'Seed OSS 36B Instruct',
id: 'ByteDance-Seed/Seed-OSS-36B-Instruct',
pricing: {
currency: 'CNY',
units: [
{ name: 'textInput', rate: 1.5, strategy: 'fixed', unit: 'millionTokens' },
{ name: 'textOutput', rate: 4, strategy: 'fixed', unit: 'millionTokens' },
],
},
releasedAt: '2025-08-20',
type: 'chat',
},
{
abilities: {
functionCall: true,
+141 -15
View File
@@ -1,7 +1,6 @@
import { AIChatModelCard, AIImageModelCard } from '../types/aiModel';
// modelInfo https://www.volcengine.com/docs/82379/1330310
// pricing https://console.volcengine.com/ark/region:ark+cn-beijing/openManagement
// https://www.volcengine.com/docs/82379/1330310
const doubaoChatModels: AIChatModelCard[] = [
{
@@ -42,7 +41,6 @@ const doubaoChatModels: AIChatModelCard[] = [
description:
'Kimi-K2 是一款Moonshot AI推出的具备超强代码和 Agent 能力的 MoE 架构基础模型,总参数 1T,激活参数 32B。在通用知识推理、编程、数学、Agent 等主要类别的基准性能测试中,K2 模型的性能超过其他主流开源模型。',
displayName: 'Kimi K2',
enabled: true,
id: 'kimi-k2',
maxOutput: 16_384,
pricing: {
@@ -61,7 +59,59 @@ const doubaoChatModels: AIChatModelCard[] = [
vision: true,
},
config: {
deploymentName: 'doubao-seed-1-6-thinking-250615',
deploymentName: 'doubao-seed-1-6-vision-250815',
},
contextWindowTokens: 256_000,
description:
'Doubao-Seed-1.6-vision 视觉深度思考模型,在教育、图像审核、巡检与安防和AI 搜索问答等场景下展现出更强的通用多模态理解和推理能力。支持 256k 上下文窗口,输出长度支持最大 64k tokens。',
displayName: 'Doubao Seed 1.6 Vision',
id: 'doubao-seed-1.6-vision',
maxOutput: 32_000,
pricing: {
currency: 'CNY',
units: [
{
lookup: {
prices: {
'[0, 32_000]': 0.8,
'[32_000, 128_000]': 2.4,
'[128_000, infinity]': 4.8,
},
pricingParams: ['textInputRange'],
},
name: 'textInput',
strategy: 'lookup',
unit: 'millionTokens',
},
{
lookup: {
prices: {
'[0, 32_000]': 8,
'[32_000, 128_000]': 16,
'[128_000, infinity]': 24,
},
pricingParams: ['textInputRange'],
},
name: 'textOutput',
strategy: 'lookup',
unit: 'millionTokens',
},
{ name: 'textInput_cacheRead', rate: 0.16, strategy: 'fixed', unit: 'millionTokens' },
],
},
settings: {
extendParams: ['enableReasoning'],
},
type: 'chat',
},
{
abilities: {
functionCall: true,
reasoning: true,
vision: true,
},
config: {
deploymentName: 'doubao-seed-1-6-thinking-250715',
},
contextWindowTokens: 256_000,
description:
@@ -69,12 +119,37 @@ const doubaoChatModels: AIChatModelCard[] = [
displayName: 'Doubao Seed 1.6 Thinking',
enabled: true,
id: 'doubao-seed-1.6-thinking',
maxOutput: 16_000,
maxOutput: 32_000,
pricing: {
currency: 'CNY',
units: [
{ name: 'textInput', rate: 1.2, strategy: 'fixed', unit: 'millionTokens' },
{ name: 'textOutput', rate: 16, strategy: 'fixed', unit: 'millionTokens' },
{
lookup: {
prices: {
'[0, 32_000]': 0.8,
'[32_000, 128_000]': 1.2,
'[128_000, infinity]': 2.4,
},
pricingParams: ['textInputRange'],
},
name: 'textInput',
strategy: 'lookup',
unit: 'millionTokens',
},
{
lookup: {
prices: {
'[0, 32_000]': 8,
'[32_000, 128_000]': 16,
'[128_000, infinity]': 24,
},
pricingParams: ['textInputRange'],
},
name: 'textOutput',
strategy: 'lookup',
unit: 'millionTokens',
},
{ name: 'textInput_cacheRead', rate: 0.16, strategy: 'fixed', unit: 'millionTokens' },
],
},
type: 'chat',
@@ -94,12 +169,38 @@ const doubaoChatModels: AIChatModelCard[] = [
displayName: 'Doubao Seed 1.6',
enabled: true,
id: 'doubao-seed-1.6',
maxOutput: 16_000,
maxOutput: 32_000,
pricing: {
currency: 'CNY',
units: [
{ name: 'textInput', rate: 1.2, strategy: 'fixed', unit: 'millionTokens' },
{ name: 'textOutput', rate: 16, strategy: 'fixed', unit: 'millionTokens' },
{
lookup: {
prices: {
'[0, 32_000]': 0.8,
'[32_000, 128_000]': 1.2,
'[128_000, infinity]': 2.4,
},
pricingParams: ['textInputRange'],
},
name: 'textInput',
strategy: 'lookup',
unit: 'millionTokens',
},
{
lookup: {
prices: {
'[0, 32_000]_[0, 8192]': 2,
'[0, 32_000]_[8192, infinity]': 8,
'[32_000, 128_000]_[0, infinity]': 16,
'[128_000, infinity]_[0, infinity]': 24,
},
pricingParams: ['textInputRange', 'textOutputRange'],
},
name: 'textOutput',
strategy: 'lookup',
unit: 'millionTokens',
},
{ name: 'textInput_cacheRead', rate: 0.16, strategy: 'fixed', unit: 'millionTokens' },
],
},
settings: {
@@ -114,7 +215,7 @@ const doubaoChatModels: AIChatModelCard[] = [
vision: true,
},
config: {
deploymentName: 'doubao-seed-1-6-flash-250615',
deploymentName: 'doubao-seed-1-6-flash-250828',
},
contextWindowTokens: 256_000,
description:
@@ -122,12 +223,37 @@ const doubaoChatModels: AIChatModelCard[] = [
displayName: 'Doubao Seed 1.6 Flash',
enabled: true,
id: 'doubao-seed-1.6-flash',
maxOutput: 16_000,
maxOutput: 32_000,
pricing: {
currency: 'CNY',
units: [
{ name: 'textInput', rate: 0.3, strategy: 'fixed', unit: 'millionTokens' },
{ name: 'textOutput', rate: 3, strategy: 'fixed', unit: 'millionTokens' },
{
lookup: {
prices: {
'[0, 32_000]': 0.15,
'[32_000, 128_000]': 0.3,
'[128_000, infinity]': 0.6,
},
pricingParams: ['textInputRange'],
},
name: 'textInput',
strategy: 'lookup',
unit: 'millionTokens',
},
{
lookup: {
prices: {
'[0, 32_000]': 1.5,
'[32_000, 128_000]': 3,
'[128_000, infinity]': 6,
},
pricingParams: ['textInputRange'],
},
name: 'textOutput',
strategy: 'lookup',
unit: 'millionTokens',
},
{ name: 'textInput_cacheRead', rate: 0.03, strategy: 'fixed', unit: 'millionTokens' },
],
},
settings: {
@@ -235,7 +361,7 @@ const doubaoChatModels: AIChatModelCard[] = [
],
},
settings: {
extendParams: ['enableReasoning'],
extendParams: ['thinking'],
},
type: 'chat',
},
+2 -1
View File
@@ -8,7 +8,8 @@
},
"scripts": {
"test": "vitest",
"test:coverage": "vitest --coverage"
"test:coverage": "vitest --coverage",
"test:update": "vitest -u"
},
"dependencies": {
"@aws-sdk/client-bedrock-runtime": "^3.862.0",
@@ -1,7 +1,7 @@
// @vitest-environment node
import { ModelProvider } from '@/libs/model-runtime';
import { testProvider } from '@/libs/model-runtime/providerTestUtils';
import { ModelProvider } from '@lobechat/model-runtime';
import { testProvider } from '../providerTestUtils';
import { LobeAi21AI } from './index';
testProvider({
@@ -1,7 +1,7 @@
// @vitest-environment node
import { ModelProvider } from '@/libs/model-runtime';
import { testProvider } from '@/libs/model-runtime/providerTestUtils';
import { ModelProvider } from '@lobechat/model-runtime';
import { testProvider } from '../providerTestUtils';
import { LobeAi360AI } from './index';
testProvider({
@@ -0,0 +1,19 @@
// @vitest-environment node
import { ModelProvider } from '@lobechat/model-runtime';
import { testProvider } from '../providerTestUtils';
import { LobeAkashChatAI } from './index';
const provider = ModelProvider.AkashChat;
const defaultBaseURL = 'https://chatapi.akash.network/api/v1';
testProvider({
Runtime: LobeAkashChatAI,
provider,
defaultBaseURL,
chatDebugEnv: 'DEBUG_AKASH_CHAT_COMPLETION',
chatModel: 'llama-3.1-8b-instruct',
test: {
skipAPICall: true,
},
});
@@ -1,8 +1,7 @@
// @vitest-environment node
import { ChatCompletionTool, ChatStreamPayload } from '@lobechat/model-runtime';
import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { ChatCompletionTool, ChatStreamPayload } from '@/libs/model-runtime';
import * as anthropicHelpers from '../utils/anthropicHelpers';
import * as debugStreamModule from '../utils/debugStream';
import { LobeAnthropicAI } from './index';
@@ -1,8 +1,7 @@
// @vitest-environment node
import { LobeOpenAICompatibleRuntime, ModelProvider } from '@lobechat/model-runtime';
import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { LobeOpenAICompatibleRuntime, ModelProvider } from '@/libs/model-runtime';
import { testProvider } from '../providerTestUtils';
import { LobeBaichuanAI } from './index';
@@ -1,9 +1,8 @@
// @vitest-environment node
import { InvokeModelWithResponseStreamCommand } from '@aws-sdk/client-bedrock-runtime';
import { AgentRuntimeErrorType, ModelProvider } from '@lobechat/model-runtime';
import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { AgentRuntimeErrorType, ModelProvider } from '@/libs/model-runtime';
import * as debugStreamModule from '../utils/debugStream';
import { LobeBedrockAI } from './index';
@@ -1,8 +1,7 @@
// @vitest-environment node
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { CreateImagePayload } from '@/libs/model-runtime/types/image';
import { CreateImagePayload } from '../types/image';
import { createBflImage } from './createImage';
import { BflStatusResponse } from './types';
+1 -2
View File
@@ -1,8 +1,7 @@
// @vitest-environment node
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { CreateImagePayload } from '@/libs/model-runtime/types/image';
import { CreateImagePayload } from '../types/image';
import { LobeBflAI } from './index';
// Mock the createBflImage function
@@ -1,8 +1,7 @@
// @vitest-environment node
import { ChatCompletionTool } from '@lobechat/model-runtime';
import { Mock, afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
import { ChatCompletionTool } from '@/libs/model-runtime';
import * as debugStreamModule from '../utils/debugStream';
import { LobeCloudflareAI } from './index';
@@ -0,0 +1,19 @@
// @vitest-environment node
import { ModelProvider } from '@lobechat/model-runtime';
import { testProvider } from '../providerTestUtils';
import { LobeCohereAI } from './index';
const provider = ModelProvider.Cohere;
const defaultBaseURL = 'https://api.cohere.ai/compatibility/v1';
testProvider({
Runtime: LobeCohereAI,
provider,
defaultBaseURL,
chatDebugEnv: 'DEBUG_COHERE_CHAT_COMPLETION',
chatModel: 'command-r7b',
test: {
skipAPICall: true,
},
});
@@ -1,7 +1,7 @@
// @vitest-environment node
import { ModelProvider } from '@/libs/model-runtime';
import { testProvider } from '@/libs/model-runtime/providerTestUtils';
import { ModelProvider } from '@lobechat/model-runtime';
import { testProvider } from '../providerTestUtils';
import { LobeDeepSeekAI } from './index';
const provider = ModelProvider.DeepSeek;
@@ -1,7 +1,7 @@
// @vitest-environment node
import { ModelProvider } from '@/libs/model-runtime';
import { testProvider } from '@/libs/model-runtime/providerTestUtils';
import { ModelProvider } from '@lobechat/model-runtime';
import { testProvider } from '../providerTestUtils';
import { LobeFireworksAI } from './index';
const provider = ModelProvider.FireworksAI;

Some files were not shown because too many files have changed in this diff Show More