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 @@