@lobehub/chat 1.111.1 → 1.111.2

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 (99) hide show
  1. package/.cursor/rules/code-review.mdc +2 -19
  2. package/.cursor/rules/cursor-ux.mdc +0 -72
  3. package/.cursor/rules/project-introduce.mdc +5 -5
  4. package/.cursor/rules/react-component.mdc +92 -73
  5. package/.cursor/rules/rules-attach.mdc +28 -61
  6. package/.cursor/rules/system-role.mdc +8 -20
  7. package/.cursor/rules/typescript.mdc +55 -14
  8. package/CHANGELOG.md +25 -0
  9. package/changelog/v1.json +5 -0
  10. package/package.json +1 -1
  11. package/packages/types/src/aiModel.ts +67 -46
  12. package/packages/types/src/llm.ts +3 -3
  13. package/src/app/[variants]/(main)/discover/(detail)/model/[...slugs]/features/Details/Overview/ProviderList/index.tsx +23 -12
  14. package/src/app/[variants]/(main)/discover/(detail)/provider/[...slugs]/features/Details/Overview/ModelList/index.tsx +23 -10
  15. package/src/app/[variants]/(main)/settings/provider/features/ModelList/ModelItem.tsx +21 -12
  16. package/src/config/aiModels/ai21.ts +8 -4
  17. package/src/config/aiModels/ai360.ts +28 -14
  18. package/src/config/aiModels/aihubmix.ts +174 -86
  19. package/src/config/aiModels/anthropic.ts +97 -38
  20. package/src/config/aiModels/azure.ts +54 -32
  21. package/src/config/aiModels/azureai.ts +63 -37
  22. package/src/config/aiModels/baichuan.ts +24 -12
  23. package/src/config/aiModels/bedrock.ts +60 -30
  24. package/src/config/aiModels/cohere.ts +60 -30
  25. package/src/config/aiModels/deepseek.ts +10 -6
  26. package/src/config/aiModels/fireworksai.ts +88 -44
  27. package/src/config/aiModels/giteeai.ts +1 -1
  28. package/src/config/aiModels/github.ts +44 -26
  29. package/src/config/aiModels/google.ts +119 -68
  30. package/src/config/aiModels/groq.ts +48 -24
  31. package/src/config/aiModels/higress.ts +617 -310
  32. package/src/config/aiModels/hunyuan.ts +105 -54
  33. package/src/config/aiModels/infiniai.ts +104 -52
  34. package/src/config/aiModels/internlm.ts +16 -8
  35. package/src/config/aiModels/jina.ts +4 -2
  36. package/src/config/aiModels/minimax.ts +11 -10
  37. package/src/config/aiModels/mistral.ts +40 -20
  38. package/src/config/aiModels/moonshot.ts +42 -22
  39. package/src/config/aiModels/novita.ts +196 -98
  40. package/src/config/aiModels/openai.ts +270 -137
  41. package/src/config/aiModels/openrouter.ts +205 -100
  42. package/src/config/aiModels/perplexity.ts +36 -6
  43. package/src/config/aiModels/ppio.ts +76 -38
  44. package/src/config/aiModels/qwen.ts +257 -133
  45. package/src/config/aiModels/sambanova.ts +56 -28
  46. package/src/config/aiModels/sensenova.ts +100 -50
  47. package/src/config/aiModels/siliconcloud.ts +224 -112
  48. package/src/config/aiModels/stepfun.ts +44 -22
  49. package/src/config/aiModels/taichu.ts +8 -4
  50. package/src/config/aiModels/tencentcloud.ts +12 -6
  51. package/src/config/aiModels/upstage.ts +8 -4
  52. package/src/config/aiModels/v0.ts +15 -12
  53. package/src/config/aiModels/vertexai.ts +49 -27
  54. package/src/config/aiModels/volcengine.ts +110 -51
  55. package/src/config/aiModels/wenxin.ts +179 -73
  56. package/src/config/aiModels/xai.ts +33 -19
  57. package/src/config/aiModels/zeroone.ts +48 -24
  58. package/src/config/aiModels/zhipu.ts +118 -69
  59. package/src/config/modelProviders/ai21.ts +0 -8
  60. package/src/config/modelProviders/ai360.ts +0 -20
  61. package/src/config/modelProviders/anthropic.ts +0 -56
  62. package/src/config/modelProviders/baichuan.ts +0 -30
  63. package/src/config/modelProviders/bedrock.ts +0 -74
  64. package/src/config/modelProviders/deepseek.ts +0 -13
  65. package/src/config/modelProviders/fireworksai.ts +0 -88
  66. package/src/config/modelProviders/google.ts +0 -59
  67. package/src/config/modelProviders/groq.ts +0 -48
  68. package/src/config/modelProviders/higress.ts +0 -727
  69. package/src/config/modelProviders/hunyuan.ts +0 -45
  70. package/src/config/modelProviders/infiniai.ts +0 -60
  71. package/src/config/modelProviders/internlm.ts +0 -8
  72. package/src/config/modelProviders/mistral.ts +0 -48
  73. package/src/config/modelProviders/modelscope.ts +2 -1
  74. package/src/config/modelProviders/openai.ts +5 -100
  75. package/src/config/modelProviders/openrouter.ts +0 -77
  76. package/src/config/modelProviders/ppio.ts +0 -95
  77. package/src/config/modelProviders/qwen.ts +0 -165
  78. package/src/config/modelProviders/sensenova.ts +0 -45
  79. package/src/config/modelProviders/siliconcloud.ts +0 -266
  80. package/src/config/modelProviders/stepfun.ts +0 -60
  81. package/src/config/modelProviders/taichu.ts +0 -10
  82. package/src/config/modelProviders/wenxin.ts +0 -90
  83. package/src/config/modelProviders/xai.ts +0 -16
  84. package/src/config/modelProviders/zeroone.ts +0 -60
  85. package/src/config/modelProviders/zhipu.ts +0 -80
  86. package/src/features/Conversation/Extras/Usage/UsageDetail/ModelCard.tsx +4 -3
  87. package/src/features/Conversation/Extras/Usage/UsageDetail/pricing.ts +25 -15
  88. package/src/features/Conversation/Extras/Usage/UsageDetail/tokens.test.ts +7 -5
  89. package/src/features/Conversation/Extras/Usage/UsageDetail/tokens.ts +6 -5
  90. package/src/libs/model-runtime/utils/openaiCompatibleFactory/index.test.ts +54 -8
  91. package/src/server/routers/lambda/agent.ts +2 -2
  92. package/src/server/routers/lambda/config/__snapshots__/index.test.ts.snap +0 -28
  93. package/src/server/services/discover/index.ts +7 -6
  94. package/src/server/services/user/index.ts +1 -2
  95. package/src/utils/__snapshots__/parseModels.test.ts.snap +28 -4
  96. package/src/utils/_deprecated/__snapshots__/parseModels.test.ts.snap +0 -8
  97. package/src/utils/parseModels.test.ts +60 -9
  98. package/src/utils/pricing.test.ts +183 -0
  99. package/src/utils/pricing.ts +90 -0
@@ -107,6 +107,65 @@ export interface ChatModelPricing extends BasicModelPricing {
107
107
  writeCacheInput?: number;
108
108
  }
109
109
 
110
+ // New pricing system types
111
+ export type PricingUnitName =
112
+ // Text-based pricing units
113
+ | 'textInput' // corresponds to ChatModelPricing.input
114
+ | 'textOutput' // corresponds to ChatModelPricing.output
115
+ | 'textInput_cacheRead' // corresponds to ChatModelPricing.cachedInput
116
+ | 'textInput_cacheWrite' // corresponds to ChatModelPricing.writeCacheInput
117
+
118
+ // Audio-based pricing units
119
+ | 'audioInput' // corresponds to ChatModelPricing.audioInput
120
+ | 'audioOutput' // corresponds to ChatModelPricing.audioOutput
121
+ | 'audioInput_cacheRead' // corresponds to ChatModelPricing.cachedAudioInput
122
+
123
+ // Image-based pricing units
124
+ | 'imageGeneration'; // for image generation models
125
+
126
+ export type PricingUnitType =
127
+ | 'millionTokens' // per 1M tokens
128
+ | 'millionCharacters' // per 1M characters
129
+ | 'image' // per image
130
+ | 'megapixel' // per megapixel
131
+ | 'second'; // per second
132
+
133
+ export type PricingStrategy = 'fixed' | 'tiered' | 'lookup';
134
+
135
+ export interface PricingUnitBase {
136
+ name: PricingUnitName;
137
+ strategy: PricingStrategy;
138
+ unit: PricingUnitType;
139
+ }
140
+
141
+ export interface FixedPricingUnit extends PricingUnitBase {
142
+ rate: number;
143
+ strategy: 'fixed';
144
+ }
145
+
146
+ export interface TieredPricingUnit extends PricingUnitBase {
147
+ strategy: 'tiered';
148
+ tiers: Array<{
149
+ rate: number;
150
+ upTo: number | 'infinity';
151
+ }>;
152
+ }
153
+
154
+ export interface LookupPricingUnit extends PricingUnitBase {
155
+ lookup: {
156
+ prices: Record<string, number>;
157
+ pricingParams: string[];
158
+ };
159
+ strategy: 'lookup';
160
+ }
161
+
162
+ export type PricingUnit = FixedPricingUnit | TieredPricingUnit | LookupPricingUnit;
163
+
164
+ export interface Pricing {
165
+ currency?: ModelPriceCurrency;
166
+ units: PricingUnit[];
167
+ }
168
+
110
169
  export interface AIBaseModelCard {
111
170
  /**
112
171
  * the context window (or input + output tokens limit)
@@ -167,69 +226,31 @@ export interface AIChatModelCard extends AIBaseModelCard {
167
226
  abilities?: ModelAbilities;
168
227
  config?: AiModelConfig;
169
228
  maxOutput?: number;
170
- pricing?: ChatModelPricing;
229
+ pricing?: Pricing;
171
230
  settings?: AiModelSettings;
172
231
  type: 'chat';
173
232
  }
174
233
 
175
234
  export interface AIEmbeddingModelCard extends AIBaseModelCard {
176
235
  maxDimension: number;
177
- pricing?: {
178
- /**
179
- * the currency of the pricing
180
- * @default USD
181
- */
182
- currency?: ModelPriceCurrency;
183
- /**
184
- * the input pricing, e.g. $1 / 1M tokens
185
- */
186
- input?: number;
187
- };
236
+ pricing?: Pricing;
188
237
  type: 'embedding';
189
238
  }
190
239
 
191
240
  export interface AIImageModelCard extends AIBaseModelCard {
192
241
  parameters?: ModelParamsSchema;
193
- pricing?: {
194
- /**
195
- * the currency of the pricing
196
- * @default USD
197
- */
198
- currency?: ModelPriceCurrency;
199
- } & Record<string, number>;
242
+ pricing?: Pricing;
200
243
  resolutions?: string[];
201
244
  type: 'image';
202
245
  }
203
246
 
204
247
  export interface AITTSModelCard extends AIBaseModelCard {
205
- pricing?: {
206
- /**
207
- * the currency of the pricing
208
- * @default USD
209
- */
210
- currency?: ModelPriceCurrency;
211
- /**
212
- * the input pricing, e.g. $1 / 1M tokens
213
- */
214
- input?: number;
215
- output?: number;
216
- };
248
+ pricing?: Pricing;
217
249
  type: 'tts';
218
250
  }
219
251
 
220
252
  export interface AISTTModelCard extends AIBaseModelCard {
221
- pricing?: {
222
- /**
223
- * the currency of the pricing
224
- * @default USD
225
- */
226
- currency?: ModelPriceCurrency;
227
- /**
228
- * the input pricing, e.g. $1 / 1M tokens
229
- */
230
- input?: number;
231
- output?: number;
232
- };
253
+ pricing?: Pricing;
233
254
  type: 'stt';
234
255
  }
235
256
 
@@ -257,7 +278,7 @@ export interface AIRealtimeModelCard extends AIBaseModelCard {
257
278
  */
258
279
  deploymentName?: string;
259
280
  maxOutput?: number;
260
- pricing?: ChatModelPricing;
281
+ pricing?: Pricing;
261
282
  type: 'realtime';
262
283
  }
263
284
 
@@ -269,7 +290,7 @@ export interface AiFullModelCard extends AIBaseModelCard {
269
290
  id: string;
270
291
  maxDimension?: number;
271
292
  parameters?: ModelParamsSchema;
272
- pricing?: ChatModelPricing;
293
+ pricing?: Pricing;
273
294
  type: AiModelType;
274
295
  }
275
296
 
@@ -304,7 +325,7 @@ export interface AiProviderModelListItem {
304
325
  enabled: boolean;
305
326
  id: string;
306
327
  parameters?: Record<string, any>;
307
- pricing?: ChatModelPricing;
328
+ pricing?: Pricing;
308
329
  releasedAt?: string;
309
330
  settings?: AiModelSettings;
310
331
  source?: AiModelSourceType;
@@ -1,7 +1,7 @@
1
1
  import { ReactNode } from 'react';
2
2
 
3
- import { AiModelType, ChatModelPricing } from './aiModel';
4
- import { AiProviderSettings } from './aiProvider';
3
+ import { AiModelType, Pricing } from '@/types/aiModel';
4
+ import { AiProviderSettings } from '@/types/aiProvider';
5
5
 
6
6
  export type ModelPriceCurrency = 'CNY' | 'USD';
7
7
 
@@ -41,7 +41,7 @@ export interface ChatModelCard {
41
41
  */
42
42
  legacy?: boolean;
43
43
  maxOutput?: number;
44
- pricing?: ChatModelPricing;
44
+ pricing?: Pricing;
45
45
 
46
46
  /**
47
47
  * whether model supports reasoning
@@ -14,6 +14,7 @@ import InlineTable from '@/components/InlineTable';
14
14
  import { ModelInfoTags } from '@/components/ModelSelect';
15
15
  import { BASE_PROVIDER_DOC_URL } from '@/const/url';
16
16
  import { formatPriceByCurrency, formatTokenNumber } from '@/utils/format';
17
+ import { getTextInputUnitRate, getTextOutputUnitRate } from '@/utils/pricing';
17
18
 
18
19
  import { useDetailContext } from '../../../DetailProvider';
19
20
 
@@ -89,12 +90,17 @@ const ProviderList = memo(() => {
89
90
  {
90
91
  dataIndex: 'model.inputPrice',
91
92
  key: 'inputPrice',
92
- render: (_, record) =>
93
- record.model?.pricing?.input
94
- ? '$' +
95
- formatPriceByCurrency(record.model.pricing.input, record.model.pricing?.currency)
96
- : '--',
97
- sorter: (a, b) => (a.model?.pricing?.input || 0) - (b.model?.pricing?.input || 0),
93
+ render: (_, record) => {
94
+ const inputRate = getTextInputUnitRate(record.model?.pricing);
95
+ return inputRate
96
+ ? '$' + formatPriceByCurrency(inputRate, record.model.pricing?.currency)
97
+ : '--';
98
+ },
99
+ sorter: (a, b) => {
100
+ const aRate = getTextInputUnitRate(a.model?.pricing) || 0;
101
+ const bRate = getTextInputUnitRate(b.model?.pricing) || 0;
102
+ return aRate - bRate;
103
+ },
98
104
  title: (
99
105
  <Tooltip title={t('models.providerInfo.inputTooltip')}>
100
106
  {t('models.providerInfo.input')}
@@ -105,12 +111,17 @@ const ProviderList = memo(() => {
105
111
  {
106
112
  dataIndex: 'model.outputPrice',
107
113
  key: 'outputPrice',
108
- render: (_, record) =>
109
- record.model?.pricing?.output
110
- ? '$' +
111
- formatPriceByCurrency(record.model.pricing.output, record.model.pricing?.currency)
112
- : '--',
113
- sorter: (a, b) => (a.model?.pricing?.output || 0) - (b.model?.pricing?.output || 0),
114
+ render: (_, record) => {
115
+ const outputRate = getTextOutputUnitRate(record.model?.pricing);
116
+ return outputRate
117
+ ? '$' + formatPriceByCurrency(outputRate, record.model.pricing?.currency)
118
+ : '--';
119
+ },
120
+ sorter: (a, b) => {
121
+ const aRate = getTextOutputUnitRate(a.model?.pricing) || 0;
122
+ const bRate = getTextOutputUnitRate(b.model?.pricing) || 0;
123
+ return aRate - bRate;
124
+ },
114
125
  title: (
115
126
  <Tooltip title={t('models.providerInfo.outputTooltip')}>
116
127
  {t('models.providerInfo.output')}
@@ -13,6 +13,7 @@ import urlJoin from 'url-join';
13
13
  import InlineTable from '@/components/InlineTable';
14
14
  import { ModelInfoTags } from '@/components/ModelSelect';
15
15
  import { formatPriceByCurrency, formatTokenNumber } from '@/utils/format';
16
+ import { getTextInputUnitRate, getTextOutputUnitRate } from '@/utils/pricing';
16
17
 
17
18
  import { useDetailContext } from '../../../DetailProvider';
18
19
 
@@ -82,11 +83,17 @@ const ModelList = memo(() => {
82
83
  {
83
84
  dataIndex: 'inputPrice',
84
85
  key: 'inputPrice',
85
- render: (_, record) =>
86
- record.pricing?.input
87
- ? '$' + formatPriceByCurrency(record.pricing.input, record.pricing?.currency)
88
- : '--',
89
- sorter: (a, b) => (a.pricing?.input || 0) - (b.pricing?.input || 0),
86
+ render: (_, record) => {
87
+ const inputRate = getTextInputUnitRate(record.pricing);
88
+ return inputRate
89
+ ? '$' + formatPriceByCurrency(inputRate, record.pricing?.currency)
90
+ : '--';
91
+ },
92
+ sorter: (a, b) => {
93
+ const aRate = getTextInputUnitRate(a.pricing) || 0;
94
+ const bRate = getTextInputUnitRate(b.pricing) || 0;
95
+ return aRate - bRate;
96
+ },
90
97
  title: (
91
98
  <Tooltip title={t('models.providerInfo.inputTooltip')}>
92
99
  {t('models.providerInfo.input')}
@@ -97,11 +104,17 @@ const ModelList = memo(() => {
97
104
  {
98
105
  dataIndex: 'outputPrice',
99
106
  key: 'outputPrice',
100
- render: (_, record) =>
101
- record.pricing?.output
102
- ? '$' + formatPriceByCurrency(record.pricing.output, record.pricing?.currency)
103
- : '--',
104
- sorter: (a, b) => (a.pricing?.output || 0) - (b.pricing?.output || 0),
107
+ render: (_, record) => {
108
+ const outputRate = getTextOutputUnitRate(record.pricing);
109
+ return outputRate
110
+ ? '$' + formatPriceByCurrency(outputRate, record.pricing?.currency)
111
+ : '--';
112
+ },
113
+ sorter: (a, b) => {
114
+ const aRate = getTextOutputUnitRate(a.pricing) || 0;
115
+ const bRate = getTextOutputUnitRate(b.pricing) || 0;
116
+ return aRate - bRate;
117
+ },
105
118
  title: (
106
119
  <Tooltip title={t('models.providerInfo.outputTooltip')}>
107
120
  {t('models.providerInfo.output')}
@@ -10,8 +10,13 @@ import { Flexbox } from 'react-layout-kit';
10
10
  import { ModelInfoTags } from '@/components/ModelSelect';
11
11
  import { useIsMobile } from '@/hooks/useIsMobile';
12
12
  import { aiModelSelectors, useAiInfraStore } from '@/store/aiInfra';
13
- import { AiModelSourceEnum, AiProviderModelListItem, ChatModelPricing } from '@/types/aiModel';
13
+ import { AiModelSourceEnum, AiProviderModelListItem } from '@/types/aiModel';
14
14
  import { formatPriceByCurrency } from '@/utils/format';
15
+ import {
16
+ getAudioInputUnitRate,
17
+ getTextInputUnitRate,
18
+ getTextOutputUnitRate,
19
+ } from '@/utils/pricing';
15
20
 
16
21
  import ModelConfigModal from './ModelConfigModal';
17
22
  import { ProviderSettingsContext } from './ProviderSettingsContext';
@@ -54,7 +59,6 @@ interface ModelItemProps extends AiProviderModelListItem {
54
59
  enabled: boolean;
55
60
  id: string;
56
61
  isAzure?: boolean;
57
- pricing?: ChatModelPricing;
58
62
  releasedAt?: string;
59
63
  removed?: boolean;
60
64
  }
@@ -94,38 +98,43 @@ const ModelItem = memo<ModelItemProps>(
94
98
 
95
99
  switch (type) {
96
100
  case 'chat': {
101
+ const inputRate = getTextInputUnitRate(pricing);
102
+ const outputRate = getTextOutputUnitRate(pricing);
97
103
  return [
98
- typeof pricing.input === 'number' &&
104
+ typeof inputRate === 'number' &&
99
105
  t('providerModels.item.pricing.inputTokens', {
100
- amount: formatPriceByCurrency(pricing.input, pricing?.currency),
106
+ amount: formatPriceByCurrency(inputRate, pricing?.currency),
101
107
  }),
102
- typeof pricing.output === 'number' &&
108
+ typeof outputRate === 'number' &&
103
109
  t('providerModels.item.pricing.outputTokens', {
104
- amount: formatPriceByCurrency(pricing.output, pricing?.currency),
110
+ amount: formatPriceByCurrency(outputRate, pricing?.currency),
105
111
  }),
106
112
  ].filter(Boolean) as string[];
107
113
  }
108
114
  case 'embedding': {
115
+ const inputRate = getTextInputUnitRate(pricing);
109
116
  return [
110
- typeof pricing.input === 'number' &&
117
+ typeof inputRate === 'number' &&
111
118
  t('providerModels.item.pricing.inputTokens', {
112
- amount: formatPriceByCurrency(pricing.input, pricing?.currency),
119
+ amount: formatPriceByCurrency(inputRate, pricing?.currency),
113
120
  }),
114
121
  ].filter(Boolean) as string[];
115
122
  }
116
123
  case 'tts': {
124
+ const inputRate = getAudioInputUnitRate(pricing);
117
125
  return [
118
- typeof pricing.input === 'number' &&
126
+ typeof inputRate === 'number' &&
119
127
  t('providerModels.item.pricing.inputCharts', {
120
- amount: formatPriceByCurrency(pricing.input, pricing?.currency),
128
+ amount: formatPriceByCurrency(inputRate, pricing?.currency),
121
129
  }),
122
130
  ].filter(Boolean) as string[];
123
131
  }
124
132
  case 'stt': {
133
+ const inputRate = getAudioInputUnitRate(pricing);
125
134
  return [
126
- typeof pricing.input === 'number' &&
135
+ typeof inputRate === 'number' &&
127
136
  t('providerModels.item.pricing.inputMinutes', {
128
- amount: formatPriceByCurrency(pricing.input, pricing?.currency),
137
+ amount: formatPriceByCurrency(inputRate, pricing?.currency),
129
138
  }),
130
139
  ].filter(Boolean) as string[];
131
140
  }
@@ -11,8 +11,10 @@ const ai21ChatModels: AIChatModelCard[] = [
11
11
  enabled: true,
12
12
  id: 'jamba-mini',
13
13
  pricing: {
14
- input: 0.2,
15
- output: 0.4,
14
+ units: [
15
+ { name: 'textInput', rate: 0.2, strategy: 'fixed', unit: 'millionTokens' },
16
+ { name: 'textOutput', rate: 0.4, strategy: 'fixed', unit: 'millionTokens' },
17
+ ],
16
18
  },
17
19
  releasedAt: '2025-03-06',
18
20
  type: 'chat',
@@ -27,8 +29,10 @@ const ai21ChatModels: AIChatModelCard[] = [
27
29
  enabled: true,
28
30
  id: 'jamba-large',
29
31
  pricing: {
30
- input: 2,
31
- output: 8,
32
+ units: [
33
+ { name: 'textInput', rate: 2, strategy: 'fixed', unit: 'millionTokens' },
34
+ { name: 'textOutput', rate: 8, strategy: 'fixed', unit: 'millionTokens' },
35
+ ],
32
36
  },
33
37
  releasedAt: '2025-03-06',
34
38
  type: 'chat',
@@ -13,8 +13,10 @@ const ai360ChatModels: AIChatModelCard[] = [
13
13
  id: '360zhinao2-o1',
14
14
  pricing: {
15
15
  currency: 'CNY',
16
- input: 4,
17
- output: 10,
16
+ units: [
17
+ { name: 'textInput', rate: 4, strategy: 'fixed', unit: 'millionTokens' },
18
+ { name: 'textOutput', rate: 10, strategy: 'fixed', unit: 'millionTokens' },
19
+ ],
18
20
  },
19
21
  type: 'chat',
20
22
  },
@@ -29,8 +31,10 @@ const ai360ChatModels: AIChatModelCard[] = [
29
31
  id: '360gpt2-o1',
30
32
  pricing: {
31
33
  currency: 'CNY',
32
- input: 4,
33
- output: 10,
34
+ units: [
35
+ { name: 'textInput', rate: 4, strategy: 'fixed', unit: 'millionTokens' },
36
+ { name: 'textOutput', rate: 10, strategy: 'fixed', unit: 'millionTokens' },
37
+ ],
34
38
  },
35
39
  type: 'chat',
36
40
  },
@@ -46,8 +50,10 @@ const ai360ChatModels: AIChatModelCard[] = [
46
50
  id: '360gpt2-pro',
47
51
  pricing: {
48
52
  currency: 'CNY',
49
- input: 2,
50
- output: 5,
53
+ units: [
54
+ { name: 'textInput', rate: 2, strategy: 'fixed', unit: 'millionTokens' },
55
+ { name: 'textOutput', rate: 5, strategy: 'fixed', unit: 'millionTokens' },
56
+ ],
51
57
  },
52
58
  settings: {
53
59
  searchImpl: 'params',
@@ -65,8 +71,10 @@ const ai360ChatModels: AIChatModelCard[] = [
65
71
  id: '360gpt-pro',
66
72
  pricing: {
67
73
  currency: 'CNY',
68
- input: 2,
69
- output: 5,
74
+ units: [
75
+ { name: 'textInput', rate: 2, strategy: 'fixed', unit: 'millionTokens' },
76
+ { name: 'textOutput', rate: 5, strategy: 'fixed', unit: 'millionTokens' },
77
+ ],
70
78
  },
71
79
  settings: {
72
80
  searchImpl: 'params',
@@ -80,8 +88,10 @@ const ai360ChatModels: AIChatModelCard[] = [
80
88
  id: '360gpt-pro-trans',
81
89
  pricing: {
82
90
  currency: 'CNY',
83
- input: 2,
84
- output: 5,
91
+ units: [
92
+ { name: 'textInput', rate: 2, strategy: 'fixed', unit: 'millionTokens' },
93
+ { name: 'textOutput', rate: 5, strategy: 'fixed', unit: 'millionTokens' },
94
+ ],
85
95
  },
86
96
  type: 'chat',
87
97
  },
@@ -93,8 +103,10 @@ const ai360ChatModels: AIChatModelCard[] = [
93
103
  id: '360gpt-turbo',
94
104
  pricing: {
95
105
  currency: 'CNY',
96
- input: 1,
97
- output: 2,
106
+ units: [
107
+ { name: 'textInput', rate: 1, strategy: 'fixed', unit: 'millionTokens' },
108
+ { name: 'textOutput', rate: 2, strategy: 'fixed', unit: 'millionTokens' },
109
+ ],
98
110
  },
99
111
  type: 'chat',
100
112
  },
@@ -109,8 +121,10 @@ const ai360ChatModels: AIChatModelCard[] = [
109
121
  id: '360/deepseek-r1',
110
122
  pricing: {
111
123
  currency: 'CNY',
112
- input: 4,
113
- output: 16,
124
+ units: [
125
+ { name: 'textInput', rate: 4, strategy: 'fixed', unit: 'millionTokens' },
126
+ { name: 'textOutput', rate: 16, strategy: 'fixed', unit: 'millionTokens' },
127
+ ],
114
128
  },
115
129
  type: 'chat',
116
130
  },