@pactor-app/skills 1.33.0 → 1.35.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.
Files changed (44) hide show
  1. package/package.json +1 -1
  2. package/pactor-prd/SKILL.md +20 -23
  3. package/pactor-prd/references/acceptance-checklist.md +1 -1
  4. package/pactor-prd/references/data-api.md +35 -0
  5. package/pactor-prd/references/incremental-wireframe-delta.md +8 -9
  6. package/pactor-prd/references/page-inventory-and-files.md +2 -2
  7. package/pactor-prd/references/page-templates.md +59 -12
  8. package/pactor-prd/references/project-structure.md +1 -1
  9. package/pactor-prd/template/README.md +4 -4
  10. package/pactor-prd/template/app/api/d/[...parts]/route.ts +80 -0
  11. package/pactor-prd/template/app/layout.tsx +1 -3
  12. package/pactor-prd/template/next-env.d.ts +2 -2
  13. package/pactor-prd/template/next.config.js +2 -2
  14. package/pactor-prd/template/package.json +4 -4
  15. package/pactor-prd/template/pnpm-lock.yaml +97 -97
  16. package/pactor-prd/template/src/pactor/App.tsx +3 -2
  17. package/pactor-prd/template/src/pactor/actions.ts +5 -431
  18. package/pactor-prd/template/src/pactor/config.ts +12 -4
  19. package/pactor-prd/template/src/server/yaml/common/dashboard.yaml +1 -1
  20. package/pactor-prd/template/src/server/yaml/common/login.yaml +46 -75
  21. package/pactor-prd/template/src/server/yaml/models/data-list.yaml +344 -0
  22. package/pactor-prd/template/src/server/yaml/provider/provider-detail.yaml +2 -2
  23. package/pactor-prd/template/src/server/yaml/provider/provider-edit.yaml +1 -1
  24. package/pactor-prd/template/src/server/yaml/provider/provider-list.yaml +1 -1
  25. package/pactor-prd/template/src/server/yaml/route/route-detail.yaml +1 -1
  26. package/pactor-prd/template/src/server/yaml/route/route-edit.yaml +1 -1
  27. package/pactor-prd/template/src/server/yaml/route/route-list.yaml +1 -1
  28. package/pactor-prd/template/src/server/yaml/sitemap.yaml +23 -6
  29. package/pactor-prd/references/mock-data-routes.md +0 -66
  30. package/pactor-prd/template/app/api/data/[...parts]/route.ts +0 -118
  31. package/pactor-prd/template/app/login.css +0 -122
  32. package/pactor-prd/template/src/pactor/mocks/audit-mock.ts +0 -403
  33. package/pactor-prd/template/src/pactor/mocks/call-logs-mock.ts +0 -875
  34. package/pactor-prd/template/src/pactor/mocks/client-debug-mock.ts +0 -188
  35. package/pactor-prd/template/src/pactor/mocks/client-templates-mock.ts +0 -497
  36. package/pactor-prd/template/src/pactor/mocks/clients-mock.ts +0 -483
  37. package/pactor-prd/template/src/pactor/mocks/costs-mock.ts +0 -406
  38. package/pactor-prd/template/src/pactor/mocks/dashboard-mock.ts +0 -192
  39. package/pactor-prd/template/src/pactor/mocks/model-debug-mock.ts +0 -144
  40. package/pactor-prd/template/src/pactor/mocks/models-mock.ts +0 -799
  41. package/pactor-prd/template/src/pactor/mocks/ops-usage-mock.ts +0 -806
  42. package/pactor-prd/template/src/pactor/mocks/providers-mock.ts +0 -424
  43. package/pactor-prd/template/src/pactor/mocks/routes-mock.ts +0 -604
  44. package/pactor-prd/template/src/pactor/services.ts +0 -185
@@ -1,806 +0,0 @@
1
- /**
2
- * 运行管理 mock:模型/供应商/客户端用量 + 供应商可用性(可靠性)。
3
- * 行数据以原始数值存储(基准口径 = 7d),查询时按时间范围因子缩放
4
- * (请求数 / Token / 费用随范围线性缩放,比率与延迟不变),并在 mock 层
5
- * 预计算全部展示文案(Token 紧凑 K/M/B 与数字两种格式、$ 金额、百分比、
6
- * ms、配额用量)——DSL 表达式引擎不支持函数调用与数组方法,单元格只做
7
- * 字段拼接与 compact/raw 三元切换。
8
- * 模型 / 供应商 / 客户端名称均取自 models-mock / providers-mock /
9
- * clients-mock 中真实存在的记录,路由组取自 routes-mock 的路由标识。
10
- */
11
-
12
- export interface OpsUsageQuery {
13
- /** ISO 日期对(DatePicker range 值,同仪表盘) */
14
- start?: string;
15
- end?: string;
16
- }
17
-
18
- /** 一天毫秒数与 ISO 日期解析(yyyy-MM-dd;非法返回 undefined) */
19
- const DAY_MS = 86400000;
20
-
21
- function parseDay(s?: string): number | undefined {
22
- if (!s) return undefined;
23
- const t = Date.parse(`${s}T00:00:00`);
24
- return Number.isFinite(t) ? t : undefined;
25
- }
26
-
27
- /** 用量缩放因子:区间天数 / 7(基准 7d = 1;缺省或非法按 7d 计) */
28
- function rangeFactor(q: OpsUsageQuery): number {
29
- const start = parseDay(q.start);
30
- const end = parseDay(q.end);
31
- if (start === undefined || end === undefined || end < start) return 1;
32
- const days = Math.round((end - start) / DAY_MS) + 1;
33
- return days / 7;
34
- }
35
-
36
- // ── 格式化(mock 层预计算,DSL 侧不调用函数) ─────────────────────
37
-
38
- const fmtInt = (n: number) => Math.round(n).toLocaleString("en-US");
39
-
40
- function fmtCompact(n: number): string {
41
- if (n >= 1e9) return `${(n / 1e9).toFixed(1)}B`;
42
- if (n >= 1e6) return `${(n / 1e6).toFixed(1)}M`;
43
- if (n >= 1e3) return `${(n / 1e3).toFixed(1)}K`;
44
- return String(Math.round(n));
45
- }
46
-
47
- const fmtMoney = (n: number) => `$${n.toFixed(2)}`;
48
- const fmtMoney4 = (n: number) => `$${n.toFixed(4)}`;
49
- const fmtPct = (x: number) => `${(x * 100).toFixed(1)}%`;
50
- const fmtMs = (n: number) => `${Math.round(n)}ms`;
51
- const fmtAttempts = (n: number) => n.toFixed(2);
52
-
53
- // ── 原始指标行(7d 基准) ────────────────────────────────────────
54
-
55
- interface RawMetrics {
56
- requests: number;
57
- inputTokens: number;
58
- outputTokens: number;
59
- cacheHitRate: number;
60
- /** 标准价合计(USD) */
61
- standard: number;
62
- /** 对用户计费合计(USD) */
63
- billed: number;
64
- /** 供应侧成本合计(USD) */
65
- cost: number;
66
- successRate: number;
67
- latencyMs: number;
68
- ttftMs: number;
69
- upstreamMs: number;
70
- /** Token/秒 吞吐 */
71
- tps: number;
72
- failoverRate: number;
73
- /** 含重试的平均尝试次数 */
74
- attempts: number;
75
- }
76
-
77
- /** 用量宽表展示行(全部为预计算文案) */
78
- export interface UsageDisplay {
79
- requests: string;
80
- inputCompact: string;
81
- inputRaw: string;
82
- outputCompact: string;
83
- outputRaw: string;
84
- cacheHit: string;
85
- standard: string;
86
- billed: string;
87
- cost: string;
88
- avgBilled: string;
89
- successRate: string;
90
- avgLatency: string;
91
- ttft: string;
92
- avgUpstream: string;
93
- tps: string;
94
- failoverRate: string;
95
- avgAttempts: string;
96
- }
97
-
98
- /** 原始指标 → 展示行:量纲字段按范围因子缩放,比率 / 延迟不变 */
99
- function toUsageDisplay(r: RawMetrics, f: number): UsageDisplay {
100
- const requests = r.requests * f;
101
- const input = r.inputTokens * f;
102
- const output = r.outputTokens * f;
103
- const billed = r.billed * f;
104
- return {
105
- requests: fmtCompact(requests),
106
- inputCompact: fmtCompact(input),
107
- inputRaw: fmtInt(input),
108
- outputCompact: fmtCompact(output),
109
- outputRaw: fmtInt(output),
110
- cacheHit: fmtPct(r.cacheHitRate),
111
- standard: fmtMoney(r.standard * f),
112
- billed: fmtMoney(billed),
113
- cost: fmtMoney(r.cost * f),
114
- avgBilled: fmtMoney4(r.billed / r.requests),
115
- successRate: fmtPct(r.successRate),
116
- avgLatency: fmtMs(r.latencyMs),
117
- ttft: fmtMs(r.ttftMs),
118
- avgUpstream: fmtMs(r.upstreamMs),
119
- tps: fmtCompact(r.tps),
120
- failoverRate: fmtPct(r.failoverRate),
121
- avgAttempts: fmtAttempts(r.attempts),
122
- };
123
- }
124
-
125
- /** 可靠性展示行(无 Token / 缓存列,错误数随范围缩放) */
126
- interface QualityDisplay {
127
- requests: string;
128
- successRate: string;
129
- avgLatency: string;
130
- avgUpstream: string;
131
- failoverRate: string;
132
- avgAttempts: string;
133
- standard: string;
134
- billed: string;
135
- cost: string;
136
- }
137
-
138
- function toQualityDisplay(r: RawMetrics, f: number): QualityDisplay {
139
- return {
140
- requests: fmtCompact(r.requests * f),
141
- successRate: fmtPct(r.successRate),
142
- avgLatency: fmtMs(r.latencyMs),
143
- avgUpstream: fmtMs(r.upstreamMs),
144
- failoverRate: fmtPct(r.failoverRate),
145
- avgAttempts: fmtAttempts(r.attempts),
146
- standard: fmtMoney(r.standard * f),
147
- billed: fmtMoney(r.billed * f),
148
- cost: fmtMoney(r.cost * f),
149
- };
150
- }
151
-
152
- export interface UsageSummary {
153
- standard: string;
154
- billed: string;
155
- cost: string;
156
- }
157
-
158
- function summarize(rows: RawMetrics[], f: number): UsageSummary {
159
- const sum = (pick: (r: RawMetrics) => number) =>
160
- rows.reduce((acc, r) => acc + pick(r), 0) * f;
161
- return {
162
- standard: fmtMoney(sum((r) => r.standard)),
163
- billed: fmtMoney(sum((r) => r.billed)),
164
- cost: fmtMoney(sum((r) => r.cost)),
165
- };
166
- }
167
-
168
- // ── 模型用量(模型 × 路由组) ────────────────────────────────────
169
-
170
- interface RawModelUsage extends RawMetrics {
171
- key: string;
172
- model: string;
173
- route: string;
174
- }
175
-
176
- const MODEL_USAGE_RAW: RawModelUsage[] = [
177
- {
178
- key: "gpt-5/reasoning-default",
179
- model: "GPT-5",
180
- route: "reasoning-default",
181
- requests: 12400,
182
- inputTokens: 2_100_000,
183
- outputTokens: 1_800_000,
184
- cacheHitRate: 0.325,
185
- standard: 186.0,
186
- billed: 223.2,
187
- cost: 148.8,
188
- successRate: 0.992,
189
- latencyMs: 1820,
190
- ttftMs: 340,
191
- upstreamMs: 1650,
192
- tps: 1280,
193
- failoverRate: 0.008,
194
- attempts: 1.02,
195
- },
196
- {
197
- key: "qwen3.5-flash/general-chat",
198
- model: "Qwen3.5 Flash",
199
- route: "general-chat",
200
- requests: 45200,
201
- inputTokens: 8_600_000,
202
- outputTokens: 5_200_000,
203
- cacheHitRate: 0.412,
204
- standard: 52.4,
205
- billed: 68.1,
206
- cost: 41.3,
207
- successRate: 0.997,
208
- latencyMs: 640,
209
- ttftMs: 180,
210
- upstreamMs: 560,
211
- tps: 3420,
212
- failoverRate: 0.004,
213
- attempts: 1.01,
214
- },
215
- {
216
- key: "gpt-5/coding-assistant",
217
- model: "GPT-5",
218
- route: "coding-assistant",
219
- requests: 8400,
220
- inputTokens: 5_800_000,
221
- outputTokens: 3_900_000,
222
- cacheHitRate: 0.354,
223
- standard: 210.5,
224
- billed: 252.6,
225
- cost: 168.4,
226
- successRate: 0.988,
227
- latencyMs: 2460,
228
- ttftMs: 480,
229
- upstreamMs: 2280,
230
- tps: 1120,
231
- failoverRate: 0.015,
232
- attempts: 1.05,
233
- },
234
- {
235
- key: "gemini-3-flash/mobile-lite",
236
- model: "Gemini 3 Flash",
237
- route: "mobile-lite",
238
- requests: 23800,
239
- inputTokens: 4_100_000,
240
- outputTokens: 2_600_000,
241
- cacheHitRate: 0.286,
242
- standard: 38.2,
243
- billed: 45.9,
244
- cost: 30.6,
245
- successRate: 0.991,
246
- latencyMs: 720,
247
- ttftMs: 210,
248
- upstreamMs: 640,
249
- tps: 2650,
250
- failoverRate: 0.012,
251
- attempts: 1.04,
252
- },
253
- {
254
- key: "qwen3-vl-plus/vision-router",
255
- model: "Qwen3-VL Plus",
256
- route: "vision-router",
257
- requests: 6800,
258
- inputTokens: 3_400_000,
259
- outputTokens: 890_000,
260
- cacheHitRate: 0.128,
261
- standard: 96.8,
262
- billed: 116.2,
263
- cost: 77.4,
264
- successRate: 0.985,
265
- latencyMs: 2350,
266
- ttftMs: 520,
267
- upstreamMs: 2140,
268
- tps: 860,
269
- failoverRate: 0.021,
270
- attempts: 1.08,
271
- },
272
- {
273
- key: "text-embedding-3-large/embeddings-std",
274
- model: "Text Embedding 3 Large",
275
- route: "embeddings-std",
276
- requests: 96400,
277
- inputTokens: 12_400_000,
278
- outputTokens: 0,
279
- cacheHitRate: 0.052,
280
- standard: 12.8,
281
- billed: 15.4,
282
- cost: 10.2,
283
- successRate: 0.999,
284
- latencyMs: 180,
285
- ttftMs: 90,
286
- upstreamMs: 150,
287
- tps: 18500,
288
- failoverRate: 0.001,
289
- attempts: 1.0,
290
- },
291
- ];
292
-
293
- export interface ModelUsageRow extends UsageDisplay {
294
- key: string;
295
- model: string;
296
- route: string;
297
- }
298
-
299
- export function queryModelUsage(q: OpsUsageQuery): {
300
- items: ModelUsageRow[];
301
- summary: UsageSummary;
302
- total: number;
303
- } {
304
- const f = rangeFactor(q);
305
- const items = MODEL_USAGE_RAW.map((r) => ({
306
- key: r.key,
307
- model: r.model,
308
- route: r.route,
309
- ...toUsageDisplay(r, f),
310
- }));
311
- return { items, summary: summarize(MODEL_USAGE_RAW, f), total: items.length };
312
- }
313
-
314
- // ── 供应商用量 ───────────────────────────────────────────────────
315
-
316
- interface RawProviderUsage extends RawMetrics {
317
- key: string;
318
- provider: string;
319
- }
320
-
321
- const PROVIDER_USAGE_RAW: RawProviderUsage[] = [
322
- {
323
- key: "openai",
324
- provider: "OpenAI",
325
- requests: 48200,
326
- inputTokens: 9_800_000,
327
- outputTokens: 6_400_000,
328
- cacheHitRate: 0.301,
329
- standard: 312.4,
330
- billed: 374.9,
331
- cost: 249.9,
332
- successRate: 0.993,
333
- latencyMs: 1240,
334
- ttftMs: 310,
335
- upstreamMs: 1120,
336
- tps: 1420,
337
- failoverRate: 0.006,
338
- attempts: 1.02,
339
- },
340
- {
341
- key: "dashscope",
342
- provider: "阿里云百炼",
343
- requests: 52400,
344
- inputTokens: 12_600_000,
345
- outputTokens: 7_800_000,
346
- cacheHitRate: 0.386,
347
- standard: 86.4,
348
- billed: 103.7,
349
- cost: 69.1,
350
- successRate: 0.988,
351
- latencyMs: 580,
352
- ttftMs: 190,
353
- upstreamMs: 520,
354
- tps: 3240,
355
- failoverRate: 0.018,
356
- attempts: 1.06,
357
- },
358
- {
359
- key: "deepseek",
360
- provider: "DeepSeek",
361
- requests: 31200,
362
- inputTokens: 7_400_000,
363
- outputTokens: 4_600_000,
364
- cacheHitRate: 0.294,
365
- standard: 42.8,
366
- billed: 51.4,
367
- cost: 34.2,
368
- successRate: 0.984,
369
- latencyMs: 890,
370
- ttftMs: 260,
371
- upstreamMs: 810,
372
- tps: 2180,
373
- failoverRate: 0.022,
374
- attempts: 1.09,
375
- },
376
- {
377
- key: "gemini",
378
- provider: "Google Gemini",
379
- requests: 24800,
380
- inputTokens: 4_400_000,
381
- outputTokens: 2_800_000,
382
- cacheHitRate: 0.272,
383
- standard: 44.6,
384
- billed: 53.5,
385
- cost: 35.7,
386
- successRate: 0.99,
387
- latencyMs: 740,
388
- ttftMs: 220,
389
- upstreamMs: 660,
390
- tps: 2560,
391
- failoverRate: 0.011,
392
- attempts: 1.03,
393
- },
394
- {
395
- key: "anthropic",
396
- provider: "Anthropic",
397
- requests: 18400,
398
- inputTokens: 6_800_000,
399
- outputTokens: 4_200_000,
400
- cacheHitRate: 0.338,
401
- standard: 186.2,
402
- billed: 223.4,
403
- cost: 148.9,
404
- successRate: 0.996,
405
- latencyMs: 1420,
406
- ttftMs: 380,
407
- upstreamMs: 1300,
408
- tps: 1180,
409
- failoverRate: 0.003,
410
- attempts: 1.01,
411
- },
412
- {
413
- key: "azure-openai",
414
- provider: "Azure OpenAI",
415
- requests: 12600,
416
- inputTokens: 3_200_000,
417
- outputTokens: 2_100_000,
418
- cacheHitRate: 0.264,
419
- standard: 98.6,
420
- billed: 118.3,
421
- cost: 78.9,
422
- successRate: 0.971,
423
- latencyMs: 1580,
424
- ttftMs: 420,
425
- upstreamMs: 1460,
426
- tps: 980,
427
- failoverRate: 0.034,
428
- attempts: 1.12,
429
- },
430
- ];
431
-
432
- export interface ProviderUsageRow extends UsageDisplay {
433
- key: string;
434
- provider: string;
435
- }
436
-
437
- export function queryProviderUsage(q: OpsUsageQuery): {
438
- items: ProviderUsageRow[];
439
- summary: UsageSummary;
440
- total: number;
441
- } {
442
- const f = rangeFactor(q);
443
- const items = PROVIDER_USAGE_RAW.map((r) => ({
444
- key: r.key,
445
- provider: r.provider,
446
- ...toUsageDisplay(r, f),
447
- }));
448
- return {
449
- items,
450
- summary: summarize(PROVIDER_USAGE_RAW, f),
451
- total: items.length,
452
- };
453
- }
454
-
455
- // ── 客户端用量(客户端 × AppKey,含配额用量) ────────────────────
456
-
457
- interface RawClientUsage extends RawMetrics {
458
- key: string;
459
- name: string;
460
- code: string;
461
- appKeyId: string;
462
- /** 配额用量(当前周期 用量/上限;周期口径,不随时间范围缩放) */
463
- quotaUsage: string;
464
- }
465
-
466
- const CLIENT_USAGE_RAW: RawClientUsage[] = [
467
- {
468
- key: "agent-app",
469
- name: "agent-app",
470
- code: "agent-app",
471
- appKeyId: "gw-ak-7f3a2b1c",
472
- quotaUsage: "520K/1M",
473
- requests: 32400,
474
- inputTokens: 5_200_000,
475
- outputTokens: 3_100_000,
476
- cacheHitRate: 0.22,
477
- standard: 52.6,
478
- billed: 68.4,
479
- cost: 41.2,
480
- successRate: 0.991,
481
- latencyMs: 960,
482
- ttftMs: 280,
483
- upstreamMs: 860,
484
- tps: 1640,
485
- failoverRate: 0.009,
486
- attempts: 1.03,
487
- },
488
- {
489
- key: "web-portal",
490
- name: "web-portal",
491
- code: "web-portal",
492
- appKeyId: "gw-ak-9c1d4e5f",
493
- quotaUsage: "1.2M/2M",
494
- requests: 58200,
495
- inputTokens: 9_600_000,
496
- outputTokens: 6_200_000,
497
- cacheHitRate: 0.348,
498
- standard: 96.2,
499
- billed: 115.4,
500
- cost: 76.9,
501
- successRate: 0.994,
502
- latencyMs: 820,
503
- ttftMs: 240,
504
- upstreamMs: 740,
505
- tps: 2260,
506
- failoverRate: 0.007,
507
- attempts: 1.02,
508
- },
509
- {
510
- key: "internal-batch",
511
- name: "internal-batch",
512
- code: "internal-batch",
513
- appKeyId: "gw-ak-2b8e6a0d",
514
- quotaUsage: "860K/5M",
515
- requests: 12800,
516
- inputTokens: 18_400_000,
517
- outputTokens: 2_200_000,
518
- cacheHitRate: 0.086,
519
- standard: 64.8,
520
- billed: 77.8,
521
- cost: 51.8,
522
- successRate: 0.982,
523
- latencyMs: 2340,
524
- ttftMs: 460,
525
- upstreamMs: 2180,
526
- tps: 1480,
527
- failoverRate: 0.026,
528
- attempts: 1.11,
529
- },
530
- {
531
- key: "legacy-mobile",
532
- name: "legacy-mobile",
533
- code: "legacy-mobile",
534
- appKeyId: "gw-ak-5d7c9b2e",
535
- quotaUsage: "96K/500K",
536
- requests: 8600,
537
- inputTokens: 1_200_000,
538
- outputTokens: 680_000,
539
- cacheHitRate: 0.194,
540
- standard: 12.4,
541
- billed: 14.9,
542
- cost: 9.9,
543
- successRate: 0.968,
544
- latencyMs: 1120,
545
- ttftMs: 340,
546
- upstreamMs: 1020,
547
- tps: 620,
548
- failoverRate: 0.041,
549
- attempts: 1.16,
550
- },
551
- {
552
- key: "expired-trial",
553
- name: "expired-trial",
554
- code: "expired-trial",
555
- appKeyId: "gw-ak-0a4f8c6b",
556
- quotaUsage: "100K/100K",
557
- requests: 2400,
558
- inputTokens: 380_000,
559
- outputTokens: 210_000,
560
- cacheHitRate: 0.122,
561
- standard: 4.2,
562
- billed: 5.0,
563
- cost: 3.4,
564
- successRate: 0.955,
565
- latencyMs: 1380,
566
- ttftMs: 390,
567
- upstreamMs: 1260,
568
- tps: 340,
569
- failoverRate: 0.058,
570
- attempts: 1.21,
571
- },
572
- ];
573
-
574
- export interface ClientUsageRow extends UsageDisplay {
575
- key: string;
576
- name: string;
577
- code: string;
578
- appKeyId: string;
579
- quotaUsage: string;
580
- }
581
-
582
- export function queryClientUsage(q: OpsUsageQuery): {
583
- items: ClientUsageRow[];
584
- summary: UsageSummary;
585
- total: number;
586
- } {
587
- const f = rangeFactor(q);
588
- const items = CLIENT_USAGE_RAW.map((r) => ({
589
- key: r.key,
590
- name: r.name,
591
- code: r.code,
592
- appKeyId: r.appKeyId,
593
- quotaUsage: r.quotaUsage,
594
- ...toUsageDisplay(r, f),
595
- }));
596
- return { items, summary: summarize(CLIENT_USAGE_RAW, f), total: items.length };
597
- }
598
-
599
- // ── 供应商可用性(可靠性) ───────────────────────────────────────
600
-
601
- export interface ProviderQualityRow extends QualityDisplay {
602
- key: string;
603
- provider: string;
604
- /** 失败请求数(随范围缩放) */
605
- errors: string;
606
- }
607
-
608
- export interface ModelProviderCompareRow extends QualityDisplay {
609
- key: string;
610
- model: string;
611
- provider: string;
612
- }
613
-
614
- export interface RecentErrorRow {
615
- id: string;
616
- /** UTC 时间(MM-DD HH:mm:ss) */
617
- time: string;
618
- /** 模型 / 供应商 */
619
- target: string;
620
- error: string;
621
- }
622
-
623
- interface RawCompare extends RawMetrics {
624
- key: string;
625
- model: string;
626
- provider: string;
627
- }
628
-
629
- const COMPARE_RAW: RawCompare[] = [
630
- {
631
- key: "gpt-5/openai",
632
- model: "GPT-5",
633
- provider: "OpenAI",
634
- requests: 9200,
635
- inputTokens: 0,
636
- outputTokens: 0,
637
- cacheHitRate: 0,
638
- standard: 142.6,
639
- billed: 171.1,
640
- cost: 114.1,
641
- successRate: 0.995,
642
- latencyMs: 1680,
643
- ttftMs: 0,
644
- upstreamMs: 1520,
645
- tps: 0,
646
- failoverRate: 0.005,
647
- attempts: 1.01,
648
- },
649
- {
650
- key: "gpt-5/azure-openai",
651
- model: "GPT-5",
652
- provider: "Azure OpenAI",
653
- requests: 3200,
654
- inputTokens: 0,
655
- outputTokens: 0,
656
- cacheHitRate: 0,
657
- standard: 68.4,
658
- billed: 82.1,
659
- cost: 54.7,
660
- successRate: 0.972,
661
- latencyMs: 2120,
662
- ttftMs: 0,
663
- upstreamMs: 1960,
664
- tps: 0,
665
- failoverRate: 0.032,
666
- attempts: 1.11,
667
- },
668
- {
669
- key: "qwen3.5-flash/dashscope",
670
- model: "Qwen3.5 Flash",
671
- provider: "阿里云百炼",
672
- requests: 38600,
673
- inputTokens: 0,
674
- outputTokens: 0,
675
- cacheHitRate: 0,
676
- standard: 44.2,
677
- billed: 53.0,
678
- cost: 35.4,
679
- successRate: 0.998,
680
- latencyMs: 560,
681
- ttftMs: 0,
682
- upstreamMs: 500,
683
- tps: 0,
684
- failoverRate: 0.002,
685
- attempts: 1.0,
686
- },
687
- {
688
- key: "qwen3-vl-plus/dashscope",
689
- model: "Qwen3-VL Plus",
690
- provider: "阿里云百炼",
691
- requests: 6800,
692
- inputTokens: 0,
693
- outputTokens: 0,
694
- cacheHitRate: 0,
695
- standard: 96.8,
696
- billed: 116.2,
697
- cost: 77.4,
698
- successRate: 0.986,
699
- latencyMs: 2280,
700
- ttftMs: 0,
701
- upstreamMs: 2080,
702
- tps: 0,
703
- failoverRate: 0.019,
704
- attempts: 1.07,
705
- },
706
- {
707
- key: "gemini-3-flash/gemini",
708
- model: "Gemini 3 Flash",
709
- provider: "Google Gemini",
710
- requests: 23800,
711
- inputTokens: 0,
712
- outputTokens: 0,
713
- cacheHitRate: 0,
714
- standard: 38.2,
715
- billed: 45.9,
716
- cost: 30.6,
717
- successRate: 0.991,
718
- latencyMs: 720,
719
- ttftMs: 0,
720
- upstreamMs: 640,
721
- tps: 0,
722
- failoverRate: 0.012,
723
- attempts: 1.04,
724
- },
725
- {
726
- key: "text-embedding-3-large/openai",
727
- model: "Text Embedding 3 Large",
728
- provider: "OpenAI",
729
- requests: 96400,
730
- inputTokens: 0,
731
- outputTokens: 0,
732
- cacheHitRate: 0,
733
- standard: 12.8,
734
- billed: 15.4,
735
- cost: 10.2,
736
- successRate: 0.999,
737
- latencyMs: 180,
738
- ttftMs: 0,
739
- upstreamMs: 150,
740
- tps: 0,
741
- failoverRate: 0.001,
742
- attempts: 1.0,
743
- },
744
- ];
745
-
746
- const RECENT_ERRORS: RecentErrorRow[] = [
747
- {
748
- id: "e1",
749
- time: "09-19 08:42:18",
750
- target: "GPT-5 / Azure OpenAI",
751
- error: "upstream timeout (504)",
752
- },
753
- {
754
- id: "e2",
755
- time: "09-19 08:31:05",
756
- target: "Qwen3-VL Plus / 阿里云百炼",
757
- error: "rate limit exceeded (429)",
758
- },
759
- {
760
- id: "e3",
761
- time: "09-19 07:58:44",
762
- target: "GPT-5 / OpenAI",
763
- error: "connection reset by peer",
764
- },
765
- {
766
- id: "e4",
767
- time: "09-19 07:12:30",
768
- target: "Gemini 3 Flash / Google Gemini",
769
- error: "upstream timeout (504)",
770
- },
771
- {
772
- id: "e5",
773
- time: "09-19 06:45:02",
774
- target: "Qwen3.5 Flash / 阿里云百炼",
775
- error: "context length exceeded (400)",
776
- },
777
- {
778
- id: "e6",
779
- time: "09-19 05:20:37",
780
- target: "GPT-5 / Azure OpenAI",
781
- error: "service unavailable (503)",
782
- },
783
- ];
784
-
785
- export function queryAvailability(q: OpsUsageQuery): {
786
- providers: ProviderQualityRow[];
787
- compare: ModelProviderCompareRow[];
788
- errors: RecentErrorRow[];
789
- } {
790
- const f = rangeFactor(q);
791
- const providers = PROVIDER_USAGE_RAW.map((r) => ({
792
- key: r.key,
793
- provider: r.provider,
794
- errors: fmtInt(r.requests * f * (1 - r.successRate)),
795
- ...toQualityDisplay(r, f),
796
- }));
797
- const compare = COMPARE_RAW.map((r) => ({
798
- key: r.key,
799
- model: r.model,
800
- provider: r.provider,
801
- ...toQualityDisplay(r, f),
802
- }));
803
- // 极短范围仅保留最近几条错误(演示)
804
- const errors = f < 0.1 ? RECENT_ERRORS.slice(0, 2) : RECENT_ERRORS;
805
- return { providers, compare, errors };
806
- }