docs: update architecture docs for Vue 3 + FastAPI separation, add one-click start.bat
- CLAUDE.md: remove duplicate architecture section, fix MAX_RETRY 5→3 - README.md: update architecture diagram to 3-tier, add start.bat instructions - ROADMAP.md: add 阶段六 layered generation v5 (items 16-20) - start.bat: one-click startup with auto port-kill and path-with-spaces fix - package-lock.json: updated from npm install
This commit is contained in:
@@ -4,20 +4,7 @@
|
||||
|
||||
一个**本地桌面应用**,通过自然语言多轮对话帮助非技术用户创建 JasperReports 模板(JRXML 文件)。核心技术栈:Vue 3 前端 + FastAPI SSE 后端 + LangGraph 状态机 + LLM 生成/修改 + 自动验证修正循环。
|
||||
|
||||
**一句话**:用户用中文描述报表需求 → LLM 生成 JRXML → 自动验证 → 失败则自动修正(最多5次) → 重试耗尽后失败上下文自动注入下一轮 → 返回可编译的 JRXML 文件。
|
||||
|
||||
## 架构
|
||||
|
||||
```
|
||||
前端 (Vue 3 + Vite, 端口 5173)
|
||||
│ 聊天界面 + 统一输入框 + 流式显示 + 文件上传/粘贴/拖拽
|
||||
▼ HTTP + SSE (Server-Sent Events)
|
||||
后端 API (FastAPI, 端口 8000)
|
||||
│ REST 接口 + SSE 流式推送
|
||||
│ 包装 LangGraph Agent 不变
|
||||
▼ HTTP
|
||||
验证服务 (FastAPI, 端口 8001) — 不变
|
||||
```
|
||||
**一句话**:用户用中文描述报表需求 → LLM 生成 JRXML → 自动验证 → 失败则自动修正(最多3次) → 重试耗尽后失败上下文自动注入下一轮 → 返回可编译的 JRXML 文件。
|
||||
|
||||
## 启动命令
|
||||
|
||||
@@ -47,7 +34,7 @@ cd frontend && npm run dev
|
||||
- **向量库**: ChromaDB 持久化在 `./db/chroma`
|
||||
- **验证服务**: FastAPI `localhost:8001`
|
||||
- **日志**: JSON 格式化,`logs/app.log` + `logs/llm.log`,中国时区 (UTC+8)
|
||||
- **MAX_RETRY**: 5
|
||||
- **MAX_RETRY**: 3
|
||||
|
||||
## 架构
|
||||
|
||||
@@ -246,7 +233,7 @@ validation_service/ (FastAPI, 端口 8001) — 不变
|
||||
- **OCR 引擎**: 优先 PaddleOCR 2.9.x(精确识别,`pip install paddleocr`),回退 EasyOCR 1.7+。两者均未安装时仅返回图片元信息。PaddlePaddle 3.x 在 Windows 上有 ONEDNN bug,固定在 2.6.x。
|
||||
- **OCR 字段提取**: `process_input` 自动检测上传图片,调用 `OcrExtractor` 提取常见中文字段(发票代码/号码/金额/日期等),提取结果自动注入 LLM 上下文。
|
||||
- **会话持久化**: `session_id` 现已包含在 `save_session_node` 的持久化字段中,避免切换会话时因 `session_id` 丢失导致的无限 rerun bug。`create_session` 存盘前强制写入 `agent_state["session_id"] = sid`。`load_session_node` 不从磁盘覆盖 `session_id`。切换会话增加 `_last_switched_to` 哨兵防止重复触发。
|
||||
- **MAX_RETRY**: 默认 5 次。重试耗尽后 `pending_failure_context` 记录失败信息,下次用户输入时自动注入。
|
||||
- **MAX_RETRY**: 默认 3 次。重试耗尽后 `pending_failure_context` 记录失败信息,下次用户输入时自动注入。
|
||||
- **验证最小内容检查**: 验证服务额外检查至少 1 个 `<band>` + 1 个 `<textField>` 或 `<staticText>`,拦截空壳 JRXML。
|
||||
- **XLSX 支持 (v3)**: 需要 `openpyxl>=3.1.0`(已加入 requirements.txt)。表格按工作表逐行读取,单元格用 `|` 分隔。
|
||||
- **粘贴功能限制**: 文件以 base64 编码在 sessionStorage 中传递,单文件上限 20MB。大文件建议使用 file_uploader 按钮。
|
||||
|
||||
@@ -18,18 +18,20 @@
|
||||
## 架构
|
||||
|
||||
```
|
||||
Streamlit 界面 (app.py)
|
||||
|
|
||||
LangGraph 代理 (agent/)
|
||||
|-- retrieve (Chroma/embeddings)
|
||||
|-- generate / generate_skeleton → refine_layout → map_fields (分层生成)
|
||||
|-- validate (FastAPI service)
|
||||
|-- explain + correct (auto-fix loop)
|
||||
|-- modify (multi-turn edits)
|
||||
|
|
||||
前端 (Vue 3 + Vite, 端口 5173)
|
||||
│ 聊天界面 + SSE 流式显示 + 文件上传/粘贴/拖拽
|
||||
▼ HTTP + SSE
|
||||
后端 API (FastAPI, 端口 8000)
|
||||
│ REST 接口 + SSE 流式推送
|
||||
│ 包装 LangGraph Agent ──► agent/
|
||||
│ ├─ retrieve (Chroma/embeddings)
|
||||
│ ├─ generate / generate_skeleton → refine_layout → map_fields (分层生成)
|
||||
│ ├─ validate (FastAPI service)
|
||||
│ ├─ explain + correct (auto-fix loop)
|
||||
│ └─ modify (multi-turn edits)
|
||||
▼
|
||||
FastAPI 验证服务 (:8001)
|
||||
|-- Structural checks (field references, SQL, page dimensions)
|
||||
|-- XSD schema validation (if jasperreport.xsd available)
|
||||
└─ Structural checks + XSD schema validation
|
||||
```
|
||||
|
||||
## 前置要求
|
||||
@@ -60,21 +62,24 @@ cp .env.example .env
|
||||
python scripts/init_kb.py
|
||||
```
|
||||
|
||||
### 4. 启动验证服务
|
||||
### 4. 启动服务
|
||||
|
||||
**一键启动(推荐)**:双击 `start.bat`,自动启动验证服务、后端 API、前端开发服务器。停止用 `stop.bat`。
|
||||
|
||||
**手动启动**(需要三个终端):
|
||||
|
||||
在一个终端中运行:
|
||||
```bash
|
||||
python -m uvicorn validation_service.main:app --port 8001
|
||||
# 终端 1 — 验证服务(必须先启动)
|
||||
python -m uvicorn validation_service.main:app --port 8001 --host 0.0.0.0
|
||||
|
||||
# 终端 2 — 后端 API(SSE + REST)
|
||||
python -m uvicorn api_server:app --port 8000 --host 0.0.0.0
|
||||
|
||||
# 终端 3 — 前端开发服务器
|
||||
cd frontend && npm install && npm run dev
|
||||
```
|
||||
|
||||
### 5. 启动 Streamlit 界面
|
||||
|
||||
在另一个终端中运行:
|
||||
```bash
|
||||
streamlit run app.py
|
||||
```
|
||||
|
||||
在浏览器中打开 http://localhost:8501。
|
||||
在浏览器中打开 http://localhost:5173。
|
||||
|
||||
## 使用示例
|
||||
|
||||
@@ -110,7 +115,14 @@ pytest tests/ -v
|
||||
|
||||
```
|
||||
jrxml-agent/
|
||||
app.py Streamlit 聊天界面(多模态输入)
|
||||
api_server.py FastAPI SSE 后端(REST + 流式推送)
|
||||
start.bat 一键启动脚本
|
||||
stop.bat 一键停止脚本
|
||||
frontend/ Vue 3 + Vite 前端(聊天 UI)
|
||||
src/
|
||||
api/client.ts SSE 客户端 + fetch 封装
|
||||
stores/ Pinia 状态管理(chat + session)
|
||||
components/ 聊天界面组件(6 个)
|
||||
agent/
|
||||
state.py AgentState 定义(28 字段)
|
||||
nodes.py 图节点(generate, generate_skeleton, refine_layout 等,18 节点)
|
||||
|
||||
+2
-2
@@ -82,11 +82,11 @@
|
||||
- [x] `backend/llm.py` — `_LLMLoggingWrapper` 包装所有 LLM 后端
|
||||
- [x] 记录每次 invoke/stream 的请求 prompt、响应内容、耗时、模型、调用来源
|
||||
- [x] 异常时也记录完整 prompt
|
||||
- [x] `agent/nodes.py` — `@log_node` 装饰器覆盖 17 个节点
|
||||
- [x] `agent/nodes.py` — `@log_node` 装饰器覆盖 18 个节点
|
||||
- [x] 入口/出口/异常三个阶段的日志
|
||||
- [x] 自动记录 state 关键字段摘要(session_id、intent、status、jrxml_length 等)
|
||||
- [x] 每个节点耗时(duration_ms)
|
||||
- [x] `agent/graph.py` — `@_log_route` 装饰器覆盖 8 个路由函数
|
||||
- [x] `agent/graph.py` — `@_log_route` 装饰器覆盖 9 个路由函数
|
||||
- [x] 记录每次路由决策(来源 → 目标)
|
||||
- [x] `app.py` — 用户交互日志
|
||||
- [x] 收到用户输入(含上传文件信息)
|
||||
|
||||
Generated
+23
-5
@@ -66,6 +66,29 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/core": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz",
|
||||
"integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/wasi-threads": "1.2.1",
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/runtime": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz",
|
||||
"integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/wasi-threads": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz",
|
||||
@@ -393,7 +416,6 @@
|
||||
"integrity": "sha512-GUUEShf+PBCGW2KaXwcIt3Yk+e3pkKwWKb9GSyM9WQVE+ep2jzmHdGsHzu4wgcZy5fN9FBdVzjpBQsYlpfpgLA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~7.16.0"
|
||||
}
|
||||
@@ -1054,7 +1076,6 @@
|
||||
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
@@ -1212,7 +1233,6 @@
|
||||
"integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==",
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"peer": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
@@ -1234,7 +1254,6 @@
|
||||
"integrity": "sha512-s4BJJ+5y1pYL6Otw51FHhVJQhPnuRinKig64g/1+EUNaJsd3gCKdD31IPFvswUgW9/60QT9oFHbZHbQK5imcxw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"lightningcss": "^1.32.0",
|
||||
"picomatch": "^4.0.4",
|
||||
@@ -1319,7 +1338,6 @@
|
||||
"resolved": "https://registry.npmjs.org/vue/-/vue-3.5.34.tgz",
|
||||
"integrity": "sha512-WdLBG9gm02OgJIG9axd5Hpx0TFLdzVgfG2evFFu8Rur5O/IoGc5cMjnjh3tPL6GnRGsYvUhBSKVPYVcxRKpMCA==",
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@vue/compiler-dom": "3.5.34",
|
||||
"@vue/compiler-sfc": "3.5.34",
|
||||
|
||||
@@ -1,31 +1,53 @@
|
||||
@echo off
|
||||
echo ============================================
|
||||
echo JRXML 代理 - 全自动启动 (验证 + API + UI)
|
||||
echo ============================================
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
echo ============================================
|
||||
echo JRXML Agent - One-Click Start
|
||||
echo ============================================
|
||||
echo.
|
||||
echo [1/3] 启动验证服务 (端口 8001)...
|
||||
start "JRXML 验证服务" cmd /c "cd /d %~dp0 && .venv\Scripts\python -m uvicorn validation_service.main:app --port 8001 --host 0.0.0.0"
|
||||
|
||||
REM ========== Kill processes on ports ==========
|
||||
echo [Pre-check] Cleaning up occupied ports...
|
||||
for /f "tokens=5" %%a in ('netstat -ano ^| findstr ":8001.*LISTENING" 2^>nul') do (
|
||||
echo Killing PID %%a on port 8001...
|
||||
taskkill /PID %%a /F 2>nul
|
||||
)
|
||||
for /f "tokens=5" %%a in ('netstat -ano ^| findstr ":8000.*LISTENING" 2^>nul') do (
|
||||
echo Killing PID %%a on port 8000...
|
||||
taskkill /PID %%a /F 2>nul
|
||||
)
|
||||
for /f "tokens=5" %%a in ('netstat -ano ^| findstr ":5173.*LISTENING" 2^>nul') do (
|
||||
echo Killing PID %%a on port 5173...
|
||||
taskkill /PID %%a /F 2>nul
|
||||
)
|
||||
echo.
|
||||
|
||||
REM ========== Detect Python ==========
|
||||
set PYTHON=python
|
||||
if exist "%~dp0.venv\Scripts\python.exe" set "PYTHON=%~dp0.venv\Scripts\python.exe"
|
||||
echo Using Python: %PYTHON%
|
||||
echo.
|
||||
|
||||
REM ========== Start services ==========
|
||||
echo [1/3] Starting validation service on port 8001...
|
||||
start "JRXML-Validator" cmd /k "cd /d "%~dp0" && %PYTHON% -m uvicorn validation_service.main:app --port 8001 --host 0.0.0.0"
|
||||
timeout /t 3 /nobreak >nul
|
||||
|
||||
echo [2/3] 启动后端 API (端口 8000)...
|
||||
start "JRXML API" cmd /c "cd /d %~dp0 && .venv\Scripts\python -m uvicorn api_server:app --port 8000 --host 0.0.0.0"
|
||||
|
||||
echo [2/3] Starting backend API on port 8000...
|
||||
start "JRXML-API" cmd /k "cd /d "%~dp0" && %PYTHON% -m uvicorn api_server:app --port 8000 --host 0.0.0.0"
|
||||
timeout /t 3 /nobreak >nul
|
||||
|
||||
echo [3/3] 启动前端开发服务器 (端口 5173)...
|
||||
start "JRXML Frontend" cmd /c "cd /d %~dp0\frontend && npm run dev"
|
||||
|
||||
echo [3/3] Starting frontend dev server on port 5173...
|
||||
start "JRXML-Frontend" cmd /k "cd /d "%~dp0frontend" && npm run dev"
|
||||
timeout /t 3 /nobreak >nul
|
||||
|
||||
echo.
|
||||
echo ============================================
|
||||
echo 启动完成
|
||||
echo 验证服务: http://localhost:8001
|
||||
echo 后端 API: http://localhost:8000
|
||||
echo 前端界面: http://localhost:5173
|
||||
echo All services started!
|
||||
echo Frontend : http://localhost:5173
|
||||
echo Backend : http://localhost:8000
|
||||
echo Validator : http://localhost:8001
|
||||
echo ============================================
|
||||
echo.
|
||||
echo 关闭此窗口不会停止服务。关闭服务窗口或运行 stop.bat 停止。
|
||||
echo Close the service windows or run stop.bat to stop.
|
||||
pause
|
||||
|
||||
Reference in New Issue
Block a user