/** * 扩展 ai_providers.provider 枚举:添加 'ollama' 用于本地 Ollama 连接 * * 背景: * - Ollama 提供 OpenAI 兼容的 /v1/chat/completions 端点 * - 无需 API Key(本地部署),无需公网 * - 默认地址 http://localhost:11434/v1 * * 变更: * - ai_providers.provider ENUM 增加 'ollama' * * 幂等:脚本会先读取当前枚举值,若已包含 'ollama' 则跳过。 */ require("dotenv/config"); const mysql = require("mysql2/promise"); async function getCurrentEnum(conn) { const [rows] = await conn.execute( `SELECT COLUMN_TYPE FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'ai_providers' AND COLUMN_NAME = 'provider'`, ); if (rows.length === 0) return null; // 形如 "enum('zhipu','openai','gemini','custom')" const match = rows[0].COLUMN_TYPE.match(/enum\((.*)\)/i); if (!match) return null; return match[1] .split(",") .map((s) => s.trim().replace(/^'|'$/g, "")); } async function main() { const conn = await mysql.createConnection({ uri: process.env.DATABASE_URL }); console.log("✅ 已连接数据库\n"); const current = await getCurrentEnum(conn); if (!current) { console.error("❌ 无法读取 ai_providers.provider 列定义,请确认表已创建"); await conn.end(); process.exit(1); } console.log(`当前枚举值: [${current.join(", ")}]`); if (current.includes("ollama")) { console.log("⏭️ 枚举已包含 'ollama',无需修改"); await conn.end(); process.exitCode = 0; return; } const nextValues = [...current, "ollama"]; const nextEnum = nextValues.map((v) => `'${v}'`).join(","); const sql = `ALTER TABLE \`ai_providers\` MODIFY COLUMN \`provider\` ENUM(${nextEnum}) NOT NULL`; try { await conn.execute(sql); console.log(`✅ 执行成功: ${sql}`); } catch (err) { console.error(`❌ 执行失败: ${err.message}`); console.error(` SQL: ${sql}`); await conn.end(); process.exit(1); } // 验证 const verify = await getCurrentEnum(conn); if (verify && verify.includes("ollama")) { console.log(`\n✅ 验证通过,新枚举值: [${verify.join(", ")}]`); } else { console.log("\n❌ 验证失败,ollama 未出现在枚举中"); } await conn.end(); process.exitCode = 0; } main().catch((err) => { console.error("致命错误:", err); process.exit(1); });