feat(wp7-02): support Gemini chat image relay
Dada P0-A isolated Windows CI / validate-and-package (push) Canceled after 0s

This commit is contained in:
suyx
2026-08-04 18:38:33 +08:00
parent 6e5313e283
commit a54efb146a
+43 -3
View File
@@ -26,7 +26,7 @@ function assertModelConfig(modelConfig) {
const profile = modelConfig.route_profile; const profile = modelConfig.route_profile;
if (!profile || typeof profile !== "object" || typeof profile.endpoint !== "string" if (!profile || typeof profile !== "object" || typeof profile.endpoint !== "string"
|| !profile.endpoint.startsWith("https://oneapi.intelligrow.cn/") || !profile.endpoint.startsWith("https://oneapi.intelligrow.cn/")
|| !["gemini-interactions-v1beta", "gemini-native-v1beta", "openai-images-v1"].includes(profile.protocol_version)) { || !["gemini-interactions-v1beta", "gemini-native-v1beta", "gemini-openai-chat-v1", "openai-images-v1"].includes(profile.protocol_version)) {
throw new Error("WP7_02_ROUTE_PROFILE_INVALID"); throw new Error("WP7_02_ROUTE_PROFILE_INVALID");
} }
if (profile.protocol_version === "gemini-interactions-v1beta" if (profile.protocol_version === "gemini-interactions-v1beta"
@@ -34,6 +34,11 @@ function assertModelConfig(modelConfig) {
|| profile.provider_model_id !== "gemini-3.1-flash-image")) { || profile.provider_model_id !== "gemini-3.1-flash-image")) {
throw new Error("WP7_02_ROUTE_PROFILE_INVALID"); throw new Error("WP7_02_ROUTE_PROFILE_INVALID");
} }
if (profile.protocol_version === "gemini-openai-chat-v1"
&& (profile.endpoint !== "https://oneapi.intelligrow.cn/v1/chat/completions"
|| profile.provider_model_id !== "gemini-3.1-flash-image")) {
throw new Error("WP7_02_ROUTE_PROFILE_INVALID");
}
if (profile.protocol_version === "openai-images-v1" if (profile.protocol_version === "openai-images-v1"
&& (profile.reference_endpoint !== "https://oneapi.intelligrow.cn/v1/images/edits")) { && (profile.reference_endpoint !== "https://oneapi.intelligrow.cn/v1/images/edits")) {
throw new Error("WP7_02_REFERENCE_ROUTE_PROFILE_INVALID"); throw new Error("WP7_02_REFERENCE_ROUTE_PROFILE_INVALID");
@@ -108,6 +113,28 @@ export function buildProviderRequest({ modelConfig, prompt, ratio, reference })
url: config.route_profile.endpoint, url: config.route_profile.endpoint,
}; };
} }
if (config.route_profile.protocol_version === "gemini-openai-chat-v1") {
const content = reference
? [
{ text: prompt, type: "text" },
{
image_url: { url: `data:${reference.mime_type};base64,${reference.bytes.toString("base64")}` },
type: "image_url",
},
]
: prompt;
return {
body: {
extra_body: { google: { image_config: { aspect_ratio: ratio, image_size: "1K" } } },
messages: [{ content, role: "user" }],
model: config.route_profile.provider_model_id,
stream: false,
},
headers,
method: "POST",
url: config.route_profile.endpoint,
};
}
const providerModelId = config.route_profile.provider_model_id ?? config.model_id; const providerModelId = config.route_profile.provider_model_id ?? config.model_id;
const body = { const body = {
model: providerModelId, model: providerModelId,
@@ -193,12 +220,20 @@ function geminiUsage(response) {
function openAiUsage(response) { function openAiUsage(response) {
const usage = response?.usage; const usage = response?.usage;
return { return {
input_units: integerOrZero(usage?.input_tokens ?? usage?.inputTokens), input_units: integerOrZero(usage?.input_tokens ?? usage?.inputTokens ?? usage?.prompt_tokens ?? usage?.promptTokens),
output_units: integerOrZero(usage?.output_tokens ?? usage?.outputTokens), output_units: integerOrZero(usage?.output_tokens ?? usage?.outputTokens ?? usage?.completion_tokens ?? usage?.completionTokens),
total_units: integerOrZero(usage?.total_tokens ?? usage?.totalTokens), total_units: integerOrZero(usage?.total_tokens ?? usage?.totalTokens),
}; };
} }
function openAiChatImage(response) {
const content = response?.choices?.[0]?.message?.content;
if (typeof content !== "string") throw new Error("WP7_02_RESPONSE_SINGLE_IMAGE_REQUIRED");
const matches = [...content.matchAll(/!\[[^\]]*\]\(\s*data:(image\/(?:jpeg|png|webp));base64,([A-Za-z0-9+/=\r\n]+)\s*\)/gi)];
if (matches.length !== 1) throw new Error("WP7_02_RESPONSE_SINGLE_IMAGE_REQUIRED");
return { data: matches[0][2], mime: matches[0][1].toLowerCase() };
}
function interactionUsage(response) { function interactionUsage(response) {
const usage = response?.usage; const usage = response?.usage;
return { return {
@@ -230,6 +265,11 @@ export function normalizeProviderResponse(modelConfig, response) {
mime = images[0].mimeType ?? images[0].mime_type; mime = images[0].mimeType ?? images[0].mime_type;
bytes = Buffer.from(images[0].data, "base64"); bytes = Buffer.from(images[0].data, "base64");
usageSummary = geminiUsage(response); usageSummary = geminiUsage(response);
} else if (config.route_profile.protocol_version === "gemini-openai-chat-v1") {
const image = openAiChatImage(response);
bytes = Buffer.from(image.data, "base64");
mime = image.mime;
usageSummary = openAiUsage(response);
} else { } else {
if (!Array.isArray(response?.data) || response.data.length !== 1 || typeof response.data[0]?.b64_json !== "string") { if (!Array.isArray(response?.data) || response.data.length !== 1 || typeof response.data[0]?.b64_json !== "string") {
throw new Error("WP7_02_RESPONSE_SINGLE_IMAGE_REQUIRED"); throw new Error("WP7_02_RESPONSE_SINGLE_IMAGE_REQUIRED");