This commit is contained in:
95
backend/app/tasks/__init__.py
Normal file
95
backend/app/tasks/__init__.py
Normal file
@@ -0,0 +1,95 @@
|
||||
import json
|
||||
import uuid
|
||||
import redis
|
||||
from app.config import settings
|
||||
from app.models.db import SessionLocal, AnalysisTask, Match
|
||||
from app.core.analyzer import DocumentAnalyzer
|
||||
from app.celery_app import celery_app
|
||||
from datetime import datetime
|
||||
|
||||
_analyzer: DocumentAnalyzer | None = None
|
||||
_redis: redis.Redis | None = None
|
||||
|
||||
|
||||
def get_analyzer() -> DocumentAnalyzer:
|
||||
global _analyzer
|
||||
if _analyzer is None:
|
||||
_analyzer = DocumentAnalyzer()
|
||||
return _analyzer
|
||||
|
||||
|
||||
def get_redis() -> redis.Redis:
|
||||
global _redis
|
||||
if _redis is None:
|
||||
_redis = redis.from_url(settings.REDIS_URL)
|
||||
return _redis
|
||||
|
||||
|
||||
def _publish(task_id: str, stage: str, progress: int):
|
||||
try:
|
||||
get_redis().publish(
|
||||
f"progress:{task_id}",
|
||||
json.dumps({"stage": stage, "progress": progress}),
|
||||
)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
|
||||
@celery_app.task(bind=True, name="tasks.analyze_document")
|
||||
def analyze_document(self, text: str, task_id: str):
|
||||
db = SessionLocal()
|
||||
try:
|
||||
analyzer = get_analyzer()
|
||||
|
||||
_publish(task_id, "fingerprint", 10)
|
||||
exact = analyzer._level_1_exact_match(text)
|
||||
|
||||
_publish(task_id, "fuzzy", 40)
|
||||
fuzzy = analyzer._level_2_fuzzy_match(text)
|
||||
|
||||
_publish(task_id, "semantic", 70)
|
||||
semantic = analyzer._level_3_semantic_match(text)
|
||||
|
||||
matches = exact + fuzzy + semantic
|
||||
overall_similarity = analyzer._calculate_overall_similarity(matches)
|
||||
|
||||
_publish(task_id, "saving", 90)
|
||||
|
||||
task = db.query(AnalysisTask).filter(AnalysisTask.id == task_id).first()
|
||||
if not task:
|
||||
return
|
||||
|
||||
task.status = "completed"
|
||||
task.overall_similarity = overall_similarity
|
||||
task.completed_at = datetime.utcnow()
|
||||
|
||||
for match in matches[:settings.TOP_K_RESULTS]:
|
||||
raw_id = match.get("source_id")
|
||||
try:
|
||||
doc_id = uuid.UUID(str(raw_id)) if raw_id is not None else None
|
||||
except (ValueError, TypeError, AttributeError):
|
||||
doc_id = None
|
||||
|
||||
db.add(Match(
|
||||
task_id=task_id,
|
||||
doc_id=doc_id,
|
||||
similarity=float(match["similarity"]),
|
||||
method=match["method"],
|
||||
fragment_start=match.get("fragment_start"),
|
||||
fragment_end=match.get("fragment_end"),
|
||||
fragment_text=match.get("fragment_text"),
|
||||
))
|
||||
|
||||
db.commit()
|
||||
_publish(task_id, "done", 100)
|
||||
|
||||
except Exception as exc:
|
||||
task = db.query(AnalysisTask).filter(AnalysisTask.id == task_id).first()
|
||||
if task:
|
||||
task.status = "failed"
|
||||
db.commit()
|
||||
_publish(task_id, "failed", 0)
|
||||
raise self.retry(exc=exc, countdown=5, max_retries=2)
|
||||
|
||||
finally:
|
||||
db.close()
|
||||
Reference in New Issue
Block a user