- 新增 README_CN.md 中文文档 - 新增 frontend/ Vue 3 前端项目 - 新增 web/ FastAPI 后端项目 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
99 lines
3.2 KiB
Python
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() |