系统框架文档
一、项目结构
bossagents/
├── app/
│ ├── (auth)/
│ │ ├── auth.ts # 认证配置
│ │ ├── login/
│ │ │ └── page.tsx # 登录页
│ │ └── register/
│ │ └── page.tsx # 注册页
│ ├── (chat)/
│ │ ├── chat/
│ │ │ └── [id]/
│ │ │ └── page.tsx # 聊天页
│ │ ├── api/
│ │ │ └── chat/
│ │ │ └── route.ts # 聊天API
│ │ └── layout.tsx # 聊天布局
│ ├── api/
│ │ ├── auth/
│ │ │ ├── login/route.ts # 登录API
│ │ │ ├── logout/route.ts # 登出API
│ │ │ ├── register/route.ts # 注册API
│ │ │ └── session/route.ts # 会话API
│ │ ├── objects/
│ │ │ └── route.ts # 统一对象API
│ │ ├── models/
│ │ │ └── route.ts # 模型配置API
│ │ └── ai-proxy/
│ │ └── route.ts # AI代理API
│ ├── change-management/
│ │ ├── page.tsx # 变更管理页
│ │ └── layout.tsx # 变更管理布局
│ ├── layout.tsx # 根布局
│ ├── page.tsx # 首页
│ └── globals.css # 全局样式
├── components/
│ ├── ui/ # UI组件
│ ├── sidebar.tsx # 侧边栏
│ └── ...
├── lib/
│ ├── aras/ # SCSAI相关
│ │ ├── client.ts # SCSAI客户端
│ │ ├── aml.ts # AML执行
│ │ └── fallback.ts # 降级策略
│ ├── db/ # 数据库相关
│ │ ├── index.ts # 数据库初始化
│ │ ├── auth.ts # 认证数据库操作
│ │ └── local-data.ts # 本地数据
│ ├── llm/ # 大模型相关
│ │ ├── index.ts # 大模型配置
│ │ └── providers.ts # 模型提供商
│ └── aml/ # AML模板
│ ├── queries.ts # 查询模板
│ ├── creates.ts # 创建模板
│ ├── edits.ts # 编辑模板
│ └── deletes.ts # 删除模板
├── docs/ # 文档
└── data/ # 数据目录
└── chatbot.db # SQLite数据库
二、数据库设计
2.1 数据库初始化
文件位置:/app/lib/db/index.ts
import Database from 'better-sqlite3';
import path from 'path';
const dbPath = path.join(process.cwd(), 'data', 'chatbot.db');
let db: Database.Database | null = null;
export function getDatabase(): Database.Database {
if (!db) {
db = new Database(dbPath);
db.pragma('journal_mode = WAL');
initDatabase(db);
}
return db;
}
function initDatabase(database: Database.Database) {
// 用户表
database.exec(`
CREATE TABLE IF NOT EXISTS "User" (
id INTEGER PRIMARY KEY AUTOINCREMENT,
email TEXT UNIQUE NOT NULL,
password TEXT NOT NULL,
name TEXT,
type TEXT DEFAULT 'regular',
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
)
`);
// 会话表
database.exec(`
CREATE TABLE IF NOT EXISTS "Session" (
id TEXT PRIMARY KEY,
user_id INTEGER NOT NULL,
expires_at TEXT NOT NULL,
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES "User"(id)
)
`);
// 模型配置表
database.exec(`
CREATE TABLE IF NOT EXISTS "ModelConfig" (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT UNIQUE NOT NULL,
provider TEXT NOT NULL,
model TEXT NOT NULL,
api_key TEXT,
base_url TEXT,
temperature REAL DEFAULT 0.7,
max_tokens INTEGER DEFAULT 2000,
is_default INTEGER DEFAULT 0,
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
)
`);
// 聊天历史表
database.exec(`
CREATE TABLE IF NOT EXISTS "ChatHistory" (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER NOT NULL,
message TEXT NOT NULL,
response TEXT,
model TEXT,
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (user_id) REFERENCES "User"(id)
)
`);
// AML模板表
database.exec(`
CREATE TABLE IF NOT EXISTS "AmlTemplate" (
id INTEGER PRIMARY KEY AUTOINCREMENT,
name TEXT UNIQUE NOT NULL,
type TEXT NOT NULL,
item_type TEXT NOT NULL,
template TEXT NOT NULL,
description TEXT,
parameters TEXT,
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
)
`);
// AML对象表
database.exec(`
CREATE TABLE IF NOT EXISTS "AmlObject" (
id INTEGER PRIMARY KEY AUTOINCREMENT,
item_type TEXT NOT NULL,
name TEXT,
aml TEXT NOT NULL,
schema TEXT,
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
updated_at TEXT DEFAULT CURRENT_TIMESTAMP
)
`);
// 初始化默认模型配置
initDefaultModels(database);
}
function initDefaultModels(database: Database.Database) {
const existingModels = database.prepare('SELECT COUNT(*) as count FROM "ModelConfig"').get() as { count: number };
if (existingModels.count === 0) {
// 插入星火模型
database.prepare(`
INSERT INTO "ModelConfig" (name, provider, model, api_key, base_url, temperature, max_tokens, is_default)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`).run(
'讯飞星火',
'spark',
'astron-code-latest',
process.env.SPARK_API_KEY || '',
'https://maas-coding-api.cn-huabei-1.xf-yun.com/v2',
0.7,
2000,
1
);
// 插入DeepSeek模型
database.prepare(`
INSERT INTO "ModelConfig" (name, provider, model, api_key, base_url, temperature, max_tokens, is_default)
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
`).run(
'DeepSeek',
'deepseek',
'deepseek-chat',
process.env.DEEPSEEK_API_KEY || '',
'https://api.deepseek.com/v1',
0.7,
2000,
0
);
console.log('Default models initialized');
}
}
2.2 数据库表结构
用户表 (User)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | INTEGER | 主键 |
| email | TEXT | 邮箱(唯一) |
| password | TEXT | 密码(MD5) |
| name | TEXT | 用户名 |
| type | TEXT | 用户类型 |
| created_at | TEXT | 创建时间 |
| updated_at | TEXT | 更新时间 |
会话表 (Session)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | TEXT | 会话ID(UUID) |
| user_id | INTEGER | 用户ID |
| expires_at | TEXT | 过期时间 |
| created_at | TEXT | 创建时间 |
模型配置表 (ModelConfig)
| 字段 | 类型 | 说明 |
|------|------|------|
| id | INTEGER | 主键 |
| name | TEXT | 模型名称 |
| provider | TEXT | 提供商 |
| model | TEXT | 模型标识 |
| api_key | TEXT | API密钥 |
| base_url | TEXT | 基础URL |
| temperature | REAL | 温度参数 |
| max_tokens | INTEGER | 最大tokens |
| is_default | INTEGER | 是否默认 |
三、认证系统
3.1 认证配置
文件位置:/app/(auth)/auth.ts
import { getDatabase } from '@/app/lib/db';
import { cookies } from 'next/headers';
export type UserType = 'admin' | 'regular';
export interface SessionUser {
id: number;
email: string;
name: string;
type: UserType;
}
export async function auth(): Promise<{ user: SessionUser } | null> {
const cookieStore = await cookies();
const sessionId = cookieStore.get('sessionId')?.value;
if (!sessionId) {
return null;
}
const db = getDatabase();
const session = db.prepare(`
SELECT s.*, u.id as user_id, u.email, u.name, u.type
FROM "Session" s
JOIN "User" u ON s.user_id = u.id
WHERE s.id = ? AND s.expires_at > datetime('now')
`).get(sessionId) as any;
if (!session) {
return null;
}
return {
user: {
id: session.user_id,
email: session.email,
name: session.name,
type: session.type as UserType
}
};
}
3.2 登录API
文件位置:/app/api/auth/login/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { getDatabase } from '@/app/lib/db';
import crypto from 'crypto';
function md5(str: string): string {
return crypto.createHash('md5').update(str).digest('hex');
}
export async function POST(request: NextRequest) {
try {
const { email, password } = await request.json();
if (!email || !password) {
return NextResponse.json(
{ success: false, message: 'Email and password are required' },
{ status: 400 }
);
}
const db = getDatabase();
const user = db.prepare('SELECT * FROM "User" WHERE email = ?').get(email) as any;
if (!user) {
return NextResponse.json(
{ success: false, message: 'Invalid email or password' },
{ status: 401 }
);
}
// 开发环境允许任意密码
const isPasswordValid = process.env.NODE_ENV === 'development' || user.password === md5(password);
if (!isPasswordValid) {
return NextResponse.json(
{ success: false, message: 'Invalid email or password' },
{ status: 401 }
);
}
// 创建会话
const sessionId = crypto.randomUUID();
const expiresAt = new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString();
db.prepare(`
INSERT INTO "Session" (id, user_id, expires_at)
VALUES (?, ?, ?)
`).run(sessionId, user.id, expiresAt);
const response = NextResponse.json({
success: true,
message: 'Login successful',
data: {
id: user.id,
email: user.email,
name: user.name,
type: user.type
}
});
response.cookies.set('sessionId', sessionId, {
httpOnly: true,
secure: process.env.NODE_ENV === 'production',
sameSite: 'lax',
expires: new Date(Date.now() + 24 * 60 * 60 * 1000)
});
return response;
} catch (error: any) {
console.error('Login error:', error);
return NextResponse.json(
{ success: false, message: 'Internal server error' },
{ status: 500 }
);
}
}
3.3 注册API
文件位置:/app/api/auth/register/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { getDatabase } from '@/app/lib/db';
import crypto from 'crypto';
function md5(str: string): string {
return crypto.createHash('md5').update(str).digest('hex');
}
export async function POST(request: NextRequest) {
try {
const { email, password, name } = await request.json();
if (!email || !password) {
return NextResponse.json(
{ success: false, message: 'Email and password are required' },
{ status: 400 }
);
}
const db = getDatabase();
// 检查邮箱是否已存在
const existingUser = db.prepare('SELECT id FROM "User" WHERE email = ?').get(email);
if (existingUser) {
return NextResponse.json(
{ success: false, message: 'Email already exists' },
{ status: 400 }
);
}
// 创建用户
const hashedPassword = md5(password);
const result = db.prepare(`
INSERT INTO "User" (email, password, name, type)
VALUES (?, ?, ?, ?)
`).run(email, hashedPassword, name || '', 'regular');
return NextResponse.json({
success: true,
message: 'Registration successful',
data: {
id: result.lastInsertRowid,
email,
name: name || ''
}
});
} catch (error: any) {
console.error('Registration error:', error);
return NextResponse.json(
{ success: false, message: 'Internal server error' },
{ status: 500 }
);
}
}
四、大模型配置
4.1 默认模型配置
文件位置:/app/lib/llm/providers.ts
// 默认模型配置
export const defaultModels = [
{
name: '讯飞星火',
provider: 'spark',
model: 'astron-code-latest',
apiKey: process.env.SPARK_API_KEY || 'your-spark-api-key',
baseURL: 'https://maas-coding-api.cn-huabei-1.xf-yun.com/v2',
temperature: 0.7,
maxTokens: 2000,
isDefault: true
},
{
name: 'DeepSeek',
provider: 'deepseek',
model: 'deepseek-chat',
apiKey: process.env.DEEPSEEK_API_KEY || 'your-deepseek-api-key',
baseURL: 'https://api.deepseek.com/v1',
temperature: 0.7,
maxTokens: 2000,
isDefault: false
}
];
// 模型提供商配置
export const modelProviders = {
spark: {
name: '讯飞星火',
baseURL: 'https://maas-coding-api.cn-huabei-1.xf-yun.com/v2',
apiKeyEnv: 'SPARK_API_KEY'
},
deepseek: {
name: 'DeepSeek',
baseURL: 'https://api.deepseek.com/v1',
apiKeyEnv: 'DEEPSEEK_API_KEY'
},
openai: {
name: 'OpenAI',
baseURL: 'https://api.openai.com/v1',
apiKeyEnv: 'OPENAI_API_KEY'
},
anthropic: {
name: 'Claude',
baseURL: 'https://api.anthropic.com/v1',
apiKeyEnv: 'ANTHROPIC_API_KEY'
},
qianwen: {
name: '通义千问',
baseURL: 'https://dashscope.aliyuncs.com/api/v1',
apiKeyEnv: 'DASHSCOPE_API_KEY'
},
moonshotai: {
name: '月之暗面',
baseURL: 'https://api.moonshot.cn/v1',
apiKeyEnv: 'MOONSHOTAI_API_KEY'
}
};
4.2 大模型调用
文件位置:/app/lib/llm/index.ts
import { getDatabase } from '@/app/lib/db';
import { defaultModels } from './providers';
export interface LLMConfig {
provider: string;
model: string;
apiKey: string;
baseURL: string;
temperature: number;
maxTokens: number;
}
// 获取默认模型
export function getDefaultModel(): LLMConfig | null {
const db = getDatabase();
// 先从数据库获取
const dbModel = db.prepare(
'SELECT * FROM "ModelConfig" WHERE is_default = 1 LIMIT 1'
).get() as any;
if (dbModel) {
return {
provider: dbModel.provider,
model: dbModel.model,
apiKey: dbModel.api_key || '',
baseURL: dbModel.base_url || '',
temperature: dbModel.temperature,
maxTokens: dbModel.max_tokens
};
}
// 如果数据库没有,返回默认配置
const defaultModel = defaultModels.find(m => m.isDefault);
if (defaultModel) {
return {
provider: defaultModel.provider,
model: defaultModel.model,
apiKey: defaultModel.apiKey,
baseURL: defaultModel.baseURL,
temperature: defaultModel.temperature,
maxTokens: defaultModel.maxTokens
};
}
return null;
}
// 获取所有模型
export function getAllModels() {
const db = getDatabase();
const dbModels = db.prepare('SELECT * FROM "ModelConfig"').get() as any[];
if (dbModels && dbModels.length > 0) {
return dbModels.map(m => ({
id: m.id,
name: m.name,
provider: m.provider,
model: m.model,
apiKey: m.api_key,
baseURL: m.base_url,
temperature: m.temperature,
maxTokens: m.max_tokens,
isDefault: m.is_default === 1
}));
}
return defaultModels;
}
4.3 AI代理API
文件位置:/app/api/ai-proxy/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { getDefaultModel } from '@/app/lib/llm';
export async function POST(request: NextRequest) {
try {
const body = await request.json();
const { messages, provider, model: modelName, apiKey, baseURL } = body;
// 使用传入的配置或默认模型
let config;
if (provider && modelName) {
config = {
provider,
model: modelName,
apiKey: apiKey || '',
baseURL: baseURL || ''
};
} else {
config = getDefaultModel();
if (!config) {
return NextResponse.json(
{ success: false, error: 'No model configured' },
{ status: 400 }
);
}
}
let apiEndpoint = '';
const headers: Record<string, string> = {
'Content-Type': 'application/json'
};
// 根据提供商设置API端点和认证
switch (config.provider) {
case 'spark':
apiEndpoint = config.baseURL || 'https://maas-coding-api.cn-huabei-1.xf-yun.com/v2';
headers['Authorization'] = `Bearer ${config.apiKey}`;
break;
case 'deepseek':
apiEndpoint = config.baseURL || 'https://api.deepseek.com/v1/chat/completions';
headers['Authorization'] = `Bearer ${config.apiKey}`;
break;
case 'openai':
apiEndpoint = (config.baseURL || 'https://api.openai.com/v1') + '/chat/completions';
headers['Authorization'] = `Bearer ${config.apiKey}`;
break;
default:
return NextResponse.json(
{ success: false, error: `Unsupported provider: ${config.provider}` },
{ status: 400 }
);
}
// 调用大模型API
const response = await fetch(apiEndpoint, {
method: 'POST',
headers,
body: JSON.stringify({
model: config.model,
messages,
temperature: 0.7,
max_tokens: 2000
})
});
if (!response.ok) {
const errorText = await response.text();
console.error('AI API error:', errorText);
return NextResponse.json(
{ success: false, error: `AI API error: ${response.status}` },
{ status: response.status }
);
}
const data = await response.json();
return NextResponse.json({
success: true,
data: {
content: data.choices?.[0]?.message?.content || '',
usage: data.usage
}
});
} catch (error: any) {
console.error('AI proxy error:', error);
return NextResponse.json(
{ success: false, error: error.message },
{ status: 500 }
);
}
}
五、环境变量配置
文件位置:/app/.env.local
# SCSAI配置
ARAS_SERVER=http://114.113.153.234/scplm
ARAS_DATABASE=Innovator
# 大模型API密钥(默认配置)
SPARK_API_KEY=0508e2d155d689743f9fef6e9fd20400:MDlkZDI1YTU0ZTkyZDMyOTllOWMwMzQ5
DEEPSEEK_API_KEY=your-deepseek-api-key
OPENAI_API_KEY=your-openai-api-key
# 应用配置
NEXT_PUBLIC_APP_NAME=老板智能体工作台
NEXT_PUBLIC_APP_VERSION=1.0.0
六、关键文件位置总结
| 功能 | 文件位置 |
|------|----------|
| 数据库初始化 | /app/lib/db/index.ts |
| 认证配置 | /app/(auth)/auth.ts |
| 登录API | /app/api/auth/login/route.ts |
| 注册API | /app/api/auth/register/route.ts |
| 大模型配置 | /app/lib/llm/providers.ts |
| 大模型调用 | /app/lib/llm/index.ts |
| AI代理API | /app/api/ai-proxy/route.ts |
| SCSAI客户端 | /app/lib/aras/client.ts |
| AML操作 | /app/lib/aml/index.ts |
| 对象API | /app/api/objects/route.ts |
BossAgents