"use strict"; // On the application host: APP_ROOT=/var/www/ai-chatbot node scripts/configure-aliyun-canvas-analysis.cjs [--apply] // Dry-run by default. Reuses the existing official Aliyun provider and never prints its key. const fs = require("node:fs"); const root = process.env.APP_ROOT || process.cwd(); require(root + "/node_modules/dotenv").config({ path: root + "/.env.local", quiet: true }); const sql = require(root + "/node_modules/postgres")(process.env.POSTGRES_URL, { max: 1 }); const apply = process.argv.includes("--apply"); const models = [ { id: "qwen3.8-max", name: "千问3.8 Max(视频画面理解)", order: 410 }, { id: "qwen3.8-omni-flash", name: "千问3.8 Omni Flash(视频画面与声音)", order: 411 }, ]; (async () => { const providers = await sql`select id,"baseUrl","isEnabled",("apiKey" is not null and length("apiKey") > 0) as "hasKey" from "AiProvider" where type='alibaba'`; const provider = providers.find((row) => { try { return row.isEnabled && row.hasKey && new URL(row.baseUrl).hostname === "dashscope.aliyuncs.com"; } catch { return false; } }); if (!provider) throw new Error("Enabled official Aliyun provider with key not found"); const existingModels = await sql`select * from "AiModel" where "providerId"=${provider.id} and "modelId" in ${sql(models.map((m) => m.id))}`; if (apply) { const dir = root + "/.model-config-backups"; fs.mkdirSync(dir, { recursive: true, mode: 0o700 }); fs.writeFileSync(dir + "/canvas-analysis-" + Date.now() + ".json", JSON.stringify({ providerId: provider.id, models: existingModels }, null, 2), { mode: 0o600 }); } await sql.begin(async (tx) => { for (const model of models) { const rows = existingModels.filter((row) => row.modelId === model.id); if (rows.length > 1) throw new Error("Duplicate model rows: " + model.id); const row = rows[0]; if (apply && row) { await tx`update "AiModel" set "isEnabled"=true,"supportsVision"=true, "updatedAt"=now() where id=${row.id}`; } else if (apply) { await tx`insert into "AiModel" ("providerId","modelId","displayName","supportsVision","isEnabled","isHidden",capabilities,"sortOrder") values (${provider.id},${model.id},${model.name},true,true,false, ${tx.json({ kind: "chat", modality: ["text", "image", "video"], supportsVideo: true, supportsVideoAudio: model.id.includes("omni") })},${model.order})`; } console.log(JSON.stringify({ mode: apply ? "applied" : "dry-run", modelId: model.id, existed: !!row, enabled: apply ? true : row?.isEnabled || false, vision: apply ? true : row?.supportsVision || false })); } }); })().catch((error) => { console.error(error.name || "Configuration error"); process.exitCode = 1; }).finally(() => sql.end());