feat(ai): 添加 AI 助手功能支持多模型对话

- 集成 OpenAI 兼容网关和 Ollama 原生 API 接口
- 新增 AI 测试页面支持流式对话和模型切换
- 配置开发环境同源反向代理解决浏览器 CORS 问题
- 添加环境变量配置支持 AI API 和 Ollama 接口设置
- 实现聊天历史记录、中断请求和参数调节功能
- 提供 Nginx 反向代理配置文档用于生产环境部署
This commit is contained in:
2026-02-27 22:15:41 +08:00
parent acec6570e1
commit b40326c3a9
9 changed files with 832 additions and 3 deletions

View File

@@ -1,4 +1,4 @@
import { defineConfig } from 'vite';
import { defineConfig, loadEnv } from 'vite';
import vue from '@vitejs/plugin-vue';
import ViteCompression from 'vite-plugin-compression';
import ViteComponents from 'unplugin-vue-components/vite';
@@ -44,7 +44,9 @@ function getSmartPort() {
}
}
export default defineConfig(({ command }) => {
export default defineConfig(({ command, mode }) => {
// Load env for Vite config usage (including non-VITE_ keys like AI_API_KEY).
const env = loadEnv(mode, process.cwd(), '');
const isBuild = command === 'build';
// 智能端口配置(仅在开发模式下)
@@ -68,7 +70,7 @@ export default defineConfig(({ command }) => {
// 代理配置
proxy: {
'/api': {
target: process.env.VITE_API_URL || 'https://server.websoft.top',
target: env.VITE_API_URL || process.env.VITE_API_URL || 'https://server.websoft.top',
changeOrigin: true,
secure: false,
configure: (proxy, _options) => {
@@ -82,6 +84,39 @@ export default defineConfig(({ command }) => {
console.log('Received Response from the Target:', proxyRes.statusCode, req.url);
});
},
},
// OpenAI-compatible gateway reverse proxy (dev only).
// Example:
// GET /ai-proxy/models -> https://ai.websoft.top/api/v1/models
// POST /ai-proxy/chat/completions -> https://ai.websoft.top/api/v1/chat/completions
'/ai-proxy': {
target: env.AI_PROXY_TARGET || 'https://ai-api.websoft.top',
changeOrigin: true,
secure: false,
rewrite: (path) =>
path.replace(/^\/ai-proxy/, env.AI_PROXY_REWRITE_PREFIX || '/api/v1'),
configure: (proxy) => {
proxy.on('proxyReq', (proxyReq) => {
// Inject auth for local dev to avoid putting API keys in the browser.
const key = env.AI_API_KEY || process.env.AI_API_KEY;
if (key && !proxyReq.getHeader('Authorization')) {
const trimmed = String(key).trim();
const value = /^bearer\\s+/i.test(trimmed)
? trimmed
: `Bearer ${trimmed}`;
proxyReq.setHeader('Authorization', value);
}
});
}
},
// Ollama native API reverse proxy (dev only).
// GET /ollama-proxy/api/tags -> http://47.119.165.234:11434/api/tags
// POST /ollama-proxy/api/chat -> http://47.119.165.234:11434/api/chat
'/ollama-proxy': {
target: 'http://47.119.165.234:11434',
changeOrigin: true,
secure: false,
rewrite: (path) => path.replace(/^\/ollama-proxy/, '')
}
},
// 端口冲突时的处理