diff --git a/backend/app/api/graph.py b/backend/app/api/graph.py
index 12ff1ba2d..bbc82c86f 100644
--- a/backend/app/api/graph.py
+++ b/backend/app/api/graph.py
@@ -17,6 +17,7 @@
from ..utils.logger import get_logger
from ..models.task import TaskManager, TaskStatus
from ..models.project import ProjectManager, ProjectStatus
+from ..utils.messages import msg, get_request_language
# 获取日志器
logger = get_logger('mirofish.api')
@@ -42,9 +43,9 @@ def get_project(project_id: str):
if not project:
return jsonify({
"success": False,
- "error": f"项目不存在: {project_id}"
+ "error": msg('project_not_found', id=project_id)
}), 404
-
+
return jsonify({
"success": True,
"data": project.to_dict()
@@ -76,12 +77,12 @@ def delete_project(project_id: str):
if not success:
return jsonify({
"success": False,
- "error": f"项目不存在或删除失败: {project_id}"
+ "error": msg('project_delete_failed', id=project_id)
}), 404
-
+
return jsonify({
"success": True,
- "message": f"项目已删除: {project_id}"
+ "message": msg('project_deleted', id=project_id)
})
@@ -95,9 +96,9 @@ def reset_project(project_id: str):
if not project:
return jsonify({
"success": False,
- "error": f"项目不存在: {project_id}"
+ "error": msg('project_not_found', id=project_id)
}), 404
-
+
# 重置到本体已生成状态
if project.ontology:
project.status = ProjectStatus.ONTOLOGY_GENERATED
@@ -111,7 +112,7 @@ def reset_project(project_id: str):
return jsonify({
"success": True,
- "message": f"项目已重置: {project_id}",
+ "message": msg('project_reset', id=project_id),
"data": project.to_dict()
})
@@ -160,7 +161,7 @@ def generate_ontology():
if not simulation_requirement:
return jsonify({
"success": False,
- "error": "请提供模拟需求描述 (simulation_requirement)"
+ "error": msg('missing_simulation_requirement')
}), 400
# 获取上传的文件
@@ -168,7 +169,7 @@ def generate_ontology():
if not uploaded_files or all(not f.filename for f in uploaded_files):
return jsonify({
"success": False,
- "error": "请至少上传一个文档文件"
+ "error": msg('missing_files')
}), 400
# 创建项目
@@ -203,7 +204,7 @@ def generate_ontology():
ProjectManager.delete_project(project.project_id)
return jsonify({
"success": False,
- "error": "没有成功处理任何文档,请检查文件格式"
+ "error": msg('no_docs_processed')
}), 400
# 保存提取的文本
@@ -285,7 +286,7 @@ def build_graph():
# 检查配置
errors = []
if not Config.ZEP_API_KEY:
- errors.append("ZEP_API_KEY未配置")
+ errors.append(msg('zep_not_configured'))
if errors:
logger.error(f"配置错误: {errors}")
return jsonify({
@@ -301,15 +302,15 @@ def build_graph():
if not project_id:
return jsonify({
"success": False,
- "error": "请提供 project_id"
+ "error": msg('missing_project_id')
}), 400
-
+
# 获取项目
project = ProjectManager.get_project(project_id)
if not project:
return jsonify({
"success": False,
- "error": f"项目不存在: {project_id}"
+ "error": msg('project_not_found', id=project_id)
}), 404
# 检查项目状态
@@ -318,13 +319,13 @@ def build_graph():
if project.status == ProjectStatus.CREATED:
return jsonify({
"success": False,
- "error": "项目尚未生成本体,请先调用 /ontology/generate"
+ "error": msg('ontology_not_generated')
}), 400
if project.status == ProjectStatus.GRAPH_BUILDING and not force:
return jsonify({
"success": False,
- "error": "图谱正在构建中,请勿重复提交。如需强制重建,请添加 force: true",
+ "error": msg('graph_building_in_progress'),
"task_id": project.graph_build_task_id
}), 400
@@ -370,6 +371,9 @@ def build_graph():
project.graph_build_task_id = task_id
ProjectManager.save_project(project)
+ # Capture language before entering background thread
+ language = get_request_language()
+
# 启动后台任务
def build_task():
build_logger = get_logger('mirofish.build')
@@ -378,7 +382,7 @@ def build_task():
task_manager.update_task(
task_id,
status=TaskStatus.PROCESSING,
- message="初始化图谱构建服务..."
+ message=msg('init_graph_service', lang=language)
)
# 创建图谱构建服务
@@ -387,7 +391,7 @@ def build_task():
# 分块
task_manager.update_task(
task_id,
- message="文本分块中...",
+ message=msg('text_chunking', lang=language),
progress=5
)
chunks = TextProcessor.split_text(
@@ -476,7 +480,7 @@ def wait_progress_callback(msg, progress_ratio):
task_manager.update_task(
task_id,
status=TaskStatus.COMPLETED,
- message="图谱构建完成",
+ message=msg('graph_build_complete', lang=language),
progress=100,
result={
"project_id": project_id,
@@ -512,7 +516,7 @@ def wait_progress_callback(msg, progress_ratio):
"data": {
"project_id": project_id,
"task_id": task_id,
- "message": "图谱构建任务已启动,请通过 /task/{task_id} 查询进度"
+ "message": msg('graph_build_started')
}
})
@@ -536,7 +540,7 @@ def get_task(task_id: str):
if not task:
return jsonify({
"success": False,
- "error": f"任务不存在: {task_id}"
+ "error": msg('task_not_found', id=task_id)
}), 404
return jsonify({
@@ -570,7 +574,7 @@ def get_graph_data(graph_id: str):
if not Config.ZEP_API_KEY:
return jsonify({
"success": False,
- "error": "ZEP_API_KEY未配置"
+ "error": msg('zep_not_configured')
}), 500
builder = GraphBuilderService(api_key=Config.ZEP_API_KEY)
@@ -598,7 +602,7 @@ def delete_graph(graph_id: str):
if not Config.ZEP_API_KEY:
return jsonify({
"success": False,
- "error": "ZEP_API_KEY未配置"
+ "error": msg('zep_not_configured')
}), 500
builder = GraphBuilderService(api_key=Config.ZEP_API_KEY)
@@ -606,7 +610,7 @@ def delete_graph(graph_id: str):
return jsonify({
"success": True,
- "message": f"图谱已删除: {graph_id}"
+ "message": msg('graph_deleted', id=graph_id)
})
except Exception as e:
diff --git a/backend/app/api/report.py b/backend/app/api/report.py
index e05c73c39..f87d8f858 100644
--- a/backend/app/api/report.py
+++ b/backend/app/api/report.py
@@ -15,6 +15,7 @@
from ..models.project import ProjectManager
from ..models.task import TaskManager, TaskStatus
from ..utils.logger import get_logger
+from ..utils.messages import msg, get_request_language
logger = get_logger('mirofish.api.report')
@@ -53,19 +54,19 @@ def generate_report():
if not simulation_id:
return jsonify({
"success": False,
- "error": "请提供 simulation_id"
+ "error": msg('missing_simulation_id')
}), 400
-
+
force_regenerate = data.get('force_regenerate', False)
-
+
# 获取模拟信息
manager = SimulationManager()
state = manager.get_simulation(simulation_id)
-
+
if not state:
return jsonify({
"success": False,
- "error": f"模拟不存在: {simulation_id}"
+ "error": msg('simulation_not_found', id=simulation_id)
}), 404
# 检查是否已有报告
@@ -78,7 +79,7 @@ def generate_report():
"simulation_id": simulation_id,
"report_id": existing_report.report_id,
"status": "completed",
- "message": "报告已存在",
+ "message": msg('report_already_generated'),
"already_generated": True
}
})
@@ -88,21 +89,21 @@ def generate_report():
if not project:
return jsonify({
"success": False,
- "error": f"项目不存在: {state.project_id}"
+ "error": msg('project_not_found', id=state.project_id)
}), 404
-
+
graph_id = state.graph_id or project.graph_id
if not graph_id:
return jsonify({
"success": False,
- "error": "缺少图谱ID,请确保已构建图谱"
+ "error": msg('missing_graph_id')
}), 400
-
+
simulation_requirement = project.simulation_requirement
if not simulation_requirement:
return jsonify({
"success": False,
- "error": "缺少模拟需求描述"
+ "error": msg('missing_requirement')
}), 400
# 提前生成 report_id,以便立即返回给前端
@@ -120,6 +121,9 @@ def generate_report():
}
)
+ # Capture language before entering background thread
+ language = get_request_language()
+
# 定义后台任务
def run_generate():
try:
@@ -127,7 +131,7 @@ def run_generate():
task_id,
status=TaskStatus.PROCESSING,
progress=0,
- message="初始化Report Agent..."
+ message=msg('init_report_agent', lang=language)
)
# 创建Report Agent
@@ -164,7 +168,7 @@ def progress_callback(stage, progress, message):
}
)
else:
- task_manager.fail_task(task_id, report.error or "报告生成失败")
+ task_manager.fail_task(task_id, report.error or msg('report_generation_failed', lang=language))
except Exception as e:
logger.error(f"报告生成失败: {str(e)}")
@@ -181,7 +185,7 @@ def progress_callback(stage, progress, message):
"report_id": report_id,
"task_id": task_id,
"status": "generating",
- "message": "报告生成任务已启动,请通过 /api/report/generate/status 查询进度",
+ "message": msg('report_task_started_long'),
"already_generated": False
}
})
@@ -234,7 +238,7 @@ def get_generate_status():
"report_id": existing_report.report_id,
"status": "completed",
"progress": 100,
- "message": "报告已生成",
+ "message": msg('report_already_generated'),
"already_completed": True
}
})
@@ -242,7 +246,7 @@ def get_generate_status():
if not task_id:
return jsonify({
"success": False,
- "error": "请提供 task_id 或 simulation_id"
+ "error": msg('missing_simulation_id')
}), 400
task_manager = TaskManager()
@@ -251,7 +255,7 @@ def get_generate_status():
if not task:
return jsonify({
"success": False,
- "error": f"任务不存在: {task_id}"
+ "error": msg('task_not_found', id=task_id)
}), 404
return jsonify({
@@ -294,14 +298,14 @@ def get_report(report_id: str):
if not report:
return jsonify({
"success": False,
- "error": f"报告不存在: {report_id}"
+ "error": msg('report_not_found')
}), 404
-
+
return jsonify({
"success": True,
"data": report.to_dict()
})
-
+
except Exception as e:
logger.error(f"获取报告失败: {str(e)}")
return jsonify({
@@ -331,7 +335,7 @@ def get_report_by_simulation(simulation_id: str):
if not report:
return jsonify({
"success": False,
- "error": f"该模拟暂无报告: {simulation_id}",
+ "error": msg('report_not_found'),
"has_report": False
}), 404
@@ -403,9 +407,9 @@ def download_report(report_id: str):
if not report:
return jsonify({
"success": False,
- "error": f"报告不存在: {report_id}"
+ "error": msg('report_not_found')
}), 404
-
+
md_path = ReportManager._get_report_markdown_path(report_id)
if not os.path.exists(md_path):
@@ -445,12 +449,12 @@ def delete_report(report_id: str):
if not success:
return jsonify({
"success": False,
- "error": f"报告不存在: {report_id}"
+ "error": msg('report_not_found')
}), 404
-
+
return jsonify({
"success": True,
- "message": f"报告已删除: {report_id}"
+ "message": msg('report_deleted', id=report_id)
})
except Exception as e:
@@ -501,37 +505,37 @@ def chat_with_report_agent():
if not simulation_id:
return jsonify({
"success": False,
- "error": "请提供 simulation_id"
+ "error": msg('missing_simulation_id')
}), 400
-
+
if not message:
return jsonify({
"success": False,
"error": "请提供 message"
}), 400
-
+
# 获取模拟和项目信息
manager = SimulationManager()
state = manager.get_simulation(simulation_id)
-
+
if not state:
return jsonify({
"success": False,
- "error": f"模拟不存在: {simulation_id}"
+ "error": msg('simulation_not_found', id=simulation_id)
}), 404
-
+
project = ProjectManager.get_project(state.project_id)
if not project:
return jsonify({
"success": False,
- "error": f"项目不存在: {state.project_id}"
+ "error": msg('project_not_found', id=state.project_id)
}), 404
-
+
graph_id = state.graph_id or project.graph_id
if not graph_id:
return jsonify({
"success": False,
- "error": "缺少图谱ID"
+ "error": msg('missing_graph_id')
}), 400
simulation_requirement = project.simulation_requirement or ""
@@ -949,7 +953,7 @@ def search_graph_tool():
if not graph_id or not query:
return jsonify({
"success": False,
- "error": "请提供 graph_id 和 query"
+ "error": msg('missing_graph_id')
}), 400
from ..services.zep_tools import ZepToolsService
@@ -993,11 +997,11 @@ def get_graph_statistics_tool():
if not graph_id:
return jsonify({
"success": False,
- "error": "请提供 graph_id"
+ "error": msg('missing_graph_id')
}), 400
-
+
from ..services.zep_tools import ZepToolsService
-
+
tools = ZepToolsService()
result = tools.get_graph_statistics(graph_id)
diff --git a/backend/app/api/simulation.py b/backend/app/api/simulation.py
index 3a0f68168..2ec349af6 100644
--- a/backend/app/api/simulation.py
+++ b/backend/app/api/simulation.py
@@ -15,31 +15,36 @@
from ..services.simulation_runner import SimulationRunner, RunnerStatus
from ..utils.logger import get_logger
from ..models.project import ProjectManager
+from ..utils.messages import msg, get_request_language
logger = get_logger('mirofish.api.simulation')
# Interview prompt 优化前缀
-# 添加此前缀可以避免Agent调用工具,直接用文本回复
-INTERVIEW_PROMPT_PREFIX = "结合你的人设、所有的过往记忆与行动,不调用任何工具直接用文本回复我:"
+def get_interview_prefix(lang=None):
+ return msg('interview_prefix', lang=lang)
-def optimize_interview_prompt(prompt: str) -> str:
+def optimize_interview_prompt(prompt: str, lang=None) -> str:
"""
优化Interview提问,添加前缀避免Agent调用工具
-
+
Args:
prompt: 原始提问
-
+ lang: Language code ('en' or 'zh'). If None, reads from request header.
+
Returns:
优化后的提问
"""
if not prompt:
return prompt
- # 避免重复添加前缀
- if prompt.startswith(INTERVIEW_PROMPT_PREFIX):
+ prefix = get_interview_prefix(lang=lang)
+ # 避免重复添加前缀(check both languages)
+ en_prefix = msg('interview_prefix', lang='en')
+ zh_prefix = msg('interview_prefix', lang='zh')
+ if prompt.startswith(en_prefix) or prompt.startswith(zh_prefix):
return prompt
- return f"{INTERVIEW_PROMPT_PREFIX}{prompt}"
+ return f"{prefix}{prompt}"
# ============== 实体读取接口 ==============
@@ -59,7 +64,7 @@ def get_graph_entities(graph_id: str):
if not Config.ZEP_API_KEY:
return jsonify({
"success": False,
- "error": "ZEP_API_KEY未配置"
+ "error": msg('zep_not_configured')
}), 500
entity_types_str = request.args.get('entity_types', '')
@@ -96,7 +101,7 @@ def get_entity_detail(graph_id: str, entity_uuid: str):
if not Config.ZEP_API_KEY:
return jsonify({
"success": False,
- "error": "ZEP_API_KEY未配置"
+ "error": msg('zep_not_configured')
}), 500
reader = ZepEntityReader()
@@ -105,7 +110,7 @@ def get_entity_detail(graph_id: str, entity_uuid: str):
if not entity:
return jsonify({
"success": False,
- "error": f"实体不存在: {entity_uuid}"
+ "error": msg('entity_not_found', id=entity_uuid)
}), 404
return jsonify({
@@ -129,7 +134,7 @@ def get_entities_by_type(graph_id: str, entity_type: str):
if not Config.ZEP_API_KEY:
return jsonify({
"success": False,
- "error": "ZEP_API_KEY未配置"
+ "error": msg('zep_not_configured')
}), 500
enrich = request.args.get('enrich', 'true').lower() == 'true'
@@ -197,21 +202,21 @@ def create_simulation():
if not project_id:
return jsonify({
"success": False,
- "error": "请提供 project_id"
+ "error": msg('missing_project_id')
}), 400
project = ProjectManager.get_project(project_id)
if not project:
return jsonify({
"success": False,
- "error": f"项目不存在: {project_id}"
+ "error": msg('project_not_found', id=project_id)
}), 404
graph_id = data.get('graph_id') or project.graph_id
if not graph_id:
return jsonify({
"success": False,
- "error": "项目尚未构建图谱,请先调用 /api/graph/build"
+ "error": msg('graph_not_built')
}), 400
manager = SimulationManager()
@@ -408,7 +413,7 @@ def prepare_simulation():
if not simulation_id:
return jsonify({
"success": False,
- "error": "请提供 simulation_id"
+ "error": msg('missing_simulation_id')
}), 400
manager = SimulationManager()
@@ -417,7 +422,7 @@ def prepare_simulation():
if not state:
return jsonify({
"success": False,
- "error": f"模拟不存在: {simulation_id}"
+ "error": msg('simulation_not_found', id=simulation_id)
}), 404
# 检查是否强制重新生成
@@ -449,7 +454,7 @@ def prepare_simulation():
if not project:
return jsonify({
"success": False,
- "error": f"项目不存在: {state.project_id}"
+ "error": msg('project_not_found', id=state.project_id)
}), 404
# 获取模拟需求
@@ -457,7 +462,7 @@ def prepare_simulation():
if not simulation_requirement:
return jsonify({
"success": False,
- "error": "项目缺少模拟需求描述 (simulation_requirement)"
+ "error": msg('missing_simulation_requirement')
}), 400
# 获取文档文本
@@ -702,7 +707,7 @@ def get_prepare_status():
})
return jsonify({
"success": False,
- "error": "请提供 task_id 或 simulation_id"
+ "error": msg('missing_simulation_id')
}), 400
task_manager = TaskManager()
@@ -728,7 +733,7 @@ def get_prepare_status():
return jsonify({
"success": False,
- "error": f"任务不存在: {task_id}"
+ "error": msg('task_not_found', id=task_id)
}), 404
task_dict = task.to_dict()
@@ -757,7 +762,7 @@ def get_simulation(simulation_id: str):
if not state:
return jsonify({
"success": False,
- "error": f"模拟不存在: {simulation_id}"
+ "error": msg('simulation_not_found', id=simulation_id)
}), 404
result = state.to_dict()
@@ -1061,7 +1066,7 @@ def get_simulation_profiles_realtime(simulation_id: str):
if not os.path.exists(sim_dir):
return jsonify({
"success": False,
- "error": f"模拟不存在: {simulation_id}"
+ "error": msg('simulation_not_found', id=simulation_id)
}), 404
# 确定文件路径
@@ -1164,7 +1169,7 @@ def get_simulation_config_realtime(simulation_id: str):
if not os.path.exists(sim_dir):
return jsonify({
"success": False,
- "error": f"模拟不存在: {simulation_id}"
+ "error": msg('simulation_not_found', id=simulation_id)
}), 404
# 配置文件路径
@@ -1389,7 +1394,7 @@ def generate_profiles():
if not graph_id:
return jsonify({
"success": False,
- "error": "请提供 graph_id"
+ "error": msg('missing_graph_id')
}), 400
entity_types = data.get('entity_types')
@@ -1491,7 +1496,7 @@ def start_simulation():
if not simulation_id:
return jsonify({
"success": False,
- "error": "请提供 simulation_id"
+ "error": msg('missing_simulation_id')
}), 400
platform = data.get('platform', 'parallel')
@@ -1527,7 +1532,7 @@ def start_simulation():
if not state:
return jsonify({
"success": False,
- "error": f"模拟不存在: {simulation_id}"
+ "error": msg('simulation_not_found', id=simulation_id)
}), 404
force_restarted = False
@@ -1663,7 +1668,7 @@ def stop_simulation():
if not simulation_id:
return jsonify({
"success": False,
- "error": "请提供 simulation_id"
+ "error": msg('missing_simulation_id')
}), 400
run_state = SimulationRunner.stop_simulation(simulation_id)
@@ -2197,7 +2202,7 @@ def interview_agent():
if not simulation_id:
return jsonify({
"success": False,
- "error": "请提供 simulation_id"
+ "error": msg('missing_simulation_id')
}), 400
if agent_id is None:
@@ -2318,7 +2323,7 @@ def interview_agents_batch():
if not simulation_id:
return jsonify({
"success": False,
- "error": "请提供 simulation_id"
+ "error": msg('missing_simulation_id')
}), 400
if not interviews or not isinstance(interviews, list):
@@ -2445,7 +2450,7 @@ def interview_all_agents():
if not simulation_id:
return jsonify({
"success": False,
- "error": "请提供 simulation_id"
+ "error": msg('missing_simulation_id')
}), 400
if not prompt:
@@ -2549,7 +2554,7 @@ def get_interview_history():
if not simulation_id:
return jsonify({
"success": False,
- "error": "请提供 simulation_id"
+ "error": msg('missing_simulation_id')
}), 400
history = SimulationRunner.get_interview_history(
@@ -2608,7 +2613,7 @@ def get_env_status():
if not simulation_id:
return jsonify({
"success": False,
- "error": "请提供 simulation_id"
+ "error": msg('missing_simulation_id')
}), 400
env_alive = SimulationRunner.check_env_alive(simulation_id)
@@ -2676,7 +2681,7 @@ def close_simulation_env():
if not simulation_id:
return jsonify({
"success": False,
- "error": "请提供 simulation_id"
+ "error": msg('missing_simulation_id')
}), 400
result = SimulationRunner.close_simulation_env(
diff --git a/backend/app/models/project.py b/backend/app/models/project.py
index 089789374..c9c7256fd 100644
--- a/backend/app/models/project.py
+++ b/backend/app/models/project.py
@@ -51,6 +51,9 @@ class Project:
# 错误信息
error: Optional[str] = None
+
+ # 语言
+ language: str = 'en'
def to_dict(self) -> Dict[str, Any]:
"""转换为字典"""
@@ -69,7 +72,8 @@ def to_dict(self) -> Dict[str, Any]:
"simulation_requirement": self.simulation_requirement,
"chunk_size": self.chunk_size,
"chunk_overlap": self.chunk_overlap,
- "error": self.error
+ "error": self.error,
+ "language": self.language
}
@classmethod
@@ -94,7 +98,8 @@ def from_dict(cls, data: Dict[str, Any]) -> 'Project':
simulation_requirement=data.get('simulation_requirement'),
chunk_size=data.get('chunk_size', 500),
chunk_overlap=data.get('chunk_overlap', 50),
- error=data.get('error')
+ error=data.get('error'),
+ language=data.get('language', 'en')
)
diff --git a/backend/app/services/oasis_profile_generator.py b/backend/app/services/oasis_profile_generator.py
index 57836c539..dd5f5319c 100644
--- a/backend/app/services/oasis_profile_generator.py
+++ b/backend/app/services/oasis_profile_generator.py
@@ -178,13 +178,15 @@ class OasisProfileGenerator:
]
def __init__(
- self,
+ self,
api_key: Optional[str] = None,
base_url: Optional[str] = None,
model_name: Optional[str] = None,
zep_api_key: Optional[str] = None,
- graph_id: Optional[str] = None
+ graph_id: Optional[str] = None,
+ language: str = 'en'
):
+ self.language = language
self.api_key = api_key or Config.LLM_API_KEY
self.base_url = base_url or Config.LLM_BASE_URL
self.model_name = model_name or Config.LLM_MODEL_NAME
@@ -668,9 +670,13 @@ def fix_string_newlines(match):
"persona": entity_summary or f"{entity_name}是一个{entity_type}。"
}
- def _get_system_prompt(self, is_individual: bool) -> str:
+ def _get_system_prompt(self, is_individual: bool, language: str = None) -> str:
"""获取系统提示词"""
- base_prompt = "你是社交媒体用户画像生成专家。生成详细、真实的人设用于舆论模拟,最大程度还原已有现实情况。必须返回有效的JSON格式,所有字符串值不能包含未转义的换行符。使用中文。"
+ lang = language or self.language
+ if lang == 'en':
+ base_prompt = "You are a social media user profile generation expert. Generate detailed, realistic personas for public opinion simulation, faithfully reproducing known real-world information. You must return valid JSON format, and all string values must not contain unescaped newline characters. Use English."
+ else:
+ base_prompt = "你是社交媒体用户画像生成专家。生成详细、真实的人设用于舆论模拟,最大程度还原已有现实情况。必须返回有效的JSON格式,所有字符串值不能包含未转义的换行符。使用中文。"
return base_prompt
def _build_individual_persona_prompt(
@@ -679,14 +685,53 @@ def _build_individual_persona_prompt(
entity_type: str,
entity_summary: str,
entity_attributes: Dict[str, Any],
- context: str
+ context: str,
+ language: str = None
) -> str:
"""构建个人实体的详细人设提示词"""
-
- attrs_str = json.dumps(entity_attributes, ensure_ascii=False) if entity_attributes else "无"
- context_str = context[:3000] if context else "无额外上下文"
-
- return f"""为实体生成详细的社交媒体用户人设,最大程度还原已有现实情况。
+ lang = language or self.language
+
+ attrs_str = json.dumps(entity_attributes, ensure_ascii=False) if entity_attributes else ("None" if lang == 'en' else "无")
+ context_str = context[:3000] if context else ("No additional context" if lang == 'en' else "无额外上下文")
+
+ if lang == 'en':
+ return f"""Generate a detailed social media user persona for this entity, faithfully reproducing known real-world information.
+
+Entity Name: {entity_name}
+Entity Type: {entity_type}
+Entity Summary: {entity_summary}
+Entity Attributes: {attrs_str}
+
+Context Information:
+{context_str}
+
+Please generate JSON with the following fields:
+
+1. bio: Social media bio, 200 words
+2. persona: Detailed persona description (2000 words of plain text), must include:
+ - Basic information (age, occupation, educational background, location)
+ - Background (important experiences, connection to events, social relationships)
+ - Personality traits (MBTI type, core personality, emotional expression style)
+ - Social media behavior (posting frequency, content preferences, interaction style, language characteristics)
+ - Stances and viewpoints (attitudes on topics, content that might provoke or move them)
+ - Unique characteristics (catchphrases, special experiences, personal hobbies)
+ - Personal memory (important part of the persona, introduce this individual's connection to events, and their existing actions and reactions in the events)
+3. age: Age number (must be an integer)
+4. gender: Gender, must be English: "male" or "female"
+5. mbti: MBTI type (e.g., INTJ, ENFP)
+6. country: Country (e.g., "United States", "China")
+7. profession: Profession
+8. interested_topics: Array of interested topics
+
+Important:
+- All field values must be strings or numbers, do not use newline characters
+- persona must be a coherent text description
+- Use English (gender field must be English male/female)
+- Content must be consistent with entity information
+- age must be a valid integer, gender must be "male" or "female"
+"""
+ else:
+ return f"""为实体生成详细的社交媒体用户人设,最大程度还原已有现实情况。
实体名称: {entity_name}
实体类型: {entity_type}
@@ -728,14 +773,52 @@ def _build_group_persona_prompt(
entity_type: str,
entity_summary: str,
entity_attributes: Dict[str, Any],
- context: str
+ context: str,
+ language: str = None
) -> str:
"""构建群体/机构实体的详细人设提示词"""
-
- attrs_str = json.dumps(entity_attributes, ensure_ascii=False) if entity_attributes else "无"
- context_str = context[:3000] if context else "无额外上下文"
-
- return f"""为机构/群体实体生成详细的社交媒体账号设定,最大程度还原已有现实情况。
+ lang = language or self.language
+
+ attrs_str = json.dumps(entity_attributes, ensure_ascii=False) if entity_attributes else ("None" if lang == 'en' else "无")
+ context_str = context[:3000] if context else ("No additional context" if lang == 'en' else "无额外上下文")
+
+ if lang == 'en':
+ return f"""Generate a detailed social media account profile for an organization/group entity, faithfully reproducing known real-world information.
+
+Entity Name: {entity_name}
+Entity Type: {entity_type}
+Entity Summary: {entity_summary}
+Entity Attributes: {attrs_str}
+
+Context Information:
+{context_str}
+
+Please generate JSON with the following fields:
+
+1. bio: Official account bio, 200 words, professional and appropriate
+2. persona: Detailed account profile description (2000 words of plain text), must include:
+ - Organization basic information (official name, nature of organization, founding background, main functions)
+ - Account positioning (account type, target audience, core functions)
+ - Speaking style (language characteristics, common expressions, taboo topics)
+ - Content characteristics (content types, posting frequency, active time periods)
+ - Stance and attitude (official stance on core topics, approach to handling controversies)
+ - Special notes (represented group profile, operational habits)
+ - Organizational memory (important part of the persona, introduce this organization's connection to events, and its existing actions and reactions in events)
+3. age: Fixed at 30 (virtual age for organizational accounts)
+4. gender: Fixed at "other" (organizational accounts use "other" to indicate non-individual)
+5. mbti: MBTI type, used to describe account style, e.g., ISTJ for rigorous and conservative
+6. country: Country (e.g., "United States", "China")
+7. profession: Organizational function description
+8. interested_topics: Array of focus areas
+
+Important:
+- All field values must be strings or numbers, no null values allowed
+- persona must be a coherent text description, do not use newline characters
+- Use English (gender field must be English "other")
+- age must be integer 30, gender must be string "other"
+- Organizational account statements must match its identity positioning"""
+ else:
+ return f"""为机构/群体实体生成详细的社交媒体账号设定,最大程度还原已有现实情况。
实体名称: {entity_name}
实体类型: {entity_type}
diff --git a/backend/app/services/ontology_generator.py b/backend/app/services/ontology_generator.py
index 2d3e39bd8..b668ec220 100644
--- a/backend/app/services/ontology_generator.py
+++ b/backend/app/services/ontology_generator.py
@@ -154,6 +154,151 @@
- COMPETES_WITH: 竞争
"""
+ONTOLOGY_SYSTEM_PROMPT_EN = """You are a professional knowledge graph ontology design expert. Your task is to analyze the given text content and simulation requirements, and design entity types and relationship types suitable for **social media public opinion simulation**.
+
+**Important: You must output valid JSON format data. Do not output anything else.**
+
+## Core Task Background
+
+We are building a **social media public opinion simulation system**. In this system:
+- Each entity is an "account" or "agent" that can speak, interact, and spread information on social media
+- Entities influence each other through forwarding, commenting, and responding
+- We need to simulate the reactions of various parties and the information propagation paths during public opinion events
+
+Therefore, **entities must be real-world agents that can speak and interact on social media**:
+
+**Acceptable**:
+- Specific individuals (public figures, parties involved, opinion leaders, scholars, ordinary people)
+- Companies and enterprises (including their official accounts)
+- Organizations and institutions (universities, associations, NGOs, unions, etc.)
+- Government departments and regulatory agencies
+- Media organizations (newspapers, TV stations, self-media, websites)
+- Social media platforms themselves
+- Representatives of specific groups (e.g., alumni associations, fan groups, advocacy groups, etc.)
+
+**Not acceptable**:
+- Abstract concepts (e.g., "public opinion", "sentiment", "trend")
+- Topics/themes (e.g., "academic integrity", "education reform")
+- Viewpoints/attitudes (e.g., "supporters", "opponents")
+
+## Output Format
+
+Please output in JSON format with the following structure:
+
+```json
+{
+ "entity_types": [
+ {
+ "name": "Entity type name (English, PascalCase)",
+ "description": "Brief description (English, no more than 100 characters)",
+ "attributes": [
+ {
+ "name": "attribute_name (English, snake_case)",
+ "type": "text",
+ "description": "Attribute description"
+ }
+ ],
+ "examples": ["Example entity 1", "Example entity 2"]
+ }
+ ],
+ "edge_types": [
+ {
+ "name": "Relationship type name (English, UPPER_SNAKE_CASE)",
+ "description": "Brief description (English, no more than 100 characters)",
+ "source_targets": [
+ {"source": "Source entity type", "target": "Target entity type"}
+ ],
+ "attributes": []
+ }
+ ],
+ "analysis_summary": "Brief analysis summary of the text content (in English)"
+}
+```
+
+## Design Guidelines (Extremely Important!)
+
+### 1. Entity Type Design - Must Be Strictly Followed
+
+**Quantity requirement: Exactly 10 entity types**
+
+**Hierarchy requirements (must include both specific types and fallback types)**:
+
+Your 10 entity types must include the following layers:
+
+A. **Fallback types (must include, placed at the end of the list)**:
+ - `Person`: Fallback type for any natural person. When a person does not belong to other more specific person types, classify them here.
+ - `Organization`: Fallback type for any organization. When an organization does not belong to other more specific organization types, classify it here.
+
+B. **Specific types (8, designed based on text content)**:
+ - Design more specific types for the main roles appearing in the text
+ - Example: If the text involves academic events, you can have `Student`, `Professor`, `University`
+ - Example: If the text involves business events, you can have `Company`, `CEO`, `Employee`
+
+**Why fallback types are needed**:
+- Various people appear in the text, such as "elementary school teachers", "bystanders", "some netizen"
+- If there is no specific type match, they should be classified as `Person`
+- Similarly, small organizations, temporary groups, etc. should be classified as `Organization`
+
+**Design principles for specific types**:
+- Identify high-frequency or key role types from the text
+- Each specific type should have clear boundaries to avoid overlap
+- The description must clearly explain the difference between this type and the fallback type
+
+### 2. Relationship Type Design
+
+- Quantity: 6-10
+- Relationships should reflect real connections in social media interactions
+- Ensure that the source_targets of relationships cover your defined entity types
+
+### 3. Attribute Design
+
+- 1-3 key attributes per entity type
+- **Note**: Attribute names cannot use `name`, `uuid`, `group_id`, `created_at`, `summary` (these are system reserved words)
+- Recommended: `full_name`, `title`, `role`, `position`, `location`, `description`, etc.
+
+## Entity Type Reference
+
+**Individual (specific)**:
+- Student: Student
+- Professor: Professor/Scholar
+- Journalist: Journalist
+- Celebrity: Celebrity/Influencer
+- Executive: Executive
+- Official: Government official
+- Lawyer: Lawyer
+- Doctor: Doctor
+
+**Individual (fallback)**:
+- Person: Any natural person (used when not belonging to the above specific types)
+
+**Organization (specific)**:
+- University: University/College
+- Company: Company/Enterprise
+- GovernmentAgency: Government agency
+- MediaOutlet: Media organization
+- Hospital: Hospital
+- School: Elementary/Secondary school
+- NGO: Non-governmental organization
+
+**Organization (fallback)**:
+- Organization: Any organization (used when not belonging to the above specific types)
+
+## Relationship Type Reference
+
+- WORKS_FOR: Works for
+- STUDIES_AT: Studies at
+- AFFILIATED_WITH: Affiliated with
+- REPRESENTS: Represents
+- REGULATES: Regulates
+- REPORTS_ON: Reports on
+- COMMENTS_ON: Comments on
+- RESPONDS_TO: Responds to
+- SUPPORTS: Supports
+- OPPOSES: Opposes
+- COLLABORATES_WITH: Collaborates with
+- COMPETES_WITH: Competes with
+"""
+
class OntologyGenerator:
"""
@@ -168,28 +313,33 @@ def generate(
self,
document_texts: List[str],
simulation_requirement: str,
- additional_context: Optional[str] = None
+ additional_context: Optional[str] = None,
+ language: str = 'en'
) -> Dict[str, Any]:
"""
生成本体定义
-
+
Args:
document_texts: 文档文本列表
simulation_requirement: 模拟需求描述
additional_context: 额外上下文
-
+ language: 语言选择,'en' 为英文,'zh' 为中文
+
Returns:
本体定义(entity_types, edge_types等)
"""
# 构建用户消息
user_message = self._build_user_message(
- document_texts,
+ document_texts,
simulation_requirement,
- additional_context
+ additional_context,
+ language=language
)
-
+
+ system_prompt = ONTOLOGY_SYSTEM_PROMPT_EN if language == 'en' else ONTOLOGY_SYSTEM_PROMPT
+
messages = [
- {"role": "system", "content": ONTOLOGY_SYSTEM_PROMPT},
+ {"role": "system", "content": system_prompt},
{"role": "user", "content": user_message}
]
@@ -212,20 +362,52 @@ def _build_user_message(
self,
document_texts: List[str],
simulation_requirement: str,
- additional_context: Optional[str]
+ additional_context: Optional[str],
+ language: str = 'en'
) -> str:
"""构建用户消息"""
-
+
# 合并文本
combined_text = "\n\n---\n\n".join(document_texts)
original_length = len(combined_text)
-
+
# 如果文本超过5万字,截断(仅影响传给LLM的内容,不影响图谱构建)
if len(combined_text) > self.MAX_TEXT_LENGTH_FOR_LLM:
combined_text = combined_text[:self.MAX_TEXT_LENGTH_FOR_LLM]
- combined_text += f"\n\n...(原文共{original_length}字,已截取前{self.MAX_TEXT_LENGTH_FOR_LLM}字用于本体分析)..."
-
- message = f"""## 模拟需求
+ if language == 'en':
+ combined_text += f"\n\n...(Original text has {original_length} characters, truncated to first {self.MAX_TEXT_LENGTH_FOR_LLM} characters for ontology analysis)..."
+ else:
+ combined_text += f"\n\n...(原文共{original_length}字,已截取前{self.MAX_TEXT_LENGTH_FOR_LLM}字用于本体分析)..."
+
+ if language == 'en':
+ message = f"""## Simulation Requirement
+
+{simulation_requirement}
+
+## Document Content
+
+{combined_text}
+"""
+
+ if additional_context:
+ message += f"""
+## Additional Notes
+
+{additional_context}
+"""
+
+ message += """
+Based on the above content, design entity types and relationship types suitable for social media public opinion simulation.
+
+**Rules that must be followed**:
+1. You must output exactly 10 entity types
+2. The last 2 must be fallback types: Person (individual fallback) and Organization (organization fallback)
+3. The first 8 are specific types designed based on the text content
+4. All entity types must be real-world agents that can speak on social media, not abstract concepts
+5. Attribute names cannot use reserved words like name, uuid, group_id; use full_name, org_name, etc. instead
+"""
+ else:
+ message = f"""## 模拟需求
{simulation_requirement}
@@ -233,15 +415,15 @@ def _build_user_message(
{combined_text}
"""
-
- if additional_context:
- message += f"""
+
+ if additional_context:
+ message += f"""
## 额外说明
{additional_context}
"""
-
- message += """
+
+ message += """
请根据以上内容,设计适合社会舆论模拟的实体类型和关系类型。
**必须遵守的规则**:
@@ -251,7 +433,7 @@ def _build_user_message(
4. 所有实体类型必须是现实中可以发声的主体,不能是抽象概念
5. 属性名不能使用 name、uuid、group_id 等保留字,用 full_name、org_name 等替代
"""
-
+
return message
def _validate_and_process(self, result: Dict[str, Any]) -> Dict[str, Any]:
diff --git a/backend/app/services/report_agent.py b/backend/app/services/report_agent.py
index 02ca5bdc2..99d0854f9 100644
--- a/backend/app/services/report_agent.py
+++ b/backend/app/services/report_agent.py
@@ -472,6 +472,80 @@ def to_dict(self) -> Dict[str, Any]:
# ── 工具描述 ──
+TOOL_DESC_INSIGHT_FORGE_EN = """\
+[Deep Insight Retrieval - Powerful Retrieval Tool]
+This is our most powerful retrieval function, designed for in-depth analysis. It will:
+1. Automatically decompose your question into multiple sub-questions
+2. Retrieve information from the simulation graph across multiple dimensions
+3. Integrate results from semantic search, entity analysis, and relationship chain tracing
+4. Return the most comprehensive and in-depth retrieval content
+
+[Use Cases]
+- Need to deeply analyze a topic
+- Need to understand multiple aspects of an event
+- Need to obtain rich supporting material for report sections
+
+[Returns]
+- Relevant fact quotations (can be directly cited)
+- Core entity insights
+- Relationship chain analysis"""
+
+TOOL_DESC_PANORAMA_SEARCH_EN = """\
+[Panorama Search - Get the Full Picture]
+This tool is used to get the complete picture of simulation results, especially suitable for understanding event evolution. It will:
+1. Get all related nodes and relationships
+2. Distinguish between currently valid facts and historical/expired facts
+3. Help you understand how public opinion evolved
+
+[Use Cases]
+- Need to understand the complete development trajectory of an event
+- Need to compare public opinion changes across different stages
+- Need to obtain comprehensive entity and relationship information
+
+[Returns]
+- Currently valid facts (latest simulation results)
+- Historical/expired facts (evolution records)
+- All involved entities"""
+
+TOOL_DESC_QUICK_SEARCH_EN = """\
+[Quick Search - Fast Retrieval]
+A lightweight fast retrieval tool, suitable for simple, direct information queries.
+
+[Use Cases]
+- Need to quickly find specific information
+- Need to verify a fact
+- Simple information retrieval
+
+[Returns]
+- List of facts most relevant to the query"""
+
+TOOL_DESC_INTERVIEW_AGENTS_EN = """\
+[Deep Interview - Real Agent Interview (Dual Platform)]
+Calls the OASIS simulation environment's interview API to conduct real interviews with running simulation Agents!
+This is not LLM simulation, but calls the actual interview interface to get the original responses from simulation Agents.
+By default, interviews are conducted simultaneously on both Twitter and Reddit platforms for more comprehensive perspectives.
+
+Workflow:
+1. Automatically reads persona files to understand all simulation Agents
+2. Intelligently selects Agents most relevant to the interview topic (e.g., students, media, officials, etc.)
+3. Automatically generates interview questions
+4. Calls /api/simulation/interview/batch interface to conduct real interviews on both platforms
+5. Integrates all interview results, providing multi-perspective analysis
+
+[Use Cases]
+- Need to understand event perspectives from different roles (What do students think? What does media think? What do officials say?)
+- Need to collect opinions and stances from multiple parties
+- Need to obtain real answers from simulation Agents (from OASIS simulation environment)
+- Want to make reports more vivid, including "interview transcripts"
+
+[Returns]
+- Interviewed Agent identity information
+- Each Agent's interview responses on both Twitter and Reddit platforms
+- Key quotes (can be directly cited)
+- Interview summary and viewpoint comparison
+
+[Important] Requires OASIS simulation environment to be running!"""
+
TOOL_DESC_INSIGHT_FORGE = """\
【深度洞察检索 - 强大的检索工具】
这是我们强大的检索函数,专为深度分析设计。它会:
@@ -855,6 +929,311 @@ def to_dict(self) -> Dict[str, Any]:
CHAT_OBSERVATION_SUFFIX = "\n\n请简洁回答问题。"
+# ═══════════════════════════════════════════════════════════════
+# English Prompt Templates
+# ═══════════════════════════════════════════════════════════════
+
+PLAN_SYSTEM_PROMPT_EN = """\
+You are a "Future Prediction Report" writing expert with a "God's eye view" of the simulated world — you can observe every Agent's behavior, statements, and interactions within the simulation.
+
+[Core Concept]
+We have built a simulated world and injected specific "simulation requirements" as variables. The evolution results of the simulated world serve as predictions of what may happen in the future. You are observing not "experimental data", but "a rehearsal of the future".
+
+[Your Task]
+Write a "Future Prediction Report" that answers:
+1. Under our set conditions, what happened in the future?
+2. How did various Agents (groups of people) react and act?
+3. What noteworthy future trends and risks does this simulation reveal?
+
+[Report Positioning]
+- This is a simulation-based future prediction report, revealing "if this happens, what will the future look like"
+- Focus on prediction results: event trajectories, group reactions, emergent phenomena, potential risks
+- Agent behaviors and statements in the simulated world are predictions of future human behavior
+- This is NOT an analysis of current real-world conditions
+- This is NOT a generic public opinion overview
+
+[Section Limit]
+- Minimum 2 sections, maximum 5 sections
+- No sub-sections needed, each section should contain complete content directly
+- Content should be concise, focused on core prediction findings
+- Section structure should be designed by you based on prediction results
+
+Please output the report outline in JSON format:
+{
+ "title": "Report Title",
+ "summary": "Report summary (one sentence summarizing core prediction findings)",
+ "sections": [
+ {
+ "title": "Section Title",
+ "description": "Section content description"
+ }
+ ]
+}
+
+Note: The sections array must have at least 2 and at most 5 elements!"""
+
+PLAN_USER_PROMPT_TEMPLATE_EN = """\
+[Prediction Scenario Setup]
+Variable injected into the simulated world (simulation requirement): {simulation_requirement}
+
+[Simulated World Scale]
+- Number of entities participating in simulation: {total_nodes}
+- Number of relationships generated between entities: {total_edges}
+- Entity type distribution: {entity_types}
+- Active Agent count: {total_entities}
+
+[Sample Future Facts Predicted by Simulation]
+{related_facts_json}
+
+Please examine this future rehearsal from a "God's eye view":
+1. Under our set conditions, what state did the future present?
+2. How did various groups (Agents) react and act?
+3. What noteworthy future trends does this simulation reveal?
+
+Design the most appropriate report section structure based on prediction results.
+
+[Reminder] Report sections: minimum 2, maximum 5, content should be concise and focused on core prediction findings."""
+
+SECTION_SYSTEM_PROMPT_TEMPLATE_EN = """\
+You are a "Future Prediction Report" writing expert, currently writing a section of the report.
+
+Report Title: {report_title}
+Report Summary: {report_summary}
+Prediction Scenario (Simulation Requirement): {simulation_requirement}
+
+Current section to write: {section_title}
+
+═══════════════════════════════════════════════════════════════
+[Core Concept]
+═══════════════════════════════════════════════════════════════
+
+The simulated world is a rehearsal of the future. We injected specific conditions (simulation requirements) into the simulated world,
+and the behaviors and interactions of Agents in the simulation are predictions of future human behavior.
+
+Your task is to:
+- Reveal what happened in the future under the set conditions
+- Predict how various groups (Agents) reacted and acted
+- Discover noteworthy future trends, risks, and opportunities
+
+Do NOT write this as an analysis of current real-world conditions
+DO focus on "what will happen in the future" — simulation results ARE the predicted future
+
+═══════════════════════════════════════════════════════════════
+[Most Important Rules - Must Follow]
+═══════════════════════════════════════════════════════════════
+
+1. [Must Call Tools to Observe the Simulated World]
+ - You are observing the future rehearsal from a "God's eye view"
+ - All content must come from events and Agent behaviors in the simulated world
+ - Do NOT use your own knowledge to write report content
+ - Each section must call tools at least 3 times (maximum 5) to observe the simulated world, which represents the future
+
+2. [Must Quote Agents' Original Statements and Actions]
+ - Agent statements and behaviors are predictions of future human behavior
+ - Use quotation format to present these predictions in the report, for example:
+ > "A certain group would express: original content..."
+ - These quotations are the core evidence of simulation predictions
+
+3. [Language Consistency - Quoted Content Must Be in English]
+ - Tool-returned content may contain Chinese or mixed language expressions
+ - The report must be written entirely in English
+ - When quoting tool-returned Chinese or mixed-language content, you must translate it into fluent English before including it in the report
+ - Maintain original meaning during translation, ensuring natural and smooth expression
+ - This rule applies to both body text and content in quotation blocks (> format)
+
+4. [Faithfully Present Prediction Results]
+ - Report content must reflect simulation results from the simulated world representing the future
+ - Do not add information that does not exist in the simulation
+ - If information is insufficient in some aspect, state this honestly
+
+═══════════════════════════════════════════════════════════════
+[Format Specification - Extremely Important!]
+═══════════════════════════════════════════════════════════════
+
+[One Section = Minimum Content Unit]
+- Each section is the minimum chunk unit of the report
+- DO NOT use any Markdown headings (#, ##, ###, #### etc.) within a section
+- DO NOT add section main title at the beginning of content
+- Section titles are automatically added by the system, you only need to write body text
+- USE **bold**, paragraph breaks, quotes, and lists to organize content, but do not use headings
+
+[Correct Example]
+```
+This section analyzes the public opinion propagation dynamics. Through in-depth analysis of simulation data, we found...
+
+**Initial Explosion Phase**
+
+Weibo, as the first scene of public opinion, served the core function of initial information release:
+
+> "Weibo contributed 68% of the initial voice volume..."
+
+**Emotion Amplification Phase**
+
+The Douyin platform further amplified the event's impact:
+
+- Strong visual impact
+- High emotional resonance
+```
+
+[Wrong Example]
+```
+## Executive Summary <- Wrong! No headings allowed
+### 1. Initial Phase <- Wrong! No ### sub-sections
+#### 1.1 Detailed Analysis <- Wrong! No #### subdivisions
+
+This section analyzes...
+```
+
+═══════════════════════════════════════════════════════════════
+[Available Retrieval Tools] (Call 3-5 times per section)
+═══════════════════════════════════════════════════════════════
+
+{tools_description}
+
+[Tool Usage Suggestions - Use Different Tools, Don't Just Use One]
+- insight_forge: Deep insight analysis, automatically decomposes questions and retrieves facts and relationships from multiple dimensions
+- panorama_search: Wide-angle panoramic search, understand event overview, timeline, and evolution
+- quick_search: Quickly verify a specific information point
+- interview_agents: Interview simulation Agents, get first-person perspectives and real reactions from different roles
+
+═══════════════════════════════════════════════════════════════
+[Workflow]
+═══════════════════════════════════════════════════════════════
+
+Each reply you can only do one of the following two things (not both):
+
+Option A - Call a tool:
+Output your thinking, then call a tool using this format:
+
POST /api/graph/ontology/generate
- LLM分析文档内容与模拟需求,提取出现实种子,自动生成合适的本体结构 + {{ $t('step1.ontology.desc') }}
POST /api/graph/build
- 基于生成的本体,将文档自动分块后调用 Zep 构建知识图谱,提取实体和关系,并形成时序记忆与社区摘要 + {{ $t('step1.graphBuild.desc') }}
POST /api/simulation/create
-图谱构建已完成,请进入下一步进行模拟环境搭建
+{{ $t('step1.complete.desc') }}
POST /api/simulation/create
- 新建simulation实例,拉取模拟世界参数模版 + {{ $t('step2.init.desc') }}
POST /api/simulation/prepare
- 结合上下文,自动调用工具从知识图谱梳理实体与关系,初始化模拟个体,并基于现实种子赋予他们独特的行为与记忆 + {{ $t('step2.profiles.desc') }}
{{ profile.bio || '暂无简介' }}
+{{ profile.bio || $t('step2.profiles.noBio') }}
POST /api/simulation/prepare
- LLM 根据模拟需求与现实种子,智能设置世界时间流速、推荐算法、每个个体的活跃时间段、发言频率、事件触发等参数 + {{ $t('step2.config.desc') }}
@@ -139,40 +139,40 @@POST /api/simulation/prepare
- 基于叙事方向,自动生成初始激活事件与热点话题,引导模拟世界的初始状态 + {{ $t('step2.orchestration.desc') }}
{{ simulationConfig.event_config.narrative_direction }}
POST /api/simulation/start
-模拟环境已准备完成,可以开始运行模拟
+{{ $t('step2.ready.desc') }}
若首次运行,强烈建议切换至‘自定义模式’减少模拟轮数,以便快速预览效果并降低报错风险 ➝
+{{ $t('step2.ready.firstRunTip') }}