106 lines
3.3 KiB
TypeScript
106 lines
3.3 KiB
TypeScript
import type { VisualTaskQueryResponse, VisualTaskSubmitResponse } from "@/lib/types";
|
|
import { signVolcengineRequest } from "@/lib/volcengine/signature";
|
|
|
|
export type VisualClientConfig = {
|
|
accessKeyId: string;
|
|
secretAccessKey: string;
|
|
region: string;
|
|
service: string;
|
|
endpoint: string;
|
|
};
|
|
|
|
export function getVisualClientConfig(): VisualClientConfig | null {
|
|
const accessKeyId = process.env.VOLCENGINE_ACCESS_KEY_ID;
|
|
const secretAccessKey = process.env.VOLCENGINE_SECRET_ACCESS_KEY;
|
|
if (!accessKeyId || !secretAccessKey) return null;
|
|
return {
|
|
accessKeyId,
|
|
secretAccessKey,
|
|
region: process.env.VOLCENGINE_REGION || "cn-north-1",
|
|
service: process.env.VOLCENGINE_SERVICE || "cv",
|
|
endpoint: process.env.VOLCENGINE_VISUAL_ENDPOINT || "https://visual.volcengineapi.com"
|
|
};
|
|
}
|
|
|
|
export async function submitVisualTask(
|
|
payload: Record<string, unknown>,
|
|
config = getVisualClientConfig()
|
|
): Promise<VisualTaskSubmitResponse> {
|
|
if (!config) throw new Error("Volcengine Visual credentials are not configured.");
|
|
const protocol = visualProtocolForPayload(payload);
|
|
return callVisualApi<VisualTaskSubmitResponse>(protocol.submitAction, protocol.version, payload, config);
|
|
}
|
|
|
|
export async function queryVisualTask(
|
|
payload: Record<string, unknown>,
|
|
config = getVisualClientConfig()
|
|
): Promise<VisualTaskQueryResponse> {
|
|
if (!config) throw new Error("Volcengine Visual credentials are not configured.");
|
|
const protocol = visualProtocolForPayload(payload);
|
|
return callVisualApi<VisualTaskQueryResponse>(protocol.queryAction, protocol.version, payload, config);
|
|
}
|
|
|
|
type VisualAction =
|
|
| "CVSync2AsyncSubmitTask"
|
|
| "CVSync2AsyncGetResult"
|
|
| "JimengSeedream46CVToBSubmitTask"
|
|
| "JimengSeedream46CVToBGetResult";
|
|
|
|
function visualProtocolForPayload(payload: Record<string, unknown>): {
|
|
submitAction: VisualAction;
|
|
queryAction: VisualAction;
|
|
version: string;
|
|
} {
|
|
if (String(payload.req_key || "").trim() === "jimeng_seedream46_cvtob") {
|
|
return {
|
|
submitAction: "JimengSeedream46CVToBSubmitTask",
|
|
queryAction: "JimengSeedream46CVToBGetResult",
|
|
version: "2024-06-06"
|
|
};
|
|
}
|
|
return {
|
|
submitAction: "CVSync2AsyncSubmitTask",
|
|
queryAction: "CVSync2AsyncGetResult",
|
|
version: "2022-08-31"
|
|
};
|
|
}
|
|
|
|
async function callVisualApi<T>(
|
|
action: VisualAction,
|
|
version: string,
|
|
payload: Record<string, unknown>,
|
|
config: VisualClientConfig
|
|
): Promise<T> {
|
|
const body = JSON.stringify(payload);
|
|
const signed = signVolcengineRequest({
|
|
method: "POST",
|
|
endpoint: config.endpoint,
|
|
query: {
|
|
Action: action,
|
|
Version: version
|
|
},
|
|
body,
|
|
accessKeyId: config.accessKeyId,
|
|
secretAccessKey: config.secretAccessKey,
|
|
region: config.region,
|
|
service: config.service
|
|
});
|
|
const response = await fetch(signed.url, {
|
|
method: "POST",
|
|
headers: signed.headers,
|
|
body
|
|
});
|
|
const text = await response.text();
|
|
let json: unknown;
|
|
try {
|
|
json = JSON.parse(text);
|
|
} catch {
|
|
throw new Error(`Volcengine Visual returned non-JSON response: ${response.status} ${text.slice(0, 240)}`);
|
|
}
|
|
if (!response.ok) {
|
|
const message = typeof json === "object" && json && "message" in json ? String(json.message) : text;
|
|
throw new Error(`Volcengine Visual HTTP ${response.status}: ${message}`);
|
|
}
|
|
return json as T;
|
|
}
|