@lobehub/lobehub 2.0.0-next.212 → 2.0.0-next.213

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/.github/workflows/auto-i18n.yml +1 -1
  2. package/.github/workflows/bundle-analyzer.yml +1 -1
  3. package/.github/workflows/claude-auto-testing.yml +1 -1
  4. package/.github/workflows/claude-dedupe-issues.yml +1 -1
  5. package/.github/workflows/claude-issue-triage.yml +1 -1
  6. package/.github/workflows/claude-translate-comments.yml +1 -1
  7. package/.github/workflows/claude-translator.yml +1 -1
  8. package/.github/workflows/claude.yml +1 -1
  9. package/.github/workflows/desktop-build-electron.yml +2 -2
  10. package/.github/workflows/e2e.yml +1 -1
  11. package/.github/workflows/issue-auto-close-duplicates.yml +1 -1
  12. package/.github/workflows/lighthouse.yml +2 -2
  13. package/.github/workflows/lock-closed-issues.yml +1 -1
  14. package/.github/workflows/manual-build-desktop.yml +6 -6
  15. package/.github/workflows/pr-build-desktop.yml +5 -5
  16. package/.github/workflows/pr-build-docker.yml +2 -2
  17. package/.github/workflows/release-desktop-beta.yml +4 -4
  18. package/.github/workflows/release-docker.yml +2 -2
  19. package/.github/workflows/release.yml +1 -1
  20. package/.github/workflows/sync-database-schema.yml +1 -1
  21. package/.github/workflows/sync.yml +1 -1
  22. package/.github/workflows/test.yml +5 -5
  23. package/.github/workflows/verify-desktop-patch.yml +1 -1
  24. package/CHANGELOG.md +33 -0
  25. package/changelog/v1.json +9 -0
  26. package/locales/ar/models.json +35 -4
  27. package/locales/ar/providers.json +1 -0
  28. package/locales/bg-BG/models.json +24 -1
  29. package/locales/bg-BG/providers.json +1 -0
  30. package/locales/de-DE/models.json +30 -1
  31. package/locales/de-DE/providers.json +1 -0
  32. package/locales/en-US/models.json +1 -0
  33. package/locales/en-US/providers.json +1 -0
  34. package/locales/es-ES/models.json +32 -1
  35. package/locales/es-ES/providers.json +1 -0
  36. package/locales/fa-IR/models.json +48 -1
  37. package/locales/fa-IR/providers.json +1 -0
  38. package/locales/fr-FR/models.json +47 -1
  39. package/locales/fr-FR/providers.json +1 -0
  40. package/locales/it-IT/models.json +32 -1
  41. package/locales/it-IT/providers.json +1 -0
  42. package/locales/ja-JP/models.json +2 -1
  43. package/locales/ja-JP/providers.json +1 -0
  44. package/locales/ko-KR/models.json +24 -1
  45. package/locales/ko-KR/providers.json +1 -0
  46. package/locales/nl-NL/models.json +46 -1
  47. package/locales/nl-NL/providers.json +1 -0
  48. package/locales/pl-PL/models.json +41 -1
  49. package/locales/pl-PL/providers.json +1 -0
  50. package/locales/pt-BR/models.json +32 -1
  51. package/locales/pt-BR/providers.json +1 -0
  52. package/locales/ru-RU/models.json +54 -2
  53. package/locales/ru-RU/providers.json +1 -0
  54. package/locales/tr-TR/models.json +32 -1
  55. package/locales/tr-TR/providers.json +1 -0
  56. package/locales/vi-VN/models.json +37 -1
  57. package/locales/vi-VN/providers.json +1 -0
  58. package/locales/zh-CN/models.json +24 -3
  59. package/locales/zh-CN/providers.json +1 -0
  60. package/locales/zh-TW/models.json +11 -1
  61. package/locales/zh-TW/providers.json +1 -0
  62. package/package.json +1 -1
  63. package/packages/context-engine/src/engine/messages/types.ts +1 -1
  64. package/packages/model-runtime/src/core/BaseAI.ts +1 -1
  65. package/packages/model-runtime/src/core/streams/qwen.test.ts +140 -0
  66. package/packages/model-runtime/src/core/streams/qwen.ts +17 -5
  67. package/packages/model-runtime/src/types/chat.ts +12 -12
  68. package/packages/model-runtime/src/types/error.ts +1 -1
  69. package/packages/model-runtime/src/types/image.ts +1 -1
  70. package/src/app/[variants]/(main)/chat/features/Conversation/Header/index.tsx +2 -1
  71. package/src/server/services/comfyui/config/constants.ts +7 -7
  72. package/src/server/services/comfyui/config/promptToolConst.ts +26 -26
  73. package/src/server/services/comfyui/utils/promptSplitter.ts +23 -23
  74. package/src/server/services/comfyui/utils/weightDType.ts +4 -5
@@ -481,6 +481,16 @@
481
481
  "fal-ai/nano-banana.description": "Nano Banana 是 Google 最新、最快且最高效的原生多模態模型,支援透過對話進行圖像生成與編輯。",
482
482
  "fal-ai/qwen-image-edit.description": "來自 Qwen 團隊的專業圖像編輯模型,支援語義與外觀編輯,能精準處理中英文文字,並實現風格轉換、物體旋轉等高品質編輯。",
483
483
  "fal-ai/qwen-image.description": "來自 Qwen 團隊的強大圖像生成模型,具備優秀的中文文字渲染與多樣化視覺風格。",
484
+ "flux-1-schnell.description": "來自黑森林實驗室的 12B 參數文字轉圖像模型,透過潛在對抗擴散蒸餾技術,在 1 至 4 步內生成高品質圖像。其表現媲美封閉式替代方案,並以 Apache-2.0 授權釋出,供個人、研究與商業用途。",
485
+ "flux-dev.description": "FLUX.1 [dev] 是一款開放權重的蒸餾模型,僅限非商業用途。它保有接近專業水準的圖像品質與指令遵循能力,同時運行更高效,資源使用優於同等大小的標準模型。",
486
+ "flux-kontext-max.description": "最先進的語境圖像生成與編輯技術,結合文字與圖像輸入,實現精準且一致的結果。",
487
+ "flux-kontext-pro.description": "最先進的語境圖像生成與編輯技術,結合文字與圖像輸入,實現精準且一致的結果。",
488
+ "flux-merged.description": "FLUX.1-merged 結合了「DEV」版本的深層特徵與「Schnell」版本的高速優勢,拓展性能極限並擴大應用範圍。",
489
+ "flux-pro-1.1-ultra.description": "支援 4MP 輸出的超高解析度圖像生成,10 秒內產出清晰圖像。",
490
+ "flux-pro-1.1.description": "升級版專業級圖像生成模型,具備卓越圖像品質與精準提示遵循能力。",
491
+ "flux-pro.description": "頂級商業圖像生成模型,擁有無與倫比的圖像品質與多樣化輸出能力。",
492
+ "flux-schnell.description": "FLUX.1 [schnell] 是最先進的開源少步驟模型,超越同類競品,甚至優於如 Midjourney v6.0 與 DALL-E 3(HD)等強大非蒸餾模型。其精細調校保留預訓練多樣性,顯著提升視覺品質、指令遵循、尺寸與比例變化、字體處理與輸出多樣性。",
493
+ "flux.1-schnell.description": "FLUX.1-schnell 是一款高效能圖像生成模型,支援快速多風格輸出。",
484
494
  "gemini-flash-latest.description": "Gemini Flash 最新版本",
485
495
  "gemini-flash-lite-latest.description": "Gemini Flash-Lite 最新版本",
486
496
  "gemini-pro-latest.description": "Gemini Pro 最新版本",
@@ -746,4 +756,4 @@
746
756
  "zai/glm-4.5.description": "GLM-4.5 系列專為代理設計。旗艦版 GLM-4.5 結合推理、編碼與代理能力,總參數 355B(啟用 32B),提供混合推理系統的雙模式運行。",
747
757
  "zai/glm-4.5v.description": "GLM-4.5V 建構於 GLM-4.5-Air 基礎上,延續 GLM-4.1V-Thinking 技術,並以強大的 106B MoE 架構擴展能力。",
748
758
  "zenmux/auto.description": "ZenMux 自動路由會根據您的請求,從支援的選項中選擇性價比最高、效能最佳的模型。"
749
- }
759
+ }
@@ -63,6 +63,7 @@
63
63
  "volcengine.description": "字節跳動的模型服務平台,提供安全、功能豐富且具成本效益的模型存取,並支援資料、微調、推理與評估的端到端工具鏈。",
64
64
  "wenxin.description": "文心是一個企業級的基礎模型與 AI 原生應用開發平台,提供生成式 AI 模型與應用流程的端到端工具。",
65
65
  "xai.description": "xAI 致力於加速科學發現,目標是深化人類對宇宙的理解。",
66
+ "xiaomimimo.description": "小米 MiMo 提供一項支援 OpenAI 相容 API 的對話模型服務。mimo-v2-flash 模型支援深度推理、串流輸出、函式呼叫、256K 上下文視窗,以及最多 128K 的輸出。",
66
67
  "xinference.description": "Xorbits Inference(Xinference)是一個開源平台,簡化 AI 模型的運行與整合,支援在本地或雲端運行開源 LLM、嵌入模型與多模態模型,打造強大的 AI 應用。",
67
68
  "zenmux.description": "ZenMux 是一個統一的 AI 聚合平台,支援 OpenAI、Anthropic、Google VertexAI 等,具備靈活路由功能,便於模型切換與管理。",
68
69
  "zeroone.description": "01.AI 推動以人為本的 AI 2.0 革命,透過大型語言模型創造經濟與社會價值,構建全新 AI 生態與商業模式。",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lobehub/lobehub",
3
- "version": "2.0.0-next.212",
3
+ "version": "2.0.0-next.213",
4
4
  "description": "LobeHub - an open-source,comprehensive AI Agent 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",
@@ -90,7 +90,7 @@ export interface UserMemoryIdentityItem {
90
90
  description?: string | null;
91
91
  id?: string;
92
92
  role?: string | null;
93
- /** Identity type: personal (角色), professional (职业), demographic (属性) */
93
+ /** Identity type: personal (role), professional (occupation), demographic (attribute) */
94
94
  type?: 'demographic' | 'personal' | 'professional' | string | null;
95
95
  [key: string]: unknown;
96
96
  }
@@ -36,7 +36,7 @@ export interface LobeRuntimeAI {
36
36
  options?: TextToSpeechOptions,
37
37
  ) => Promise<ArrayBuffer>;
38
38
 
39
- // 模型管理相关接口
39
+ // Model management related interface
40
40
  pullModel?(params: PullModelParams, options?: ModelRequestOptions): Promise<Response>;
41
41
  }
42
42
  /* eslint-enabled */
@@ -479,6 +479,146 @@ describe('QwenAIStream', () => {
479
479
  `data: [{"function":{"arguments":"","name":"get_weather"},"id":"call_123","index":0,"type":"function"}]\n\n`,
480
480
  ]);
481
481
  });
482
+
483
+ it('should handle mixed text content followed by streaming tool calls (DeepSeek style)', async () => {
484
+ // This test simulates the stream pattern from DeepSeek models via Qwen API
485
+ // where text content is streamed first, followed by incremental tool call chunks
486
+ const mockOpenAIStream = new ReadableStream({
487
+ start(controller) {
488
+ // Text content chunks with role in first chunk
489
+ controller.enqueue({
490
+ choices: [
491
+ {
492
+ delta: { content: '看来', role: 'assistant' },
493
+ finish_reason: null,
494
+ index: 0,
495
+ },
496
+ ],
497
+ id: 'chatcmpl-4f901cb2-91bc-9763-a2c8-3ed58e9f4075',
498
+ model: 'deepseek-v3',
499
+ object: 'chat.completion.chunk',
500
+ created: 1767574524,
501
+ });
502
+ controller.enqueue({
503
+ choices: [
504
+ {
505
+ delta: { content: '我的' },
506
+ finish_reason: null,
507
+ index: 0,
508
+ },
509
+ ],
510
+ id: 'chatcmpl-4f901cb2-91bc-9763-a2c8-3ed58e9f4075',
511
+ model: 'deepseek-v3',
512
+ object: 'chat.completion.chunk',
513
+ created: 1767574524,
514
+ });
515
+ controller.enqueue({
516
+ choices: [
517
+ {
518
+ delta: { content: '函数调用格式有误。' },
519
+ finish_reason: null,
520
+ index: 0,
521
+ },
522
+ ],
523
+ id: 'chatcmpl-4f901cb2-91bc-9763-a2c8-3ed58e9f4075',
524
+ model: 'deepseek-v3',
525
+ object: 'chat.completion.chunk',
526
+ created: 1767574524,
527
+ });
528
+
529
+ // First tool call chunk with id, name, and partial arguments
530
+ controller.enqueue({
531
+ choices: [
532
+ {
533
+ delta: {
534
+ tool_calls: [
535
+ {
536
+ id: 'call_ff00c42325d74b979990cb',
537
+ type: 'function',
538
+ function: {
539
+ name: 'modelscope-time____get_current_time____mcp',
540
+ arguments: '{"',
541
+ },
542
+ index: 0,
543
+ },
544
+ ],
545
+ },
546
+ finish_reason: null,
547
+ index: 0,
548
+ },
549
+ ],
550
+ id: 'chatcmpl-4f901cb2-91bc-9763-a2c8-3ed58e9f4075',
551
+ model: 'deepseek-v3',
552
+ object: 'chat.completion.chunk',
553
+ created: 1767574524,
554
+ });
555
+
556
+ // Subsequent tool call chunk with only incremental arguments (no id)
557
+ controller.enqueue({
558
+ choices: [
559
+ {
560
+ delta: {
561
+ tool_calls: [
562
+ {
563
+ type: 'function',
564
+ function: {
565
+ arguments: 'timezone":"America/New_York"}',
566
+ },
567
+ index: 0,
568
+ },
569
+ ],
570
+ },
571
+ finish_reason: null,
572
+ index: 0,
573
+ },
574
+ ],
575
+ id: 'chatcmpl-4f901cb2-91bc-9763-a2c8-3ed58e9f4075',
576
+ model: 'deepseek-v3',
577
+ object: 'chat.completion.chunk',
578
+ created: 1767574524,
579
+ });
580
+
581
+ controller.close();
582
+ },
583
+ });
584
+
585
+ const onTextMock = vi.fn();
586
+ const onToolCallMock = vi.fn();
587
+
588
+ const protocolStream = QwenAIStream(mockOpenAIStream, {
589
+ callbacks: {
590
+ onText: onTextMock,
591
+ onToolsCalling: onToolCallMock,
592
+ },
593
+ });
594
+
595
+ const decoder = new TextDecoder();
596
+ const chunks = [];
597
+
598
+ // @ts-ignore
599
+ for await (const chunk of protocolStream) {
600
+ chunks.push(decoder.decode(chunk, { stream: true }));
601
+ }
602
+
603
+ // Verify complete chunks array
604
+ expect(chunks).toEqual([
605
+ 'id: chatcmpl-4f901cb2-91bc-9763-a2c8-3ed58e9f4075\n',
606
+ 'event: text\n',
607
+ 'data: "看来"\n\n',
608
+ 'id: chatcmpl-4f901cb2-91bc-9763-a2c8-3ed58e9f4075\n',
609
+ 'event: text\n',
610
+ 'data: "我的"\n\n',
611
+ 'id: chatcmpl-4f901cb2-91bc-9763-a2c8-3ed58e9f4075\n',
612
+ 'event: text\n',
613
+ 'data: "函数调用格式有误。"\n\n',
614
+ 'id: chatcmpl-4f901cb2-91bc-9763-a2c8-3ed58e9f4075\n',
615
+ 'event: tool_calls\n',
616
+ 'data: [{"function":{"arguments":"{\\"","name":"modelscope-time____get_current_time____mcp"},"id":"call_ff00c42325d74b979990cb","index":0,"type":"function"}]\n\n',
617
+ 'id: chatcmpl-4f901cb2-91bc-9763-a2c8-3ed58e9f4075\n',
618
+ 'event: tool_calls\n',
619
+ 'data: [{"function":{"arguments":"timezone\\":\\"America/New_York\\"}","name":null},"id":"call_ff00c42325d74b979990cb","index":0,"type":"function"}]\n\n',
620
+ ]);
621
+ });
482
622
  });
483
623
 
484
624
  describe('transformQwenStream', () => {
@@ -70,8 +70,18 @@ export const transformQwenStream = (
70
70
 
71
71
  if (item.delta?.tool_calls) {
72
72
  return {
73
- data: item.delta.tool_calls.map(
74
- (value, index): StreamToolCallChunkData => ({
73
+ data: item.delta.tool_calls.map((value, index): StreamToolCallChunkData => {
74
+ // Store first tool call's info in streamContext for subsequent chunks
75
+ // (similar pattern to OpenAI stream handling)
76
+ if (streamContext && !streamContext.tool && value.id && value.function?.name) {
77
+ streamContext.tool = {
78
+ id: value.id,
79
+ index: typeof value.index !== 'undefined' ? value.index : index,
80
+ name: value.function.name,
81
+ };
82
+ }
83
+
84
+ return {
75
85
  // Qwen models may send tool_calls in two separate chunks:
76
86
  // 1. First chunk: {id, name} without arguments
77
87
  // 2. Second chunk: {id, arguments} without name
@@ -81,11 +91,13 @@ export const transformQwenStream = (
81
91
  arguments: value.function?.arguments ?? '',
82
92
  name: value.function?.name ?? null,
83
93
  },
84
- id: value.id || generateToolCallId(index, value.function?.name),
94
+ // For incremental chunks without id, use the stored tool id from streamContext
95
+ id:
96
+ value.id || streamContext?.tool?.id || generateToolCallId(index, value.function?.name),
85
97
  index: typeof value.index !== 'undefined' ? value.index : index,
86
98
  type: value.type || 'function',
87
- }),
88
- ),
99
+ };
100
+ }),
89
101
  id: chunk.id,
90
102
  type: 'tool_calls',
91
103
  } as StreamProtocolToolCallChunk;
@@ -62,15 +62,15 @@ export interface OpenAIChatMessage {
62
62
  export interface ChatStreamPayload {
63
63
  apiMode?: 'chatCompletion' | 'responses';
64
64
  /**
65
- * 开启上下文缓存
65
+ * Enable context caching
66
66
  */
67
67
  enabledContextCaching?: boolean;
68
68
  /**
69
- * 是否开启搜索
69
+ * Whether to enable search
70
70
  */
71
71
  enabledSearch?: boolean;
72
72
  /**
73
- * @title 控制生成文本中的惩罚系数,用于减少重复性
73
+ * @title Penalty coefficient for reducing repetitiveness in generated text
74
74
  * @default 0
75
75
  */
76
76
  frequency_penalty?: number;
@@ -83,23 +83,23 @@ export interface ChatStreamPayload {
83
83
  */
84
84
  imageResolution?: '1K' | '2K' | '4K';
85
85
  /**
86
- * @title 生成文本的最大长度
86
+ * @title Maximum length of generated text
87
87
  */
88
88
  max_tokens?: number;
89
89
  /**
90
- * @title 聊天信息列表
90
+ * @title List of chat messages
91
91
  */
92
92
  messages: OpenAIChatMessage[];
93
93
  /**
94
- * @title 模型名称
94
+ * @title Model name
95
95
  */
96
96
  model: string;
97
97
  /**
98
- * @title 返回的文本数量
98
+ * @title Number of text responses to return
99
99
  */
100
100
  n?: number;
101
101
  /**
102
- * @title 控制生成文本中的惩罚系数,用于减少主题的变化
102
+ * @title Penalty coefficient for reducing topic variation in generated text
103
103
  * @default 0
104
104
  */
105
105
  presence_penalty?: number;
@@ -112,12 +112,12 @@ export interface ChatStreamPayload {
112
112
  responseMode?: 'stream' | 'json';
113
113
  response_format?: ChatResponseFormat;
114
114
  /**
115
- * @title 是否开启流式请求
115
+ * @title Whether to enable streaming requests
116
116
  * @default true
117
117
  */
118
118
  stream?: boolean;
119
119
  /**
120
- * @title 生成文本的随机度量,用于控制文本的创造性和多样性
120
+ * @title Randomness measure for generated text, controls creativity and diversity
121
121
  * @default 1
122
122
  */
123
123
  temperature?: number;
@@ -139,13 +139,13 @@ export interface ChatStreamPayload {
139
139
  tool_choice?: string;
140
140
  tools?: ChatCompletionTool[];
141
141
  /**
142
- * @title 控制生成文本中最高概率的单个令牌
142
+ * @title Controls the highest probability single token in generated text
143
143
  * @default 1
144
144
  */
145
145
  top_p?: number;
146
146
  truncation?: 'auto' | 'disabled';
147
147
  /**
148
- * @title Gemini URL 上下文获取工具开关
148
+ * @title Gemini URL context fetching tool toggle
149
149
  */
150
150
  urlContext?: boolean;
151
151
  verbosity?: 'low' | 'medium' | 'high';
@@ -23,7 +23,7 @@ export const StandardErrorType = {
23
23
  export type ErrorType = (typeof StandardErrorType)[keyof typeof StandardErrorType];
24
24
 
25
25
  /**
26
- * 聊天消息错误对象
26
+ * Chat message error object
27
27
  */
28
28
  export interface ChatMessageError {
29
29
  body?: any;
@@ -34,7 +34,7 @@ export type CreateImageResponse = {
34
34
  modelUsage?: ModelUsage;
35
35
  };
36
36
 
37
- // 新增:支持认证图片下载的运行时接口
37
+ // New: Runtime interface for authenticated image download support
38
38
  export interface AuthenticatedImageRuntime {
39
39
  /**
40
40
  * Get authentication headers for image download
@@ -1,5 +1,6 @@
1
1
  'use client';
2
2
 
3
+ import { isDesktop } from '@lobechat/const';
3
4
  import { Flexbox } from '@lobehub/ui';
4
5
  import { cssVar } from 'antd-style';
5
6
  import { memo } from 'react';
@@ -22,7 +23,7 @@ const Header = memo(() => {
22
23
  }
23
24
  right={
24
25
  <Flexbox align={'center'} horizontal style={{ backgroundColor: cssVar.colorBgContainer }}>
25
- <WorkingDirectory />
26
+ {isDesktop && <WorkingDirectory />}
26
27
  <NotebookButton />
27
28
  <ShareButton />
28
29
  <HeaderActions />
@@ -1,11 +1,11 @@
1
1
  /**
2
2
  * ComfyUI framework constants configuration
3
- * Unified management of hardcoded values with environment variable overrides / 统一管理硬编码值,支持环境变量覆盖
3
+ * Unified management of hardcoded values with environment variable overrides
4
4
  */
5
5
 
6
6
  /**
7
- * Default configuration / 默认配置
8
- * 注意:BASE_URL不再处理环境变量,由构造函数统一处理优先级
7
+ * Default configuration
8
+ * Note: BASE_URL no longer handles environment variables, priority is uniformly handled by constructor
9
9
  */
10
10
  export const COMFYUI_DEFAULTS = {
11
11
  BASE_URL: 'http://localhost:8000',
@@ -14,8 +14,8 @@ export const COMFYUI_DEFAULTS = {
14
14
  } as const;
15
15
 
16
16
  /**
17
- * FLUX model configuration / FLUX 模型配置
18
- * Removed over-engineered dynamic T5 selection, maintain simple fixed configuration / 移除过度工程化的动态T5选择,保持简单固定配置
17
+ * FLUX model configuration
18
+ * Removed over-engineered dynamic T5 selection, maintain simple fixed configuration
19
19
  */
20
20
  export const FLUX_MODEL_CONFIG = {
21
21
  FILENAME_PREFIXES: {
@@ -40,8 +40,8 @@ export const SD_MODEL_CONFIG = {
40
40
  } as const;
41
41
 
42
42
  /**
43
- * Default workflow node parameters / 工作流节点默认参数
44
- * Based on 2024 community best practices configuration / 基于 2024 年社区最佳实践配置
43
+ * Default workflow node parameters
44
+ * Based on 2024 community best practices configuration
45
45
  */
46
46
 
47
47
  /**
@@ -1,16 +1,16 @@
1
1
  /**
2
2
  * Prompt Optimizer Configuration
3
- * 提示词优化器配置 - 用于智能分割和优化提示词
3
+ * Prompt optimizer configuration - for intelligent splitting and optimization of prompts
4
4
  */
5
5
 
6
6
  /**
7
7
  * Style keywords configuration - organized by category
8
- * 风格关键词配置 - 按类别组织便于维护和扩展
8
+ * Style keyword configuration - organized by category for easy maintenance and extension
9
9
  */
10
10
 
11
11
  /* eslint-disable sort-keys-fix/sort-keys-fix */
12
12
  export const STYLE_KEYWORDS = {
13
- // Artists and platforms / 艺术家和平台
13
+ // Artists and platforms
14
14
  ARTISTS: [
15
15
  'by greg rutkowski',
16
16
  'by artgerm',
@@ -34,7 +34,7 @@ export const STYLE_KEYWORDS = {
34
34
  'digital painting',
35
35
  ],
36
36
 
37
- // Art styles / 艺术风格
37
+ // Art styles
38
38
  ART_STYLES: [
39
39
  'photorealistic',
40
40
  'photo realistic',
@@ -90,7 +90,7 @@ export const STYLE_KEYWORDS = {
90
90
  'retrowave',
91
91
  ],
92
92
 
93
- // Lighting effects / 光照效果
93
+ // Lighting effects
94
94
  LIGHTING: [
95
95
  'dramatic lighting',
96
96
  'soft lighting',
@@ -131,7 +131,7 @@ export const STYLE_KEYWORDS = {
131
131
  'incandescent',
132
132
  ],
133
133
 
134
- // Photography terms / 摄影术语
134
+ // Photography terms
135
135
  PHOTOGRAPHY: [
136
136
  'depth of field',
137
137
  'shallow depth of field',
@@ -184,7 +184,7 @@ export const STYLE_KEYWORDS = {
184
184
  'instant photo',
185
185
  ],
186
186
 
187
- // Quality descriptions / 质量描述
187
+ // Quality descriptions
188
188
  QUALITY: [
189
189
  'high quality',
190
190
  'best quality',
@@ -227,7 +227,7 @@ export const STYLE_KEYWORDS = {
227
227
  'exquisite',
228
228
  ],
229
229
 
230
- // Rendering and effects / 渲染和效果
230
+ // Rendering and effects
231
231
  RENDERING: [
232
232
  'octane render',
233
233
  'octane',
@@ -270,7 +270,7 @@ export const STYLE_KEYWORDS = {
270
270
  'high dynamic range',
271
271
  ],
272
272
 
273
- // Color and mood / 颜色和氛围
273
+ // Color and mood
274
274
  COLOR_MOOD: [
275
275
  'vibrant',
276
276
  'vibrant colors',
@@ -330,7 +330,7 @@ export const STYLE_KEYWORDS = {
330
330
  'gothic atmosphere',
331
331
  ],
332
332
 
333
- // Texture and materials / 纹理和材质
333
+ // Texture and materials
334
334
  TEXTURE_MATERIAL: [
335
335
  'glossy',
336
336
  'matte',
@@ -397,7 +397,7 @@ export const STYLE_KEYWORDS = {
397
397
 
398
398
  /**
399
399
  * Style synonyms mapping for better recognition
400
- * 同义词映射,提高识别准确率
400
+ * Synonym mapping to improve recognition accuracy
401
401
  */
402
402
  export const STYLE_SYNONYMS: Record<string, string[]> = {
403
403
  // Photography variations
@@ -443,7 +443,7 @@ export const STYLE_SYNONYMS: Record<string, string[]> = {
443
443
 
444
444
  /**
445
445
  * Compound styles that should be recognized as a whole
446
- * 组合风格,应该作为整体识别
446
+ * Compound styles that should be recognized as a complete unit
447
447
  */
448
448
  export const COMPOUND_STYLES = [
449
449
  // Studio and brand styles
@@ -536,37 +536,37 @@ export const COMPOUND_STYLES = [
536
536
 
537
537
  /**
538
538
  * Precise adjective patterns for style extraction
539
- * 精确的形容词模式,用于风格提取
539
+ * Precise adjective patterns for style extraction
540
540
  */
541
541
  export const STYLE_ADJECTIVE_PATTERNS = {
542
- // Visual quality related / 视觉质量相关
542
+ // Visual quality related
543
543
  quality:
544
544
  /^(sharp|blur(ry)?|clear|crisp|clean|smooth|rough|grainy|noisy|pristine|flawless|perfect|polished)$/i,
545
545
 
546
- // Artistic style related / 艺术风格相关
546
+ // Artistic style related
547
547
  artistic:
548
548
  /^(abstract|surreal|minimal(ist)?|ornate|baroque|gothic|modern|contemporary|traditional|classical|vintage|retro|antique|futuristic|avant-garde)$/i,
549
549
 
550
- // Color and lighting / 颜色和光照
550
+ // Color and lighting
551
551
  visual:
552
552
  /^(bright|dark|dim|vibrant|vivid|muted|saturated|desaturated|warm|cool|cold|hot|soft|hard|harsh|gentle|subtle|bold|pale|rich|deep)$/i,
553
553
 
554
- // Mood and atmosphere / 情绪和氛围
554
+ // Mood and atmosphere
555
555
  mood: /^(dramatic|peaceful|chaotic|serene|calm|mysterious|mystical|magical|epic|legendary|heroic|romantic|melancholic|nostalgic|whimsical|playful|serious|solemn|cheerful|gloomy|ominous|eerie|creepy|scary|dreamy|ethereal|fantastical|moody|atmospheric)$/i,
556
556
 
557
- // Texture and material / 纹理和材质
557
+ // Texture and material
558
558
  texture:
559
559
  /^(metallic|wooden|glass(y)?|crystalline|fabric|leather|plastic|rubber|organic|synthetic|liquid|solid|transparent|translucent|opaque|reflective|matte|glossy|satin|rough|smooth|wet|dry|dusty|rusty|weathered|aged|new|fresh|worn)$/i,
560
560
 
561
- // Size and scale / 尺寸和规模
561
+ // Size and scale
562
562
  scale:
563
563
  /^(tiny|small|medium|large|huge|massive|gigantic|colossal|enormous|microscopic|miniature|oversized|epic-scale|human-scale|intimate|vast|infinite)$/i,
564
564
 
565
- // Complexity and detail / 复杂度和细节
565
+ // Complexity and detail
566
566
  detail:
567
567
  /^(simple|complex|intricate|elaborate|detailed|minimal|advanced|sophisticated|primitive|refined|crude|delicate|robust)$/i,
568
568
 
569
- // Professional quality / 专业质量
569
+ // Professional quality
570
570
  professional:
571
571
  /^(professional|amateur|masterful|skilled|expert|novice|polished|raw|finished|unfinished|complete|incomplete|refined|rough)$/i,
572
572
  } as const;
@@ -575,7 +575,7 @@ export const STYLE_ADJECTIVE_PATTERNS = {
575
575
 
576
576
  /**
577
577
  * Get all style keywords as a flattened array
578
- * 获取所有风格关键词的扁平数组
578
+ * Get all style keywords as a flattened array
579
579
  */
580
580
  export function getAllStyleKeywords(): readonly string[] {
581
581
  return Object.values(STYLE_KEYWORDS).flat();
@@ -583,7 +583,7 @@ export function getAllStyleKeywords(): readonly string[] {
583
583
 
584
584
  /**
585
585
  * Get all compound styles
586
- * 获取所有组合风格
586
+ * Get all compound styles
587
587
  */
588
588
  export function getCompoundStyles(): readonly string[] {
589
589
  return COMPOUND_STYLES;
@@ -591,7 +591,7 @@ export function getCompoundStyles(): readonly string[] {
591
591
 
592
592
  /**
593
593
  * Normalize a style term using synonyms
594
- * 使用同义词标准化风格术语
594
+ * Normalize a style term using synonyms
595
595
  */
596
596
  export function normalizeStyleTerm(term: string): string {
597
597
  const lowerTerm = term.toLowerCase();
@@ -608,7 +608,7 @@ export function normalizeStyleTerm(term: string): string {
608
608
 
609
609
  /**
610
610
  * Check if a word matches any style adjective pattern
611
- * 检查词语是否匹配任何风格形容词模式
611
+ * Check if a word matches any style adjective pattern
612
612
  */
613
613
  export function isStyleAdjective(word: string): boolean {
614
614
  const lowerWord = word.toLowerCase();
@@ -617,7 +617,7 @@ export function isStyleAdjective(word: string): boolean {
617
617
 
618
618
  /**
619
619
  * Extract style adjectives from words based on precise patterns
620
- * 基于精确模式从词语中提取风格形容词
620
+ * Extract style adjectives from words based on precise patterns
621
621
  */
622
622
  export function extractStyleAdjectives(words: string[]): string[] {
623
623
  return words.filter((word) => isStyleAdjective(word));