From 6701212d1505aa31e86651b0c775fcc6796bc934 Mon Sep 17 00:00:00 2001 From: shayswrld <145751122+shayswrld@users.noreply.github.com> Date: Wed, 22 Jul 2026 21:40:39 +0200 Subject: [PATCH] feat: remove Zep Cloud, add local SQLite graph store, English-first defaults & Ollama support - Remove Zep Cloud dependency entirely (zep_entity_reader, zep_graph_memory_updater, zep_tools, zep_paging) - Add local SQLite-based graph store with LLM-powered entity extraction - Add local embeddings utility and graph tools service - Translate all backend docstrings, LLM prompts, and UI to English - Set English as default language, remove Chinese locale (zh.json) - Add Ollama setup guide and configure .env.example for Ollama - Add AGENTS.md for AI agent context - Fix pyright type errors in models/services - Add Nedbank Africa expansion preset - Clean up Docker configuration and README --- .env.example | 43 +- .gitignore | 2 +- AGENTS.md | 176 + Dockerfile | 12 +- README-ZH.md | 203 -- README.md | 59 +- backend/app/__init__.py | 95 +- backend/app/api/__init__.py | 9 +- backend/app/api/graph.py | 1061 ++---- backend/app/api/report.py | 1311 +++---- backend/app/api/simulation.py | 3246 ++++++++--------- backend/app/config.py | 129 +- backend/app/models/__init__.py | 5 +- backend/app/models/project.py | 298 +- backend/app/models/task.py | 135 +- backend/app/services/__init__.py | 77 +- backend/app/services/entity_reader.py | 292 ++ backend/app/services/graph_builder.py | 912 +---- backend/app/services/graph_tools.py | 1745 +++++++++ backend/app/services/local_graph_extractor.py | 146 + backend/app/services/local_graph_store.py | 426 +++ .../app/services/oasis_profile_generator.py | 1335 +++---- backend/app/services/ontology_generator.py | 882 ++--- backend/app/services/report_agent.py | 2660 +++++++------- .../services/simulation_config_generator.py | 983 ++--- backend/app/services/simulation_ipc.py | 350 +- backend/app/services/simulation_manager.py | 479 ++- backend/app/services/simulation_runner.py | 1958 +++++----- backend/app/services/text_processor.py | 75 +- backend/app/services/zep_entity_reader.py | 446 --- .../app/services/zep_graph_memory_updater.py | 791 ---- backend/app/services/zep_tools.py | 1734 --------- backend/app/utils/__init__.py | 12 +- backend/app/utils/embeddings.py | 55 + backend/app/utils/file_parser.py | 188 +- backend/app/utils/llm_client.py | 79 +- backend/app/utils/locale.py | 28 +- backend/app/utils/logger.py | 118 +- backend/app/utils/retry.py | 182 +- backend/app/utils/zep_paging.py | 160 - backend/presets/nedbank_africa_expansion.md | 127 + backend/pyproject.toml | 24 +- backend/requirements.txt | 26 +- backend/run.py | 49 +- backend/scripts/action_logger.py | 231 +- backend/scripts/run_parallel_simulation.py | 1615 ++++---- backend/scripts/run_reddit_simulation.py | 658 ++-- backend/scripts/run_twitter_simulation.py | 697 ++-- backend/scripts/test_profile_format.py | 138 +- backend/uv.lock | 754 +++- docker-compose.yml | 2 +- frontend/index.html | 10 +- frontend/src/App.vue | 43 +- frontend/src/api/graph.js | 20 +- frontend/src/api/index.js | 28 +- frontend/src/api/report.js | 16 +- frontend/src/api/simulation.js | 93 +- frontend/src/components/GraphPanel.vue | 168 +- frontend/src/components/HistoryDatabase.vue | 248 +- frontend/src/components/Step1GraphBuild.vue | 10 +- frontend/src/components/Step2EnvSetup.vue | 152 +- frontend/src/components/Step3Simulation.vue | 111 +- frontend/src/components/Step4Report.vue | 352 +- frontend/src/components/Step5Interaction.vue | 68 +- frontend/src/i18n/index.js | 4 +- frontend/src/store/pendingUpload.js | 4 +- frontend/src/views/Home.vue | 1473 ++++---- frontend/src/views/InteractionView.vue | 12 +- frontend/src/views/MainView.vue | 8 +- frontend/src/views/Process.vue | 387 +- frontend/src/views/ReportView.vue | 12 +- frontend/src/views/SimulationRunView.vue | 36 +- frontend/src/views/SimulationView.vue | 44 +- locales/en.json | 153 +- locales/languages.json | 4 - locales/zh.json | 667 ---- package.json | 2 +- .../{运行截图1.png => screenshot1.png} | Bin .../{运行截图2.png => screenshot2.png} | Bin .../{运行截图3.png => screenshot3.png} | Bin .../{运行截图4.png => screenshot4.png} | Bin .../{运行截图5.png => screenshot5.png} | Bin .../{运行截图6.png => screenshot6.png} | Bin static/image/{QQ群.png => qq_group.png} | Bin ...拟推演封面.jpg => red_mansion_demo_cover.jpg} | Bin ...大模拟演示封面.png => wuda_demo_cover.png} | Bin 86 files changed, 14907 insertions(+), 16436 deletions(-) create mode 100644 AGENTS.md delete mode 100644 README-ZH.md create mode 100644 backend/app/services/entity_reader.py create mode 100644 backend/app/services/graph_tools.py create mode 100644 backend/app/services/local_graph_extractor.py create mode 100644 backend/app/services/local_graph_store.py delete mode 100644 backend/app/services/zep_entity_reader.py delete mode 100644 backend/app/services/zep_graph_memory_updater.py delete mode 100644 backend/app/services/zep_tools.py create mode 100644 backend/app/utils/embeddings.py delete mode 100644 backend/app/utils/zep_paging.py create mode 100644 backend/presets/nedbank_africa_expansion.md delete mode 100644 locales/zh.json rename static/image/Screenshot/{运行截图1.png => screenshot1.png} (100%) rename static/image/Screenshot/{运行截图2.png => screenshot2.png} (100%) rename static/image/Screenshot/{运行截图3.png => screenshot3.png} (100%) rename static/image/Screenshot/{运行截图4.png => screenshot4.png} (100%) rename static/image/Screenshot/{运行截图5.png => screenshot5.png} (100%) rename static/image/Screenshot/{运行截图6.png => screenshot6.png} (100%) rename static/image/{QQ群.png => qq_group.png} (100%) rename static/image/{红楼梦模拟推演封面.jpg => red_mansion_demo_cover.jpg} (100%) rename static/image/{武大模拟演示封面.png => wuda_demo_cover.png} (100%) diff --git a/.env.example b/.env.example index 542e0859..6df178d9 100644 --- a/.env.example +++ b/.env.example @@ -1,16 +1,31 @@ -# LLM API配置(支持 OpenAI SDK 格式的任意 LLM API) -# 推荐使用阿里百炼平台qwen-plus模型:https://bailian.console.aliyun.com/ -# 注意消耗较大,可先进行小于40轮的模拟尝试 -LLM_API_KEY=your_api_key_here -LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1 -LLM_MODEL_NAME=qwen-plus +# ===== LLM Configuration ===== +# Supports any OpenAI-compatible API. Three options: -# ===== ZEP记忆图谱配置 ===== -# 每月免费额度即可支撑简单使用:https://app.getzep.com/ -ZEP_API_KEY=your_zep_api_key_here +# --- Option A: Ollama Cloud (recommended) --- +# 1. Create an API key: https://ollama.com/settings/keys +# 2. Pick a cloud model from: https://ollama.com/search?c=cloud +LLM_API_KEY=your_ollama_api_key_here +LLM_BASE_URL=https://ollama.com/v1 +LLM_MODEL_NAME=qwen3.5:397b -# ===== 加速 LLM 配置(可选)===== -# 注意如果不使用加速配置,env文件中就不要出现下面的配置项 -LLM_BOOST_API_KEY=your_api_key_here -LLM_BOOST_BASE_URL=your_base_url_here -LLM_BOOST_MODEL_NAME=your_model_name_here +# --- Option B: Local Ollama --- +# 1. Install Ollama: https://ollama.com +# 2. Pull a model: ollama pull qwen2.5:7b +# LLM_API_KEY=ollama +# LLM_BASE_URL=http://localhost:11434/v1 +# LLM_MODEL_NAME=qwen2.5:7b + +# --- Option C: Other cloud providers (OpenAI, DeepSeek, Alibaba Bailian, etc.) --- +# LLM_API_KEY=your_cloud_api_key +# LLM_BASE_URL=https://dashscope.aliyuncs.com/compatible-mode/v1 +# LLM_MODEL_NAME=qwen-plus + +# ===== Optional: Boost LLM (faster/cheaper model for high-volume agent calls) ===== +# If you don't use this, DELETE these lines entirely — leaving placeholders breaks things. +# LLM_BOOST_API_KEY= +# LLM_BOOST_BASE_URL= +# LLM_BOOST_MODEL_NAME= + +# ===== Optional: Flask / Simulation config ===== +# FLASK_DEBUG=True +# OASIS_DEFAULT_MAX_ROUNDS=10 \ No newline at end of file diff --git a/.gitignore b/.gitignore index 55d3ef19..3af0a92a 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,7 @@ .DS_Store Thumbs.db -# 环境变量(保护敏感信息) +# Environment variables (protect sensitive info) .env .env.local .env.*.local diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..cbb4dae6 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,176 @@ +# AGENTS.md + +Guide for coding agents operating in this repository. MiroFish is a multi-agent +AI prediction engine: Flask backend (`backend/`) + Vue 3 frontend (`frontend/`) ++ shared i18n (`locales/`). Monorepo orchestrated by root `package.json` via +`concurrently`. Code comments/docstrings are **English**; identifiers +are English. License: AGPL-3.0. + +## Build / Run / Test Commands + +All commands run from repo root unless noted. Node >=18, Python >=3.11 <=3.12, +`uv` for Python packages. + +```bash +# Install everything (root + frontend npm + backend uv venv) +npm run setup:all + +# Dev (both services, concurrent, --kill-others) +npm run dev +npm run backend # cd backend && uv run python run.py (Flask :5001) +npm run frontend # cd frontend && npm run dev (Vite :3000) + +# Production build (frontend only) +npm run build + +# Backend deps only +npm run setup:backend # cd backend && uv sync + +# Docker +docker compose up -d # reads root .env, ports 3000+5001, mounts backend/uploads +``` + +### Tests + +**There are no automated tests.** `pytest` + `pytest-asyncio` are declared in +`backend/pyproject.toml` but unused — no `tests/` dir, no `conftest.py`, no +`[tool.pytest.ini_options]`. Frontend has no vitest/jest. + +If you add tests, run them with: +```bash +cd backend && uv run pytest # all +cd backend && uv run pytest path/to/test_file.py # single file +cd backend && uv run pytest path/to/test_file.py::test_name # single test +``` +`backend/scripts/test_profile_format.py` is a **manual print-based script**, not +a pytest test — run it with `uv run python scripts/test_profile_format.py`. + +### Lint / Format + +**None configured.** No ruff/black/flake8/mypy/isort on the backend; no +eslint/prettier on the frontend. No CI lint workflow (only Docker image build). +Match the existing de-facto style described below; do not add a linter unless +asked. + +## Backend Conventions (Python / Flask) + +**Package layout:** `backend/app/` with `api/` (blueprints), `models/` +(dataclasses), `services/` (business logic), `utils/` (logger, retry, llm_client, +locale). Entry point `backend/run.py`. Each `__init__.py` is a manifest: docstring ++ relative imports + `__all__`. + +**Imports:** Relative for intra-package (`from .config import Config`, +`from ..services.x import Y`). Absolute `from app...` only in `run.py` and +`scripts/` (which shim `sys.path`). Group: stdlib → third-party → local, blank-line +separated. Late imports inside functions are acceptable for optional/heavy deps. + +**Naming:** `snake_case` modules/functions, `PascalCase` classes, `UPPER_SNAKE` +constants, `_`-prefixed private helpers. Blueprints: `snake_case_bp` +(`graph_bp`, `simulation_bp`, `report_bp`). String IDs prefixed +(`proj_`, `sim_`, `mirofish_`). + +**Models:** `@dataclass` + `(str, Enum)` for status enums. Hand-written +`to_dict()` / `from_dict()` on every model. **No app-defined Pydantic models** — +pydantic is only used in generated ontology code templates and the OASIS SDK. + +**Type hints:** Annotate function signatures (`typing.Dict/Any/List/Optional/ +Callable/Tuple`). Locals usually unannotated. Be consistent with neighbors. + +**Errors:** No custom exception classes; raise `ValueError` for bad state. Every +Flask route wraps in `try/except Exception as e:` returning the uniform envelope: +```python +except Exception as e: + return jsonify({"success": False, "error": str(e), + "traceback": traceback.format_exc()}), 500 +``` +Success: `{"success": True, "data": {...}}` (often + `"count"`, `"message"`). +`ValueError` → 400/404. Background threads catch exceptions and flip the +`TaskManager`/`Project` status to `FAILED`. + +**Logging:** `from ..utils.logger import get_logger` then +`logger = get_logger('mirofish.')` at module top (areas: `api`, +`api.simulation`, `build`, `request`, `retry`, `simulation`, etc.). +f-string messages. Do **not** use `logging.getLogger(__name__)` — +`ontology_generator.py` does this and is the one known inconsistency. Rotating +file handler writes to `backend/logs/.log`. + +**Async:** Flask is sync (`threaded=True`). Long work goes to +`threading.Thread(target=..., daemon=True)`. **Background threads must re-call +`set_locale()`** — locale is thread-local; capture `get_locale()` before spawning +and restore it inside the thread. Retry helpers in `utils/retry.py`: +`retry_with_backoff` (sync), `retry_with_backoff_async` (async), +`RetryableAPIClient`. + +**Config:** `app/config.py` `Config` class loads root `.env` via +`dotenv.load_dotenv('../../.env')` (relative to `config.py`). Required: +`LLM_API_KEY`. Optional: `LLM_BASE_URL`, `LLM_MODEL_NAME`, +`LLM_BOOST_*`, `FLASK_HOST/PORT/DEBUG`, `OASIS_DEFAULT_MAX_ROUNDS`, +`REPORT_AGENT_*`, `SECRET_KEY`. `Config.validate()` is called in `run.py` before +serving. Frontend env: `VITE_API_BASE_URL` (default `http://localhost:5001`). + +**Docstrings:** Module docstring (English, one line) at top of every `.py`. +Functions/classes: English summary, Google-style `Args:`/`Returns:`. Flask routes +embed request/response JSON shapes as literal blocks — treat these as the API docs. + +**Windows:** `run.py` applies a UTF-8 stdout fix before other imports. Keep that +block first. + +## Frontend Conventions (Vue 3 + Vite, plain JS) + +**SFCs:** ` + - + - - MiroFish - 预测万物 + + MiroFish - Predict Everything
diff --git a/frontend/src/App.vue b/frontend/src/App.vue index b7cd71ca..73b62500 100644 --- a/frontend/src/App.vue +++ b/frontend/src/App.vue @@ -3,11 +3,11 @@ + +/* Global focus visible styles */ +*:focus-visible { + outline: 2px solid #C4751A; + outline-offset: 2px; +} + +/* Respect reduced-motion */ +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + transition-duration: 0.01ms !important; + } +} + \ No newline at end of file diff --git a/frontend/src/api/graph.js b/frontend/src/api/graph.js index 85669559..bf2018f8 100644 --- a/frontend/src/api/graph.js +++ b/frontend/src/api/graph.js @@ -1,8 +1,8 @@ import service from './index' /** - * 生成本体(上传文档和模拟需求) - * @param {Object} data - 包含files, simulation_requirement, project_name等 + * Generate ontology (upload documents and simulation requirement) + * @param {Object} data - Contains files, simulation_requirement, project_name, etc. * @returns {Promise} */ export function generateOntology(formData) { @@ -17,8 +17,8 @@ export function generateOntology(formData) { } /** - * 构建图谱 - * @param {Object} data - 包含project_id, graph_name等 + * Build graph + * @param {Object} data - Contains project_id, graph_name, etc. * @returns {Promise} */ export function buildGraph(data) { @@ -30,8 +30,8 @@ export function buildGraph(data) { } /** - * 查询任务状态 - * @param {String} taskId - 任务ID + * Query task status + * @param {String} taskId - Task ID * @returns {Promise} */ export function getTaskStatus(taskId) { @@ -42,8 +42,8 @@ export function getTaskStatus(taskId) { } /** - * 获取图谱数据 - * @param {String} graphId - 图谱ID + * Get graph data + * @param {String} graphId - Graph ID * @returns {Promise} */ export function getGraphData(graphId) { @@ -54,8 +54,8 @@ export function getGraphData(graphId) { } /** - * 获取项目信息 - * @param {String} projectId - 项目ID + * Get project info + * @param {String} projectId - Project ID * @returns {Promise} */ export function getProject(projectId) { diff --git a/frontend/src/api/index.js b/frontend/src/api/index.js index 807a0b4e..a70f4d51 100644 --- a/frontend/src/api/index.js +++ b/frontend/src/api/index.js @@ -1,16 +1,16 @@ import axios from 'axios' import i18n from '../i18n' -// 创建axios实例 +// Create axios instance const service = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL || 'http://localhost:5001', - timeout: 300000, // 5分钟超时(本体生成可能需要较长时间) + timeout: 300000, // 5 minute timeout (ontology generation may take longer) headers: { 'Content-Type': 'application/json' } }) -// 请求拦截器 +// Request interceptor service.interceptors.request.use( config => { config.headers['Accept-Language'] = i18n.global.locale.value @@ -22,12 +22,12 @@ service.interceptors.request.use( } ) -// 响应拦截器(容错重试机制) +// Response interceptor (fault-tolerant retry mechanism) service.interceptors.response.use( response => { const res = response.data - // 如果返回的状态码不是success,则抛出错误 + // If returned status code is not success, throw error if (!res.success && res.success !== undefined) { console.error('API Error:', res.error || res.message || 'Unknown error') return Promise.reject(new Error(res.error || res.message || 'Error')) @@ -38,12 +38,12 @@ service.interceptors.response.use( error => { console.error('Response error:', error) - // 处理超时 + // Handle timeout if (error.code === 'ECONNABORTED' && error.message.includes('timeout')) { console.error('Request timeout') } - // 处理网络错误 + // Handle network error if (error.message === 'Network Error') { console.error('Network error - please check your connection') } @@ -52,4 +52,18 @@ service.interceptors.response.use( } ) +// Request function with retry +export const requestWithRetry = async (requestFn, maxRetries = 3, delay = 1000) => { + for (let i = 0; i < maxRetries; i++) { + try { + return await requestFn() + } catch (error) { + if (i === maxRetries - 1) throw error + + console.warn(`Request failed, retrying (${i + 1}/${maxRetries})...`) + await new Promise(resolve => setTimeout(resolve, delay * Math.pow(2, i))) + } + } +} + export default service diff --git a/frontend/src/api/report.js b/frontend/src/api/report.js index 9b61ce72..f0a97aea 100644 --- a/frontend/src/api/report.js +++ b/frontend/src/api/report.js @@ -1,7 +1,7 @@ import service from './index' /** - * 开始报告生成 + * Start report generation * @param {Object} data - { simulation_id, force_regenerate? } */ export const generateReport = (data) => { @@ -9,7 +9,7 @@ export const generateReport = (data) => { } /** - * 获取报告生成状态 + * Get report generation status * @param {string} reportId */ export const getReportStatus = (reportId) => { @@ -17,25 +17,25 @@ export const getReportStatus = (reportId) => { } /** - * 获取 Agent 日志(增量) + * Get Agent log (incremental) * @param {string} reportId - * @param {number} fromLine - 从第几行开始获取 + * @param {number} fromLine - Starting line number */ export const getAgentLog = (reportId, fromLine = 0) => { return service.get(`/api/report/${reportId}/agent-log`, { params: { from_line: fromLine } }) } /** - * 获取控制台日志(增量) + * Get console log (incremental) * @param {string} reportId - * @param {number} fromLine - 从第几行开始获取 + * @param {number} fromLine - Starting line number */ export const getConsoleLog = (reportId, fromLine = 0) => { return service.get(`/api/report/${reportId}/console-log`, { params: { from_line: fromLine } }) } /** - * 获取报告详情 + * Get report details * @param {string} reportId */ export const getReport = (reportId) => { @@ -43,7 +43,7 @@ export const getReport = (reportId) => { } /** - * 与 Report Agent 对话 + * Chat with Report Agent * @param {Object} data - { simulation_id, message, chat_history? } */ export const chatWithReport = (data) => { diff --git a/frontend/src/api/simulation.js b/frontend/src/api/simulation.js index d495afae..3b54b6fd 100644 --- a/frontend/src/api/simulation.js +++ b/frontend/src/api/simulation.js @@ -1,23 +1,23 @@ -import service from './index' +import service, { requestWithRetry } from './index' /** - * 创建模拟 + * Create simulation * @param {Object} data - { project_id, graph_id?, enable_twitter?, enable_reddit? } */ export const createSimulation = (data) => { - return service.post('/api/simulation/create', data) + return requestWithRetry(() => service.post('/api/simulation/create', data), 3, 1000) } /** - * 准备模拟环境(异步任务) + * Prepare simulation environment (async task) * @param {Object} data - { simulation_id, entity_types?, use_llm_for_profiles?, parallel_profile_count?, force_regenerate? } */ export const prepareSimulation = (data) => { - return service.post('/api/simulation/prepare', data) + return requestWithRetry(() => service.post('/api/simulation/prepare', data), 3, 1000) } /** - * 查询准备任务进度 + * Query preparation task progress * @param {Object} data - { task_id?, simulation_id? } */ export const getPrepareStatus = (data) => { @@ -25,7 +25,7 @@ export const getPrepareStatus = (data) => { } /** - * 获取模拟状态 + * Get simulation status * @param {string} simulationId */ export const getSimulation = (simulationId) => { @@ -33,27 +33,25 @@ export const getSimulation = (simulationId) => { } /** - * 获取模拟的 Agent Profiles + * Get simulation Agent Profiles * @param {string} simulationId - * @param {string} [platform] - 'reddit' | 'twitter'(省略时由后端根据模拟配置自动选择) + * @param {string} platform - 'reddit' | 'twitter' */ -export const getSimulationProfiles = (simulationId, platform) => { - const params = platform ? { platform } : {} - return service.get(`/api/simulation/${simulationId}/profiles`, { params }) +export const getSimulationProfiles = (simulationId, platform = 'reddit') => { + return service.get(`/api/simulation/${simulationId}/profiles`, { params: { platform } }) } /** - * 实时获取生成中的 Agent Profiles + * Get in-progress Agent Profiles in real-time * @param {string} simulationId - * @param {string} [platform] - 'reddit' | 'twitter'(省略时由后端根据模拟配置自动选择) + * @param {string} platform - 'reddit' | 'twitter' */ -export const getSimulationProfilesRealtime = (simulationId, platform) => { - const params = platform ? { platform } : {} - return service.get(`/api/simulation/${simulationId}/profiles/realtime`, { params }) +export const getSimulationProfilesRealtime = (simulationId, platform = 'reddit') => { + return service.get(`/api/simulation/${simulationId}/profiles/realtime`, { params: { platform } }) } /** - * 获取模拟配置 + * Get simulation config * @param {string} simulationId */ export const getSimulationConfig = (simulationId) => { @@ -61,17 +59,17 @@ export const getSimulationConfig = (simulationId) => { } /** - * 实时获取生成中的模拟配置 + * Get in-progress simulation config in real-time * @param {string} simulationId - * @returns {Promise} 返回配置信息,包含元数据和配置内容 + * @returns {Promise} Returns config info including metadata and config content */ export const getSimulationConfigRealtime = (simulationId) => { return service.get(`/api/simulation/${simulationId}/config/realtime`) } /** - * 列出所有模拟 - * @param {string} projectId - 可选,按项目ID过滤 + * List all simulations + * @param {string} projectId - Optional, filter by project ID */ export const listSimulations = (projectId) => { const params = projectId ? { project_id: projectId } : {} @@ -79,15 +77,15 @@ export const listSimulations = (projectId) => { } /** - * 启动模拟 + * Start simulation * @param {Object} data - { simulation_id, platform?, max_rounds?, enable_graph_memory_update? } */ export const startSimulation = (data) => { - return service.post('/api/simulation/start', data) + return requestWithRetry(() => service.post('/api/simulation/start', data), 3, 1000) } /** - * 停止模拟 + * Stop simulation * @param {Object} data - { simulation_id } */ export const stopSimulation = (data) => { @@ -95,7 +93,7 @@ export const stopSimulation = (data) => { } /** - * 获取模拟运行实时状态 + * Get simulation run real-time status * @param {string} simulationId */ export const getRunStatus = (simulationId) => { @@ -103,7 +101,7 @@ export const getRunStatus = (simulationId) => { } /** - * 获取模拟运行详细状态(包含最近动作) + * Get simulation run detailed status (including recent actions) * @param {string} simulationId */ export const getRunStatusDetail = (simulationId) => { @@ -111,23 +109,23 @@ export const getRunStatusDetail = (simulationId) => { } /** - * 获取模拟中的帖子 + * Get posts in simulation * @param {string} simulationId - * @param {string} [platform] - 'reddit' | 'twitter'(省略时由后端根据模拟配置自动选择) - * @param {number} limit - 返回数量 - * @param {number} offset - 偏移量 + * @param {string} platform - 'reddit' | 'twitter' + * @param {number} limit - Return count + * @param {number} offset - Offset */ -export const getSimulationPosts = (simulationId, platform, limit = 50, offset = 0) => { - const params = { limit, offset } - if (platform) params.platform = platform - return service.get(`/api/simulation/${simulationId}/posts`, { params }) +export const getSimulationPosts = (simulationId, platform = 'reddit', limit = 50, offset = 0) => { + return service.get(`/api/simulation/${simulationId}/posts`, { + params: { platform, limit, offset } + }) } /** - * 获取模拟时间线(按轮次汇总) + * Get simulation timeline (grouped by round) * @param {string} simulationId - * @param {number} startRound - 起始轮次 - * @param {number} endRound - 结束轮次 + * @param {number} startRound - Start round + * @param {number} endRound - End round */ export const getSimulationTimeline = (simulationId, startRound = 0, endRound = null) => { const params = { start_round: startRound } @@ -138,7 +136,7 @@ export const getSimulationTimeline = (simulationId, startRound = 0, endRound = n } /** - * 获取Agent统计信息 + * Get Agent statistics * @param {string} simulationId */ export const getAgentStats = (simulationId) => { @@ -146,7 +144,7 @@ export const getAgentStats = (simulationId) => { } /** - * 获取模拟动作历史 + * Get simulation action history * @param {string} simulationId * @param {Object} params - { limit, offset, platform, agent_id, round_num } */ @@ -155,7 +153,7 @@ export const getSimulationActions = (simulationId, params = {}) => { } /** - * 关闭模拟环境(优雅退出) + * Close simulation environment (graceful exit) * @param {Object} data - { simulation_id, timeout? } */ export const closeSimulationEnv = (data) => { @@ -163,7 +161,7 @@ export const closeSimulationEnv = (data) => { } /** - * 获取模拟环境状态 + * Get simulation environment status * @param {Object} data - { simulation_id } */ export const getEnvStatus = (data) => { @@ -171,18 +169,19 @@ export const getEnvStatus = (data) => { } /** - * 批量采访 Agent + * Batch interview Agents * @param {Object} data - { simulation_id, interviews: [{ agent_id, prompt }] } */ export const interviewAgents = (data) => { - return service.post('/api/simulation/interview/batch', data) + return requestWithRetry(() => service.post('/api/simulation/interview/batch', data), 3, 1000) } /** - * 获取历史模拟列表(带项目详情) - * 用于首页历史项目展示 - * @param {number} limit - 返回数量限制 + * Get historical simulation list (with project details) + * For home page historical project display + * @param {number} limit - Return count limit */ export const getSimulationHistory = (limit = 20) => { return service.get('/api/simulation/history', { params: { limit } }) } + diff --git a/frontend/src/components/GraphPanel.vue b/frontend/src/components/GraphPanel.vue index db188298..ea510ed4 100644 --- a/frontend/src/components/GraphPanel.vue +++ b/frontend/src/components/GraphPanel.vue @@ -2,7 +2,7 @@
{{ $t('graph.panelTitle') }} - +
- +
- +
@@ -30,7 +30,7 @@ {{ isSimulating ? $t('graph.graphMemoryRealtime') : $t('graph.realtimeUpdating') }}
- +
@@ -48,7 +48,7 @@
- +
{{ selectedItem.type === 'node' ? $t('graph.nodeDetails') : $t('graph.relationship') }} @@ -58,7 +58,7 @@
- +
Name: @@ -101,9 +101,9 @@
- +
- + - +