Files
video-create/web/server/routes/configs.ts

111 lines
3.8 KiB
TypeScript
Raw Normal View History

2026-05-07 02:27:18 +08:00
import { Router } from 'express';
import { randomUUID } from 'crypto';
import Anthropic from '@anthropic-ai/sdk';
import OpenAI from 'openai';
import fs from 'fs';
import path from 'path';
import { fileURLToPath } from 'url';
2026-05-07 02:27:18 +08:00
import { getDb } from '../db';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const PROJECT_ROOT = path.resolve(__dirname, '..', '..', '..');
const SKILLS_CONFIG_PATH = path.join(PROJECT_ROOT, '.claude', 'skills', 'config.json');
2026-05-07 02:27:18 +08:00
export const configsRouter = Router();
configsRouter.get('/', (_req, res) => {
const rows = getDb().prepare('SELECT * FROM configs ORDER BY key').all();
res.json(rows);
});
configsRouter.get('/:key', (req, res) => {
const row = getDb().prepare('SELECT * FROM configs WHERE key = ?').get(req.params.key);
if (!row) return res.status(404).json({ error: 'Config not found' });
res.json(row);
});
configsRouter.put('/:key', (req, res) => {
const { value } = req.body;
getDb().prepare(`
INSERT INTO configs (id, key, value, updated_at)
VALUES (?, ?, ?, datetime('now'))
ON CONFLICT(key) DO UPDATE SET value = excluded.value, updated_at = excluded.updated_at
`).run(randomUUID(), req.params.key, JSON.stringify(value));
res.json({ key: req.params.key, ok: true });
});
// Skills config.json (pipeline tools configuration)
configsRouter.get('/skills/file', (_req, res) => {
try {
const data = JSON.parse(fs.readFileSync(SKILLS_CONFIG_PATH, 'utf-8'));
res.json(data);
} catch {
res.status(404).json({ error: 'Skills config not found' });
}
});
configsRouter.put('/skills/file', (req, res) => {
try {
fs.writeFileSync(SKILLS_CONFIG_PATH, JSON.stringify(req.body, null, 2), 'utf-8');
res.json({ ok: true });
} catch (e) {
res.status(500).json({ error: (e as Error).message });
}
});
// Test API connection
configsRouter.post('/test-connection', async (_req, res) => {
const configRow = getDb().prepare('SELECT value FROM configs WHERE key = ?').get('api_keys') as { value: string } | undefined;
if (!configRow) return res.json({ ok: false, error: '未配置 API Key' });
let apiKey = '';
let baseURL: string | undefined;
let protocol: string = 'anthropic';
let model: string = 'claude-sonnet-4-6';
try {
const cfg = JSON.parse(configRow.value);
apiKey = cfg.ANTHROPIC_AUTH_TOKEN || '';
baseURL = cfg.ANTHROPIC_BASE_URL;
protocol = cfg.PROTOCOL || 'anthropic';
model = cfg.ANTHROPIC_MODEL || model;
} catch {
return res.json({ ok: false, error: '配置解析失败' });
}
if (!apiKey) return res.json({ ok: false, error: 'API Key 为空' });
try {
if (protocol === 'openai') {
const client = new OpenAI({ apiKey, baseURL: baseURL || 'https://api.openai.com/v1' });
const models = await client.models.list();
const modelIds: string[] = [];
for await (const m of models) { modelIds.push(m.id); if (modelIds.length >= 5) break; }
res.json({ ok: true, models: modelIds });
} else {
const client = new Anthropic({ apiKey, baseURL });
// Anthropic SDK doesn't have a models.list() in all versions, try a minimal request
try {
await client.messages.create({
model,
max_tokens: 1,
messages: [{ role: 'user', content: 'hi' }],
});
res.json({ ok: true, models: [model] });
} catch (e: unknown) {
const err = e as { status?: number; message?: string };
if (err.status === 401) {
res.json({ ok: false, error: `认证失败: ${err.message}` });
} else if (err.status === 400 || err.status === undefined) {
res.json({ ok: true, models: [model] });
} else {
res.json({ ok: false, error: `错误 (${err.status}): ${err.message}` });
}
}
}
} catch (e) {
res.json({ ok: false, error: (e as Error).message });
}
});