Refactor: Unified pipeline execution, simplified UI, and fixed Docker config

- Backend: Refactored tasks.py to directly invoke run_single_fna_pipeline.py for consistency.
- Backend: Changed output format to ZIP and added auto-cleanup of intermediate files.
- Backend: Fixed language parameter passing in API and tasks.
- Frontend: Removed CRISPR Fusion UI elements from Submit and Monitor views.
- Frontend: Implemented simulated progress bar for better UX.
- Frontend: Restored One-click load button and added result file structure documentation.
- Docker: Fixed critical Restarting loop by removing incorrect image directive in docker-compose.yml.
- Docker: Optimized Dockerfile to correct .pixi environment path issues and prevent accidental deletion of frontend assets.
This commit is contained in:
zly
2026-01-20 20:25:25 +08:00
parent 5067169b0b
commit c75c85c53b
134 changed files with 146457 additions and 996647 deletions

View File

@@ -1,19 +1,4 @@
from celery import Celery
from .config import settings
celery_app = Celery(
"bttoxin",
broker=settings.get_celery_broker_url(),
backend=settings.get_celery_result_backend(),
)
celery_app.conf.update(
task_track_started=True,
worker_prefetch_multiplier=1,
)
"""Celery 配置"""
"""Celery Configuration"""
from celery import Celery
from ..config import settings

View File

@@ -1,72 +0,0 @@
"""Docker 客户端管理"""
import docker
from typing import Dict, Any
from pathlib import Path
import logging
logger = logging.getLogger(__name__)
class DockerManager:
"""Docker 容器管理器"""
def __init__(self, image: str = None):
from ..config import settings
self.client = docker.from_env()
self.image = image or settings.DOCKER_IMAGE
def ensure_image(self) -> bool:
"""确保镜像存在"""
try:
self.client.images.get(self.image)
return True
except docker.errors.ImageNotFound:
logger.info(f"Pulling image {self.image}...")
self.client.images.pull(self.image)
return True
def run_bttoxin_digger(
self,
input_dir: Path,
output_dir: Path,
sequence_type: str = "nucl",
scaf_suffix: str = ".fna",
threads: int = 4
) -> Dict[str, Any]:
"""运行 BtToxin_Digger"""
self.ensure_image()
volumes = {
str(input_dir.absolute()): {'bind': '/data', 'mode': 'ro'},
str(output_dir.absolute()): {'bind': '/results', 'mode': 'rw'}
}
command = [
"/usr/local/env-execute", "BtToxin_Digger",
"--SeqPath", "/data",
"--SequenceType", sequence_type,
"--Scaf_suffix", scaf_suffix,
"--threads", str(threads)
]
try:
container = self.client.containers.run(
self.image,
command=command,
volumes=volumes,
platform="linux/amd64",
detach=True,
remove=False
)
result = container.wait()
logs = container.logs().decode('utf-8')
container.remove()
return {
'success': result['StatusCode'] == 0,
'logs': logs,
'exit_code': result['StatusCode']
}
except Exception as e:
logger.error(f"Error: {e}")
return {'success': False, 'error': str(e)}

View File

@@ -0,0 +1,73 @@
"""本地工具运行器 - 替代 Docker 调用"""
import subprocess
import logging
from pathlib import Path
from typing import Dict, Any
import os
logger = logging.getLogger(__name__)
class ToolRunner:
"""本地工具运行管理器"""
def run_bttoxin_digger(
self,
input_dir: Path,
output_dir: Path,
sequence_type: str = "nucl",
scaf_suffix: str = ".fna",
threads: int = 4
) -> Dict[str, Any]:
"""
在本地环境运行 BtToxin_Digger
使用 'pixi run -e digger' 激活环境
"""
# Ensure output directory exists
output_dir.mkdir(parents=True, exist_ok=True)
# BtToxin_Digger expects to read files from --SeqPath.
# It scans the directory for files matching *suffix.
# We point it to the input directory.
seq_path = input_dir.absolute()
# Construct command
# Note: We run this from output_dir so 'Results/' are created there.
command = [
"pixi", "run", "-e", "digger", "BtToxin_Digger",
"--SeqPath", str(seq_path),
"--SequenceType", sequence_type,
"--Scaf_suffix", scaf_suffix,
"--threads", str(threads)
]
logger.info(f"Running command: {' '.join(command)}")
logger.info(f"Working directory: {output_dir}")
try:
# Run subprocess
# Capture both stdout and stderr
process = subprocess.run(
command,
cwd=str(output_dir),
capture_output=True,
text=True,
check=False,
env=os.environ.copy() # Inherit env vars (PATH, etc)
)
success = (process.returncode == 0)
logs = f"STDOUT:\n{process.stdout}\n\nSTDERR:\n{process.stderr}"
if not success:
logger.error(f"BtToxin_Digger failed with exit code {process.returncode}")
logger.error(process.stderr)
return {
'success': success,
'logs': logs,
'exit_code': process.returncode
}
except Exception as e:
logger.error(f"Execution error: {e}")
return {'success': False, 'error': str(e)}