Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
c8a1bd5
feat(i18n): add shared translation files and language registry
Ghostubborn Apr 1, 2026
2ffadd3
feat(i18n): add Accept-Language header to all API requests
Ghostubborn Apr 1, 2026
0c18e1a
feat(i18n): add backend translation utility with shared locale files
Ghostubborn Apr 1, 2026
22bf50f
feat(i18n): set up vue-i18n with dynamic locale loading
Ghostubborn Apr 1, 2026
8f6110d
feat(i18n): inject language instruction into LLM system prompts
Ghostubborn Apr 1, 2026
3d5e5d0
feat(i18n): add language switcher component to navigation
Ghostubborn Apr 1, 2026
74f673a
feat(i18n): replace hardcoded Chinese in backend API responses with t…
Ghostubborn Apr 1, 2026
7083382
feat(i18n): replace hardcoded Chinese in frontend views with i18n calls
Ghostubborn Apr 1, 2026
fc47ae8
feat(i18n): replace hardcoded Chinese in frontend components with i18…
Ghostubborn Apr 1, 2026
fbaa3db
fix(i18n): fix curly quotes and missing @ alias in vite config
Ghostubborn Apr 1, 2026
f75c648
fix(i18n): replace remaining hardcoded language directives in LLM pro…
Ghostubborn Apr 1, 2026
ffe6369
fix(i18n): fix curly quotes in Home.vue and remove unused dark theme …
Ghostubborn Apr 1, 2026
9d43b77
feat(i18n): replace hardcoded Chinese in backend SSE progress messages
Ghostubborn Apr 1, 2026
e1db8ba
feat(i18n): replace hardcoded Chinese in frontend addLog() messages
Ghostubborn Apr 1, 2026
97aa583
fix(i18n): ensure ontology names stay PascalCase regardless of langua…
Ghostubborn Apr 1, 2026
da2490e
fix(i18n): protect JSON field values from language instruction in con…
Ghostubborn Apr 1, 2026
592ee52
feat(i18n): replace remaining hardcoded Chinese in progress callbacks
Ghostubborn Apr 1, 2026
7c07237
fix(i18n): pass locale to background threads via thread-local storage
Ghostubborn Apr 1, 2026
0e55e4c
feat(i18n): replace remaining Chinese in config generator and profile…
Ghostubborn Apr 1, 2026
3a8451c
feat(i18n): replace remaining hardcoded Chinese in frontend addLog calls
Ghostubborn Apr 1, 2026
380e456
fix(i18n): replace hardcoded Chinese stage names in simulation prepar…
Ghostubborn Apr 1, 2026
1d358fc
feat(i18n): replace expand/collapse Chinese text in Step4Report.vue
Ghostubborn Apr 1, 2026
e79569a
feat(i18n): replace all user-visible Chinese in report_agent.py
Ghostubborn Apr 1, 2026
24e9bee
feat(i18n): replace all user-visible Chinese logger messages in zep_t…
Ghostubborn Apr 1, 2026
6db3f98
fix(i18n): fix English homepage layout with proper font and shorter copy
Ghostubborn Apr 1, 2026
5072a2e
feat(i18n): replace Chinese UI text in Step4Report.vue render functions
Ghostubborn Apr 1, 2026
c6cafdd
fix(i18n): translate world1/world2 platform labels in interview tool …
Ghostubborn Apr 1, 2026
21922da
fix(i18n): improve English layout for homepage left-pane and report t…
Ghostubborn Apr 1, 2026
3929c3a
fix(i18n): further shorten English metrics and improve workflow layout
Ghostubborn Apr 1, 2026
2421010
fix(i18n): fix English workflow desc font size with correct CSS selec…
Ghostubborn Apr 1, 2026
f240490
fix(i18n): validate Accept-Language header against registered locales
Ghostubborn Apr 2, 2026
65df257
chore(deps): upgrade vue-i18n from v9 to v11
Ghostubborn Apr 2, 2026
ed46590
fix(i18n): set HTML lang attribute before Vue mounts via inline script
Ghostubborn Apr 2, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
73 changes: 39 additions & 34 deletions backend/app/api/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from ..services.text_processor import TextProcessor
from ..utils.file_parser import FileParser
from ..utils.logger import get_logger
from ..utils.locale import t, get_locale, set_locale
from ..models.task import TaskManager, TaskStatus
from ..models.project import ProjectManager, ProjectStatus

Expand Down Expand Up @@ -42,9 +43,9 @@ def get_project(project_id: str):
if not project:
return jsonify({
"success": False,
"error": f"项目不存在: {project_id}"
"error": t('api.projectNotFound', id=project_id)
}), 404

return jsonify({
"success": True,
"data": project.to_dict()
Expand Down Expand Up @@ -76,12 +77,12 @@ def delete_project(project_id: str):
if not success:
return jsonify({
"success": False,
"error": f"项目不存在或删除失败: {project_id}"
"error": t('api.projectDeleteFailed', id=project_id)
}), 404

return jsonify({
"success": True,
"message": f"项目已删除: {project_id}"
"message": t('api.projectDeleted', id=project_id)
})


Expand All @@ -95,9 +96,9 @@ def reset_project(project_id: str):
if not project:
return jsonify({
"success": False,
"error": f"项目不存在: {project_id}"
"error": t('api.projectNotFound', id=project_id)
}), 404

# 重置到本体已生成状态
if project.ontology:
project.status = ProjectStatus.ONTOLOGY_GENERATED
Expand All @@ -111,7 +112,7 @@ def reset_project(project_id: str):

return jsonify({
"success": True,
"message": f"项目已重置: {project_id}",
"message": t('api.projectReset', id=project_id),
"data": project.to_dict()
})

Expand Down Expand Up @@ -160,15 +161,15 @@ def generate_ontology():
if not simulation_requirement:
return jsonify({
"success": False,
"error": "请提供模拟需求描述 (simulation_requirement)"
"error": t('api.requireSimulationRequirement')
}), 400

# 获取上传的文件
uploaded_files = request.files.getlist('files')
if not uploaded_files or all(not f.filename for f in uploaded_files):
return jsonify({
"success": False,
"error": "请至少上传一个文档文件"
"error": t('api.requireFileUpload')
}), 400

# 创建项目
Expand Down Expand Up @@ -203,7 +204,7 @@ def generate_ontology():
ProjectManager.delete_project(project.project_id)
return jsonify({
"success": False,
"error": "没有成功处理任何文档,请检查文件格式"
"error": t('api.noDocProcessed')
}), 400

# 保存提取的文本
Expand Down Expand Up @@ -285,12 +286,12 @@ def build_graph():
# 检查配置
errors = []
if not Config.ZEP_API_KEY:
errors.append("ZEP_API_KEY未配置")
errors.append(t('api.zepApiKeyMissing'))
if errors:
logger.error(f"配置错误: {errors}")
return jsonify({
"success": False,
"error": "配置错误: " + "; ".join(errors)
"error": t('api.configError', details="; ".join(errors))
}), 500

# 解析请求
Expand All @@ -301,30 +302,30 @@ def build_graph():
if not project_id:
return jsonify({
"success": False,
"error": "请提供 project_id"
"error": t('api.requireProjectId')
}), 400

# 获取项目
project = ProjectManager.get_project(project_id)
if not project:
return jsonify({
"success": False,
"error": f"项目不存在: {project_id}"
"error": t('api.projectNotFound', id=project_id)
}), 404

# 检查项目状态
force = data.get('force', False) # 强制重新构建

if project.status == ProjectStatus.CREATED:
return jsonify({
"success": False,
"error": "项目尚未生成本体,请先调用 /ontology/generate"
"error": t('api.ontologyNotGenerated')
}), 400

if project.status == ProjectStatus.GRAPH_BUILDING and not force:
return jsonify({
"success": False,
"error": "图谱正在构建中,请勿重复提交。如需强制重建,请添加 force: true",
"error": t('api.graphBuilding'),
"task_id": project.graph_build_task_id
}), 400

Expand All @@ -349,15 +350,15 @@ def build_graph():
if not text:
return jsonify({
"success": False,
"error": "未找到提取的文本内容"
"error": t('api.textNotFound')
}), 400

# 获取本体
ontology = project.ontology
if not ontology:
return jsonify({
"success": False,
"error": "未找到本体定义"
"error": t('api.ontologyNotFound')
}), 400

# 创建异步任务
Expand All @@ -370,15 +371,19 @@ def build_graph():
project.graph_build_task_id = task_id
ProjectManager.save_project(project)

# Capture locale before spawning background thread
current_locale = get_locale()

# 启动后台任务
def build_task():
set_locale(current_locale)
build_logger = get_logger('mirofish.build')
try:
build_logger.info(f"[{task_id}] 开始构建图谱...")
task_manager.update_task(
task_id,
status=TaskStatus.PROCESSING,
message="初始化图谱构建服务..."
message=t('progress.initGraphService')
)

# 创建图谱构建服务
Expand All @@ -387,7 +392,7 @@ def build_task():
# 分块
task_manager.update_task(
task_id,
message="文本分块中...",
message=t('progress.textChunking'),
progress=5
)
chunks = TextProcessor.split_text(
Expand All @@ -400,7 +405,7 @@ def build_task():
# 创建图谱
task_manager.update_task(
task_id,
message="创建Zep图谱...",
message=t('progress.creatingZepGraph'),
progress=10
)
graph_id = builder.create_graph(name=graph_name)
Expand All @@ -412,7 +417,7 @@ def build_task():
# 设置本体
task_manager.update_task(
task_id,
message="设置本体定义...",
message=t('progress.settingOntology'),
progress=15
)
builder.set_ontology(graph_id, ontology)
Expand All @@ -428,7 +433,7 @@ def add_progress_callback(msg, progress_ratio):

task_manager.update_task(
task_id,
message=f"开始添加 {total_chunks} 个文本块...",
message=t('progress.addingChunks', count=total_chunks),
progress=15
)

Expand All @@ -442,7 +447,7 @@ def add_progress_callback(msg, progress_ratio):
# 等待Zep处理完成(查询每个episode的processed状态)
task_manager.update_task(
task_id,
message="等待Zep处理数据...",
message=t('progress.waitingZepProcess'),
progress=55
)

Expand All @@ -459,7 +464,7 @@ def wait_progress_callback(msg, progress_ratio):
# 获取图谱数据
task_manager.update_task(
task_id,
message="获取图谱数据...",
message=t('progress.fetchingGraphData'),
progress=95
)
graph_data = builder.get_graph_data(graph_id)
Expand All @@ -476,7 +481,7 @@ def wait_progress_callback(msg, progress_ratio):
task_manager.update_task(
task_id,
status=TaskStatus.COMPLETED,
message="图谱构建完成",
message=t('progress.graphBuildComplete'),
progress=100,
result={
"project_id": project_id,
Expand All @@ -499,7 +504,7 @@ def wait_progress_callback(msg, progress_ratio):
task_manager.update_task(
task_id,
status=TaskStatus.FAILED,
message=f"构建失败: {str(e)}",
message=t('progress.buildFailed', error=str(e)),
error=traceback.format_exc()
)

Expand All @@ -512,7 +517,7 @@ def wait_progress_callback(msg, progress_ratio):
"data": {
"project_id": project_id,
"task_id": task_id,
"message": "图谱构建任务已启动,请通过 /task/{task_id} 查询进度"
"message": t('api.graphBuildStarted', taskId=task_id)
}
})

Expand All @@ -536,7 +541,7 @@ def get_task(task_id: str):
if not task:
return jsonify({
"success": False,
"error": f"任务不存在: {task_id}"
"error": t('api.taskNotFound', id=task_id)
}), 404

return jsonify({
Expand Down Expand Up @@ -570,7 +575,7 @@ def get_graph_data(graph_id: str):
if not Config.ZEP_API_KEY:
return jsonify({
"success": False,
"error": "ZEP_API_KEY未配置"
"error": t('api.zepApiKeyMissing')
}), 500

builder = GraphBuilderService(api_key=Config.ZEP_API_KEY)
Expand Down Expand Up @@ -598,15 +603,15 @@ def delete_graph(graph_id: str):
if not Config.ZEP_API_KEY:
return jsonify({
"success": False,
"error": "ZEP_API_KEY未配置"
"error": t('api.zepApiKeyMissing')
}), 500

builder = GraphBuilderService(api_key=Config.ZEP_API_KEY)
builder.delete_graph(graph_id)

return jsonify({
"success": True,
"message": f"图谱已删除: {graph_id}"
"message": t('api.graphDeleted', id=graph_id)
})

except Exception as e:
Expand Down
Loading