translation comment code - backend - models folder

This commit is contained in:
ththu0205 2026-03-24 16:51:40 +00:00 committed by TQuynh109
parent 985f89f49a
commit 950e8a80cb
2 changed files with 88 additions and 87 deletions

View File

@ -1,6 +1,7 @@
"""
项目上下文管理
用于在服务端持久化项目状态避免前端在接口间传递大量数据
Quản context (ngữ cảnh) của dự án
Được sử dụng để lưu trữ trạng thái dự án trên server (persistence),
giúp tránh việc frontend phải gửi đi một lượng lớn dữ liệu mỗi lần gọi API.
"""
import os
@ -15,45 +16,45 @@ from ..config import Config
class ProjectStatus(str, Enum):
"""项目状态"""
CREATED = "created" # 刚创建,文件已上传
ONTOLOGY_GENERATED = "ontology_generated" # 本体已生成
GRAPH_BUILDING = "graph_building" # 图谱构建中
GRAPH_COMPLETED = "graph_completed" # 图谱构建完成
FAILED = "failed" # 失败
"""Trạng thái hiện tại của dự án"""
CREATED = "created" # Dự án vừa được tạo, các file đã được tải lên thành công
ONTOLOGY_GENERATED = "ontology_generated" # Đã hoàn tất khởi tạo Ontology
GRAPH_BUILDING = "graph_building" # Tri thức đồ thị (Knowledge Graph) đang được xây dựng
GRAPH_COMPLETED = "graph_completed" # Đã hoàn thành quá trình Graph
FAILED = "failed" # Thiết lập / Xử lý gặp lỗi
@dataclass
class Project:
"""项目数据模型"""
"""Mô hình dữ liệu (Data model) của dự án"""
project_id: str
name: str
status: ProjectStatus
created_at: str
updated_at: str
# 文件信息
# File information
files: List[Dict[str, str]] = field(default_factory=list) # [{filename, path, size}]
total_text_length: int = 0
# 本体信息接口1生成后填充
# Thông tin ontology (được điền sau khi API 1 xử lý xong)
ontology: Optional[Dict[str, Any]] = None
analysis_summary: Optional[str] = None
# 图谱信息接口2完成后填充
# Thông tin graph (được điền sau khi API 2 hoàn thành)
graph_id: Optional[str] = None
graph_build_task_id: Optional[str] = None
# 配置
# Cấu hình
simulation_requirement: Optional[str] = None
chunk_size: int = 500
chunk_overlap: int = 50
# 错误信息
# Thông tin lỗi
error: Optional[str] = None
def to_dict(self) -> Dict[str, Any]:
"""转换为字典"""
"""Biến đổi đối tượng (Object) thành Dictionary (để dễ dàng chuyển thành JSON và lưu trữ)"""
return {
"project_id": self.project_id,
"name": self.name,
@ -74,7 +75,7 @@ class Project:
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'Project':
"""从字典创建"""
"""Khởi tạo một instance Project từ dữ liệu kiểu Dictionary (khi load lên từ hệ thống lưu trữ)"""
status = data.get('status', 'created')
if isinstance(status, str):
status = ProjectStatus(status)
@ -99,46 +100,46 @@ class Project:
class ProjectManager:
"""项目管理器 - 负责项目的持久化存储和检索"""
"""Quản lý các dự án (ProjectManager) - Chịu trách nhiệm lưu trữ và truy xuất thông tin dự án"""
# 项目存储根目录
# Thư mục gốc để lưu trữ toàn bộ dữ liệu dự án trên máy chủ
PROJECTS_DIR = os.path.join(Config.UPLOAD_FOLDER, 'projects')
@classmethod
def _ensure_projects_dir(cls):
"""确保项目目录存在"""
"""Đảm bảo thư mục lưu trữ dự án đã được tạo, nếu không có thì self tạo mới"""
os.makedirs(cls.PROJECTS_DIR, exist_ok=True)
@classmethod
def _get_project_dir(cls, project_id: str) -> str:
"""获取项目目录路径"""
"""Đường dẫn tới thư mục lưu trữ tương ứng với project_id"""
return os.path.join(cls.PROJECTS_DIR, project_id)
@classmethod
def _get_project_meta_path(cls, project_id: str) -> str:
"""获取项目元数据文件路径"""
"""Đường dẫn lấy file cài đặt metadata (thường là project.json)"""
return os.path.join(cls._get_project_dir(project_id), 'project.json')
@classmethod
def _get_project_files_dir(cls, project_id: str) -> str:
"""获取项目文件存储目录"""
"""Đường dẫn đến thư mục chứa các file nguyên thuỷ do người dùng kéo thả tải lên cho dự án"""
return os.path.join(cls._get_project_dir(project_id), 'files')
@classmethod
def _get_project_text_path(cls, project_id: str) -> str:
"""获取项目提取文本存储路径"""
"""Lấy vị trí của tệp văn bản (txt) đã được hệ thống trích xuất nội dung"""
return os.path.join(cls._get_project_dir(project_id), 'extracted_text.txt')
@classmethod
def create_project(cls, name: str = "Unnamed Project") -> Project:
"""
创建新项目
Khởi tạo tạo mới cấu trúc dự án trên server
Args:
name: 项目名称
name: Tên của dự án
Returns:
新创建的Project对象
Project object vừa được tạo
"""
cls._ensure_projects_dir()
@ -153,20 +154,20 @@ class ProjectManager:
updated_at=now
)
# 创建项目目录结构
# Thiết lập các thư mục con trong không gian thư mục của project
project_dir = cls._get_project_dir(project_id)
files_dir = cls._get_project_files_dir(project_id)
os.makedirs(project_dir, exist_ok=True)
os.makedirs(files_dir, exist_ok=True)
# 保存项目元数据
# Ghi các trường thông tin (metadata) của project vào file cứng
cls.save_project(project)
return project
@classmethod
def save_project(cls, project: Project) -> None:
"""保存项目元数据"""
"""Ghi chồng cấu hình cập nhật (metadata mới) đối của project vào file (Mặc định: project.json) """
project.updated_at = datetime.now().isoformat()
meta_path = cls._get_project_meta_path(project.project_id)
@ -176,10 +177,10 @@ class ProjectManager:
@classmethod
def get_project(cls, project_id: str) -> Optional[Project]:
"""
获取项目
Get Project
Args:
project_id: 项目ID
project_id: Project ID
Returns:
Project对象如果不存在返回None
@ -197,13 +198,13 @@ class ProjectManager:
@classmethod
def list_projects(cls, limit: int = 50) -> List[Project]:
"""
列出所有项目
Lấy danh sách tất cả các dự án (projects) đang trên system
Args:
limit: 返回数量限制
limit: Giới hạn số lượng hiển thị (mặc định lấy 50 project)
Returns:
项目列表按创建时间倒序
Danh sách gồm các Object Project, xếp theo ngày/giờ giảm dần (từ mới tạo -> nhất)
"""
cls._ensure_projects_dir()
@ -213,7 +214,7 @@ class ProjectManager:
if project:
projects.append(project)
# 按创建时间倒序排序
# Sắp xếp lại lịch sử project theo thứ tự giảm dần thời gian
projects.sort(key=lambda p: p.created_at, reverse=True)
return projects[:limit]
@ -221,47 +222,47 @@ class ProjectManager:
@classmethod
def delete_project(cls, project_id: str) -> bool:
"""
删除项目及其所有文件
Xoá vĩnh viễn dữ liệu về project mọi file liên quan của khỏi server
Args:
project_id: 项目ID
project_id: ID của Project
Returns:
是否删除成功
Boolean đại diện cờ Thành công / Thất bại của việc xoá
"""
project_dir = cls._get_project_dir(project_id)
if not os.path.exists(project_dir):
return False
shutil.rmtree(project_dir)
shutil.rmtree(project_dir) # Xoá toàn bộ thư mục dữ liệu project_id
return True
@classmethod
def save_file_to_project(cls, project_id: str, file_storage, original_filename: str) -> Dict[str, str]:
"""
保存上传的文件到项目目录
Ghi dữ liệu file đính kèm người dùng upload lên vào kho dự án
Args:
project_id: 项目ID
file_storage: Flask的FileStorage对象
original_filename: 原始文件名
project_id: định danh của Project
file_storage: Đối tượng Request File (từ framework, VD: của thư viện Flask/FastAPI) chứa nội dung file byte
original_filename: Tên ban đầu từ máy tính người dùng
Returns:
文件信息字典 {filename, path, size}
Object chứa kết quả lưu file mới gồm {tên ban đầu, tên hash được lưu, đường dẫn đầy đủ, dung lượng}
"""
files_dir = cls._get_project_files_dir(project_id)
os.makedirs(files_dir, exist_ok=True)
# 生成安全的文件名
# Biến đổi tên file thành chuỗi an toàn độc nhất (UUID) để giữ các phiên bản không bị ghi đè, với phần mở rộng ban đầu
ext = os.path.splitext(original_filename)[1].lower()
safe_filename = f"{uuid.uuid4().hex[:8]}{ext}"
file_path = os.path.join(files_dir, safe_filename)
# 保存文件
# Uỷ quyền lưu vào đường dẫn đích
file_storage.save(file_path)
# 获取文件大小
# Đếm kích thước dung lượng (byte) của tập tin tĩnh tại ổ cứng
file_size = os.path.getsize(file_path)
return {
@ -273,14 +274,14 @@ class ProjectManager:
@classmethod
def save_extracted_text(cls, project_id: str, text: str) -> None:
"""保存提取的文本"""
"""Tạo/ghi văn bản trích xuất (từ nội dung phân tích File upload) cho dự án vào folder dữ liệu"""
text_path = cls._get_project_text_path(project_id)
with open(text_path, 'w', encoding='utf-8') as f:
f.write(text)
@classmethod
def get_extracted_text(cls, project_id: str) -> Optional[str]:
"""获取提取的文本"""
"""Đọc và lấy nội dung File văn bản được trích xuất nếu có trước đó"""
text_path = cls._get_project_text_path(project_id)
if not os.path.exists(text_path):
@ -291,7 +292,7 @@ class ProjectManager:
@classmethod
def get_project_files(cls, project_id: str) -> List[str]:
"""获取项目的所有文件路径"""
"""Lấy danh sách link đường dẫn gốc (absolute path) của các files (Tài liệu upload) thuộc dự án này"""
files_dir = cls._get_project_files_dir(project_id)
if not os.path.exists(files_dir):

View File

@ -1,6 +1,6 @@
"""
任务状态管理
用于跟踪长时间运行的任务如图谱构建
Quản trạng thái Task (tác vụ)
Được sử dụng để theo dõi các tác vụ chạy ngầm mất nhiều thời gian ( dụ: xây dựng Knowledge Graph)
"""
import uuid
@ -12,30 +12,30 @@ from dataclasses import dataclass, field
class TaskStatus(str, Enum):
"""任务状态枚举"""
PENDING = "pending" # 等待中
PROCESSING = "processing" # 处理中
COMPLETED = "completed" # 已完成
FAILED = "failed" # 失败
"""Định nghĩa các trạng thái (Enum) mà một Task có thể có"""
PENDING = "pending" # Đang chờ (Task mới được tạo, chưa được xử lý)
PROCESSING = "processing" # Đang xử lý (Hệ thống đang chạy ngầm Task này)
COMPLETED = "completed" # Đã hoàn thành thành công
FAILED = "failed" # Xảy ra lỗi và thất bại
@dataclass
class Task:
"""任务数据类"""
"""Lớp dữ liệu lưu trữ thông tin của một Task cụ thể"""
task_id: str
task_type: str
status: TaskStatus
created_at: datetime
updated_at: datetime
progress: int = 0 # 总进度百分比 0-100
message: str = "" # 状态消息
result: Optional[Dict] = None # 任务结果
error: Optional[str] = None # 错误信息
metadata: Dict = field(default_factory=dict) # 额外元数据
progress_detail: Dict = field(default_factory=dict) # 详细进度信息
progress: int = 0 # Phần trăm tiến độ quá trình chạy (0-100)
message: str = "" # Thông báo trạng thái hiện tại để hiển thị cho người dùng
result: Optional[Dict] = None # Kết quả trả về sau khi Task chạy xong
error: Optional[str] = None # Thông tin chi tiết mỗi khi Task bị lỗi
metadata: Dict = field(default_factory=dict) # Siêu dữ liệu bổ sung kèm theo (ví dụ: project_id)
progress_detail: Dict = field(default_factory=dict) # Nội dung thông tin chi tiết về các bước trong tiến trình
def to_dict(self) -> Dict[str, Any]:
"""转换为字典"""
"""Chuyển đổi Class thành Dictionary để map vào JSON API Response"""
return {
"task_id": self.task_id,
"task_type": self.task_type,
@ -53,15 +53,15 @@ class Task:
class TaskManager:
"""
任务管理器
线程安全的任务状态管理
Trình quản Task
Đảm bảo quản trạng thái của các tác vụ được đồng bộ tốt trên nhiều luồng chạy (Thread-safe)
"""
_instance = None
_lock = threading.Lock()
def __new__(cls):
"""单例模式"""
"""Kế thừa Singleton Pattern (Chỉ khởi tạo 1 instance duy nhất trên toàn ứng dụng)"""
if cls._instance is None:
with cls._lock:
if cls._instance is None:
@ -72,14 +72,14 @@ class TaskManager:
def create_task(self, task_type: str, metadata: Optional[Dict] = None) -> str:
"""
创建新任务
Tạo mới một Task cho vào hàng đợi (quản state)
Args:
task_type: 任务类型
metadata: 额外元数据
task_type: Loại tác vụ (vd: 'build_graph', 'generate_report', ...)
metadata: Dữ liệu đính kèm (vd: project_id liên quan để cập nhật dữ liệu sau này)
Returns:
任务ID
Chuỗi định danh ngẫu nhiên (UUID) của Task
"""
task_id = str(uuid.uuid4())
now = datetime.now()
@ -99,7 +99,7 @@ class TaskManager:
return task_id
def get_task(self, task_id: str) -> Optional[Task]:
"""获取任务"""
"""Lấy thông tin một Task đang chạy/kết thúc dựa theo Task UUID"""
with self._task_lock:
return self._tasks.get(task_id)
@ -114,16 +114,16 @@ class TaskManager:
progress_detail: Optional[Dict] = None
):
"""
更新任务状态
Cập nhật tiến trình của Task
Args:
task_id: 任务ID
status: 新状态
progress: 进度
message: 消息
result: 结果
error: 错误信息
progress_detail: 详细进度信息
task_id: ID của Task đang chạy
status: Trạng thái cập nhật (Pending, Processing, Completed, Failed)
progress: % Tiến độ hiện tại
message: Tin nhắn tả ngắn gọn hiện trạng làm
result: Trả về kết quả đầu ra khi thành công
error: Lời nhắn/Exception khi thất bại
progress_detail: Các sub-tiến trình chi tiết
"""
with self._task_lock:
task = self._tasks.get(task_id)
@ -143,26 +143,26 @@ class TaskManager:
task.progress_detail = progress_detail
def complete_task(self, task_id: str, result: Dict):
"""标记任务完成"""
"""Hành động đánh dấu tác vụ đã kết thúc Thành Công và gán 100% cho progress"""
self.update_task(
task_id,
status=TaskStatus.COMPLETED,
progress=100,
message="任务完成",
message="The task has been completed!",
result=result
)
def fail_task(self, task_id: str, error: str):
"""标记任务失败"""
"""Hành động đánh dấu tác vụ đã Thất Bại do lỗi"""
self.update_task(
task_id,
status=TaskStatus.FAILED,
message="任务失败",
message="The task has an error!?",
error=error
)
def list_tasks(self, task_type: Optional[str] = None) -> list:
"""列出任务"""
"""Liệt kê danh sách tất cả các Task (Hoặc filter theo type của task)"""
with self._task_lock:
tasks = list(self._tasks.values())
if task_type:
@ -170,7 +170,7 @@ class TaskManager:
return [t.to_dict() for t in sorted(tasks, key=lambda x: x.created_at, reverse=True)]
def cleanup_old_tasks(self, max_age_hours: int = 24):
"""清理旧任务"""
"""Dọn dẹp/xoá khỏi bộ nhớ các Task đã cũ (Đã hoàn thành hoặc lỗi sau N giờ) để tránh rò rỉ hoặc xài tốn RAM"""
from datetime import timedelta
cutoff = datetime.now() - timedelta(hours=max_age_hours)