系统框架文档

系统框架文档

一、项目结构

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/
│   ├── SCSAI/                    # 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配置
SCSAI_SERVER=http://114.113.153.234/scplm
SCSAI_DATABASE=Agent

# 大模型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/SCSAI/client.ts |

| AML操作 | /app/lib/aml/index.ts |

| 对象API | /app/api/objects/route.ts |

← 返回案例列表
分享:
🤖 Try Now →
🤖
🎁