Files
bttoxin-pipeline/web/backend/models.py
hotwa 4c9a7d0978 docs: 添加中文文档,新增前端和后端代码
- 新增 README_CN.md 中文文档
- 新增 frontend/ Vue 3 前端项目
- 新增 web/ FastAPI 后端项目

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2026-01-08 22:31:06 +08:00

99 lines
3.2 KiB
Python

"""Data models for BtToxin Pipeline Web Backend.
Defines TaskStatus, PipelineStage enums and TaskMeta dataclass.
Requirements: 2.2
"""
from dataclasses import dataclass, field, asdict
from datetime import datetime
from enum import Enum
from typing import Optional
import json
class TaskStatus(str, Enum):
"""Task execution status.
Status flow: PENDING -> QUEUED -> RUNNING -> COMPLETED/FAILED
"""
PENDING = "pending" # Waiting to be processed
QUEUED = "queued" # In queue, waiting for pipeline slot
RUNNING = "running" # Currently executing
COMPLETED = "completed" # Successfully finished
FAILED = "failed" # Execution failed
class PipelineStage(str, Enum):
"""Pipeline execution stages.
Stage progression: DIGGER -> SHOTER -> PLOTS -> BUNDLE
"""
DIGGER = "digger" # Running BtToxin_Digger
SHOTER = "shoter" # Running Shoter scoring
PLOTS = "plots" # Generating heatmap plots
BUNDLE = "bundle" # Bundling results
@dataclass
class TaskMeta:
"""Task metadata stored in Redis and task_meta.json.
Contains all information about a task's state and execution.
"""
task_id: str
status: TaskStatus = TaskStatus.PENDING
current_stage: Optional[PipelineStage] = None
progress: int = 0 # 0-100
submission_time: str = "" # ISO8601 format
start_time: Optional[str] = None # ISO8601 format
completion_time: Optional[str] = None # ISO8601 format
filename: str = ""
file_size: int = 0
lang: str = "en" # en or zh
error_message: Optional[str] = None
error_stage: Optional[str] = None
token_hash: str = "" # SHA256 hash of access_token
def to_dict(self) -> dict:
"""Convert to dictionary for JSON serialization."""
data = asdict(self)
# Convert enums to their string values
if self.status:
data["status"] = self.status.value
if self.current_stage:
data["current_stage"] = self.current_stage.value
return data
def to_json(self) -> str:
"""Serialize to JSON string."""
return json.dumps(self.to_dict())
@classmethod
def from_dict(cls, data: dict) -> "TaskMeta":
"""Create TaskMeta from dictionary."""
# Convert string status to enum
if "status" in data and isinstance(data["status"], str):
data["status"] = TaskStatus(data["status"])
# Convert string stage to enum
if "current_stage" in data and data["current_stage"] is not None:
if isinstance(data["current_stage"], str):
data["current_stage"] = PipelineStage(data["current_stage"])
return cls(**data)
@classmethod
def from_json(cls, json_str: str) -> "TaskMeta":
"""Create TaskMeta from JSON string."""
return cls.from_dict(json.loads(json_str))
def get_elapsed_seconds(self) -> Optional[float]:
"""Calculate elapsed time in seconds."""
if not self.submission_time:
return None
start = datetime.fromisoformat(self.submission_time)
if self.completion_time:
end = datetime.fromisoformat(self.completion_time)
else:
end = datetime.utcnow()
return (end - start).total_seconds()