feat: add sub2api source compatibility
This commit is contained in:
@@ -40,7 +40,7 @@ const emptySettings: AdminSettings = {
|
||||
},
|
||||
private: { channels: [], promptSync: { enabled: true, cron: "*/5 * * * *" }, auth: { linuxDo: { clientId: "", clientSecret: "" } } },
|
||||
};
|
||||
const emptyChannel: AdminModelChannel = { protocol: "openai", name: "", baseUrl: "", apiKey: "", models: [], weight: 1, enabled: true, remark: "" };
|
||||
const emptyChannel: AdminModelChannel = { protocol: "openai", compatibility: "openai", name: "", baseUrl: "", apiKey: "", models: [], weight: 1, enabled: true, remark: "", requestOptions: { imageResponseFormat: "b64_json" } };
|
||||
|
||||
type SettingsTabKey = "public" | "private";
|
||||
type EditorMode = "visual" | "json";
|
||||
@@ -467,15 +467,17 @@ export default function AdminSettingsPage() {
|
||||
dataIndex: "credits",
|
||||
width: 220,
|
||||
render: (_, item) => (
|
||||
<InputNumber
|
||||
min={0}
|
||||
step={1}
|
||||
precision={0}
|
||||
className="!w-full"
|
||||
value={item.credits}
|
||||
addonAfter="点"
|
||||
onChange={(value) => setModelCost(form, setModelCosts, item.model, Number(value) || 0)}
|
||||
/>
|
||||
<Space.Compact className="!w-full">
|
||||
<InputNumber
|
||||
min={0}
|
||||
step={1}
|
||||
precision={0}
|
||||
className="!w-full"
|
||||
value={item.credits}
|
||||
onChange={(value) => setModelCost(form, setModelCosts, item.model, Number(value) || 0)}
|
||||
/>
|
||||
<Button disabled>点</Button>
|
||||
</Space.Compact>
|
||||
),
|
||||
},
|
||||
]}
|
||||
@@ -558,6 +560,7 @@ export default function AdminSettingsPage() {
|
||||
columns={[
|
||||
{ title: "名称", dataIndex: "name", render: (value) => value || "未命名渠道" },
|
||||
{ title: "协议", dataIndex: "protocol", width: 96, render: (value) => <Tag>{value || "openai"}</Tag> },
|
||||
{ title: "兼容", dataIndex: "compatibility", width: 110, render: (value) => <Tag color={value === "sub2api" ? "blue" : "default"}>{value === "sub2api" ? "Sub2API" : "OpenAI"}</Tag> },
|
||||
{ title: "状态", dataIndex: "enabled", width: 96, render: (value) => <Tag color={value ? "success" : "default"}>{value ? "已启用" : "已停用"}</Tag> },
|
||||
{
|
||||
title: "模型",
|
||||
@@ -640,6 +643,20 @@ export default function AdminSettingsPage() {
|
||||
<Select options={[{ label: "OpenAI", value: "openai" }]} />
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Form.Item name="compatibility" label="接口兼容模式" extra="选择 Sub2API 后,图片请求默认使用 URL 返回格式,Base URL 仍填写 Sub2API 的 OpenAI 兼容地址。">
|
||||
<Select
|
||||
options={[
|
||||
{ label: "OpenAI 兼容", value: "openai" },
|
||||
{ label: "Sub2API", value: "sub2api" },
|
||||
]}
|
||||
onChange={(value) => {
|
||||
if (value === "sub2api") channelForm.setFieldValue(["requestOptions", "imageResponseFormat"], "url");
|
||||
if (value === "openai") channelForm.setFieldValue(["requestOptions", "imageResponseFormat"], "b64_json");
|
||||
}}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={12}>
|
||||
<Form.Item name="weight" label="权重">
|
||||
<InputNumber min={1} step={1} className="!w-full" />
|
||||
@@ -670,6 +687,16 @@ export default function AdminSettingsPage() {
|
||||
</Space.Compact>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<Form.Item name={["requestOptions", "imageResponseFormat"]} label="图片返回格式" extra="Sub2API 推荐 url;OpenAI 官方也支持 b64_json。前端两种返回都能解析。">
|
||||
<Select
|
||||
options={[
|
||||
{ label: "URL(推荐 Sub2API)", value: "url" },
|
||||
{ label: "Base64 JSON", value: "b64_json" },
|
||||
]}
|
||||
/>
|
||||
</Form.Item>
|
||||
</Col>
|
||||
<Col span={24}>
|
||||
<Form.Item name="remark" label="备注">
|
||||
<Input.TextArea rows={3} />
|
||||
@@ -870,8 +897,11 @@ function normalizePrivateSetting(setting: Partial<AdminSettings["private"]> = {}
|
||||
}
|
||||
|
||||
function normalizeChannel(item: Partial<AdminModelChannel> = {}): AdminModelChannel {
|
||||
const compatibility = item.compatibility === "sub2api" ? "sub2api" : "openai";
|
||||
const imageResponseFormat = item.requestOptions?.imageResponseFormat === "url" || item.requestOptions?.imageResponseFormat === "b64_json" ? item.requestOptions.imageResponseFormat : compatibility === "sub2api" ? "url" : "b64_json";
|
||||
return {
|
||||
protocol: "openai",
|
||||
compatibility,
|
||||
name: item.name || "",
|
||||
baseUrl: item.baseUrl || "",
|
||||
apiKey: item.apiKey || "",
|
||||
@@ -879,6 +909,7 @@ function normalizeChannel(item: Partial<AdminModelChannel> = {}): AdminModelChan
|
||||
weight: Math.max(1, Number(item.weight) || 1),
|
||||
enabled: item.enabled !== false,
|
||||
remark: item.remark || "",
|
||||
requestOptions: { imageResponseFormat },
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -158,6 +158,7 @@ export async function deleteAdminAsset(token: string, id: string) {
|
||||
|
||||
export type AdminModelChannel = {
|
||||
protocol: "openai";
|
||||
compatibility: "openai" | "sub2api";
|
||||
name: string;
|
||||
baseUrl: string;
|
||||
apiKey: string;
|
||||
@@ -165,6 +166,9 @@ export type AdminModelChannel = {
|
||||
weight: number;
|
||||
enabled: boolean;
|
||||
remark: string;
|
||||
requestOptions: {
|
||||
imageResponseFormat: "b64_json" | "url";
|
||||
};
|
||||
};
|
||||
|
||||
export type AdminPublicModelChannelSettings = {
|
||||
|
||||
Reference in New Issue
Block a user