fix(i18n): pass locale to background threads via thread-local storage
Background threads (graph building, simulation prep, report generation, profile generation) now inherit the requesting user's locale preference. Previously these fell back to 'zh' because Flask request context was unavailable in spawned threads.
This commit is contained in:
parent
592ee52f59
commit
7c07237544
|
|
@ -15,7 +15,7 @@ from ..services.graph_builder import GraphBuilderService
|
||||||
from ..services.text_processor import TextProcessor
|
from ..services.text_processor import TextProcessor
|
||||||
from ..utils.file_parser import FileParser
|
from ..utils.file_parser import FileParser
|
||||||
from ..utils.logger import get_logger
|
from ..utils.logger import get_logger
|
||||||
from ..utils.locale import t
|
from ..utils.locale import t, get_locale, set_locale
|
||||||
from ..models.task import TaskManager, TaskStatus
|
from ..models.task import TaskManager, TaskStatus
|
||||||
from ..models.project import ProjectManager, ProjectStatus
|
from ..models.project import ProjectManager, ProjectStatus
|
||||||
|
|
||||||
|
|
@ -371,8 +371,12 @@ def build_graph():
|
||||||
project.graph_build_task_id = task_id
|
project.graph_build_task_id = task_id
|
||||||
ProjectManager.save_project(project)
|
ProjectManager.save_project(project)
|
||||||
|
|
||||||
|
# Capture locale before spawning background thread
|
||||||
|
current_locale = get_locale()
|
||||||
|
|
||||||
# 启动后台任务
|
# 启动后台任务
|
||||||
def build_task():
|
def build_task():
|
||||||
|
set_locale(current_locale)
|
||||||
build_logger = get_logger('mirofish.build')
|
build_logger = get_logger('mirofish.build')
|
||||||
try:
|
try:
|
||||||
build_logger.info(f"[{task_id}] 开始构建图谱...")
|
build_logger.info(f"[{task_id}] 开始构建图谱...")
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ from ..services.simulation_manager import SimulationManager
|
||||||
from ..models.project import ProjectManager
|
from ..models.project import ProjectManager
|
||||||
from ..models.task import TaskManager, TaskStatus
|
from ..models.task import TaskManager, TaskStatus
|
||||||
from ..utils.logger import get_logger
|
from ..utils.logger import get_logger
|
||||||
from ..utils.locale import t
|
from ..utils.locale import t, get_locale, set_locale
|
||||||
|
|
||||||
logger = get_logger('mirofish.api.report')
|
logger = get_logger('mirofish.api.report')
|
||||||
|
|
||||||
|
|
@ -121,8 +121,12 @@ def generate_report():
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Capture locale before spawning background thread
|
||||||
|
current_locale = get_locale()
|
||||||
|
|
||||||
# 定义后台任务
|
# 定义后台任务
|
||||||
def run_generate():
|
def run_generate():
|
||||||
|
set_locale(current_locale)
|
||||||
try:
|
try:
|
||||||
task_manager.update_task(
|
task_manager.update_task(
|
||||||
task_id,
|
task_id,
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@ from ..services.oasis_profile_generator import OasisProfileGenerator
|
||||||
from ..services.simulation_manager import SimulationManager, SimulationStatus
|
from ..services.simulation_manager import SimulationManager, SimulationStatus
|
||||||
from ..services.simulation_runner import SimulationRunner, RunnerStatus
|
from ..services.simulation_runner import SimulationRunner, RunnerStatus
|
||||||
from ..utils.logger import get_logger
|
from ..utils.logger import get_logger
|
||||||
from ..utils.locale import t
|
from ..utils.locale import t, get_locale, set_locale
|
||||||
from ..models.project import ProjectManager
|
from ..models.project import ProjectManager
|
||||||
|
|
||||||
logger = get_logger('mirofish.api.simulation')
|
logger = get_logger('mirofish.api.simulation')
|
||||||
|
|
@ -501,8 +501,12 @@ def prepare_simulation():
|
||||||
state.status = SimulationStatus.PREPARING
|
state.status = SimulationStatus.PREPARING
|
||||||
manager._save_simulation_state(state)
|
manager._save_simulation_state(state)
|
||||||
|
|
||||||
|
# Capture locale before spawning background thread
|
||||||
|
current_locale = get_locale()
|
||||||
|
|
||||||
# 定义后台任务
|
# 定义后台任务
|
||||||
def run_prepare():
|
def run_prepare():
|
||||||
|
set_locale(current_locale)
|
||||||
try:
|
try:
|
||||||
task_manager.update_task(
|
task_manager.update_task(
|
||||||
task_id,
|
task_id,
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ from ..config import Config
|
||||||
from ..models.task import TaskManager, TaskStatus
|
from ..models.task import TaskManager, TaskStatus
|
||||||
from ..utils.zep_paging import fetch_all_nodes, fetch_all_edges
|
from ..utils.zep_paging import fetch_all_nodes, fetch_all_edges
|
||||||
from .text_processor import TextProcessor
|
from .text_processor import TextProcessor
|
||||||
from ..utils.locale import t
|
from ..utils.locale import t, get_locale, set_locale
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
|
|
@ -84,10 +84,13 @@ class GraphBuilderService:
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Capture locale before spawning background thread
|
||||||
|
current_locale = get_locale()
|
||||||
|
|
||||||
# 在后台线程中执行构建
|
# 在后台线程中执行构建
|
||||||
thread = threading.Thread(
|
thread = threading.Thread(
|
||||||
target=self._build_graph_worker,
|
target=self._build_graph_worker,
|
||||||
args=(task_id, text, ontology, graph_name, chunk_size, chunk_overlap, batch_size)
|
args=(task_id, text, ontology, graph_name, chunk_size, chunk_overlap, batch_size, current_locale)
|
||||||
)
|
)
|
||||||
thread.daemon = True
|
thread.daemon = True
|
||||||
thread.start()
|
thread.start()
|
||||||
|
|
@ -102,9 +105,11 @@ class GraphBuilderService:
|
||||||
graph_name: str,
|
graph_name: str,
|
||||||
chunk_size: int,
|
chunk_size: int,
|
||||||
chunk_overlap: int,
|
chunk_overlap: int,
|
||||||
batch_size: int
|
batch_size: int,
|
||||||
|
locale: str = 'zh'
|
||||||
):
|
):
|
||||||
"""图谱构建工作线程"""
|
"""图谱构建工作线程"""
|
||||||
|
set_locale(locale)
|
||||||
try:
|
try:
|
||||||
self.task_manager.update_task(
|
self.task_manager.update_task(
|
||||||
task_id,
|
task_id,
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ from zep_cloud.client import Zep
|
||||||
|
|
||||||
from ..config import Config
|
from ..config import Config
|
||||||
from ..utils.logger import get_logger
|
from ..utils.logger import get_logger
|
||||||
from ..utils.locale import get_language_instruction, t
|
from ..utils.locale import get_language_instruction, get_locale, set_locale, t
|
||||||
from .zep_entity_reader import EntityNode, ZepEntityReader
|
from .zep_entity_reader import EntityNode, ZepEntityReader
|
||||||
|
|
||||||
logger = get_logger('mirofish.oasis_profile')
|
logger = get_logger('mirofish.oasis_profile')
|
||||||
|
|
@ -916,8 +916,12 @@ class OasisProfileGenerator:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.warning(f"实时保存 profiles 失败: {e}")
|
logger.warning(f"实时保存 profiles 失败: {e}")
|
||||||
|
|
||||||
|
# Capture locale before spawning thread pool workers
|
||||||
|
current_locale = get_locale()
|
||||||
|
|
||||||
def generate_single_profile(idx: int, entity: EntityNode) -> tuple:
|
def generate_single_profile(idx: int, entity: EntityNode) -> tuple:
|
||||||
"""生成单个profile的工作函数"""
|
"""生成单个profile的工作函数"""
|
||||||
|
set_locale(current_locale)
|
||||||
entity_type = entity.get_entity_type() or "Entity"
|
entity_type = entity.get_entity_type() or "Entity"
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ from queue import Queue
|
||||||
|
|
||||||
from ..config import Config
|
from ..config import Config
|
||||||
from ..utils.logger import get_logger
|
from ..utils.logger import get_logger
|
||||||
|
from ..utils.locale import get_locale, set_locale
|
||||||
from .zep_graph_memory_updater import ZepGraphMemoryManager
|
from .zep_graph_memory_updater import ZepGraphMemoryManager
|
||||||
from .simulation_ipc import SimulationIPCClient, CommandType, IPCResponse
|
from .simulation_ipc import SimulationIPCClient, CommandType, IPCResponse
|
||||||
|
|
||||||
|
|
@ -455,10 +456,13 @@ class SimulationRunner:
|
||||||
cls._processes[simulation_id] = process
|
cls._processes[simulation_id] = process
|
||||||
cls._save_run_state(state)
|
cls._save_run_state(state)
|
||||||
|
|
||||||
|
# Capture locale before spawning monitor thread
|
||||||
|
current_locale = get_locale()
|
||||||
|
|
||||||
# 启动监控线程
|
# 启动监控线程
|
||||||
monitor_thread = threading.Thread(
|
monitor_thread = threading.Thread(
|
||||||
target=cls._monitor_simulation,
|
target=cls._monitor_simulation,
|
||||||
args=(simulation_id,),
|
args=(simulation_id, current_locale),
|
||||||
daemon=True
|
daemon=True
|
||||||
)
|
)
|
||||||
monitor_thread.start()
|
monitor_thread.start()
|
||||||
|
|
@ -475,8 +479,9 @@ class SimulationRunner:
|
||||||
return state
|
return state
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def _monitor_simulation(cls, simulation_id: str):
|
def _monitor_simulation(cls, simulation_id: str, locale: str = 'zh'):
|
||||||
"""监控模拟进程,解析动作日志"""
|
"""监控模拟进程,解析动作日志"""
|
||||||
|
set_locale(locale)
|
||||||
sim_dir = os.path.join(cls.RUN_STATE_DIR, simulation_id)
|
sim_dir = os.path.join(cls.RUN_STATE_DIR, simulation_id)
|
||||||
|
|
||||||
# 新的日志结构:分平台的动作日志
|
# 新的日志结构:分平台的动作日志
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ from zep_cloud.client import Zep
|
||||||
|
|
||||||
from ..config import Config
|
from ..config import Config
|
||||||
from ..utils.logger import get_logger
|
from ..utils.logger import get_logger
|
||||||
|
from ..utils.locale import get_locale, set_locale
|
||||||
|
|
||||||
logger = get_logger('mirofish.zep_graph_memory_updater')
|
logger = get_logger('mirofish.zep_graph_memory_updater')
|
||||||
|
|
||||||
|
|
@ -276,9 +277,13 @@ class ZepGraphMemoryUpdater:
|
||||||
if self._running:
|
if self._running:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
# Capture locale before spawning background thread
|
||||||
|
current_locale = get_locale()
|
||||||
|
|
||||||
self._running = True
|
self._running = True
|
||||||
self._worker_thread = threading.Thread(
|
self._worker_thread = threading.Thread(
|
||||||
target=self._worker_loop,
|
target=self._worker_loop,
|
||||||
|
args=(current_locale,),
|
||||||
daemon=True,
|
daemon=True,
|
||||||
name=f"ZepMemoryUpdater-{self.graph_id[:8]}"
|
name=f"ZepMemoryUpdater-{self.graph_id[:8]}"
|
||||||
)
|
)
|
||||||
|
|
@ -356,8 +361,9 @@ class ZepGraphMemoryUpdater:
|
||||||
|
|
||||||
self.add_activity(activity)
|
self.add_activity(activity)
|
||||||
|
|
||||||
def _worker_loop(self):
|
def _worker_loop(self, locale: str = 'zh'):
|
||||||
"""后台工作循环 - 按平台批量发送活动到Zep"""
|
"""后台工作循环 - 按平台批量发送活动到Zep"""
|
||||||
|
set_locale(locale)
|
||||||
while self._running or not self._activity_queue.empty():
|
while self._running or not self._activity_queue.empty():
|
||||||
try:
|
try:
|
||||||
# 尝试从队列获取活动(超时1秒)
|
# 尝试从队列获取活动(超时1秒)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
|
|
||||||
from .file_parser import FileParser
|
from .file_parser import FileParser
|
||||||
from .llm_client import LLMClient
|
from .llm_client import LLMClient
|
||||||
from .locale import t, get_locale, get_language_instruction
|
from .locale import t, get_locale, set_locale, get_language_instruction
|
||||||
|
|
||||||
__all__ = ['FileParser', 'LLMClient', 't', 'get_locale', 'get_language_instruction']
|
__all__ = ['FileParser', 'LLMClient', 't', 'get_locale', 'set_locale', 'get_language_instruction']
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import threading
|
||||||
from flask import request, has_request_context
|
from flask import request, has_request_context
|
||||||
|
|
||||||
|
_thread_local = threading.local()
|
||||||
|
|
||||||
_locales_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', 'locales')
|
_locales_dir = os.path.join(os.path.dirname(__file__), '..', '..', '..', 'locales')
|
||||||
|
|
||||||
# Load language registry
|
# Load language registry
|
||||||
|
|
@ -17,10 +20,15 @@ for filename in os.listdir(_locales_dir):
|
||||||
_translations[locale_name] = json.load(f)
|
_translations[locale_name] = json.load(f)
|
||||||
|
|
||||||
|
|
||||||
|
def set_locale(locale: str):
|
||||||
|
"""Set locale for current thread. Call at the start of background threads."""
|
||||||
|
_thread_local.locale = locale
|
||||||
|
|
||||||
|
|
||||||
def get_locale() -> str:
|
def get_locale() -> str:
|
||||||
if has_request_context():
|
if has_request_context():
|
||||||
return request.headers.get('Accept-Language', 'zh')
|
return request.headers.get('Accept-Language', 'zh')
|
||||||
return 'zh'
|
return getattr(_thread_local, 'locale', 'zh')
|
||||||
|
|
||||||
|
|
||||||
def t(key: str, **kwargs) -> str:
|
def t(key: str, **kwargs) -> str:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue