bio-nexus-api / app /pipeline /engine.py
Samad14's picture
Add sequencing pipeline (FASTQ -> QC -> alignment -> variant calling -> report)
da793ed verified
Raw
History Blame Contribute Delete
2.8 kB
import asyncio
import logging
from typing import Callable, List, Optional, Any
logger = logging.getLogger(__name__)
ProgressCallback = Optional[Callable[[str, List[str], int], Any]]
class PipelineEngine:
def __init__(self):
from app.tools.blast import BlastTool
from app.tools.uniprot import UniprotTool
from app.tools.alphafold import AlphaFoldTool
from app.pipeline.assembler import ContextAssembler
self.blast = BlastTool()
self.uniprot = UniprotTool()
self.alphafold = AlphaFoldTool()
self.assembler = ContextAssembler()
async def execute(
self,
job_id: str,
sequence: str,
pipeline_type: str = "protein_analysis",
database: str = "uniprotkb_swissprot",
max_hits: int = 10,
progress_callback: ProgressCallback = None,
) -> dict:
steps_completed: List[str] = []
async def _tick(step: str, pct: int) -> None:
steps_completed.append(step)
if progress_callback:
try:
result = progress_callback(job_id, list(steps_completed), pct)
if asyncio.iscoroutine(result):
await result
except Exception as e:
logger.warning(f"[{job_id}] Progress callback error (ignored): {e}")
logger.info(f"[{job_id}] Step 1/3: BLAST")
blast_result = await self.blast.run({
"sequence": sequence,
"database": database,
"max_hits": max_hits,
})
await _tick("blast", 33)
hits: list = blast_result.get("hits") or []
top_accession: Optional[str] = hits[0].get("accession") if hits else None
logger.info(f"[{job_id}] Step 2/3: UniProt (accession={top_accession})")
uniprot_result = (
await self.uniprot.run({"accession": top_accession}) if top_accession else None
)
await _tick("uniprot", 66)
logger.info(f"[{job_id}] Step 3/3: AlphaFold (accession={top_accession})")
alphafold_result = (
await self.alphafold.run({"uniprot_accession": top_accession}) if top_accession else None
)
await _tick("alphafold", 90)
logger.info(f"[{job_id}] Assembling context")
context = self.assembler.assemble(
sequence,
blast_result,
uniprot_result,
alphafold_result,
)
if hasattr(context, "model_dump"):
return context.model_dump()
if hasattr(context, "dict"):
return context.dict()
if not isinstance(context, dict):
return dict(context)
return context