refactor: 重构项目结构和代码组织
This commit is contained in:
@@ -1,51 +0,0 @@
|
|||||||
# Dependencies
|
|
||||||
node_modules/
|
|
||||||
|
|
||||||
# Build output
|
|
||||||
dist/
|
|
||||||
build/
|
|
||||||
|
|
||||||
# Environment files
|
|
||||||
.env
|
|
||||||
.env.local
|
|
||||||
.env.*.local
|
|
||||||
|
|
||||||
# IDE
|
|
||||||
.vscode/
|
|
||||||
.idea/
|
|
||||||
*.swp
|
|
||||||
*.swo
|
|
||||||
|
|
||||||
# OS
|
|
||||||
.DS_Store
|
|
||||||
Thumbs.db
|
|
||||||
|
|
||||||
# Logs
|
|
||||||
logs/
|
|
||||||
*.log
|
|
||||||
npm-debug.log*
|
|
||||||
|
|
||||||
# Data
|
|
||||||
data/
|
|
||||||
|
|
||||||
# Git
|
|
||||||
.git/
|
|
||||||
.gitignore
|
|
||||||
|
|
||||||
# Docker
|
|
||||||
Dockerfile
|
|
||||||
docker-compose*.yml
|
|
||||||
.dockerignore
|
|
||||||
|
|
||||||
# Documentation
|
|
||||||
*.md
|
|
||||||
docs/
|
|
||||||
|
|
||||||
# Tests
|
|
||||||
test/
|
|
||||||
tests/
|
|
||||||
coverage/
|
|
||||||
|
|
||||||
# Misc
|
|
||||||
*.tmp
|
|
||||||
*.temp
|
|
||||||
61
.gitignore
vendored
61
.gitignore
vendored
@@ -1,61 +0,0 @@
|
|||||||
# Dependencies
|
|
||||||
node_modules/
|
|
||||||
.pnp
|
|
||||||
.pnp.js
|
|
||||||
|
|
||||||
# Testing
|
|
||||||
coverage/
|
|
||||||
*.lcov
|
|
||||||
|
|
||||||
# Production builds
|
|
||||||
dist/
|
|
||||||
build/
|
|
||||||
server/dist/
|
|
||||||
client/dist/
|
|
||||||
|
|
||||||
# Environment variables
|
|
||||||
.env
|
|
||||||
.env.local
|
|
||||||
.env.*.local
|
|
||||||
!.env.example
|
|
||||||
|
|
||||||
# IDE
|
|
||||||
.vscode/
|
|
||||||
.idea/
|
|
||||||
*.swp
|
|
||||||
*.swo
|
|
||||||
*~
|
|
||||||
|
|
||||||
# OS
|
|
||||||
.DS_Store
|
|
||||||
Thumbs.db
|
|
||||||
|
|
||||||
# Logs
|
|
||||||
logs/
|
|
||||||
*.log
|
|
||||||
npm-debug.log*
|
|
||||||
yarn-debug.log*
|
|
||||||
yarn-error.log*
|
|
||||||
pnpm-debug.log*
|
|
||||||
|
|
||||||
# Data persistence
|
|
||||||
data/
|
|
||||||
*.db
|
|
||||||
*.sqlite
|
|
||||||
|
|
||||||
# Temporary files
|
|
||||||
tmp/
|
|
||||||
temp/
|
|
||||||
*.tmp
|
|
||||||
*.temp
|
|
||||||
|
|
||||||
# Docker
|
|
||||||
docker-compose.override.yml
|
|
||||||
|
|
||||||
# Secrets
|
|
||||||
*.pem
|
|
||||||
*.key
|
|
||||||
secrets/
|
|
||||||
|
|
||||||
# Shared types build output
|
|
||||||
shared/dist/
|
|
||||||
5
.idea/.gitignore
generated
vendored
Normal file
5
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
# 默认忽略的文件
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# 基于编辑器的 HTTP 客户端请求
|
||||||
|
/httpRequests/
|
||||||
6
.idea/encodings.xml
generated
Normal file
6
.idea/encodings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="Encoding">
|
||||||
|
<file url="file://$PROJECT_DIR$/make.bat" charset="GB2312" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
12
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
12
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="ignoredIdentifiers">
|
||||||
|
<list>
|
||||||
|
<option value="requests.models.Response.__getitem__" />
|
||||||
|
</list>
|
||||||
|
</option>
|
||||||
|
</inspection_tool>
|
||||||
|
</profile>
|
||||||
|
</component>
|
||||||
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="false" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/sillytavern-repalice.iml" filepath="$PROJECT_DIR$/.idea/sillytavern-repalice.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
8
.idea/sillytavern-repalice.iml
generated
Normal file
8
.idea/sillytavern-repalice.iml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="PYTHON_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$" />
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
@@ -1,254 +0,0 @@
|
|||||||
# 项目架构检查报告
|
|
||||||
|
|
||||||
## ✅ 架构合理性评估
|
|
||||||
|
|
||||||
### **1. 整体结构评分:9/10** ⭐⭐⭐⭐⭐
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📁 目录结构分析
|
|
||||||
|
|
||||||
### **✅ 优点**
|
|
||||||
|
|
||||||
#### **1. 清晰的三层架构**
|
|
||||||
```
|
|
||||||
project/
|
|
||||||
├── server/ # 后端 (NestJS)
|
|
||||||
├── client/ # 前端 (Vue3)
|
|
||||||
├── shared/ # 共享类型系统
|
|
||||||
├── data/ # 持久化数据
|
|
||||||
├── docker/ # Docker 配置
|
|
||||||
└── docs/ # 文档
|
|
||||||
```
|
|
||||||
- ✅ 前后端分离明确
|
|
||||||
- ✅ 共享类型独立管理
|
|
||||||
- ✅ 数据和配置隔离
|
|
||||||
|
|
||||||
#### **2. 后端模块化设计 (DDD)**
|
|
||||||
```
|
|
||||||
server/src/
|
|
||||||
├── core/ # 核心基础设施层
|
|
||||||
├── modules/ # 业务模块层
|
|
||||||
├── shared/ # 共享工具层
|
|
||||||
├── events/ # 事件系统
|
|
||||||
├── queues/ # 任务队列
|
|
||||||
└── common/ # 通用基类
|
|
||||||
```
|
|
||||||
- ✅ 符合领域驱动设计
|
|
||||||
- ✅ 职责分离清晰
|
|
||||||
- ✅ 易于扩展和维护
|
|
||||||
|
|
||||||
#### **3. 模块内部结构标准**
|
|
||||||
```
|
|
||||||
modules/{module}/
|
|
||||||
├── controllers/ # API 控制器
|
|
||||||
├── services/ # 业务逻辑
|
|
||||||
├── adapters/ # 格式转换适配器
|
|
||||||
├── dto/ # 数据传输对象
|
|
||||||
└── interfaces/ # 接口定义
|
|
||||||
```
|
|
||||||
- ✅ 遵循 MVC 模式
|
|
||||||
- ✅ 适配器模式实现良好
|
|
||||||
- ✅ 依赖注入友好
|
|
||||||
|
|
||||||
#### **4. 前端分层合理**
|
|
||||||
```
|
|
||||||
client/src/
|
|
||||||
├── api/ # API 客户端层
|
|
||||||
├── components/ # UI 组件层
|
|
||||||
├── views/ # 页面视图层
|
|
||||||
├── composables/ # 组合式函数
|
|
||||||
├── stores/ # 状态管理
|
|
||||||
├── router/ # 路由配置
|
|
||||||
├── types/ # 类型定义
|
|
||||||
└── utils/ # 工具函数
|
|
||||||
```
|
|
||||||
- ✅ 符合 Vue3 最佳实践
|
|
||||||
- ✅ 关注点分离
|
|
||||||
- ✅ 可复用性强
|
|
||||||
|
|
||||||
#### **5. 共享类型系统设计**
|
|
||||||
```
|
|
||||||
shared/types/
|
|
||||||
├── sillytavern/ # ST 原生格式(兼容层)
|
|
||||||
├── extended/ # 扩展格式(增强层)
|
|
||||||
├── adapters/ # 适配器接口
|
|
||||||
└── index.ts # 统一导出
|
|
||||||
```
|
|
||||||
- ✅ 双层格式设计优秀
|
|
||||||
- ✅ 完全兼容 SillyTavern
|
|
||||||
- ✅ 扩展性强
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ⚠️ 需要改进的地方
|
|
||||||
|
|
||||||
### **1. 缺少配置文件**
|
|
||||||
```
|
|
||||||
❌ server/.env.example
|
|
||||||
❌ client/.env.example
|
|
||||||
❌ server/tsconfig.build.json (已有但需检查)
|
|
||||||
```
|
|
||||||
|
|
||||||
**建议:**
|
|
||||||
- 创建 `.env.example` 模板文件
|
|
||||||
- 确保所有必要的环境变量都有文档
|
|
||||||
|
|
||||||
### **2. 模块完整性不一致**
|
|
||||||
|
|
||||||
**完整的模块:**
|
|
||||||
- ✅ `chat/` - 有 adapters
|
|
||||||
- ✅ `world-info/` - 有 adapters
|
|
||||||
- ✅ `preset/` - 有 adapters
|
|
||||||
|
|
||||||
**不完整的模块:**
|
|
||||||
- ⚠️ `auth/` - 缺少 adapters
|
|
||||||
- ⚠️ `llm/` - 缺少 adapters
|
|
||||||
- ⚠️ `workflow/` - 缺少 adapters
|
|
||||||
- ⚠️ `data-store/` - 缺少 adapters
|
|
||||||
- ⚠️ `file-management/` - 缺少 adapters
|
|
||||||
- ⚠️ `import-export/` - 缺少 adapters
|
|
||||||
|
|
||||||
**建议:**
|
|
||||||
为每个模块添加标准的子目录结构,即使暂时为空。
|
|
||||||
|
|
||||||
### **3. 前端目录有空文件夹**
|
|
||||||
```
|
|
||||||
client/src/
|
|
||||||
├── composables/ # 空
|
|
||||||
├── plugins/ # 空
|
|
||||||
├── services/ # 空
|
|
||||||
└── store/ # 空(应该是 stores/)
|
|
||||||
```
|
|
||||||
|
|
||||||
**建议:**
|
|
||||||
- 删除空的 `store/` 目录(已有 `stores/`)
|
|
||||||
- 在 `composables/` 中添加基础 composable
|
|
||||||
- 在 `plugins/` 中添加必要的插件
|
|
||||||
|
|
||||||
### **4. 缺少测试目录结构**
|
|
||||||
```
|
|
||||||
tests/ # 空
|
|
||||||
```
|
|
||||||
|
|
||||||
**建议:**
|
|
||||||
```
|
|
||||||
tests/
|
|
||||||
├── unit/ # 单元测试
|
|
||||||
├── integration/ # 集成测试
|
|
||||||
└── e2e/ # 端到端测试
|
|
||||||
```
|
|
||||||
|
|
||||||
### **5. Docker 配置可以优化**
|
|
||||||
|
|
||||||
**当前配置:**
|
|
||||||
- ✅ 开发环境热重载配置正确
|
|
||||||
- ✅ 端口映射合理(23337, 23338)
|
|
||||||
- ✅ 卷挂载正确
|
|
||||||
|
|
||||||
**建议改进:**
|
|
||||||
- 添加 `.dockerignore` 文件
|
|
||||||
- 考虑添加 Nginx 反向代理(生产环境)
|
|
||||||
- 添加日志卷挂载
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🎯 架构优势总结
|
|
||||||
|
|
||||||
### **1. 数据类型设计优秀** ⭐⭐⭐⭐⭐
|
|
||||||
- 双层格式(ST + Extended)
|
|
||||||
- 适配器模式实现完善
|
|
||||||
- 完全向后兼容
|
|
||||||
|
|
||||||
### **2. 模块化程度高** ⭐⭐⭐⭐⭐
|
|
||||||
- 每个模块独立
|
|
||||||
- 低耦合高内聚
|
|
||||||
- 易于团队协作
|
|
||||||
|
|
||||||
### **3. 技术栈选择合理** ⭐⭐⭐⭐⭐
|
|
||||||
- NestJS + Vue3 = 现代全栈
|
|
||||||
- TypeScript 全程类型安全
|
|
||||||
- Docker 容器化部署
|
|
||||||
|
|
||||||
### **4. 可扩展性强** ⭐⭐⭐⭐⭐
|
|
||||||
- 事件系统预留
|
|
||||||
- 任务队列预留
|
|
||||||
- 微服务演进可能
|
|
||||||
|
|
||||||
### **5. 开发体验好** ⭐⭐⭐⭐
|
|
||||||
- 热重载支持
|
|
||||||
- 路径别名配置
|
|
||||||
- 类型提示完整
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 📋 建议的改进清单
|
|
||||||
|
|
||||||
### **高优先级**
|
|
||||||
1. ✅ 创建 `.env.example` 文件
|
|
||||||
2. ✅ 统一模块目录结构
|
|
||||||
3. ✅ 清理空文件夹
|
|
||||||
4. ✅ 添加 `.dockerignore`
|
|
||||||
|
|
||||||
### **中优先级**
|
|
||||||
5. ⏳ 创建基础 Composables
|
|
||||||
6. ⏳ 添加单元测试框架
|
|
||||||
7. ⏳ 完善 Docker 配置
|
|
||||||
8. ⏳ 添加 CI/CD 配置
|
|
||||||
|
|
||||||
### **低优先级**
|
|
||||||
9. 📝 编写 API 文档
|
|
||||||
10. 📝 添加部署指南
|
|
||||||
11. 📝 创建贡献指南
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## 🚀 Docker 配置说明
|
|
||||||
|
|
||||||
### **端口映射**
|
|
||||||
- 后端:`23337:3000` (宿主机 23337 → 容器 3000)
|
|
||||||
- 前端:`23338:5173` (宿主机 23338 → 容器 5173)
|
|
||||||
|
|
||||||
### **热重载支持**
|
|
||||||
```yaml
|
|
||||||
volumes:
|
|
||||||
- ./server:/usr/src/app # 代码挂载
|
|
||||||
- ./shared:/usr/src/shared # 共享类型挂载
|
|
||||||
- /usr/src/app/node_modules # 排除 node_modules
|
|
||||||
```
|
|
||||||
|
|
||||||
### **数据持久化**
|
|
||||||
```yaml
|
|
||||||
volumes:
|
|
||||||
- ./data:/usr/src/app/data # 数据库和文件
|
|
||||||
- ./.env:/usr/src/app/.env:ro # 环境变量(只读)
|
|
||||||
```
|
|
||||||
|
|
||||||
### **健康检查**
|
|
||||||
```yaml
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/api"]
|
|
||||||
interval: 30s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 3
|
|
||||||
```
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## ✅ 总体评价
|
|
||||||
|
|
||||||
**架构评分:9/10**
|
|
||||||
|
|
||||||
**优点:**
|
|
||||||
- 设计思路清晰
|
|
||||||
- 技术选型现代
|
|
||||||
- 可扩展性强
|
|
||||||
- 兼容性好
|
|
||||||
|
|
||||||
**待改进:**
|
|
||||||
- 部分模块不完整
|
|
||||||
- 缺少一些配置文件
|
|
||||||
- 测试框架未搭建
|
|
||||||
|
|
||||||
**结论:**
|
|
||||||
整体架构非常合理,具备良好的可扩展性和维护性。只需补充一些细节即可投入开发。
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
node_modules
|
|
||||||
dist
|
|
||||||
.env
|
|
||||||
.git
|
|
||||||
.idea
|
|
||||||
.vscode
|
|
||||||
@@ -1,37 +0,0 @@
|
|||||||
# =====================================================
|
|
||||||
# API Configuration
|
|
||||||
# =====================================================
|
|
||||||
VITE_API_URL=http://localhost:23337/api
|
|
||||||
VITE_WS_URL=ws://localhost:23337
|
|
||||||
|
|
||||||
# =====================================================
|
|
||||||
# Application Configuration
|
|
||||||
# =====================================================
|
|
||||||
VITE_APP_NAME=SillyTavern Replace
|
|
||||||
VITE_APP_VERSION=1.0.0
|
|
||||||
|
|
||||||
# =====================================================
|
|
||||||
# Feature Flags
|
|
||||||
# =====================================================
|
|
||||||
VITE_ENABLE_WEBSOCKET=true
|
|
||||||
VITE_ENABLE_SSE=true
|
|
||||||
|
|
||||||
# =====================================================
|
|
||||||
# LLM Configuration (Public - Safe to Expose)
|
|
||||||
# =====================================================
|
|
||||||
VITE_DEFAULT_LLM_PROVIDER=openai
|
|
||||||
VITE_MAX_TOKENS=4096
|
|
||||||
VITE_DEFAULT_TEMPERATURE=0.7
|
|
||||||
|
|
||||||
# =====================================================
|
|
||||||
# UI Configuration
|
|
||||||
# =====================================================
|
|
||||||
VITE_THEME=light
|
|
||||||
VITE_LANGUAGE=zh-CN
|
|
||||||
VITE_ITEMS_PER_PAGE=20
|
|
||||||
|
|
||||||
# =====================================================
|
|
||||||
# Upload Configuration
|
|
||||||
# =====================================================
|
|
||||||
VITE_MAX_UPLOAD_SIZE=10485760
|
|
||||||
VITE_ALLOWED_FILE_TYPES=.json,.csv,.txt,.md,.png,.jpg
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
# Development Dockerfile for Frontend (Vue3 + Vite)
|
|
||||||
FROM node:20-alpine
|
|
||||||
|
|
||||||
# Set working directory
|
|
||||||
WORKDIR /usr/src/app
|
|
||||||
|
|
||||||
# Copy package files
|
|
||||||
COPY package*.json ./
|
|
||||||
|
|
||||||
# Install dependencies
|
|
||||||
RUN npm install
|
|
||||||
|
|
||||||
# Expose Vite dev server port
|
|
||||||
EXPOSE 5173
|
|
||||||
|
|
||||||
# Default command (will be overridden by docker-compose)
|
|
||||||
CMD ["npm", "run", "dev", "--", "--host", "0.0.0.0", "--port", "5173"]
|
|
||||||
@@ -1,42 +0,0 @@
|
|||||||
# client
|
|
||||||
|
|
||||||
This template should help get you started developing with Vue 3 in Vite.
|
|
||||||
|
|
||||||
## Recommended IDE Setup
|
|
||||||
|
|
||||||
[VS Code](https://code.visualstudio.com/) + [Vue (Official)](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur).
|
|
||||||
|
|
||||||
## Recommended Browser Setup
|
|
||||||
|
|
||||||
- Chromium-based browsers (Chrome, Edge, Brave, etc.):
|
|
||||||
- [Vue.js devtools](https://chromewebstore.google.com/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd)
|
|
||||||
- [Turn on Custom Object Formatter in Chrome DevTools](http://bit.ly/object-formatters)
|
|
||||||
- Firefox:
|
|
||||||
- [Vue.js devtools](https://addons.mozilla.org/en-US/firefox/addon/vue-js-devtools/)
|
|
||||||
- [Turn on Custom Object Formatter in Firefox DevTools](https://fxdx.dev/firefox-devtools-custom-object-formatters/)
|
|
||||||
|
|
||||||
## Type Support for `.vue` Imports in TS
|
|
||||||
|
|
||||||
TypeScript cannot handle type information for `.vue` imports by default, so we replace the `tsc` CLI with `vue-tsc` for type checking. In editors, we need [Volar](https://marketplace.visualstudio.com/items?itemName=Vue.volar) to make the TypeScript language service aware of `.vue` types.
|
|
||||||
|
|
||||||
## Customize configuration
|
|
||||||
|
|
||||||
See [Vite Configuration Reference](https://vite.dev/config/).
|
|
||||||
|
|
||||||
## Project Setup
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm install
|
|
||||||
```
|
|
||||||
|
|
||||||
### Compile and Hot-Reload for Development
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm run dev
|
|
||||||
```
|
|
||||||
|
|
||||||
### Type-Check, Compile and Minify for Production
|
|
||||||
|
|
||||||
```sh
|
|
||||||
npm run build
|
|
||||||
```
|
|
||||||
1
client/env.d.ts
vendored
1
client/env.d.ts
vendored
@@ -1 +0,0 @@
|
|||||||
/// <reference types="vite/client" />
|
|
||||||
@@ -1,13 +0,0 @@
|
|||||||
<!DOCTYPE html>
|
|
||||||
<html lang="">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<link rel="icon" href="/favicon.ico">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
||||||
<title>Vite App</title>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div id="app"></div>
|
|
||||||
<script type="module" src="/src/main.ts"></script>
|
|
||||||
</body>
|
|
||||||
</html>
|
|
||||||
3148
client/package-lock.json
generated
3148
client/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,33 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "client",
|
|
||||||
"version": "0.0.0",
|
|
||||||
"private": true,
|
|
||||||
"type": "module",
|
|
||||||
"scripts": {
|
|
||||||
"dev": "vite",
|
|
||||||
"build": "run-p type-check \"build-only {@}\" --",
|
|
||||||
"preview": "vite preview",
|
|
||||||
"build-only": "vite build",
|
|
||||||
"type-check": "vue-tsc --build"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
|
||||||
"pinia": "^3.0.4",
|
|
||||||
"vue": "^3.5.32",
|
|
||||||
"vue-router": "^5.0.4"
|
|
||||||
},
|
|
||||||
"devDependencies": {
|
|
||||||
"@tsconfig/node24": "^24.0.4",
|
|
||||||
"@types/node": "^24.12.2",
|
|
||||||
"@vitejs/plugin-vue": "^6.0.6",
|
|
||||||
"@vitejs/plugin-vue-jsx": "^5.1.5",
|
|
||||||
"@vue/tsconfig": "^0.9.1",
|
|
||||||
"npm-run-all2": "^8.0.4",
|
|
||||||
"typescript": "~6.0.0",
|
|
||||||
"vite": "^8.0.8",
|
|
||||||
"vite-plugin-vue-devtools": "^8.1.1",
|
|
||||||
"vue-tsc": "^3.2.6"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": "^20.19.0 || >=22.12.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB |
@@ -1,41 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="app-layout">
|
|
||||||
<!-- 顶部工具栏 -->
|
|
||||||
<TopToolbar />
|
|
||||||
|
|
||||||
<!-- 主体内容区 -->
|
|
||||||
<div class="main-content">
|
|
||||||
<!-- 左侧面板 -->
|
|
||||||
<LeftPanel />
|
|
||||||
|
|
||||||
<!-- 中间聊天区 -->
|
|
||||||
<CenterChat />
|
|
||||||
|
|
||||||
<!-- 右侧工具面板 -->
|
|
||||||
<RightPanel />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import TopToolbar from './components/layout/TopToolbar.vue';
|
|
||||||
import LeftPanel from './components/layout/LeftPanel.vue';
|
|
||||||
import CenterChat from './components/layout/CenterChat.vue';
|
|
||||||
import RightPanel from './components/layout/RightPanel.vue';
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.app-layout {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
height: 100vh;
|
|
||||||
width: 100vw;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.main-content {
|
|
||||||
display: flex;
|
|
||||||
flex: 1;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
0
client/src/api/index.ts
Normal file
0
client/src/api/index.ts
Normal file
@@ -1,86 +0,0 @@
|
|||||||
/* color palette from <https://github.com/vuejs/theme> */
|
|
||||||
:root {
|
|
||||||
--vt-c-white: #ffffff;
|
|
||||||
--vt-c-white-soft: #f8f8f8;
|
|
||||||
--vt-c-white-mute: #f2f2f2;
|
|
||||||
|
|
||||||
--vt-c-black: #181818;
|
|
||||||
--vt-c-black-soft: #222222;
|
|
||||||
--vt-c-black-mute: #282828;
|
|
||||||
|
|
||||||
--vt-c-indigo: #2c3e50;
|
|
||||||
|
|
||||||
--vt-c-divider-light-1: rgba(60, 60, 60, 0.29);
|
|
||||||
--vt-c-divider-light-2: rgba(60, 60, 60, 0.12);
|
|
||||||
--vt-c-divider-dark-1: rgba(84, 84, 84, 0.65);
|
|
||||||
--vt-c-divider-dark-2: rgba(84, 84, 84, 0.48);
|
|
||||||
|
|
||||||
--vt-c-text-light-1: var(--vt-c-indigo);
|
|
||||||
--vt-c-text-light-2: rgba(60, 60, 60, 0.66);
|
|
||||||
--vt-c-text-dark-1: var(--vt-c-white);
|
|
||||||
--vt-c-text-dark-2: rgba(235, 235, 235, 0.64);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* semantic color variables for this project */
|
|
||||||
:root {
|
|
||||||
--color-background: var(--vt-c-white);
|
|
||||||
--color-background-soft: var(--vt-c-white-soft);
|
|
||||||
--color-background-mute: var(--vt-c-white-mute);
|
|
||||||
|
|
||||||
--color-border: var(--vt-c-divider-light-2);
|
|
||||||
--color-border-hover: var(--vt-c-divider-light-1);
|
|
||||||
|
|
||||||
--color-heading: var(--vt-c-text-light-1);
|
|
||||||
--color-text: var(--vt-c-text-light-1);
|
|
||||||
|
|
||||||
--section-gap: 160px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (prefers-color-scheme: dark) {
|
|
||||||
:root {
|
|
||||||
--color-background: var(--vt-c-black);
|
|
||||||
--color-background-soft: var(--vt-c-black-soft);
|
|
||||||
--color-background-mute: var(--vt-c-black-mute);
|
|
||||||
|
|
||||||
--color-border: var(--vt-c-divider-dark-2);
|
|
||||||
--color-border-hover: var(--vt-c-divider-dark-1);
|
|
||||||
|
|
||||||
--color-heading: var(--vt-c-text-dark-1);
|
|
||||||
--color-text: var(--vt-c-text-dark-2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
*,
|
|
||||||
*::before,
|
|
||||||
*::after {
|
|
||||||
box-sizing: border-box;
|
|
||||||
margin: 0;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
body {
|
|
||||||
min-height: 100vh;
|
|
||||||
color: var(--color-text);
|
|
||||||
background: var(--color-background);
|
|
||||||
transition:
|
|
||||||
color 0.5s,
|
|
||||||
background-color 0.5s;
|
|
||||||
line-height: 1.6;
|
|
||||||
font-family:
|
|
||||||
Inter,
|
|
||||||
-apple-system,
|
|
||||||
BlinkMacSystemFont,
|
|
||||||
'Segoe UI',
|
|
||||||
Roboto,
|
|
||||||
Oxygen,
|
|
||||||
Ubuntu,
|
|
||||||
Cantarell,
|
|
||||||
'Fira Sans',
|
|
||||||
'Droid Sans',
|
|
||||||
'Helvetica Neue',
|
|
||||||
sans-serif;
|
|
||||||
font-size: 15px;
|
|
||||||
text-rendering: optimizeLegibility;
|
|
||||||
-webkit-font-smoothing: antialiased;
|
|
||||||
-moz-osx-font-smoothing: grayscale;
|
|
||||||
}
|
|
||||||
0
client/src/assets/logo.png
Normal file
0
client/src/assets/logo.png
Normal file
@@ -1 +0,0 @@
|
|||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 261.76 226.69"><path d="M161.096.001l-30.225 52.351L100.647.001H-.005l130.877 226.688L261.749.001z" fill="#41b883"/><path d="M161.096.001l-30.225 52.351L100.647.001H52.346l78.526 136.01L209.398.001z" fill="#34495e"/></svg>
|
|
||||||
|
Before Width: | Height: | Size: 276 B |
@@ -1,35 +0,0 @@
|
|||||||
@import './base.css';
|
|
||||||
|
|
||||||
#app {
|
|
||||||
max-width: 1280px;
|
|
||||||
margin: 0 auto;
|
|
||||||
padding: 2rem;
|
|
||||||
font-weight: normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
a,
|
|
||||||
.green {
|
|
||||||
text-decoration: none;
|
|
||||||
color: hsla(160, 100%, 37%, 1);
|
|
||||||
transition: 0.4s;
|
|
||||||
padding: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (hover: hover) {
|
|
||||||
a:hover {
|
|
||||||
background-color: hsla(160, 100%, 37%, 0.2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (min-width: 1024px) {
|
|
||||||
body {
|
|
||||||
display: flex;
|
|
||||||
place-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
#app {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: 1fr 1fr;
|
|
||||||
padding: 0 2rem;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
0
client/src/components/CenterPanel/CenterPanel.vue
Normal file
0
client/src/components/CenterPanel/CenterPanel.vue
Normal file
0
client/src/components/CenterPanel/center-panel.css
Normal file
0
client/src/components/CenterPanel/center-panel.css
Normal file
0
client/src/components/CenterPanel/useCenterPanel.ts
Normal file
0
client/src/components/CenterPanel/useCenterPanel.ts
Normal file
0
client/src/components/LeftPanel/LeftPanel.vue
Normal file
0
client/src/components/LeftPanel/LeftPanel.vue
Normal file
0
client/src/components/LeftPanel/left-panel.css
Normal file
0
client/src/components/LeftPanel/left-panel.css
Normal file
0
client/src/components/LeftPanel/useLeftPanel.ts
Normal file
0
client/src/components/LeftPanel/useLeftPanel.ts
Normal file
0
client/src/components/RightPanel/RightPanel.vue
Normal file
0
client/src/components/RightPanel/RightPanel.vue
Normal file
0
client/src/components/RightPanel/right-panel.css
Normal file
0
client/src/components/RightPanel/right-panel.css
Normal file
0
client/src/components/RightPanel/useRightPanel.ts
Normal file
0
client/src/components/RightPanel/useRightPanel.ts
Normal file
0
client/src/components/TopBar/TopBar.vue
Normal file
0
client/src/components/TopBar/TopBar.vue
Normal file
0
client/src/components/TopBar/top-bar.css
Normal file
0
client/src/components/TopBar/top-bar.css
Normal file
0
client/src/components/TopBar/useTopBar.ts
Normal file
0
client/src/components/TopBar/useTopBar.ts
Normal file
0
client/src/components/common/BaseIcon/BaseIcon.vue
Normal file
0
client/src/components/common/BaseIcon/BaseIcon.vue
Normal file
0
client/src/components/common/BaseIcon/base-icon.css
Normal file
0
client/src/components/common/BaseIcon/base-icon.css
Normal file
@@ -1,72 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div :class="['message-item', message.senderRole]">
|
|
||||||
<div class="message-header">
|
|
||||||
<span class="sender-name">{{ message.senderName }}</span>
|
|
||||||
<span class="timestamp">{{ formatTime(message.timestamp) }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="message-content">{{ message.mes }}</div>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
interface Message {
|
|
||||||
id: string;
|
|
||||||
senderName: string;
|
|
||||||
senderRole: 'user' | 'assistant' | 'system';
|
|
||||||
mes: string;
|
|
||||||
timestamp: Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
defineProps<{
|
|
||||||
message: Message;
|
|
||||||
}>();
|
|
||||||
|
|
||||||
function formatTime(date: Date) {
|
|
||||||
return new Date(date).toLocaleTimeString('zh-CN', {
|
|
||||||
hour: '2-digit',
|
|
||||||
minute: '2-digit'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.message-item {
|
|
||||||
padding: 12px;
|
|
||||||
border-radius: 8px;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
background: #ffffff;
|
|
||||||
border: 1px solid #e0e0e0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-item.user {
|
|
||||||
background: #e3f2fd;
|
|
||||||
border-color: #bbdefb;
|
|
||||||
margin-left: 20%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-item.assistant {
|
|
||||||
background: #f1f8e9;
|
|
||||||
border-color: #dcedc8;
|
|
||||||
margin-right: 20%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-header {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
margin-bottom: 8px;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #7f8c8d;
|
|
||||||
}
|
|
||||||
|
|
||||||
.sender-name {
|
|
||||||
font-weight: 600;
|
|
||||||
color: #2c3e50;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-content {
|
|
||||||
line-height: 1.6;
|
|
||||||
white-space: pre-wrap;
|
|
||||||
font-size: 14px;
|
|
||||||
color: #2c3e50;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="api-config-view">
|
|
||||||
<h3>🔌 API 配置</h3>
|
|
||||||
<p>API 配置管理界面</p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.api-config-view {
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
h3 {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #2c3e50;
|
|
||||||
margin: 0 0 12px 0;
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
font-size: 13px;
|
|
||||||
color: #7f8c8d;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="gallery-view">
|
|
||||||
<h3>🖼️ 画廊</h3>
|
|
||||||
<p>LLM 生成的图片将显示在这里</p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.gallery-view {
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
h3 {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #2c3e50;
|
|
||||||
margin: 0 0 12px 0;
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
font-size: 13px;
|
|
||||||
color: #7f8c8d;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="preset-view">
|
|
||||||
<h3>⚙️ 预设管理</h3>
|
|
||||||
<p>预设配置和条目展示</p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.preset-view {
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
h3 {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #2c3e50;
|
|
||||||
margin: 0 0 12px 0;
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
font-size: 13px;
|
|
||||||
color: #7f8c8d;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="world-book-view">
|
|
||||||
<h3>📚 世界书管理</h3>
|
|
||||||
<p>全局世界书激活和条目管理</p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.world-book-view {
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
h3 {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #2c3e50;
|
|
||||||
margin: 0 0 12px 0;
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
font-size: 13px;
|
|
||||||
color: #7f8c8d;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="dice-view">
|
|
||||||
<h3>🎲 骰子工具</h3>
|
|
||||||
<p>纯前端骰子功能</p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.dice-view {
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
h3 {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #2c3e50;
|
|
||||||
margin: 0 0 12px 0;
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
font-size: 13px;
|
|
||||||
color: #7f8c8d;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="rag-view">
|
|
||||||
<h3>🔍 RAG 检索</h3>
|
|
||||||
<p>RAG 知识检索功能</p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.rag-view {
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
h3 {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #2c3e50;
|
|
||||||
margin: 0 0 12px 0;
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
font-size: 13px;
|
|
||||||
color: #7f8c8d;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="world-book-call-view">
|
|
||||||
<h3>📚 世界书调用</h3>
|
|
||||||
<p>世界书条目调用记录</p>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.world-book-call-view {
|
|
||||||
padding: 8px;
|
|
||||||
}
|
|
||||||
h3 {
|
|
||||||
font-size: 14px;
|
|
||||||
color: #2c3e50;
|
|
||||||
margin: 0 0 12px 0;
|
|
||||||
}
|
|
||||||
p {
|
|
||||||
font-size: 13px;
|
|
||||||
color: #7f8c8d;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
<template>
|
|
||||||
<main class="center-chat">
|
|
||||||
<!-- 消息列表 -->
|
|
||||||
<div class="message-list">
|
|
||||||
<CenterMessageItem
|
|
||||||
v-for="msg in messages"
|
|
||||||
:key="msg.id"
|
|
||||||
:message="msg"
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
<!-- 输入区域 -->
|
|
||||||
<div class="input-area">
|
|
||||||
<!-- 选项框 -->
|
|
||||||
<div class="input-options">
|
|
||||||
<select v-model="sendOptions.role" class="option-select">
|
|
||||||
<option value="user">用户</option>
|
|
||||||
<option value="assistant">AI</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 输入框 -->
|
|
||||||
<textarea
|
|
||||||
v-model="inputMessage"
|
|
||||||
class="message-input"
|
|
||||||
placeholder="输入消息..."
|
|
||||||
@keydown.enter.ctrl="sendMessage"
|
|
||||||
></textarea>
|
|
||||||
|
|
||||||
<!-- 发送/停止按钮 -->
|
|
||||||
<button
|
|
||||||
:class="['send-btn', { sending: isSending }]"
|
|
||||||
@click="isSending ? stopGeneration() : sendMessage()"
|
|
||||||
>
|
|
||||||
{{ isSending ? '⏹ 停止' : '📤 发送' }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</main>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import CenterMessageItem from '../features/center/MessageItem.vue';
|
|
||||||
|
|
||||||
interface Message {
|
|
||||||
id: string;
|
|
||||||
senderName: string;
|
|
||||||
senderRole: 'user' | 'assistant' | 'system';
|
|
||||||
mes: string;
|
|
||||||
timestamp: Date;
|
|
||||||
}
|
|
||||||
|
|
||||||
const messages = ref<Message[]>([
|
|
||||||
{
|
|
||||||
id: '1',
|
|
||||||
senderName: 'Assistant',
|
|
||||||
senderRole: 'assistant',
|
|
||||||
mes: '你好!有什么可以帮助你的吗?',
|
|
||||||
timestamp: new Date(),
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
|
|
||||||
const inputMessage = ref('');
|
|
||||||
const isSending = ref(false);
|
|
||||||
const sendOptions = ref({
|
|
||||||
role: 'user' as 'user' | 'assistant',
|
|
||||||
});
|
|
||||||
|
|
||||||
function sendMessage() {
|
|
||||||
if (!inputMessage.value.trim()) return;
|
|
||||||
|
|
||||||
const newMessage: Message = {
|
|
||||||
id: Date.now().toString(),
|
|
||||||
senderName: sendOptions.value.role === 'user' ? 'User' : 'Assistant',
|
|
||||||
senderRole: sendOptions.value.role,
|
|
||||||
mes: inputMessage.value,
|
|
||||||
timestamp: new Date(),
|
|
||||||
};
|
|
||||||
|
|
||||||
messages.value.push(newMessage);
|
|
||||||
inputMessage.value = '';
|
|
||||||
isSending.value = true;
|
|
||||||
|
|
||||||
// 模拟 AI 回复
|
|
||||||
setTimeout(() => {
|
|
||||||
isSending.value = false;
|
|
||||||
}, 2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
function stopGeneration() {
|
|
||||||
isSending.value = false;
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.center-chat {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
flex: 1;
|
|
||||||
background: #ffffff;
|
|
||||||
overflow: hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-list {
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 16px;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
gap: 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-area {
|
|
||||||
display: flex;
|
|
||||||
align-items: flex-end;
|
|
||||||
gap: 8px;
|
|
||||||
padding: 16px;
|
|
||||||
background: #f8f9fa;
|
|
||||||
border-top: 2px solid #dee2e6;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.input-options {
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.option-select {
|
|
||||||
padding: 8px;
|
|
||||||
border: 1px solid #ced4da;
|
|
||||||
border-radius: 4px;
|
|
||||||
background: white;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-input {
|
|
||||||
flex: 1;
|
|
||||||
padding: 12px;
|
|
||||||
border: 1px solid #ced4da;
|
|
||||||
border-radius: 4px;
|
|
||||||
resize: none;
|
|
||||||
font-size: 14px;
|
|
||||||
min-height: 60px;
|
|
||||||
max-height: 200px;
|
|
||||||
font-family: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
.message-input:focus {
|
|
||||||
outline: none;
|
|
||||||
border-color: #3498db;
|
|
||||||
}
|
|
||||||
|
|
||||||
.send-btn {
|
|
||||||
padding: 12px 20px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
background: #3498db;
|
|
||||||
color: white;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
transition: background 0.2s;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.send-btn:hover {
|
|
||||||
background: #2980b9;
|
|
||||||
}
|
|
||||||
|
|
||||||
.send-btn.sending {
|
|
||||||
background: #e74c3c;
|
|
||||||
}
|
|
||||||
|
|
||||||
.send-btn.sending:hover {
|
|
||||||
background: #c0392b;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
<template>
|
|
||||||
<aside class="left-panel">
|
|
||||||
<!-- 左侧-顶部分页标签 -->
|
|
||||||
<div class="panel-tabs">
|
|
||||||
<button
|
|
||||||
v-for="tab in tabs"
|
|
||||||
:key="tab.id"
|
|
||||||
:class="['tab-btn', { active: currentTab === tab.id }]"
|
|
||||||
@click="currentTab = tab.id"
|
|
||||||
>
|
|
||||||
{{ tab.icon }} {{ tab.label }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 左侧-内容区域 -->
|
|
||||||
<div class="panel-content">
|
|
||||||
<LeftGalleryView v-if="currentTab === 'gallery'" />
|
|
||||||
<LeftApiConfigView v-if="currentTab === 'api'" />
|
|
||||||
<LeftPresetView v-if="currentTab === 'preset'" />
|
|
||||||
<LeftWorldBookView v-if="currentTab === 'worldbook'" />
|
|
||||||
</div>
|
|
||||||
</aside>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import LeftGalleryView from '../features/left/GalleryView.vue';
|
|
||||||
import LeftApiConfigView from '../features/left/ApiConfigView.vue';
|
|
||||||
import LeftPresetView from '../features/left/PresetView.vue';
|
|
||||||
import LeftWorldBookView from '../features/left/WorldBookView.vue';
|
|
||||||
|
|
||||||
const currentTab = ref('gallery');
|
|
||||||
|
|
||||||
const tabs = [
|
|
||||||
{ id: 'gallery', label: '画廊', icon: '🖼️' },
|
|
||||||
{ id: 'api', label: 'API', icon: '🔌' },
|
|
||||||
{ id: 'preset', label: '预设', icon: '⚙️' },
|
|
||||||
{ id: 'worldbook', label: '世界书', icon: '📚' },
|
|
||||||
];
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.left-panel {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 25%;
|
|
||||||
min-width: 300px;
|
|
||||||
max-width: 400px;
|
|
||||||
background: #ffffff;
|
|
||||||
border-right: 1px solid #e0e0e0;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel-tabs {
|
|
||||||
display: flex;
|
|
||||||
background: #f8f9fa;
|
|
||||||
border-bottom: 1px solid #e0e0e0;
|
|
||||||
padding: 6px 8px;
|
|
||||||
gap: 4px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab-btn {
|
|
||||||
flex: 1;
|
|
||||||
padding: 8px 6px;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
border-radius: 4px;
|
|
||||||
background: transparent;
|
|
||||||
color: #7f8c8d;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 12px;
|
|
||||||
font-weight: 500;
|
|
||||||
transition: all 0.2s;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
gap: 2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab-btn:hover {
|
|
||||||
background: #ffffff;
|
|
||||||
border-color: #e0e0e0;
|
|
||||||
color: #2c3e50;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab-btn.active {
|
|
||||||
background: #ffffff;
|
|
||||||
border-color: #3498db;
|
|
||||||
color: #3498db;
|
|
||||||
box-shadow: 0 1px 3px rgba(52, 152, 219, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel-content {
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 16px;
|
|
||||||
background: #fafafa;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,267 +0,0 @@
|
|||||||
<template>
|
|
||||||
<aside class="right-panel">
|
|
||||||
<!-- 右侧-顶部分页标签 -->
|
|
||||||
<div class="panel-tabs">
|
|
||||||
<button
|
|
||||||
v-for="tool in availableToolsList"
|
|
||||||
:key="tool.id"
|
|
||||||
:class="['tab-btn', { active: isToolActive(tool.id) }]"
|
|
||||||
@click="selectTool(tool.id)"
|
|
||||||
>
|
|
||||||
{{ tool.icon }} {{ tool.shortLabel }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 右侧-上部分区(最新使用的工具) -->
|
|
||||||
<div class="panel-section top-section">
|
|
||||||
<div class="section-header">
|
|
||||||
<span class="section-title">{{ recentTools[0]?.label || '未选择工具' }}</span>
|
|
||||||
<button class="collapse-btn" @click="toggleTop" title="折叠/展开">
|
|
||||||
{{ isTopCollapsed ? '▼' : '▲' }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div v-show="!isTopCollapsed" class="section-content">
|
|
||||||
<component :is="recentTools[0]?.component" v-if="recentTools[0]" />
|
|
||||||
<EmptyState v-else message="点击上方标签选择工具" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 右侧-下部分区(次新使用的工具) -->
|
|
||||||
<div class="panel-section bottom-section">
|
|
||||||
<div class="section-header">
|
|
||||||
<span class="section-title">{{ recentTools[1]?.label || '未选择工具' }}</span>
|
|
||||||
<button class="collapse-btn" @click="toggleBottom" title="折叠/展开">
|
|
||||||
{{ isBottomCollapsed ? '▼' : '▲' }}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<div v-show="!isBottomCollapsed" class="section-content">
|
|
||||||
<component :is="recentTools[1]?.component" v-if="recentTools[1]" />
|
|
||||||
<EmptyState v-else message="点击上方标签选择工具" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</aside>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import RightToolDiceView from '../features/right/DiceView.vue';
|
|
||||||
import RightToolRagView from '../features/right/RagView.vue';
|
|
||||||
import RightToolWorldBookCallView from '../features/right/WorldBookCallView.vue';
|
|
||||||
import RightToolDynamicTableView from '../features/right/DynamicTableView.vue';
|
|
||||||
import EmptyState from '../shared/EmptyState.vue';
|
|
||||||
|
|
||||||
interface ToolItem {
|
|
||||||
id: string;
|
|
||||||
label: string;
|
|
||||||
shortLabel: string;
|
|
||||||
icon: string;
|
|
||||||
component: any;
|
|
||||||
}
|
|
||||||
|
|
||||||
const isTopCollapsed = ref(false);
|
|
||||||
const isBottomCollapsed = ref(false);
|
|
||||||
const recentTools = ref<ToolItem[]>([]);
|
|
||||||
|
|
||||||
// 所有可用工具
|
|
||||||
const availableTools: Record<string, ToolItem> = {
|
|
||||||
dice: {
|
|
||||||
id: 'dice',
|
|
||||||
label: '🎲 骰子工具',
|
|
||||||
shortLabel: '骰子',
|
|
||||||
icon: '🎲',
|
|
||||||
component: RightToolDiceView,
|
|
||||||
},
|
|
||||||
rag: {
|
|
||||||
id: 'rag',
|
|
||||||
label: '🔍 RAG 检索',
|
|
||||||
shortLabel: 'RAG',
|
|
||||||
icon: '🔍',
|
|
||||||
component: RightToolRagView,
|
|
||||||
},
|
|
||||||
worldbook: {
|
|
||||||
id: 'worldbook',
|
|
||||||
label: '📚 世界书调用',
|
|
||||||
shortLabel: '世界书',
|
|
||||||
icon: '📚',
|
|
||||||
component: RightToolWorldBookCallView,
|
|
||||||
},
|
|
||||||
table: {
|
|
||||||
id: 'table',
|
|
||||||
label: '📊 动态表格',
|
|
||||||
shortLabel: '表格',
|
|
||||||
icon: '📊',
|
|
||||||
component: RightToolDynamicTableView,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// 获取工具列表(用于渲染标签)
|
|
||||||
const availableToolsList = Object.values(availableTools);
|
|
||||||
|
|
||||||
// 判断工具是否在当前显示的两个中
|
|
||||||
function isToolActive(toolId: string): boolean {
|
|
||||||
return recentTools.value.some((tool) => tool.id === toolId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 选择工具(添加到最近使用队列)
|
|
||||||
function selectTool(toolId: string) {
|
|
||||||
const tool = availableTools[toolId];
|
|
||||||
if (!tool) return;
|
|
||||||
|
|
||||||
// 移除已存在的相同工具
|
|
||||||
recentTools.value = recentTools.value.filter((t) => t.id !== toolId);
|
|
||||||
|
|
||||||
// 添加到最前面
|
|
||||||
recentTools.value.unshift(tool);
|
|
||||||
|
|
||||||
// 只保留最近两个
|
|
||||||
if (recentTools.value.length > 2) {
|
|
||||||
recentTools.value = recentTools.value.slice(0, 2);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleTop() {
|
|
||||||
isTopCollapsed.value = !isTopCollapsed.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
function toggleBottom() {
|
|
||||||
isBottomCollapsed.value = !isBottomCollapsed.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 暴露方法供外部调用
|
|
||||||
defineExpose({
|
|
||||||
selectTool,
|
|
||||||
});
|
|
||||||
|
|
||||||
// 初始化默认工具
|
|
||||||
selectTool('dice');
|
|
||||||
selectTool('worldbook');
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.right-panel {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
width: 25%;
|
|
||||||
min-width: 300px;
|
|
||||||
max-width: 400px;
|
|
||||||
background: #ffffff;
|
|
||||||
border-left: 1px solid #e0e0e0;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel-tabs {
|
|
||||||
display: flex;
|
|
||||||
background: #f8f9fa;
|
|
||||||
border-bottom: 1px solid #e0e0e0;
|
|
||||||
padding: 6px 8px;
|
|
||||||
gap: 4px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
overflow-x: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab-btn {
|
|
||||||
flex: 1;
|
|
||||||
min-width: 60px;
|
|
||||||
padding: 8px 6px;
|
|
||||||
border: 1px solid transparent;
|
|
||||||
border-radius: 4px;
|
|
||||||
background: transparent;
|
|
||||||
color: #7f8c8d;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 11px;
|
|
||||||
font-weight: 500;
|
|
||||||
transition: all 0.2s;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
gap: 2px;
|
|
||||||
white-space: nowrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab-btn:hover {
|
|
||||||
background: #ffffff;
|
|
||||||
border-color: #e0e0e0;
|
|
||||||
color: #2c3e50;
|
|
||||||
}
|
|
||||||
|
|
||||||
.tab-btn.active {
|
|
||||||
background: #ffffff;
|
|
||||||
border-color: #3498db;
|
|
||||||
color: #3498db;
|
|
||||||
box-shadow: 0 1px 3px rgba(52, 152, 219, 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel-section {
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
flex: 1;
|
|
||||||
overflow: hidden;
|
|
||||||
border-bottom: 1px solid #e0e0e0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel-section:last-child {
|
|
||||||
border-bottom: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-header {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 10px 16px;
|
|
||||||
background: #ffffff;
|
|
||||||
border-bottom: 1px solid #e0e0e0;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-title {
|
|
||||||
font-size: 13px;
|
|
||||||
font-weight: 600;
|
|
||||||
color: #2c3e50;
|
|
||||||
}
|
|
||||||
|
|
||||||
.collapse-btn {
|
|
||||||
padding: 4px 8px;
|
|
||||||
border: none;
|
|
||||||
background: transparent;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #7f8c8d;
|
|
||||||
transition: color 0.2s;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.collapse-btn:hover {
|
|
||||||
color: #2c3e50;
|
|
||||||
background: #f8f9fa;
|
|
||||||
}
|
|
||||||
|
|
||||||
.section-content {
|
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
|
||||||
padding: 12px;
|
|
||||||
background: #fafafa;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* 滚动条样式 */
|
|
||||||
.panel-tabs::-webkit-scrollbar,
|
|
||||||
.section-content::-webkit-scrollbar {
|
|
||||||
width: 6px;
|
|
||||||
height: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel-tabs::-webkit-scrollbar-track,
|
|
||||||
.section-content::-webkit-scrollbar-track {
|
|
||||||
background: transparent;
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel-tabs::-webkit-scrollbar-thumb,
|
|
||||||
.section-content::-webkit-scrollbar-thumb {
|
|
||||||
background: #d0d0d0;
|
|
||||||
border-radius: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.panel-tabs::-webkit-scrollbar-thumb:hover,
|
|
||||||
.section-content::-webkit-scrollbar-thumb:hover {
|
|
||||||
background: #b0b0b0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,18 +0,0 @@
|
|||||||
<template>
|
|
||||||
<div class="right-toolbar">
|
|
||||||
<span style="color: #bdc3c7; font-size: 12px;">工具栏</span>
|
|
||||||
</div>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
defineProps<{
|
|
||||||
rightPanelRef?: any;
|
|
||||||
}>();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.right-toolbar {
|
|
||||||
display: flex;
|
|
||||||
gap: 4px;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,125 +0,0 @@
|
|||||||
<template>
|
|
||||||
<header class="top-toolbar">
|
|
||||||
<div class="toolbar-left">
|
|
||||||
<!-- API 配置快速切换 -->
|
|
||||||
<div class="toolbar-item">
|
|
||||||
<span class="label">API:</span>
|
|
||||||
<select v-model="currentApi" class="toolbar-select">
|
|
||||||
<option value="primary">主 API</option>
|
|
||||||
<option value="secondary">副 API</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="toolbar-center">
|
|
||||||
<!-- 当前用户角色 -->
|
|
||||||
<div class="toolbar-item">
|
|
||||||
<span class="label">用户:</span>
|
|
||||||
<span class="value">{{ currentUser }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 当前 AI 角色 -->
|
|
||||||
<div class="toolbar-item">
|
|
||||||
<span class="label">AI:</span>
|
|
||||||
<span class="value">{{ currentAICharacter }}</span>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- 激活的全局世界书 -->
|
|
||||||
<div class="toolbar-item">
|
|
||||||
<span class="label">世界书:</span>
|
|
||||||
<span class="value">{{ activeWorldBooks.length }} 个激活</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="toolbar-right">
|
|
||||||
<!-- 设置按钮 -->
|
|
||||||
<button class="toolbar-btn" @click="openSettings">
|
|
||||||
⚙️ 设置
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- 拓展按钮 -->
|
|
||||||
<button class="toolbar-btn" @click="openExtensions">
|
|
||||||
🧩 拓展
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
</template>
|
|
||||||
|
|
||||||
<script setup lang="ts">
|
|
||||||
import { ref } from 'vue';
|
|
||||||
|
|
||||||
const currentApi = ref('primary');
|
|
||||||
const currentUser = ref('User');
|
|
||||||
const currentAICharacter = ref('Assistant');
|
|
||||||
const activeWorldBooks = ref(['奇幻世界', '现代都市']);
|
|
||||||
|
|
||||||
function openSettings() {
|
|
||||||
console.log('Open settings');
|
|
||||||
}
|
|
||||||
|
|
||||||
function openExtensions() {
|
|
||||||
console.log('Open extensions');
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.top-toolbar {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: space-between;
|
|
||||||
padding: 8px 16px;
|
|
||||||
background: #2c3e50;
|
|
||||||
color: white;
|
|
||||||
border-bottom: 2px solid #34495e;
|
|
||||||
height: 50px;
|
|
||||||
flex-shrink: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toolbar-left,
|
|
||||||
.toolbar-center,
|
|
||||||
.toolbar-right {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toolbar-item {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 8px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.label {
|
|
||||||
font-size: 12px;
|
|
||||||
opacity: 0.8;
|
|
||||||
}
|
|
||||||
|
|
||||||
.value {
|
|
||||||
font-size: 14px;
|
|
||||||
font-weight: 500;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toolbar-select {
|
|
||||||
padding: 4px 8px;
|
|
||||||
border-radius: 4px;
|
|
||||||
border: 1px solid #34495e;
|
|
||||||
background: #34495e;
|
|
||||||
color: white;
|
|
||||||
font-size: 13px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toolbar-btn {
|
|
||||||
padding: 6px 12px;
|
|
||||||
border: none;
|
|
||||||
border-radius: 4px;
|
|
||||||
background: #3498db;
|
|
||||||
color: white;
|
|
||||||
cursor: pointer;
|
|
||||||
font-size: 13px;
|
|
||||||
transition: background 0.2s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.toolbar-btn:hover {
|
|
||||||
background: #2980b9;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
/**
|
|
||||||
* useApi Composable
|
|
||||||
* Provides API client with error handling and loading states
|
|
||||||
*/
|
|
||||||
|
|
||||||
import { ref } from 'vue';
|
|
||||||
import type { Ref } from 'vue';
|
|
||||||
|
|
||||||
interface UseApiOptions<T> {
|
|
||||||
immediate?: boolean;
|
|
||||||
onError?: (error: Error) => void;
|
|
||||||
onSuccess?: (data: T) => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function useApi<T>(
|
|
||||||
apiCall: () => Promise<T>,
|
|
||||||
options: UseApiOptions<T> = {}
|
|
||||||
) {
|
|
||||||
const data: Ref<T | null> = ref(null);
|
|
||||||
const error: Ref<Error | null> = ref(null);
|
|
||||||
const loading: Ref<boolean> = ref(false);
|
|
||||||
|
|
||||||
const execute = async () => {
|
|
||||||
loading.value = true;
|
|
||||||
error.value = null;
|
|
||||||
|
|
||||||
try {
|
|
||||||
const result = await apiCall();
|
|
||||||
data.value = result;
|
|
||||||
options.onSuccess?.(result);
|
|
||||||
return result;
|
|
||||||
} catch (err) {
|
|
||||||
error.value = err instanceof Error ? err : new Error(String(err));
|
|
||||||
options.onError?.(error.value);
|
|
||||||
throw error.value;
|
|
||||||
} finally {
|
|
||||||
loading.value = false;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (options.immediate) {
|
|
||||||
execute();
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
data,
|
|
||||||
error,
|
|
||||||
loading,
|
|
||||||
execute,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
0
client/src/composables/useTheme.ts
Normal file
0
client/src/composables/useTheme.ts
Normal file
0
client/src/layouts/MainLayout/MainLayout.vue
Normal file
0
client/src/layouts/MainLayout/MainLayout.vue
Normal file
0
client/src/layouts/MainLayout/main-layout.css
Normal file
0
client/src/layouts/MainLayout/main-layout.css
Normal file
@@ -1,14 +0,0 @@
|
|||||||
import './assets/main.css'
|
|
||||||
|
|
||||||
import { createApp } from 'vue'
|
|
||||||
import { createPinia } from 'pinia'
|
|
||||||
|
|
||||||
import App from './App.vue'
|
|
||||||
import router from './router'
|
|
||||||
|
|
||||||
const app = createApp(App)
|
|
||||||
|
|
||||||
app.use(createPinia())
|
|
||||||
app.use(router)
|
|
||||||
|
|
||||||
app.mount('#app')
|
|
||||||
|
|||||||
0
client/src/router/index.ts
Normal file
0
client/src/router/index.ts
Normal file
0
client/src/stores/useAppStore.ts
Normal file
0
client/src/stores/useAppStore.ts
Normal file
0
client/src/styles/reset.css
Normal file
0
client/src/styles/reset.css
Normal file
0
client/src/styles/variables.css
Normal file
0
client/src/styles/variables.css
Normal file
@@ -1,19 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "@vue/tsconfig/tsconfig.dom.json",
|
|
||||||
"include": ["env.d.ts", "src/**/*", "src/**/*.vue"],
|
|
||||||
"exclude": ["src/**/__tests__/*"],
|
|
||||||
"compilerOptions": {
|
|
||||||
// Extra safety for array and object lookups, but may have false positives.
|
|
||||||
"noUncheckedIndexedAccess": true,
|
|
||||||
|
|
||||||
// Path mapping for cleaner imports.
|
|
||||||
"paths": {
|
|
||||||
"@/*": ["./src/*"],
|
|
||||||
"@shared/*": ["../shared/types/*"]
|
|
||||||
},
|
|
||||||
|
|
||||||
// `vue-tsc --build` produces a .tsbuildinfo file for incremental type-checking.
|
|
||||||
// Specified here to keep it out of the root directory.
|
|
||||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
{
|
|
||||||
"files": [],
|
|
||||||
"references": [
|
|
||||||
{
|
|
||||||
"path": "./tsconfig.node.json"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"path": "./tsconfig.app.json"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
// TSConfig for modules that run in Node.js environment via either transpilation or type-stripping.
|
|
||||||
{
|
|
||||||
"extends": "@tsconfig/node24/tsconfig.json",
|
|
||||||
"include": [
|
|
||||||
"vite.config.*",
|
|
||||||
"vitest.config.*",
|
|
||||||
"cypress.config.*",
|
|
||||||
"playwright.config.*",
|
|
||||||
"eslint.config.*"
|
|
||||||
],
|
|
||||||
"compilerOptions": {
|
|
||||||
// Most tools use transpilation instead of Node.js's native type-stripping.
|
|
||||||
// Bundler mode provides a smoother developer experience.
|
|
||||||
"module": "preserve",
|
|
||||||
"moduleResolution": "bundler",
|
|
||||||
|
|
||||||
// Include Node.js types and avoid accidentally including other `@types/*` packages.
|
|
||||||
"types": ["node"],
|
|
||||||
|
|
||||||
// Disable emitting output during `vue-tsc --build`, which is used for type-checking only.
|
|
||||||
"noEmit": true,
|
|
||||||
|
|
||||||
// `vue-tsc --build` produces a .tsbuildinfo file for incremental type-checking.
|
|
||||||
// Specified here to keep it out of the root directory.
|
|
||||||
"tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
import { fileURLToPath, URL } from 'node:url'
|
|
||||||
import { defineConfig } from 'vite'
|
|
||||||
import vue from '@vitejs/plugin-vue'
|
|
||||||
|
|
||||||
export default defineConfig({
|
|
||||||
plugins: [vue()],
|
|
||||||
resolve: {
|
|
||||||
alias: {
|
|
||||||
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
|
||||||
'@shared': fileURLToPath(new URL('../shared/types', import.meta.url))
|
|
||||||
}
|
|
||||||
},
|
|
||||||
server: {
|
|
||||||
port: 8080,
|
|
||||||
proxy: {
|
|
||||||
'/api': {
|
|
||||||
target: 'http://localhost:3000',
|
|
||||||
changeOrigin: true,
|
|
||||||
rewrite: (path) => path.replace(/^\/api/, '')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
@@ -1,68 +0,0 @@
|
|||||||
version: '3.8'
|
|
||||||
|
|
||||||
services:
|
|
||||||
# Backend Service (NestJS)
|
|
||||||
backend:
|
|
||||||
build:
|
|
||||||
context: ./server
|
|
||||||
dockerfile: Dockerfile.dev
|
|
||||||
container_name: sillytavern-backend
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
|
||||||
- "23337:3000" # Map to host port 23337
|
|
||||||
volumes:
|
|
||||||
# Mount code for hot reload (development)
|
|
||||||
- ./server:/usr/src/app
|
|
||||||
- ./shared:/usr/src/shared
|
|
||||||
# Exclude node_modules to use container's version
|
|
||||||
- /usr/src/app/node_modules
|
|
||||||
# Persistent data
|
|
||||||
- ./data:/usr/src/app/data
|
|
||||||
- ./.env:/usr/src/app/.env:ro
|
|
||||||
environment:
|
|
||||||
- NODE_ENV=development
|
|
||||||
- PORT=3000
|
|
||||||
- DB_DATABASE=./data/db/app.db
|
|
||||||
- UPLOAD_DIR=./data/files
|
|
||||||
- LOG_DIR=./data/logs
|
|
||||||
working_dir: /usr/src/app
|
|
||||||
command: npm run start:dev
|
|
||||||
networks:
|
|
||||||
- app-network
|
|
||||||
healthcheck:
|
|
||||||
test: ["CMD", "wget", "--spider", "-q", "http://localhost:3000/api"]
|
|
||||||
interval: 30s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 3
|
|
||||||
start_period: 40s
|
|
||||||
|
|
||||||
# Frontend Service (Vue3 + Vite)
|
|
||||||
frontend:
|
|
||||||
build:
|
|
||||||
context: ./client
|
|
||||||
dockerfile: Dockerfile.dev
|
|
||||||
container_name: sillytavern-frontend
|
|
||||||
restart: unless-stopped
|
|
||||||
ports:
|
|
||||||
- "23338:5173" # Vite dev server port
|
|
||||||
volumes:
|
|
||||||
# Mount code for hot reload (development)
|
|
||||||
- ./client:/usr/src/app
|
|
||||||
- ./shared:/usr/src/shared
|
|
||||||
# Exclude node_modules
|
|
||||||
- /usr/src/app/node_modules
|
|
||||||
environment:
|
|
||||||
- NODE_ENV=development
|
|
||||||
- VITE_API_URL=http://localhost:23337
|
|
||||||
- VITE_WS_URL=ws://localhost:23337
|
|
||||||
working_dir: /usr/src/app
|
|
||||||
command: npm run dev -- --host 0.0.0.0 --port 5173
|
|
||||||
depends_on:
|
|
||||||
backend:
|
|
||||||
condition: service_healthy
|
|
||||||
networks:
|
|
||||||
- app-network
|
|
||||||
|
|
||||||
networks:
|
|
||||||
app-network:
|
|
||||||
driver: bridge
|
|
||||||
|
|||||||
0
docker/backend.Dockerfile
Normal file
0
docker/backend.Dockerfile
Normal file
0
docker/frontend.Dockerfile
Normal file
0
docker/frontend.Dockerfile
Normal file
0
docker/nginx/default.conf
Normal file
0
docker/nginx/default.conf
Normal file
310
make.bat
310
make.bat
@@ -1,310 +0,0 @@
|
|||||||
NEW_FILE_CODE
|
|
||||||
@echo off
|
|
||||||
setlocal enabledelayedexpansion
|
|
||||||
|
|
||||||
echo =====================================================
|
|
||||||
echo Creating Enterprise-Grade Project Architecture...
|
|
||||||
echo Backend: NestJS with DDD + Frontend: Vue3 Composition API
|
|
||||||
echo =====================================================
|
|
||||||
|
|
||||||
:: Check if we are in the right directory
|
|
||||||
if not exist server (
|
|
||||||
echo [ERROR] Please run this script from project root directory
|
|
||||||
pause
|
|
||||||
exit /b
|
|
||||||
)
|
|
||||||
|
|
||||||
:: -------------------------------------------------------
|
|
||||||
:: 1. Restructure Backend (NestJS)
|
|
||||||
:: -------------------------------------------------------
|
|
||||||
echo.
|
|
||||||
echo [Backend] Creating complete directory structure...
|
|
||||||
|
|
||||||
cd server\src
|
|
||||||
|
|
||||||
:: Remove existing directories to start fresh
|
|
||||||
if exist core rmdir /s /q core
|
|
||||||
if exist modules rmdir /s /q modules
|
|
||||||
if exist shared rmdir /s /q shared
|
|
||||||
|
|
||||||
:: === CORE LAYER ===
|
|
||||||
echo Creating core layer...
|
|
||||||
|
|
||||||
mkdir core
|
|
||||||
mkdir core\config
|
|
||||||
mkdir core\database
|
|
||||||
mkdir core\database\migrations
|
|
||||||
mkdir core\database\seeds
|
|
||||||
mkdir core\decorators
|
|
||||||
mkdir core\filters
|
|
||||||
mkdir core\guards
|
|
||||||
mkdir core\interceptors
|
|
||||||
mkdir core\pipes
|
|
||||||
mkdir core\middleware
|
|
||||||
|
|
||||||
:: === MODULES LAYER ===
|
|
||||||
echo Creating modules layer...
|
|
||||||
|
|
||||||
mkdir modules
|
|
||||||
|
|
||||||
:: Auth Module
|
|
||||||
mkdir modules\auth
|
|
||||||
mkdir modules\auth\controllers
|
|
||||||
mkdir modules\auth\services
|
|
||||||
mkdir modules\auth\strategies
|
|
||||||
mkdir modules\auth\dto
|
|
||||||
mkdir modules\auth\interfaces
|
|
||||||
|
|
||||||
:: LLM Module
|
|
||||||
mkdir modules\llm
|
|
||||||
mkdir modules\llm\controllers
|
|
||||||
mkdir modules\llm\services
|
|
||||||
mkdir modules\llm\providers
|
|
||||||
mkdir modules\llm\dto
|
|
||||||
mkdir modules\llm\entities
|
|
||||||
mkdir modules\llm\interfaces
|
|
||||||
|
|
||||||
:: Workflow Module
|
|
||||||
mkdir modules\workflow
|
|
||||||
mkdir modules\workflow\controllers
|
|
||||||
mkdir modules\workflow\services
|
|
||||||
mkdir modules\workflow\engine
|
|
||||||
mkdir modules\workflow\nodes
|
|
||||||
mkdir modules\workflow\dto
|
|
||||||
mkdir modules\workflow\entities
|
|
||||||
mkdir modules\workflow\interfaces
|
|
||||||
|
|
||||||
:: Data Store Module
|
|
||||||
mkdir modules\data-store
|
|
||||||
mkdir modules\data-store\controllers
|
|
||||||
mkdir modules\data-store\services
|
|
||||||
mkdir modules\data-store\repositories
|
|
||||||
mkdir modules\data-store\entities
|
|
||||||
mkdir modules\data-store\schemas
|
|
||||||
mkdir modules\data-store\dto
|
|
||||||
mkdir modules\data-store\interfaces
|
|
||||||
|
|
||||||
:: Import/Export Module
|
|
||||||
mkdir modules\import-export
|
|
||||||
mkdir modules\import-export\controllers
|
|
||||||
mkdir modules\import-export\services
|
|
||||||
mkdir modules\import-export\transformers
|
|
||||||
mkdir modules\import-export\serializers
|
|
||||||
mkdir modules\import-export\parsers
|
|
||||||
mkdir modules\import-export\dto
|
|
||||||
mkdir modules\import-export\interfaces
|
|
||||||
|
|
||||||
:: File Management Module
|
|
||||||
mkdir modules\file-management
|
|
||||||
mkdir modules\file-management\controllers
|
|
||||||
mkdir modules\file-management\services
|
|
||||||
mkdir modules\file-management\storage
|
|
||||||
mkdir modules\file-management\dto
|
|
||||||
mkdir modules\file-management\entities
|
|
||||||
|
|
||||||
:: === SHARED LAYER ===
|
|
||||||
echo Creating shared layer...
|
|
||||||
|
|
||||||
mkdir shared
|
|
||||||
mkdir shared\interfaces
|
|
||||||
mkdir shared\types
|
|
||||||
mkdir shared\utils
|
|
||||||
mkdir shared\constants
|
|
||||||
mkdir shared\dtos
|
|
||||||
mkdir shared\decorators
|
|
||||||
|
|
||||||
:: === EVENTS SYSTEM ===
|
|
||||||
echo Creating events system...
|
|
||||||
|
|
||||||
mkdir events
|
|
||||||
mkdir events\event-emitter
|
|
||||||
mkdir events\events
|
|
||||||
mkdir events\listeners
|
|
||||||
|
|
||||||
:: === QUEUES SYSTEM ===
|
|
||||||
echo Creating queues system...
|
|
||||||
|
|
||||||
mkdir queues
|
|
||||||
mkdir queues\processors
|
|
||||||
mkdir queues\jobs
|
|
||||||
mkdir queues\interfaces
|
|
||||||
|
|
||||||
:: === COMMON LAYER ===
|
|
||||||
echo Creating common layer...
|
|
||||||
|
|
||||||
mkdir common
|
|
||||||
mkdir common\base
|
|
||||||
mkdir common\mixins
|
|
||||||
mkdir common\exceptions
|
|
||||||
|
|
||||||
cd ..\..
|
|
||||||
|
|
||||||
echo [Backend] Directory structure created successfully!
|
|
||||||
|
|
||||||
:: -------------------------------------------------------
|
|
||||||
:: 2. Restructure Frontend (Vue3)
|
|
||||||
:: -------------------------------------------------------
|
|
||||||
echo.
|
|
||||||
echo [Frontend] Creating complete directory structure...
|
|
||||||
|
|
||||||
cd client\src
|
|
||||||
|
|
||||||
:: Remove existing directories to start fresh
|
|
||||||
if exist api rmdir /s /q api
|
|
||||||
if exist components rmdir /s /q components
|
|
||||||
if exist views rmdir /s /q views
|
|
||||||
if exist composables rmdir /s /q composables
|
|
||||||
if exist stores rmdir /s /q stores
|
|
||||||
if exist router rmdir /s /q router
|
|
||||||
if exist types rmdir /s /q types
|
|
||||||
if exist utils rmdir /s /q utils
|
|
||||||
|
|
||||||
:: === API LAYER ===
|
|
||||||
echo Creating API layer...
|
|
||||||
|
|
||||||
mkdir api
|
|
||||||
mkdir api\clients
|
|
||||||
mkdir api\modules
|
|
||||||
mkdir api\interceptors
|
|
||||||
|
|
||||||
:: === COMPONENTS LAYER ===
|
|
||||||
echo Creating components layer...
|
|
||||||
|
|
||||||
mkdir components
|
|
||||||
mkdir components\base
|
|
||||||
mkdir components\base\buttons
|
|
||||||
mkdir components\base\inputs
|
|
||||||
mkdir components\base\modals
|
|
||||||
mkdir components\base\layouts
|
|
||||||
mkdir components\base\tables
|
|
||||||
mkdir components\base\forms
|
|
||||||
|
|
||||||
mkdir components\business
|
|
||||||
mkdir components\business\llm-chat
|
|
||||||
mkdir components\business\workflow-canvas
|
|
||||||
mkdir components\business\data-table
|
|
||||||
mkdir components\business\file-uploader
|
|
||||||
mkdir components\business\prompt-editor
|
|
||||||
mkdir components\business\node-palette
|
|
||||||
|
|
||||||
mkdir components\widgets
|
|
||||||
mkdir components\widgets\status-indicator
|
|
||||||
mkdir components\widgets\progress-bar
|
|
||||||
mkdir components\widgets\toast
|
|
||||||
|
|
||||||
:: === VIEWS LAYER ===
|
|
||||||
echo Creating views layer...
|
|
||||||
|
|
||||||
mkdir views
|
|
||||||
mkdir views\dashboard
|
|
||||||
mkdir views\workflow-editor
|
|
||||||
mkdir views\llm-playground
|
|
||||||
mkdir views\data-browser
|
|
||||||
mkdir views\settings
|
|
||||||
mkdir views\auth
|
|
||||||
|
|
||||||
:: === COMPOSABLES LAYER ===
|
|
||||||
echo Creating composables layer...
|
|
||||||
|
|
||||||
mkdir composables
|
|
||||||
|
|
||||||
:: === STORES LAYER ===
|
|
||||||
echo Creating stores layer...
|
|
||||||
|
|
||||||
mkdir stores
|
|
||||||
mkdir stores\modules
|
|
||||||
|
|
||||||
:: === ROUTER LAYER ===
|
|
||||||
echo Creating router layer...
|
|
||||||
|
|
||||||
mkdir router
|
|
||||||
mkdir router\routes
|
|
||||||
|
|
||||||
:: === TYPES LAYER ===
|
|
||||||
echo Creating types layer...
|
|
||||||
|
|
||||||
mkdir types
|
|
||||||
mkdir types\models
|
|
||||||
mkdir types\api
|
|
||||||
mkdir types\common
|
|
||||||
|
|
||||||
:: === UTILS LAYER ===
|
|
||||||
echo Creating utils layer...
|
|
||||||
|
|
||||||
mkdir utils
|
|
||||||
mkdir utils\formatters
|
|
||||||
mkdir utils\validators
|
|
||||||
mkdir utils\helpers
|
|
||||||
mkdir utils\constants
|
|
||||||
|
|
||||||
:: === ASSETS LAYER ===
|
|
||||||
echo Creating assets structure...
|
|
||||||
|
|
||||||
if not exist assets mkdir assets
|
|
||||||
mkdir assets\styles
|
|
||||||
mkdir assets\icons
|
|
||||||
mkdir assets\images
|
|
||||||
|
|
||||||
:: === PLUGINS LAYER ===
|
|
||||||
echo Creating plugins layer...
|
|
||||||
|
|
||||||
mkdir plugins
|
|
||||||
|
|
||||||
cd ..\..
|
|
||||||
|
|
||||||
echo [Frontend] Directory structure created successfully!
|
|
||||||
|
|
||||||
:: -------------------------------------------------------
|
|
||||||
:: 3. Create Root Level Directories
|
|
||||||
:: -------------------------------------------------------
|
|
||||||
echo.
|
|
||||||
echo [Infrastructure] Creating infrastructure directories...
|
|
||||||
|
|
||||||
if not exist data mkdir data
|
|
||||||
if not exist data\db mkdir data\db
|
|
||||||
if not exist data\files mkdir data\files
|
|
||||||
if not exist data\logs mkdir data\logs
|
|
||||||
if not exist data\backups mkdir data\backups
|
|
||||||
|
|
||||||
if not exist docker mkdir docker
|
|
||||||
if not exist docker\nginx mkdir docker\nginx
|
|
||||||
if not exist docker\app mkdir docker\app
|
|
||||||
if not exist docker\certs mkdir docker\certs
|
|
||||||
|
|
||||||
if not exist docs mkdir docs
|
|
||||||
if not exist scripts mkdir scripts
|
|
||||||
if not exist tests mkdir tests
|
|
||||||
|
|
||||||
echo [Infrastructure] Infrastructure directories created!
|
|
||||||
|
|
||||||
:: -------------------------------------------------------
|
|
||||||
:: 4. Summary
|
|
||||||
:: -------------------------------------------------------
|
|
||||||
echo.
|
|
||||||
echo =====================================================
|
|
||||||
echo Project architecture created successfully!
|
|
||||||
echo.
|
|
||||||
echo Backend Structure (server/src):
|
|
||||||
echo - core/ Infrastructure layer
|
|
||||||
echo - modules/ Business modules (DDD)
|
|
||||||
echo - shared/ Shared utilities
|
|
||||||
echo - events/ Event system
|
|
||||||
echo - queues/ Task queues
|
|
||||||
echo - common/ Base classes
|
|
||||||
echo.
|
|
||||||
echo Frontend Structure (client/src):
|
|
||||||
echo - api/ API clients
|
|
||||||
echo - components/ UI components
|
|
||||||
echo - views/ Page views
|
|
||||||
echo - composables/ Reusable logic
|
|
||||||
echo - stores/ State management
|
|
||||||
echo - types/ TypeScript types
|
|
||||||
echo - utils/ Utility functions
|
|
||||||
echo.
|
|
||||||
echo Next steps:
|
|
||||||
echo 1. cd server ^&^& npm install
|
|
||||||
echo 2. cd ../client ^&^& npm install
|
|
||||||
echo 3. Start implementing base classes and interfaces
|
|
||||||
echo =====================================================
|
|
||||||
|
|
||||||
pause
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
node_modules
|
|
||||||
dist
|
|
||||||
.env
|
|
||||||
.git
|
|
||||||
.idea
|
|
||||||
.vscode
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
# =====================================================
|
|
||||||
# Server Configuration
|
|
||||||
# =====================================================
|
|
||||||
NODE_ENV=development
|
|
||||||
PORT=3000
|
|
||||||
API_PREFIX=/api
|
|
||||||
|
|
||||||
# =====================================================
|
|
||||||
# Database Configuration (File-based, no DB server needed)
|
|
||||||
# =====================================================
|
|
||||||
DB_TYPE=better-sqlite3
|
|
||||||
DB_DATABASE=./data/db/app.db
|
|
||||||
|
|
||||||
# =====================================================
|
|
||||||
# JWT Authentication
|
|
||||||
# =====================================================
|
|
||||||
JWT_SECRET=change-this-to-a-random-string-at-least-32-chars
|
|
||||||
JWT_EXPIRES_IN=7d
|
|
||||||
JWT_REFRESH_SECRET=change-this-to-another-random-string
|
|
||||||
JWT_REFRESH_EXPIRES_IN=30d
|
|
||||||
|
|
||||||
# =====================================================
|
|
||||||
# LLM Provider API Keys (Backend Only - Secure)
|
|
||||||
# =====================================================
|
|
||||||
OPENAI_API_KEY=sk-your-openai-api-key-here
|
|
||||||
ANTHROPIC_API_KEY=sk-ant-your-anthropic-api-key-here
|
|
||||||
GOOGLE_API_KEY=your-google-api-key-here
|
|
||||||
LOCAL_LLM_URL=http://localhost:11434
|
|
||||||
|
|
||||||
# =====================================================
|
|
||||||
# File Storage
|
|
||||||
# =====================================================
|
|
||||||
UPLOAD_DIR=./data/files
|
|
||||||
MAX_FILE_SIZE=10485760
|
|
||||||
|
|
||||||
# =====================================================
|
|
||||||
# CORS Configuration
|
|
||||||
# =====================================================
|
|
||||||
CORS_ORIGIN=http://localhost:23338
|
|
||||||
|
|
||||||
# =====================================================
|
|
||||||
# Rate Limiting
|
|
||||||
# =====================================================
|
|
||||||
RATE_LIMIT_TTL=60
|
|
||||||
RATE_LIMIT_MAX=100
|
|
||||||
|
|
||||||
# =====================================================
|
|
||||||
# Workflow Configuration
|
|
||||||
# =====================================================
|
|
||||||
WORKFLOW_MAX_PARALLEL=5
|
|
||||||
WORKFLOW_TIMEOUT=300000
|
|
||||||
|
|
||||||
# =====================================================
|
|
||||||
# Logging
|
|
||||||
# =====================================================
|
|
||||||
LOG_LEVEL=debug
|
|
||||||
LOG_DIR=./data/logs
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user