Akbub's picture
deploy: Nexus AI v0.2.0 - SAP C4C Lead Creation UI included in fresh frontend build
d1f3f31
Raw
History Blame Contribute Delete
4.84 kB
import asyncio
from typing import Any, Dict
from pathlib import Path
from datetime import datetime, timezone
from src.nexus_ai.repositories.sqlite import JobRepository
from src.workers.job_queue import AudioJob, InMemoryJobQueue
# Global dictionary to hold job status and results
JOBS: Dict[str, Dict[str, Any]] = {}
queue = InMemoryJobQueue()
JOB_REPOSITORY = JobRepository()
def utc_now() -> str:
return datetime.now(timezone.utc).isoformat().replace("+00:00", "Z")
async def process_audio_job(job_id: str, tmp_path: str, filename: str, transcriber, diarize_fn, analyze_fn):
JOBS[job_id]["status"] = "processing"
JOBS[job_id]["progress_stage"] = "Transcribing"
JOBS[job_id]["progress_percent"] = 20
JOB_REPOSITORY.update(
job_id,
status="processing",
updated_at=utc_now(),
progress_stage="Transcribing",
progress_percent=20,
)
try:
transcriber_instance = transcriber() if callable(transcriber) else transcriber
# We run the heavy tasks in a thread pool to avoid blocking the event loop
transcription = await asyncio.to_thread(transcriber_instance.transcribe, tmp_path)
JOBS[job_id]["progress_stage"] = "Speaker Diarization"
JOBS[job_id]["progress_percent"] = 45
JOB_REPOSITORY.update(
job_id,
status="processing",
updated_at=utc_now(),
progress_stage="Speaker Diarization",
progress_percent=45,
)
diarization = await asyncio.to_thread(diarize_fn, tmp_path, transcription.segments)
JOBS[job_id]["progress_stage"] = "Feature Extraction"
JOBS[job_id]["progress_percent"] = 65
JOB_REPOSITORY.update(
job_id,
status="processing",
updated_at=utc_now(),
progress_stage="Feature Extraction",
progress_percent=65,
)
stages = [
{"id": "upload", "title": "Audio uploaded", "description": filename, "status": "completed"},
{"id": "transcription", "title": "Speech transcription", "description": "Audio converted to text", "status": "completed"},
{"id": "diarization", "title": "Speaker diarization", "description": "Agent and customer turns aligned", "status": "completed"},
{"id": "privacy", "title": "Local PII extraction", "description": "Sensitive details redacted before LLaMA", "status": "completed"},
{"id": "analysis", "title": "Feature extraction", "description": "Sales features extracted", "status": "completed"},
{"id": "prediction", "title": "Conversion scoring", "description": "Lead score calculated", "status": "completed"},
]
result = await analyze_fn(
transcription.text,
source_name=filename,
source_type="audio",
language=transcription.language,
transcription_confidence=transcription.confidence,
whisper_model=transcriber_instance.model_size,
diarization=diarization,
started=JOBS[job_id]["started_at"],
)
from src.services.sap_lead_service import sap_lead_service
result["sapLead"] = await sap_lead_service.create_lead_from_analysis(result)
JOBS[job_id]["status"] = "completed"
JOBS[job_id]["progress_stage"] = "Completed"
JOBS[job_id]["progress_percent"] = 100
JOBS[job_id]["result"] = result
JOB_REPOSITORY.update(
job_id,
status="completed",
result=result,
updated_at=utc_now(),
completed_at=utc_now(),
progress_stage="Completed",
progress_percent=100,
)
except Exception as e:
JOBS[job_id]["status"] = "failed"
JOBS[job_id]["progress_stage"] = "Failed"
JOBS[job_id]["error"] = str(e)
JOB_REPOSITORY.update(
job_id,
status="failed",
error=str(e),
updated_at=utc_now(),
completed_at=utc_now(),
progress_stage="Failed",
)
finally:
if not JOBS[job_id].get("persistent_upload"):
try:
Path(tmp_path).unlink(missing_ok=True)
except OSError:
pass
async def background_worker(transcriber, diarize_fn, analyze_fn):
print("Background worker started.")
while True:
job: AudioJob = await queue.dequeue()
job_id = job.job_id
tmp_path = job.storage_path
filename = job.filename
try:
await process_audio_job(job_id, tmp_path, filename, transcriber, diarize_fn, analyze_fn)
except Exception as e:
print(f"Worker error on job {job_id}: {e}")
finally:
queue.task_done()