fix:将ui改成扁平化ui,优化ui错误

This commit is contained in:
lsy committed 2026-03-18 21:48:50 +08:00
1 parent d87610151c
commit d6aa20e85b
36 files changed
+4023 -2973

No files matched your search

@@ -1,7 +1,7 @@
import type { D1Database } from "@cloudflare/workers-types";
import { nowIso } from "../utils/time";
import { extractModelIds } from "./channel-models";
import type { ModelEntry } from "./channel-models";
import { extractModelIds } from "./channel-models";
export type CapabilityRow = {
channel_id: string;
@@ -51,7 +51,9 @@ export async function listVerifiedModelEntries(
channels: Array<{ id: string; name: string }>,
): Promise<ModelEntry[]> {
const ids = channels.map((channel) => channel.id);
const nameMap = new Map(channels.map((channel) => [channel.id, channel.name]));
const nameMap = new Map(
channels.map((channel) => [channel.id, channel.name]),
);
const map = await listVerifiedModelsByChannel(db, ids);
const entries: ModelEntry[] = [];
for (const [channelId, models] of map.entries()) {
@@ -96,7 +98,12 @@ export async function listModelEntriesWithFallback(
continue;
}
for (const id of models) {
entries.push({ id, label: id, channelId: channel.id, channelName: channel.name });
entries.push({
id,
label: id,
channelId: channel.id,
channelName: channel.name,
});
}
}
return entries;
@@ -153,14 +160,7 @@ export async function recordChannelModelError(
.prepare(
"INSERT INTO channel_model_capabilities (channel_id, model, last_ok_at, last_err_at, last_err_code, last_err_count, created_at, updated_at) VALUES (?, ?, 0, ?, ?, 1, ?, ?) ON CONFLICT(channel_id, model) DO UPDATE SET last_err_at = excluded.last_err_at, last_err_code = excluded.last_err_code, last_err_count = COALESCE(channel_model_capabilities.last_err_count, 0) + 1, updated_at = excluded.updated_at",
)
.bind(
channelId,
model,
nowSeconds,
errorCode,
timestamp,
timestamp,
)
.bind(channelId, model, nowSeconds, errorCode, timestamp, timestamp)
.run();
}
+1 -1
View File
@@ -1,8 +1,8 @@
import type { D1Database } from "@cloudflare/workers-types";
import { nowIso } from "../utils/time";
import { normalizeBaseUrl } from "../utils/url";
import { modelsToJson, normalizeModelsInput } from "./channel-models";
import { upsertChannelModelCapabilities } from "./channel-model-capabilities";
import { modelsToJson, normalizeModelsInput } from "./channel-models";
export type ChannelTestResult = {
ok: boolean;
@@ -260,7 +260,9 @@ function writeGeminiChunk(
controller.enqueue(encoder.encode(`${JSON.stringify(data)}\n`));
}
async function adaptOpenAiJsonToAnthropic(options: AdaptOptions): Promise<Response> {
async function adaptOpenAiJsonToAnthropic(
options: AdaptOptions,
): Promise<Response> {
const payload = (await options.response
.clone()
.json()
@@ -283,7 +285,9 @@ async function adaptOpenAiJsonToAnthropic(options: AdaptOptions): Promise<Respon
: {};
const promptTokens = Number(usage.prompt_tokens ?? 0) || 0;
const completionTokens = Number(usage.completion_tokens ?? 0) || 0;
const stopReason = mapOpenAiFinishReasonToAnthropic(firstChoice.finish_reason);
const stopReason = mapOpenAiFinishReasonToAnthropic(
firstChoice.finish_reason,
);
const text = openAiContentToText(message.content);
const transformed = {
id:
@@ -460,7 +464,9 @@ function adaptOpenAiSseToAnthropic(options: AdaptOptions): Response {
});
}
async function adaptAnthropicJsonToOpenAi(options: AdaptOptions): Promise<Response> {
async function adaptAnthropicJsonToOpenAi(
options: AdaptOptions,
): Promise<Response> {
const payload = (await options.response
.clone()
.json()
@@ -552,7 +558,8 @@ function adaptAnthropicSseToOpenAi(options: AdaptOptions): Response {
newlineIndex = buffer.indexOf("\n");
continue;
}
const eventType = typeof parsed.type === "string" ? parsed.type : "";
const eventType =
typeof parsed.type === "string" ? parsed.type : "";
if (!started && eventType === "message_start") {
started = true;
writeOpenAiSseChunk(controller, encoder, {
@@ -642,7 +649,9 @@ function adaptAnthropicSseToOpenAi(options: AdaptOptions): Response {
});
}
async function adaptGeminiJsonToOpenAi(options: AdaptOptions): Promise<Response> {
async function adaptGeminiJsonToOpenAi(
options: AdaptOptions,
): Promise<Response> {
const payload = (await options.response
.clone()
.json()
@@ -651,7 +660,9 @@ async function adaptGeminiJsonToOpenAi(options: AdaptOptions): Promise<Response>
return options.response;
}
const text = geminiCandidateText(payload);
const finishReason = mapGeminiFinishReasonToOpenAi(geminiFinishReason(payload));
const finishReason = mapGeminiFinishReasonToOpenAi(
geminiFinishReason(payload),
);
const usage = geminiUsageTokens(payload);
const transformed = {
id: `chatcmpl_${Date.now()}`,
@@ -680,7 +691,9 @@ async function adaptGeminiJsonToOpenAi(options: AdaptOptions): Promise<Response>
});
}
async function adaptGeminiJsonToAnthropic(options: AdaptOptions): Promise<Response> {
async function adaptGeminiJsonToAnthropic(
options: AdaptOptions,
): Promise<Response> {
const payload = (await options.response
.clone()
.json()
@@ -712,7 +725,9 @@ async function adaptGeminiJsonToAnthropic(options: AdaptOptions): Promise<Respon
});
}
async function adaptOpenAiJsonToGemini(options: AdaptOptions): Promise<Response> {
async function adaptOpenAiJsonToGemini(
options: AdaptOptions,
): Promise<Response> {
const payload = (await options.response
.clone()
.json()
@@ -757,7 +772,9 @@ async function adaptOpenAiJsonToGemini(options: AdaptOptions): Promise<Response>
});
}
async function adaptAnthropicJsonToGemini(options: AdaptOptions): Promise<Response> {
async function adaptAnthropicJsonToGemini(
options: AdaptOptions,
): Promise<Response> {
const payload = (await options.response
.clone()
.json()
@@ -833,7 +850,11 @@ function adaptGeminiSseToOpenAi(options: AdaptOptions): Response {
created,
model: options.model ?? "",
choices: [
{ index: 0, delta: { role: "assistant" }, finish_reason: null },
{
index: 0,
delta: { role: "assistant" },
finish_reason: null,
},
],
});
}
@@ -952,7 +973,9 @@ function adaptGeminiSseToAnthropic(options: AdaptOptions): Response {
writeSseEvent(controller, encoder, "message_delta", {
type: "message_delta",
delta: { stop_reason: stopReason, stop_sequence: null },
usage: { output_tokens: geminiUsageTokens(parsed).completionTokens },
usage: {
output_tokens: geminiUsageTokens(parsed).completionTokens,
},
});
writeSseEvent(controller, encoder, "message_stop", {
type: "message_stop",
@@ -1051,7 +1074,9 @@ function adaptOpenAiSseToGemini(options: AdaptOptions): Response {
}
if (!lastFinishReason) {
writeGeminiChunk(controller, encoder, {
candidates: [{ content: { role: "model", parts: [] }, finishReason: "STOP" }],
candidates: [
{ content: { role: "model", parts: [] }, finishReason: "STOP" },
],
});
}
controller.close();
@@ -1096,7 +1121,8 @@ function adaptAnthropicSseToGemini(options: AdaptOptions): Response {
newlineIndex = buffer.indexOf("\n");
continue;
}
const eventType = typeof parsed.type === "string" ? parsed.type : "";
const eventType =
typeof parsed.type === "string" ? parsed.type : "";
if (eventType === "content_block_delta") {
const delta =
parsed.delta && typeof parsed.delta === "object"
@@ -1119,7 +1145,8 @@ function adaptAnthropicSseToGemini(options: AdaptOptions): Response {
? (parsed.delta as Record<string, unknown>)
: {};
lastFinishReason =
mapAnthropicStopReasonToGemini(delta.stop_reason) ?? lastFinishReason;
mapAnthropicStopReasonToGemini(delta.stop_reason) ??
lastFinishReason;
}
newlineIndex = buffer.indexOf("\n");
}
@@ -1185,7 +1212,9 @@ const adapters: Record<string, AdapterFn> = {
},
};
export async function adaptChatResponse(options: AdaptOptions): Promise<Response> {
export async function adaptChatResponse(
options: AdaptOptions,
): Promise<Response> {
if (options.upstreamProvider === options.downstreamProvider) {
return options.response;
}
+5 -4
View File
@@ -185,7 +185,10 @@ function parsePositiveNumber(value: string | null, fallback: number): number {
return fallback;
}
function parseNonNegativeSetting(value: string | null, fallback: number): number {
function parseNonNegativeSetting(
value: string | null,
fallback: number,
): number {
if (!value) {
return fallback;
}
@@ -259,9 +262,7 @@ function clearCacheConfigSnapshot(): void {
cacheConfigSnapshot = null;
}
function setSettingsCacheControlSnapshot(
value: SettingsCacheControl,
): void {
function setSettingsCacheControlSnapshot(value: SettingsCacheControl): void {
settingsCacheControlSnapshot = {
value,
expiresAt: Date.now() + CACHE_CONFIG_TTL_MS,
+2 -4
View File
@@ -77,8 +77,7 @@ export class UsageLimiter {
return new Response("Invalid payload", { status: 400 });
}
const nowDate = beijingDateString(new Date());
let storedDate =
(await this.state.storage.get<string>(DATE_KEY)) ?? null;
let storedDate = (await this.state.storage.get<string>(DATE_KEY)) ?? null;
let count = (await this.state.storage.get<number>(COUNT_KEY)) ?? 0;
if (storedDate !== nowDate) {
storedDate = nowDate;
@@ -106,8 +105,7 @@ export class UsageLimiter {
}
if (request.method === "GET" && url.pathname === "/status") {
const nowDate = beijingDateString(new Date());
let storedDate =
(await this.state.storage.get<string>(DATE_KEY)) ?? null;
let storedDate = (await this.state.storage.get<string>(DATE_KEY)) ?? null;
let count = (await this.state.storage.get<number>(COUNT_KEY)) ?? 0;
if (storedDate !== nowDate) {
storedDate = nowDate;
+4 -1
View File
@@ -1,6 +1,9 @@
import type { D1Database, ExecutionContext } from "@cloudflare/workers-types";
import type { Bindings } from "../env";
import { recordChannelModelError, upsertChannelModelCapabilities } from "./channel-model-capabilities";
import {
recordChannelModelError,
upsertChannelModelCapabilities,
} from "./channel-model-capabilities";
import type { UsageInput } from "./usage";
import { recordUsage } from "./usage";