feat(web): 重构前端UI并支持OpenAI协议
- 添加账号管理详情页(基本信息、提示词、CapCut、参考图标签页) - 重构资产页面,按项目组分开展示图片/视频 - 聊天界面支持深度思考内容折叠展示、复制、删除消息 - 设置页面支持Agent配置(Anthropic/OpenAI协议)和工具配置 - 后端支持OpenAI兼容协议流式输出和DeepSeek思考模式 - 添加对话置顶/删除功能、数据库迁移、资产清单API - 添加账号参考图上传/删除、技能配置持久化、连接测试API
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import Anthropic from '@anthropic-ai/sdk';
|
||||
import OpenAI from 'openai';
|
||||
import { tools, ToolDefinition } from './tools';
|
||||
import { getDb } from '../db';
|
||||
import fs from 'fs';
|
||||
@@ -9,34 +10,44 @@ const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const PROJECT_ROOT = path.resolve(__dirname, '..', '..', '..', '..');
|
||||
|
||||
function getAnthropicClient(): Anthropic {
|
||||
export type Protocol = 'anthropic' | 'openai';
|
||||
|
||||
interface ApiConfig {
|
||||
protocol: Protocol;
|
||||
apiKey: string;
|
||||
baseURL: string | undefined;
|
||||
model: string;
|
||||
}
|
||||
|
||||
function getApiConfig(): ApiConfig {
|
||||
const configRow = getDb().prepare('SELECT value FROM configs WHERE key = ?').get('api_keys') as { value: string } | undefined;
|
||||
|
||||
let apiKey = process.env.ANTHROPIC_API_KEY || '';
|
||||
let baseURL: string | undefined;
|
||||
let model = process.env.ANTHROPIC_MODEL || 'claude-sonnet-4-6';
|
||||
let protocol: Protocol = 'anthropic';
|
||||
|
||||
if (configRow) {
|
||||
try {
|
||||
const cfg = JSON.parse(configRow.value);
|
||||
if (cfg.ANTHROPIC_AUTH_TOKEN) apiKey = cfg.ANTHROPIC_AUTH_TOKEN;
|
||||
if (cfg.ANTHROPIC_BASE_URL) baseURL = cfg.ANTHROPIC_BASE_URL;
|
||||
if (cfg.ANTHROPIC_MODEL) model = cfg.ANTHROPIC_MODEL;
|
||||
if (cfg.PROTOCOL === 'openai') protocol = 'openai';
|
||||
} catch {}
|
||||
}
|
||||
|
||||
return new Anthropic({
|
||||
apiKey,
|
||||
baseURL,
|
||||
});
|
||||
return { protocol, apiKey, baseURL, model };
|
||||
}
|
||||
|
||||
function getModel(): string {
|
||||
const configRow = getDb().prepare('SELECT value FROM configs WHERE key = ?').get('api_keys') as { value: string } | undefined;
|
||||
if (configRow) {
|
||||
try {
|
||||
const cfg = JSON.parse(configRow.value);
|
||||
if (cfg.ANTHROPIC_MODEL) return cfg.ANTHROPIC_MODEL;
|
||||
} catch {}
|
||||
}
|
||||
return process.env.ANTHROPIC_MODEL || 'claude-sonnet-4-6';
|
||||
function getAnthropicClient(): Anthropic {
|
||||
const { apiKey, baseURL } = getApiConfig();
|
||||
return new Anthropic({ apiKey, baseURL });
|
||||
}
|
||||
|
||||
function getOpenAIClient(): OpenAI {
|
||||
const { apiKey, baseURL } = getApiConfig();
|
||||
return new OpenAI({ apiKey, baseURL: baseURL || 'https://api.openai.com/v1' });
|
||||
}
|
||||
|
||||
export class VideoAgent {
|
||||
@@ -46,6 +57,22 @@ export class VideoAgent {
|
||||
this.tools = tools;
|
||||
}
|
||||
|
||||
getProtocol(): Protocol {
|
||||
return getApiConfig().protocol;
|
||||
}
|
||||
|
||||
getModel(): string {
|
||||
return getApiConfig().model;
|
||||
}
|
||||
|
||||
getAnthropicClient(): Anthropic {
|
||||
return getAnthropicClient();
|
||||
}
|
||||
|
||||
getOpenAIClient(): OpenAI {
|
||||
return getOpenAIClient();
|
||||
}
|
||||
|
||||
getAnthropicTools(): Anthropic.Tool[] {
|
||||
return this.tools.map((t) => ({
|
||||
name: t.name,
|
||||
@@ -54,6 +81,17 @@ export class VideoAgent {
|
||||
}));
|
||||
}
|
||||
|
||||
getOpenAITools(): OpenAI.ChatCompletionTool[] {
|
||||
return this.tools.map((t) => ({
|
||||
type: 'function' as const,
|
||||
function: {
|
||||
name: t.name,
|
||||
description: t.description,
|
||||
parameters: t.input_schema,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
async executeTool(name: string, params: Record<string, unknown>): Promise<string> {
|
||||
const tool = this.tools.find((t) => t.name === name);
|
||||
if (!tool) throw new Error(`Unknown tool: ${name}`);
|
||||
@@ -61,7 +99,6 @@ export class VideoAgent {
|
||||
}
|
||||
|
||||
getSystemPrompt(): string {
|
||||
// Dynamically list accounts
|
||||
const accountsDir = path.join(PROJECT_ROOT, 'accounts');
|
||||
let accountList = '暂无账号';
|
||||
if (fs.existsSync(accountsDir)) {
|
||||
@@ -107,14 +144,6 @@ ${accountList}
|
||||
- 如果用户只是闲聊,就闲聊。如果用户想做视频,引导完成流程
|
||||
- 不要编造账号或文件路径,使用工具获取真实信息`;
|
||||
}
|
||||
|
||||
getClient(): Anthropic {
|
||||
return getAnthropicClient();
|
||||
}
|
||||
|
||||
getModel(): string {
|
||||
return getModel();
|
||||
}
|
||||
}
|
||||
|
||||
export const videoAgent = new VideoAgent();
|
||||
|
||||
Reference in New Issue
Block a user