@lobehub/chat 1.127.3 → 1.128.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +50 -0
- package/changelog/v1.json +18 -0
- package/locales/ar/editor.json +9 -1
- package/locales/bg-BG/editor.json +9 -1
- package/locales/de-DE/editor.json +9 -1
- package/locales/en-US/editor.json +9 -1
- package/locales/es-ES/editor.json +9 -1
- package/locales/fa-IR/editor.json +9 -1
- package/locales/fr-FR/editor.json +9 -1
- package/locales/it-IT/editor.json +9 -1
- package/locales/ja-JP/editor.json +9 -1
- package/locales/ko-KR/editor.json +9 -1
- package/locales/nl-NL/editor.json +9 -1
- package/locales/pl-PL/editor.json +9 -1
- package/locales/pt-BR/editor.json +9 -1
- package/locales/ru-RU/editor.json +9 -1
- package/locales/tr-TR/editor.json +9 -1
- package/locales/vi-VN/editor.json +9 -1
- package/locales/zh-CN/editor.json +9 -1
- package/locales/zh-TW/editor.json +9 -1
- package/package.json +3 -3
- package/packages/model-bank/src/aiModels/qwen.ts +46 -0
- package/packages/model-runtime/package.json +2 -1
- package/packages/model-runtime/src/const/modelProvider.ts +1 -0
- package/packages/model-runtime/src/core/RouterRuntime/createRuntime.ts +2 -0
- package/packages/model-runtime/src/core/RouterRuntime/index.ts +1 -0
- package/packages/model-runtime/src/core/streams/openai/openai.test.ts +36 -2
- package/packages/model-runtime/src/core/streams/openai/openai.ts +3 -2
- package/packages/model-runtime/src/index.ts +1 -0
- package/packages/types/src/user/settings/keyVaults.ts +1 -0
- package/src/features/ChatInput/Desktop/index.tsx +13 -5
- package/src/features/ChatInput/InputEditor/Placeholder.tsx +42 -0
- package/src/features/ChatInput/InputEditor/index.tsx +6 -41
- package/src/features/ChatInput/InputEditor/useSlashItems.tsx +92 -0
- package/src/features/ChatInput/TypoBar/index.tsx +1 -8
- package/src/locales/default/editor.ts +9 -1
- package/src/store/global/initialState.ts +2 -0
- package/src/store/global/selectors/systemStatus.ts +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,56 @@
|
|
|
2
2
|
|
|
3
3
|
# Changelog
|
|
4
4
|
|
|
5
|
+
## [Version 1.128.0](https://github.com/lobehub/lobe-chat/compare/v1.127.4...v1.128.0)
|
|
6
|
+
|
|
7
|
+
<sup>Released on **2025-09-12**</sup>
|
|
8
|
+
|
|
9
|
+
#### ✨ Features
|
|
10
|
+
|
|
11
|
+
- **misc**: ChatInput support resize.
|
|
12
|
+
|
|
13
|
+
<br/>
|
|
14
|
+
|
|
15
|
+
<details>
|
|
16
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
17
|
+
|
|
18
|
+
#### What's improved
|
|
19
|
+
|
|
20
|
+
- **misc**: ChatInput support resize, closes [#9215](https://github.com/lobehub/lobe-chat/issues/9215) ([5e814e0](https://github.com/lobehub/lobe-chat/commit/5e814e0))
|
|
21
|
+
|
|
22
|
+
</details>
|
|
23
|
+
|
|
24
|
+
<div align="right">
|
|
25
|
+
|
|
26
|
+
[](#readme-top)
|
|
27
|
+
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
### [Version 1.127.4](https://github.com/lobehub/lobe-chat/compare/v1.127.3...v1.127.4)
|
|
31
|
+
|
|
32
|
+
<sup>Released on **2025-09-11**</sup>
|
|
33
|
+
|
|
34
|
+
#### 🐛 Bug Fixes
|
|
35
|
+
|
|
36
|
+
- **misc**: Improve OpenAIStream processing to emit usage data for chunks lacking choices.
|
|
37
|
+
|
|
38
|
+
<br/>
|
|
39
|
+
|
|
40
|
+
<details>
|
|
41
|
+
<summary><kbd>Improvements and Fixes</kbd></summary>
|
|
42
|
+
|
|
43
|
+
#### What's fixed
|
|
44
|
+
|
|
45
|
+
- **misc**: Improve OpenAIStream processing to emit usage data for chunks lacking choices, closes [#9220](https://github.com/lobehub/lobe-chat/issues/9220) ([8ba662c](https://github.com/lobehub/lobe-chat/commit/8ba662c))
|
|
46
|
+
|
|
47
|
+
</details>
|
|
48
|
+
|
|
49
|
+
<div align="right">
|
|
50
|
+
|
|
51
|
+
[](#readme-top)
|
|
52
|
+
|
|
53
|
+
</div>
|
|
54
|
+
|
|
5
55
|
### [Version 1.127.3](https://github.com/lobehub/lobe-chat/compare/v1.127.2...v1.127.3)
|
|
6
56
|
|
|
7
57
|
<sup>Released on **2025-09-11**</sup>
|
package/changelog/v1.json
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"children": {
|
|
4
|
+
"features": [
|
|
5
|
+
"ChatInput support resize."
|
|
6
|
+
]
|
|
7
|
+
},
|
|
8
|
+
"date": "2025-09-12",
|
|
9
|
+
"version": "1.128.0"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"children": {
|
|
13
|
+
"fixes": [
|
|
14
|
+
"Improve OpenAIStream processing to emit usage data for chunks lacking choices."
|
|
15
|
+
]
|
|
16
|
+
},
|
|
17
|
+
"date": "2025-09-11",
|
|
18
|
+
"version": "1.127.4"
|
|
19
|
+
},
|
|
2
20
|
{
|
|
3
21
|
"children": {
|
|
4
22
|
"improvements": [
|
package/locales/ar/editor.json
CHANGED
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
"math": {
|
|
28
28
|
"placeholder": "يرجى إدخال معادلة TeX"
|
|
29
29
|
},
|
|
30
|
+
"slash": {
|
|
31
|
+
"h1": "عنوان رئيسي من المستوى الأول",
|
|
32
|
+
"h2": "عنوان فرعي من المستوى الثاني",
|
|
33
|
+
"h3": "عنوان فرعي من المستوى الثالث",
|
|
34
|
+
"hr": "خط فاصل",
|
|
35
|
+
"table": "جدول",
|
|
36
|
+
"tex": "معادلة TeX"
|
|
37
|
+
},
|
|
30
38
|
"table": {
|
|
31
39
|
"delete": "حذف الجدول",
|
|
32
40
|
"deleteColumn": "حذف العمود",
|
|
@@ -46,7 +54,7 @@
|
|
|
46
54
|
"link": "رابط",
|
|
47
55
|
"numberList": "قائمة مرقمة",
|
|
48
56
|
"strikethrough": "شطب",
|
|
49
|
-
"table": "
|
|
57
|
+
"table": "جدول",
|
|
50
58
|
"taskList": "قائمة المهام",
|
|
51
59
|
"tex": "معادلة TeX",
|
|
52
60
|
"underline": "تسطير"
|
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
"math": {
|
|
28
28
|
"placeholder": "Моля, въведете TeX формула"
|
|
29
29
|
},
|
|
30
|
+
"slash": {
|
|
31
|
+
"h1": "Заглавие ниво 1",
|
|
32
|
+
"h2": "Заглавие ниво 2",
|
|
33
|
+
"h3": "Заглавие ниво 3",
|
|
34
|
+
"hr": "Разделителна линия",
|
|
35
|
+
"table": "Таблица",
|
|
36
|
+
"tex": "TeX формула"
|
|
37
|
+
},
|
|
30
38
|
"table": {
|
|
31
39
|
"delete": "Премахни таблицата",
|
|
32
40
|
"deleteColumn": "Премахни колоната",
|
|
@@ -46,7 +54,7 @@
|
|
|
46
54
|
"link": "Връзка",
|
|
47
55
|
"numberList": "Номериран списък",
|
|
48
56
|
"strikethrough": "Зачеркване",
|
|
49
|
-
"table": "
|
|
57
|
+
"table": "таблица",
|
|
50
58
|
"taskList": "Списък със задачи",
|
|
51
59
|
"tex": "TeX формула",
|
|
52
60
|
"underline": "Подчертаване"
|
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
"math": {
|
|
28
28
|
"placeholder": "Bitte TeX-Formel eingeben"
|
|
29
29
|
},
|
|
30
|
+
"slash": {
|
|
31
|
+
"h1": "Überschrift 1. Ordnung",
|
|
32
|
+
"h2": "Überschrift 2. Ordnung",
|
|
33
|
+
"h3": "Überschrift 3. Ordnung",
|
|
34
|
+
"hr": "Trennlinie",
|
|
35
|
+
"table": "Tabelle",
|
|
36
|
+
"tex": "TeX-Formel"
|
|
37
|
+
},
|
|
30
38
|
"table": {
|
|
31
39
|
"delete": "Tabelle löschen",
|
|
32
40
|
"deleteColumn": "Spalte löschen",
|
|
@@ -46,7 +54,7 @@
|
|
|
46
54
|
"link": "Link",
|
|
47
55
|
"numberList": "Nummerierte Liste",
|
|
48
56
|
"strikethrough": "Durchgestrichen",
|
|
49
|
-
"table": "Tabelle
|
|
57
|
+
"table": "Tabelle",
|
|
50
58
|
"taskList": "Aufgabenliste",
|
|
51
59
|
"tex": "TeX-Formel",
|
|
52
60
|
"underline": "Unterstrichen"
|
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
"math": {
|
|
28
28
|
"placeholder": "Please enter a TeX formula"
|
|
29
29
|
},
|
|
30
|
+
"slash": {
|
|
31
|
+
"h1": "Heading 1",
|
|
32
|
+
"h2": "Heading 2",
|
|
33
|
+
"h3": "Heading 3",
|
|
34
|
+
"hr": "Divider",
|
|
35
|
+
"table": "Table",
|
|
36
|
+
"tex": "TeX Formula"
|
|
37
|
+
},
|
|
30
38
|
"table": {
|
|
31
39
|
"delete": "Delete table",
|
|
32
40
|
"deleteColumn": "Delete column",
|
|
@@ -46,7 +54,7 @@
|
|
|
46
54
|
"link": "Link",
|
|
47
55
|
"numberList": "Numbered list",
|
|
48
56
|
"strikethrough": "Strikethrough",
|
|
49
|
-
"table": "
|
|
57
|
+
"table": "Table",
|
|
50
58
|
"taskList": "Task List",
|
|
51
59
|
"tex": "TeX Formula",
|
|
52
60
|
"underline": "Underline"
|
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
"math": {
|
|
28
28
|
"placeholder": "Por favor, introduzca la fórmula TeX"
|
|
29
29
|
},
|
|
30
|
+
"slash": {
|
|
31
|
+
"h1": "Título de nivel 1",
|
|
32
|
+
"h2": "Título de nivel 2",
|
|
33
|
+
"h3": "Título de nivel 3",
|
|
34
|
+
"hr": "Línea divisoria",
|
|
35
|
+
"table": "Tabla",
|
|
36
|
+
"tex": "Fórmula TeX"
|
|
37
|
+
},
|
|
30
38
|
"table": {
|
|
31
39
|
"delete": "Eliminar tabla",
|
|
32
40
|
"deleteColumn": "Eliminar columna",
|
|
@@ -46,7 +54,7 @@
|
|
|
46
54
|
"link": "Enlace",
|
|
47
55
|
"numberList": "Lista ordenada",
|
|
48
56
|
"strikethrough": "Tachado",
|
|
49
|
-
"table": "
|
|
57
|
+
"table": "tabla",
|
|
50
58
|
"taskList": "Lista de tareas",
|
|
51
59
|
"tex": "Fórmula TeX",
|
|
52
60
|
"underline": "Subrayado"
|
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
"math": {
|
|
28
28
|
"placeholder": "لطفاً فرمول TeX را وارد کنید"
|
|
29
29
|
},
|
|
30
|
+
"slash": {
|
|
31
|
+
"h1": "عنوان سطح یک",
|
|
32
|
+
"h2": "عنوان سطح دو",
|
|
33
|
+
"h3": "عنوان سطح سه",
|
|
34
|
+
"hr": "خط جداکننده",
|
|
35
|
+
"table": "جدول",
|
|
36
|
+
"tex": "فرمول TeX"
|
|
37
|
+
},
|
|
30
38
|
"table": {
|
|
31
39
|
"delete": "حذف جدول",
|
|
32
40
|
"deleteColumn": "حذف ستون",
|
|
@@ -46,7 +54,7 @@
|
|
|
46
54
|
"link": "پیوند",
|
|
47
55
|
"numberList": "فهرست شمارهدار",
|
|
48
56
|
"strikethrough": "خط خورده",
|
|
49
|
-
"table": "
|
|
57
|
+
"table": "جدول",
|
|
50
58
|
"taskList": "فهرست وظایف",
|
|
51
59
|
"tex": "فرمول TeX",
|
|
52
60
|
"underline": "زیرخط"
|
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
"math": {
|
|
28
28
|
"placeholder": "Veuillez saisir une formule TeX"
|
|
29
29
|
},
|
|
30
|
+
"slash": {
|
|
31
|
+
"h1": "Titre de niveau 1",
|
|
32
|
+
"h2": "Titre de niveau 2",
|
|
33
|
+
"h3": "Titre de niveau 3",
|
|
34
|
+
"hr": "Ligne de séparation",
|
|
35
|
+
"table": "Tableau",
|
|
36
|
+
"tex": "Formule TeX"
|
|
37
|
+
},
|
|
30
38
|
"table": {
|
|
31
39
|
"delete": "Supprimer le tableau",
|
|
32
40
|
"deleteColumn": "Supprimer la colonne",
|
|
@@ -46,7 +54,7 @@
|
|
|
46
54
|
"link": "Lien",
|
|
47
55
|
"numberList": "Liste numérotée",
|
|
48
56
|
"strikethrough": "Barré",
|
|
49
|
-
"table": "
|
|
57
|
+
"table": "tableau",
|
|
50
58
|
"taskList": "Liste des tâches",
|
|
51
59
|
"tex": "Formule TeX",
|
|
52
60
|
"underline": "Souligné"
|
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
"math": {
|
|
28
28
|
"placeholder": "Inserisci la formula TeX"
|
|
29
29
|
},
|
|
30
|
+
"slash": {
|
|
31
|
+
"h1": "Titolo di primo livello",
|
|
32
|
+
"h2": "Titolo di secondo livello",
|
|
33
|
+
"h3": "Titolo di terzo livello",
|
|
34
|
+
"hr": "Linea di separazione",
|
|
35
|
+
"table": "Tabella",
|
|
36
|
+
"tex": "Formula TeX"
|
|
37
|
+
},
|
|
30
38
|
"table": {
|
|
31
39
|
"delete": "Elimina tabella",
|
|
32
40
|
"deleteColumn": "Elimina colonna",
|
|
@@ -46,7 +54,7 @@
|
|
|
46
54
|
"link": "Collegamento",
|
|
47
55
|
"numberList": "Elenco numerato",
|
|
48
56
|
"strikethrough": "Testo barrato",
|
|
49
|
-
"table": "
|
|
57
|
+
"table": "tabella",
|
|
50
58
|
"taskList": "Elenco attività",
|
|
51
59
|
"tex": "Formula TeX",
|
|
52
60
|
"underline": "Sottolineato"
|
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
"math": {
|
|
28
28
|
"placeholder": "TeX 公式を入力してください"
|
|
29
29
|
},
|
|
30
|
+
"slash": {
|
|
31
|
+
"h1": "見出し1",
|
|
32
|
+
"h2": "見出し2",
|
|
33
|
+
"h3": "見出し3",
|
|
34
|
+
"hr": "区切り線",
|
|
35
|
+
"table": "表",
|
|
36
|
+
"tex": "TeX 数式"
|
|
37
|
+
},
|
|
30
38
|
"table": {
|
|
31
39
|
"delete": "表を削除",
|
|
32
40
|
"deleteColumn": "列を削除",
|
|
@@ -46,7 +54,7 @@
|
|
|
46
54
|
"link": "リンク",
|
|
47
55
|
"numberList": "番号付きリスト",
|
|
48
56
|
"strikethrough": "取り消し線",
|
|
49
|
-
"table": "
|
|
57
|
+
"table": "表",
|
|
50
58
|
"taskList": "タスクリスト",
|
|
51
59
|
"tex": "TeX 公式",
|
|
52
60
|
"underline": "下線"
|
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
"math": {
|
|
28
28
|
"placeholder": "TeX 수식을 입력하세요"
|
|
29
29
|
},
|
|
30
|
+
"slash": {
|
|
31
|
+
"h1": "1단계 제목",
|
|
32
|
+
"h2": "2단계 제목",
|
|
33
|
+
"h3": "3단계 제목",
|
|
34
|
+
"hr": "구분선",
|
|
35
|
+
"table": "표",
|
|
36
|
+
"tex": "TeX 수식"
|
|
37
|
+
},
|
|
30
38
|
"table": {
|
|
31
39
|
"delete": "테이블 삭제",
|
|
32
40
|
"deleteColumn": "열 삭제",
|
|
@@ -46,7 +54,7 @@
|
|
|
46
54
|
"link": "링크",
|
|
47
55
|
"numberList": "번호 매긴 목록",
|
|
48
56
|
"strikethrough": "취소선",
|
|
49
|
-
"table": "표
|
|
57
|
+
"table": "표",
|
|
50
58
|
"taskList": "작업 목록",
|
|
51
59
|
"tex": "TeX 수식",
|
|
52
60
|
"underline": "밑줄"
|
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
"math": {
|
|
28
28
|
"placeholder": "Voer TeX-formule in"
|
|
29
29
|
},
|
|
30
|
+
"slash": {
|
|
31
|
+
"h1": "Kop 1",
|
|
32
|
+
"h2": "Kop 2",
|
|
33
|
+
"h3": "Kop 3",
|
|
34
|
+
"hr": "Scheidingslijn",
|
|
35
|
+
"table": "Tabel",
|
|
36
|
+
"tex": "TeX-formule"
|
|
37
|
+
},
|
|
30
38
|
"table": {
|
|
31
39
|
"delete": "Tabel verwijderen",
|
|
32
40
|
"deleteColumn": "Kolom verwijderen",
|
|
@@ -46,7 +54,7 @@
|
|
|
46
54
|
"link": "Link",
|
|
47
55
|
"numberList": "Genummerde lijst",
|
|
48
56
|
"strikethrough": "Doorhalen",
|
|
49
|
-
"table": "
|
|
57
|
+
"table": "tabel",
|
|
50
58
|
"taskList": "Takenlijst",
|
|
51
59
|
"tex": "TeX-formule",
|
|
52
60
|
"underline": "Onderstrepen"
|
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
"math": {
|
|
28
28
|
"placeholder": "Wprowadź formułę TeX"
|
|
29
29
|
},
|
|
30
|
+
"slash": {
|
|
31
|
+
"h1": "Nagłówek poziomu 1",
|
|
32
|
+
"h2": "Nagłówek poziomu 2",
|
|
33
|
+
"h3": "Nagłówek poziomu 3",
|
|
34
|
+
"hr": "Linia pozioma",
|
|
35
|
+
"table": "Tabela",
|
|
36
|
+
"tex": "Formuła TeX"
|
|
37
|
+
},
|
|
30
38
|
"table": {
|
|
31
39
|
"delete": "Usuń tabelę",
|
|
32
40
|
"deleteColumn": "Usuń kolumnę",
|
|
@@ -46,7 +54,7 @@
|
|
|
46
54
|
"link": "Link",
|
|
47
55
|
"numberList": "Lista numerowana",
|
|
48
56
|
"strikethrough": "Przekreślenie",
|
|
49
|
-
"table": "
|
|
57
|
+
"table": "tabela",
|
|
50
58
|
"taskList": "Lista zadań",
|
|
51
59
|
"tex": "Formuła TeX",
|
|
52
60
|
"underline": "Podkreślenie"
|
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
"math": {
|
|
28
28
|
"placeholder": "Por favor, insira a fórmula TeX"
|
|
29
29
|
},
|
|
30
|
+
"slash": {
|
|
31
|
+
"h1": "Título de Nível 1",
|
|
32
|
+
"h2": "Título de Nível 2",
|
|
33
|
+
"h3": "Título de Nível 3",
|
|
34
|
+
"hr": "Linha Divisória",
|
|
35
|
+
"table": "Tabela",
|
|
36
|
+
"tex": "Fórmula TeX"
|
|
37
|
+
},
|
|
30
38
|
"table": {
|
|
31
39
|
"delete": "Excluir tabela",
|
|
32
40
|
"deleteColumn": "Excluir coluna",
|
|
@@ -46,7 +54,7 @@
|
|
|
46
54
|
"link": "Link",
|
|
47
55
|
"numberList": "Lista numerada",
|
|
48
56
|
"strikethrough": "Tachado",
|
|
49
|
-
"table": "
|
|
57
|
+
"table": "tabela",
|
|
50
58
|
"taskList": "Lista de Tarefas",
|
|
51
59
|
"tex": "Fórmula TeX",
|
|
52
60
|
"underline": "Sublinhado"
|
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
"math": {
|
|
28
28
|
"placeholder": "Введите формулу TeX"
|
|
29
29
|
},
|
|
30
|
+
"slash": {
|
|
31
|
+
"h1": "Заголовок первого уровня",
|
|
32
|
+
"h2": "Заголовок второго уровня",
|
|
33
|
+
"h3": "Заголовок третьего уровня",
|
|
34
|
+
"hr": "Разделитель",
|
|
35
|
+
"table": "Таблица",
|
|
36
|
+
"tex": "Формула TeX"
|
|
37
|
+
},
|
|
30
38
|
"table": {
|
|
31
39
|
"delete": "Удалить таблицу",
|
|
32
40
|
"deleteColumn": "Удалить столбец",
|
|
@@ -46,7 +54,7 @@
|
|
|
46
54
|
"link": "Ссылка",
|
|
47
55
|
"numberList": "Нумерованный список",
|
|
48
56
|
"strikethrough": "Зачёркнутый",
|
|
49
|
-
"table": "
|
|
57
|
+
"table": "таблица",
|
|
50
58
|
"taskList": "Список задач",
|
|
51
59
|
"tex": "Формула TeX",
|
|
52
60
|
"underline": "Подчёркнутый"
|
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
"math": {
|
|
28
28
|
"placeholder": "Lütfen TeX formülünü girin"
|
|
29
29
|
},
|
|
30
|
+
"slash": {
|
|
31
|
+
"h1": "Birinci Seviye Başlık",
|
|
32
|
+
"h2": "İkinci Seviye Başlık",
|
|
33
|
+
"h3": "Üçüncü Seviye Başlık",
|
|
34
|
+
"hr": "Ayırıcı Çizgi",
|
|
35
|
+
"table": "Tablo",
|
|
36
|
+
"tex": "TeX Formülü"
|
|
37
|
+
},
|
|
30
38
|
"table": {
|
|
31
39
|
"delete": "Tabloyu sil",
|
|
32
40
|
"deleteColumn": "Sütunu sil",
|
|
@@ -46,7 +54,7 @@
|
|
|
46
54
|
"link": "Bağlantı",
|
|
47
55
|
"numberList": "Numaralı liste",
|
|
48
56
|
"strikethrough": "Üstü çizili",
|
|
49
|
-
"table": "
|
|
57
|
+
"table": "tablo",
|
|
50
58
|
"taskList": "Görev Listesi",
|
|
51
59
|
"tex": "TeX Formülü",
|
|
52
60
|
"underline": "Altı çizili"
|
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
"math": {
|
|
28
28
|
"placeholder": "Vui lòng nhập công thức TeX"
|
|
29
29
|
},
|
|
30
|
+
"slash": {
|
|
31
|
+
"h1": "Tiêu đề cấp 1",
|
|
32
|
+
"h2": "Tiêu đề cấp 2",
|
|
33
|
+
"h3": "Tiêu đề cấp 3",
|
|
34
|
+
"hr": "Đường phân cách",
|
|
35
|
+
"table": "Bảng",
|
|
36
|
+
"tex": "Công thức TeX"
|
|
37
|
+
},
|
|
30
38
|
"table": {
|
|
31
39
|
"delete": "Xóa bảng",
|
|
32
40
|
"deleteColumn": "Xóa cột",
|
|
@@ -46,7 +54,7 @@
|
|
|
46
54
|
"link": "Liên kết",
|
|
47
55
|
"numberList": "Danh sách có thứ tự",
|
|
48
56
|
"strikethrough": "Gạch ngang",
|
|
49
|
-
"table": "
|
|
57
|
+
"table": "bảng",
|
|
50
58
|
"taskList": "Danh sách công việc",
|
|
51
59
|
"tex": "Công thức TeX",
|
|
52
60
|
"underline": "Gạch chân"
|
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
"math": {
|
|
28
28
|
"placeholder": "请输入 TeX 公式"
|
|
29
29
|
},
|
|
30
|
+
"slash": {
|
|
31
|
+
"h1": "一级标题",
|
|
32
|
+
"h2": "二级标题",
|
|
33
|
+
"h3": "三级标题",
|
|
34
|
+
"hr": "分割线",
|
|
35
|
+
"table": "表格",
|
|
36
|
+
"tex": "TeX 公式"
|
|
37
|
+
},
|
|
30
38
|
"table": {
|
|
31
39
|
"delete": "删除表格",
|
|
32
40
|
"deleteColumn": "删除列",
|
|
@@ -46,7 +54,7 @@
|
|
|
46
54
|
"link": "链接",
|
|
47
55
|
"numberList": "有序列表",
|
|
48
56
|
"strikethrough": "删除线",
|
|
49
|
-
"table": "
|
|
57
|
+
"table": "table",
|
|
50
58
|
"taskList": "任务列表",
|
|
51
59
|
"tex": "TeX 公式",
|
|
52
60
|
"underline": "下划线"
|
|
@@ -27,6 +27,14 @@
|
|
|
27
27
|
"math": {
|
|
28
28
|
"placeholder": "請輸入 TeX 公式"
|
|
29
29
|
},
|
|
30
|
+
"slash": {
|
|
31
|
+
"h1": "一級標題",
|
|
32
|
+
"h2": "二級標題",
|
|
33
|
+
"h3": "三級標題",
|
|
34
|
+
"hr": "分隔線",
|
|
35
|
+
"table": "表格",
|
|
36
|
+
"tex": "TeX 公式"
|
|
37
|
+
},
|
|
30
38
|
"table": {
|
|
31
39
|
"delete": "刪除表格",
|
|
32
40
|
"deleteColumn": "刪除列",
|
|
@@ -46,7 +54,7 @@
|
|
|
46
54
|
"link": "連結",
|
|
47
55
|
"numberList": "有序清單",
|
|
48
56
|
"strikethrough": "刪除線",
|
|
49
|
-
"table": "
|
|
57
|
+
"table": "表格",
|
|
50
58
|
"taskList": "任務列表",
|
|
51
59
|
"tex": "TeX 公式",
|
|
52
60
|
"underline": "底線"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lobehub/chat",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.128.0",
|
|
4
4
|
"description": "Lobe Chat - an open-source, high-performance chatbot framework that supports speech synthesis, multimodal, and extensible Function Call plugin system. Supports one-click free deployment of your private ChatGPT/LLM web application.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -155,7 +155,7 @@
|
|
|
155
155
|
"@lobehub/charts": "^2.0.0",
|
|
156
156
|
"@lobehub/chat-plugin-sdk": "^1.32.4",
|
|
157
157
|
"@lobehub/chat-plugins-gateway": "^1.9.0",
|
|
158
|
-
"@lobehub/editor": "^1.
|
|
158
|
+
"@lobehub/editor": "^1.8.0",
|
|
159
159
|
"@lobehub/icons": "^2.31.0",
|
|
160
160
|
"@lobehub/market-sdk": "^0.22.7",
|
|
161
161
|
"@lobehub/tts": "^2.0.1",
|
|
@@ -363,7 +363,7 @@
|
|
|
363
363
|
"typescript": "^5.9.2",
|
|
364
364
|
"unified": "^11.0.5",
|
|
365
365
|
"unist-util-visit": "^5.0.0",
|
|
366
|
-
"vite": "^
|
|
366
|
+
"vite": "^7.1.5",
|
|
367
367
|
"vitest": "^3.2.4"
|
|
368
368
|
},
|
|
369
369
|
"packageManager": "pnpm@10.15.1",
|
|
@@ -212,6 +212,52 @@ const qwenChatModels: AIChatModelCard[] = [
|
|
|
212
212
|
releasedAt: '2025-07-29',
|
|
213
213
|
type: 'chat',
|
|
214
214
|
},
|
|
215
|
+
{
|
|
216
|
+
abilities: {
|
|
217
|
+
functionCall: true,
|
|
218
|
+
reasoning: true,
|
|
219
|
+
},
|
|
220
|
+
contextWindowTokens: 131_072,
|
|
221
|
+
description:
|
|
222
|
+
'基于 Qwen3 的新一代思考模式开源模型,相较上一版本(通义千问3-235B-A22B-Thinking-2507)指令遵循能力有提升、模型总结回复更加精简。',
|
|
223
|
+
displayName: 'Qwen3 Next 80B A3B Thinking',
|
|
224
|
+
id: 'qwen3-next-80b-a3b-thinking',
|
|
225
|
+
maxOutput: 32_768,
|
|
226
|
+
organization: 'Qwen',
|
|
227
|
+
pricing: {
|
|
228
|
+
currency: 'CNY',
|
|
229
|
+
units: [
|
|
230
|
+
{ name: 'textInput', rate: 1, strategy: 'fixed', unit: 'millionTokens' },
|
|
231
|
+
{ name: 'textOutput', rate: 4, strategy: 'fixed', unit: 'millionTokens' },
|
|
232
|
+
],
|
|
233
|
+
},
|
|
234
|
+
releasedAt: '2025-09-12',
|
|
235
|
+
settings: {
|
|
236
|
+
extendParams: ['reasoningBudgetToken'],
|
|
237
|
+
},
|
|
238
|
+
type: 'chat',
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
abilities: {
|
|
242
|
+
functionCall: true,
|
|
243
|
+
},
|
|
244
|
+
contextWindowTokens: 131_072,
|
|
245
|
+
description:
|
|
246
|
+
'基于 Qwen3 的新一代非思考模式开源模型,相较上一版本(通义千问3-235B-A22B-Instruct-2507)中文文本理解能力更佳、逻辑推理能力有增强、文本生成类任务表现更好。',
|
|
247
|
+
displayName: 'Qwen3 Next 80B A3B Instruct',
|
|
248
|
+
id: 'qwen3-next-80b-a3b-instruct',
|
|
249
|
+
maxOutput: 32_768,
|
|
250
|
+
organization: 'Qwen',
|
|
251
|
+
pricing: {
|
|
252
|
+
currency: 'CNY',
|
|
253
|
+
units: [
|
|
254
|
+
{ name: 'textInput', rate: 1, strategy: 'fixed', unit: 'millionTokens' },
|
|
255
|
+
{ name: 'textOutput', rate: 10, strategy: 'fixed', unit: 'millionTokens' },
|
|
256
|
+
],
|
|
257
|
+
},
|
|
258
|
+
releasedAt: '2025-09-12',
|
|
259
|
+
type: 'chat',
|
|
260
|
+
},
|
|
215
261
|
{
|
|
216
262
|
abilities: {
|
|
217
263
|
functionCall: true,
|
|
@@ -295,6 +295,40 @@ describe('OpenAIStream', () => {
|
|
|
295
295
|
]);
|
|
296
296
|
});
|
|
297
297
|
|
|
298
|
+
it('should emit usage when choices are missing but usage exists', async () => {
|
|
299
|
+
const mockOpenAIStream = new ReadableStream({
|
|
300
|
+
start(controller) {
|
|
301
|
+
controller.enqueue({
|
|
302
|
+
id: '99',
|
|
303
|
+
usage: {
|
|
304
|
+
prompt_tokens: 1,
|
|
305
|
+
completion_tokens: 2,
|
|
306
|
+
total_tokens: 3,
|
|
307
|
+
prompt_cache_miss_tokens: 1,
|
|
308
|
+
},
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
controller.close();
|
|
312
|
+
},
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
const protocolStream = OpenAIStream(mockOpenAIStream);
|
|
316
|
+
|
|
317
|
+
const decoder = new TextDecoder();
|
|
318
|
+
const chunks: string[] = [];
|
|
319
|
+
|
|
320
|
+
// @ts-ignore
|
|
321
|
+
for await (const chunk of protocolStream) {
|
|
322
|
+
chunks.push(decoder.decode(chunk, { stream: true }));
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
expect(chunks).toEqual([
|
|
326
|
+
'id: 99\n',
|
|
327
|
+
'event: usage\n',
|
|
328
|
+
`data: {"inputCacheMissTokens":1,"inputTextTokens":1,"outputTextTokens":2,"totalInputTokens":1,"totalOutputTokens":2,"totalTokens":3}\n\n`,
|
|
329
|
+
]);
|
|
330
|
+
});
|
|
331
|
+
|
|
298
332
|
it('should handle error when there is not correct error', async () => {
|
|
299
333
|
const mockOpenAIStream = new ReadableStream({
|
|
300
334
|
start(controller) {
|
|
@@ -331,8 +365,8 @@ describe('OpenAIStream', () => {
|
|
|
331
365
|
'event: text',
|
|
332
366
|
`data: "Hello"\n`,
|
|
333
367
|
'id: 1',
|
|
334
|
-
'event:
|
|
335
|
-
`data: {"
|
|
368
|
+
'event: data',
|
|
369
|
+
`data: {"id":"1"}\n`,
|
|
336
370
|
].map((i) => `${i}\n`),
|
|
337
371
|
);
|
|
338
372
|
});
|
|
@@ -64,8 +64,7 @@ const transformOpenAIStream = (
|
|
|
64
64
|
|
|
65
65
|
try {
|
|
66
66
|
// maybe need another structure to add support for multiple choices
|
|
67
|
-
|
|
68
|
-
if (!item) {
|
|
67
|
+
if (!Array.isArray(chunk.choices) || chunk.choices.length === 0) {
|
|
69
68
|
if (chunk.usage) {
|
|
70
69
|
const usage = chunk.usage;
|
|
71
70
|
return { data: convertUsage(usage, provider), id: chunk.id, type: 'usage' };
|
|
@@ -74,6 +73,8 @@ const transformOpenAIStream = (
|
|
|
74
73
|
return { data: chunk, id: chunk.id, type: 'data' };
|
|
75
74
|
}
|
|
76
75
|
|
|
76
|
+
const item = chunk.choices[0];
|
|
77
|
+
|
|
77
78
|
if (item && typeof item.delta?.tool_calls === 'object' && item.delta.tool_calls?.length > 0) {
|
|
78
79
|
// tools calling
|
|
79
80
|
const tool_calls = item.delta.tool_calls.filter(
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export * from './core/BaseAI';
|
|
2
2
|
export { ModelRuntime } from './core/ModelRuntime';
|
|
3
3
|
export { createOpenAICompatibleRuntime } from './core/openaiCompatibleFactory';
|
|
4
|
+
export * from './core/RouterRuntime';
|
|
4
5
|
export * from './helpers';
|
|
5
6
|
export { LobeAkashChatAI } from './providers/akashchat';
|
|
6
7
|
export { LobeAnthropicAI } from './providers/anthropic';
|
|
@@ -47,6 +47,7 @@ export interface UserKeyVaults extends SearchEngineKeyVaults {
|
|
|
47
47
|
azureai?: AzureOpenAIKeyVault;
|
|
48
48
|
baichuan?: OpenAICompatibleKeyVault;
|
|
49
49
|
bedrock?: AWSBedrockKeyVault;
|
|
50
|
+
bfl?: any;
|
|
50
51
|
cloudflare?: CloudflareKeyVault;
|
|
51
52
|
cohere?: OpenAICompatibleKeyVault;
|
|
52
53
|
cometapi?: OpenAICompatibleKeyVault;
|
|
@@ -10,6 +10,8 @@ import { Center, Flexbox } from 'react-layout-kit';
|
|
|
10
10
|
import { useChatInputStore } from '@/features/ChatInput/store';
|
|
11
11
|
import { useChatStore } from '@/store/chat';
|
|
12
12
|
import { chatSelectors } from '@/store/chat/selectors';
|
|
13
|
+
import { useGlobalStore } from '@/store/global';
|
|
14
|
+
import { systemStatusSelectors } from '@/store/global/selectors';
|
|
13
15
|
|
|
14
16
|
import ActionBar from '../ActionBar';
|
|
15
17
|
import InputEditor from '../InputEditor';
|
|
@@ -49,6 +51,10 @@ const useStyles = createStyles(({ css, token }) => ({
|
|
|
49
51
|
|
|
50
52
|
const DesktopChatInput = memo<{ showFootnote?: boolean }>(({ showFootnote }) => {
|
|
51
53
|
const { t } = useTranslation('chat');
|
|
54
|
+
const [chatInputHeight, updateSystemStatus] = useGlobalStore((s) => [
|
|
55
|
+
systemStatusSelectors.chatInputHeight(s),
|
|
56
|
+
s.updateSystemStatus,
|
|
57
|
+
]);
|
|
52
58
|
const [slashMenuRef, expand, showTypoBar, editor, leftActions] = useChatInputStore((s) => [
|
|
53
59
|
s.slashMenuRef,
|
|
54
60
|
s.expand,
|
|
@@ -77,6 +83,7 @@ const DesktopChatInput = memo<{ showFootnote?: boolean }>(({ showFootnote }) =>
|
|
|
77
83
|
paddingInline={12}
|
|
78
84
|
>
|
|
79
85
|
<ChatInput
|
|
86
|
+
defaultHeight={chatInputHeight || 32}
|
|
80
87
|
footer={
|
|
81
88
|
<ChatInputActionBar
|
|
82
89
|
left={<ActionBar />}
|
|
@@ -88,12 +95,13 @@ const DesktopChatInput = memo<{ showFootnote?: boolean }>(({ showFootnote }) =>
|
|
|
88
95
|
}
|
|
89
96
|
fullscreen={expand}
|
|
90
97
|
header={showTypoBar && <TypoBar />}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
},
|
|
98
|
+
maxHeight={320}
|
|
99
|
+
minHeight={36}
|
|
100
|
+
onSizeChange={(height) => {
|
|
101
|
+
updateSystemStatus({ chatInputHeight: height });
|
|
96
102
|
}}
|
|
103
|
+
resize={true}
|
|
104
|
+
slashMenuRef={slashMenuRef}
|
|
97
105
|
>
|
|
98
106
|
{expand && fileNode}
|
|
99
107
|
<InputEditor />
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { KeyEnum } from '@lobechat/types';
|
|
2
|
+
import { Hotkey, combineKeys } from '@lobehub/ui';
|
|
3
|
+
import { memo } from 'react';
|
|
4
|
+
import { Trans, useTranslation } from 'react-i18next';
|
|
5
|
+
import { Flexbox } from 'react-layout-kit';
|
|
6
|
+
|
|
7
|
+
import { useUserStore } from '@/store/user';
|
|
8
|
+
import { preferenceSelectors } from '@/store/user/selectors';
|
|
9
|
+
|
|
10
|
+
const Placeholder = memo(() => {
|
|
11
|
+
const { t } = useTranslation(['editor', 'chat']);
|
|
12
|
+
|
|
13
|
+
const useCmdEnterToSend = useUserStore(preferenceSelectors.useCmdEnterToSend);
|
|
14
|
+
const wrapperShortcut = useCmdEnterToSend
|
|
15
|
+
? KeyEnum.Enter
|
|
16
|
+
: combineKeys([KeyEnum.Mod, KeyEnum.Enter]);
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<Flexbox align={'center'} as={'span'} gap={4} horizontal>
|
|
20
|
+
{t('sendPlaceholder', { ns: 'chat' }).replace('...', ', ')}
|
|
21
|
+
<Trans
|
|
22
|
+
as={'span'}
|
|
23
|
+
components={{
|
|
24
|
+
key: (
|
|
25
|
+
<Hotkey
|
|
26
|
+
as={'span'}
|
|
27
|
+
keys={wrapperShortcut}
|
|
28
|
+
style={{ color: 'inherit' }}
|
|
29
|
+
styles={{ kbdStyle: { color: 'inhert' } }}
|
|
30
|
+
variant={'borderless'}
|
|
31
|
+
/>
|
|
32
|
+
),
|
|
33
|
+
}}
|
|
34
|
+
i18nKey={'input.warpWithKey'}
|
|
35
|
+
ns={'chat'}
|
|
36
|
+
/>
|
|
37
|
+
{'...'}
|
|
38
|
+
</Flexbox>
|
|
39
|
+
);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
export default Placeholder;
|
|
@@ -2,7 +2,6 @@ import { isDesktop } from '@lobechat/const';
|
|
|
2
2
|
import { HotkeyEnum, KeyEnum } from '@lobechat/types';
|
|
3
3
|
import { isCommandPressed } from '@lobechat/utils';
|
|
4
4
|
import {
|
|
5
|
-
INSERT_TABLE_COMMAND,
|
|
6
5
|
ReactCodePlugin,
|
|
7
6
|
ReactCodeblockPlugin,
|
|
8
7
|
ReactHRPlugin,
|
|
@@ -12,17 +11,16 @@ import {
|
|
|
12
11
|
ReactTablePlugin,
|
|
13
12
|
} from '@lobehub/editor';
|
|
14
13
|
import { Editor, FloatMenu, SlashMenu, useEditorState } from '@lobehub/editor/react';
|
|
15
|
-
import {
|
|
16
|
-
import { Table2Icon } from 'lucide-react';
|
|
14
|
+
import { combineKeys } from '@lobehub/ui';
|
|
17
15
|
import { memo, useEffect, useRef } from 'react';
|
|
18
16
|
import { useHotkeysContext } from 'react-hotkeys-hook';
|
|
19
|
-
import { Trans, useTranslation } from 'react-i18next';
|
|
20
|
-
import { Flexbox } from 'react-layout-kit';
|
|
21
17
|
|
|
22
18
|
import { useUserStore } from '@/store/user';
|
|
23
19
|
import { preferenceSelectors, settingsSelectors } from '@/store/user/selectors';
|
|
24
20
|
|
|
25
21
|
import { useChatInputStore, useStoreApi } from '../store';
|
|
22
|
+
import Placeholder from './Placeholder';
|
|
23
|
+
import { useSlashItems } from './useSlashItems';
|
|
26
24
|
|
|
27
25
|
const InputEditor = memo<{ defaultRows?: number }>(() => {
|
|
28
26
|
const [editor, slashMenuRef, send, updateMarkdownContent, expand] = useChatInputStore((s) => [
|
|
@@ -37,14 +35,11 @@ const InputEditor = memo<{ defaultRows?: number }>(() => {
|
|
|
37
35
|
const state = useEditorState(editor);
|
|
38
36
|
const hotkey = useUserStore(settingsSelectors.getHotkeyById(HotkeyEnum.AddUserMessage));
|
|
39
37
|
const { enableScope, disableScope } = useHotkeysContext();
|
|
40
|
-
const
|
|
38
|
+
const slashItems = useSlashItems();
|
|
41
39
|
|
|
42
40
|
const isChineseInput = useRef(false);
|
|
43
41
|
|
|
44
42
|
const useCmdEnterToSend = useUserStore(preferenceSelectors.useCmdEnterToSend);
|
|
45
|
-
const wrapperShortcut = useCmdEnterToSend
|
|
46
|
-
? KeyEnum.Enter
|
|
47
|
-
: combineKeys([KeyEnum.Mod, KeyEnum.Enter]);
|
|
48
43
|
|
|
49
44
|
useEffect(() => {
|
|
50
45
|
const fn = (e: BeforeUnloadEvent) => {
|
|
@@ -113,28 +108,7 @@ const InputEditor = memo<{ defaultRows?: number }>(() => {
|
|
|
113
108
|
}
|
|
114
109
|
}
|
|
115
110
|
}}
|
|
116
|
-
placeholder={
|
|
117
|
-
<Flexbox align={'center'} as={'span'} gap={4} horizontal>
|
|
118
|
-
{t('sendPlaceholder', { ns: 'chat' }).replace('...', ', ')}
|
|
119
|
-
<Trans
|
|
120
|
-
as={'span'}
|
|
121
|
-
components={{
|
|
122
|
-
key: (
|
|
123
|
-
<Hotkey
|
|
124
|
-
as={'span'}
|
|
125
|
-
keys={wrapperShortcut}
|
|
126
|
-
style={{ color: 'inherit' }}
|
|
127
|
-
styles={{ kbdStyle: { color: 'inhert' } }}
|
|
128
|
-
variant={'borderless'}
|
|
129
|
-
/>
|
|
130
|
-
),
|
|
131
|
-
}}
|
|
132
|
-
i18nKey={'input.warpWithKey'}
|
|
133
|
-
ns={'chat'}
|
|
134
|
-
/>
|
|
135
|
-
{'...'}
|
|
136
|
-
</Flexbox>
|
|
137
|
-
}
|
|
111
|
+
placeholder={<Placeholder />}
|
|
138
112
|
plugins={[
|
|
139
113
|
ReactListPlugin,
|
|
140
114
|
ReactLinkPlugin,
|
|
@@ -151,16 +125,7 @@ const InputEditor = memo<{ defaultRows?: number }>(() => {
|
|
|
151
125
|
}),
|
|
152
126
|
]}
|
|
153
127
|
slashOption={{
|
|
154
|
-
items:
|
|
155
|
-
{
|
|
156
|
-
icon: Table2Icon,
|
|
157
|
-
key: 'table',
|
|
158
|
-
label: t('typobar.table'),
|
|
159
|
-
onSelect: (editor) => {
|
|
160
|
-
editor.dispatchCommand(INSERT_TABLE_COMMAND, { columns: '3', rows: '3' });
|
|
161
|
-
},
|
|
162
|
-
},
|
|
163
|
-
],
|
|
128
|
+
items: slashItems,
|
|
164
129
|
renderComp: expand
|
|
165
130
|
? undefined
|
|
166
131
|
: (props) => {
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import {
|
|
2
|
+
INSERT_HEADING_COMMAND,
|
|
3
|
+
INSERT_HORIZONTAL_RULE_COMMAND,
|
|
4
|
+
INSERT_MATH_COMMAND,
|
|
5
|
+
INSERT_TABLE_COMMAND,
|
|
6
|
+
SlashOptions,
|
|
7
|
+
} from '@lobehub/editor';
|
|
8
|
+
import { Text } from '@lobehub/ui';
|
|
9
|
+
import {
|
|
10
|
+
Heading1Icon,
|
|
11
|
+
Heading2Icon,
|
|
12
|
+
Heading3Icon,
|
|
13
|
+
MinusIcon,
|
|
14
|
+
SigmaIcon,
|
|
15
|
+
Table2Icon,
|
|
16
|
+
} from 'lucide-react';
|
|
17
|
+
import { useMemo } from 'react';
|
|
18
|
+
import { useTranslation } from 'react-i18next';
|
|
19
|
+
|
|
20
|
+
export const useSlashItems = (): SlashOptions['items'] => {
|
|
21
|
+
const { t } = useTranslation('editor');
|
|
22
|
+
return useMemo(() => {
|
|
23
|
+
const data: SlashOptions['items'] = [
|
|
24
|
+
{
|
|
25
|
+
icon: Heading1Icon,
|
|
26
|
+
key: 'h1',
|
|
27
|
+
label: t('slash.h1'),
|
|
28
|
+
onSelect: (editor) => {
|
|
29
|
+
editor.dispatchCommand(INSERT_HEADING_COMMAND, { tag: 'h1' });
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
icon: Heading2Icon,
|
|
34
|
+
key: 'h2',
|
|
35
|
+
label: t('slash.h2'),
|
|
36
|
+
onSelect: (editor) => {
|
|
37
|
+
editor.dispatchCommand(INSERT_HEADING_COMMAND, { tag: 'h2' });
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
icon: Heading3Icon,
|
|
42
|
+
key: 'h3',
|
|
43
|
+
label: t('slash.h3'),
|
|
44
|
+
onSelect: (editor) => {
|
|
45
|
+
editor.dispatchCommand(INSERT_HEADING_COMMAND, { tag: 'h3' });
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
|
|
49
|
+
{
|
|
50
|
+
type: 'divider',
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
icon: MinusIcon,
|
|
54
|
+
key: 'hr',
|
|
55
|
+
label: t('slash.hr'),
|
|
56
|
+
onSelect: (editor) => {
|
|
57
|
+
editor.dispatchCommand(INSERT_HORIZONTAL_RULE_COMMAND, {});
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
icon: Table2Icon,
|
|
62
|
+
key: 'table',
|
|
63
|
+
label: t('slash.table'),
|
|
64
|
+
onSelect: (editor) => {
|
|
65
|
+
editor.dispatchCommand(INSERT_TABLE_COMMAND, { columns: '3', rows: '3' });
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
icon: SigmaIcon,
|
|
70
|
+
key: 'tex',
|
|
71
|
+
label: t('slash.tex'),
|
|
72
|
+
onSelect: (editor) => {
|
|
73
|
+
editor.dispatchCommand(INSERT_MATH_COMMAND, { code: 'x^2 + y^2 = z^2' });
|
|
74
|
+
queueMicrotask(() => {
|
|
75
|
+
editor.focus();
|
|
76
|
+
});
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
];
|
|
80
|
+
return data.map((item) => {
|
|
81
|
+
if (item.type === 'divider') return item;
|
|
82
|
+
return {
|
|
83
|
+
...item,
|
|
84
|
+
extra: (
|
|
85
|
+
<Text code fontSize={12} type={'secondary'}>
|
|
86
|
+
{item.key}
|
|
87
|
+
</Text>
|
|
88
|
+
),
|
|
89
|
+
};
|
|
90
|
+
});
|
|
91
|
+
}, [t]);
|
|
92
|
+
};
|
|
@@ -147,14 +147,7 @@ const TypoBar = memo(() => {
|
|
|
147
147
|
|
|
148
148
|
return (
|
|
149
149
|
<ChatInputActionBar
|
|
150
|
-
left={
|
|
151
|
-
<ChatInputActions
|
|
152
|
-
items={items}
|
|
153
|
-
onClick={() => {
|
|
154
|
-
editor?.focus();
|
|
155
|
-
}}
|
|
156
|
-
/>
|
|
157
|
-
}
|
|
150
|
+
left={<ChatInputActions items={items} />}
|
|
158
151
|
style={{
|
|
159
152
|
background: theme.colorFillQuaternary,
|
|
160
153
|
borderTopLeftRadius: 8,
|
|
@@ -27,6 +27,14 @@ export default {
|
|
|
27
27
|
math: {
|
|
28
28
|
placeholder: '请输入 TeX 公式',
|
|
29
29
|
},
|
|
30
|
+
slash: {
|
|
31
|
+
h1: '一级标题',
|
|
32
|
+
h2: '二级标题',
|
|
33
|
+
h3: '三级标题',
|
|
34
|
+
hr: '分割线',
|
|
35
|
+
table: '表格',
|
|
36
|
+
tex: 'TeX 公式',
|
|
37
|
+
},
|
|
30
38
|
table: {
|
|
31
39
|
delete: '删除表格',
|
|
32
40
|
deleteColumn: '删除列',
|
|
@@ -46,7 +54,7 @@ export default {
|
|
|
46
54
|
link: '链接',
|
|
47
55
|
numberList: '有序列表',
|
|
48
56
|
strikethrough: '删除线',
|
|
49
|
-
table: '
|
|
57
|
+
table: 'table',
|
|
50
58
|
taskList: '任务列表',
|
|
51
59
|
tex: 'TeX 公式',
|
|
52
60
|
underline: '下划线',
|
|
@@ -47,6 +47,7 @@ export enum ProfileTabs {
|
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
export interface SystemStatus {
|
|
50
|
+
chatInputHeight?: number;
|
|
50
51
|
expandInputActionbar?: boolean;
|
|
51
52
|
// which sessionGroup should expand
|
|
52
53
|
expandSessionGroupKeys: string[];
|
|
@@ -115,6 +116,7 @@ export interface GlobalState {
|
|
|
115
116
|
}
|
|
116
117
|
|
|
117
118
|
export const INITIAL_STATUS = {
|
|
119
|
+
chatInputHeight: 64,
|
|
118
120
|
expandInputActionbar: true,
|
|
119
121
|
expandSessionGroupKeys: [SessionDefaultGroup.Pinned, SessionDefaultGroup.Default],
|
|
120
122
|
filePanelWidth: 320,
|
|
@@ -29,6 +29,7 @@ const filePanelWidth = (s: GlobalState) => s.status.filePanelWidth;
|
|
|
29
29
|
const imagePanelWidth = (s: GlobalState) => s.status.imagePanelWidth;
|
|
30
30
|
const imageTopicPanelWidth = (s: GlobalState) => s.status.imageTopicPanelWidth;
|
|
31
31
|
const wideScreen = (s: GlobalState) => !s.status.noWideScreen;
|
|
32
|
+
const chatInputHeight = (s: GlobalState) => s.status.chatInputHeight || 64;
|
|
32
33
|
const expandInputActionbar = (s: GlobalState) => s.status.expandInputActionbar;
|
|
33
34
|
const isStatusInit = (s: GlobalState) => !!s.isStatusInit;
|
|
34
35
|
const isPgliteNotEnabled = (s: GlobalState) =>
|
|
@@ -63,6 +64,7 @@ const getAgentSystemRoleExpanded =
|
|
|
63
64
|
};
|
|
64
65
|
|
|
65
66
|
export const systemStatusSelectors = {
|
|
67
|
+
chatInputHeight,
|
|
66
68
|
expandInputActionbar,
|
|
67
69
|
filePanelWidth,
|
|
68
70
|
getAgentSystemRoleExpanded,
|