from sqlalchemy.orm import Session from app import models from app.services.ai_cleaner import AICleaner from app.services.feishu_client import FeishuClient from app.services.mock_data_service import create_mock_session from app.services.standard_qa_service import refresh_session_counts from app.utils.time_utils import utc_now class TaskRunner: def __init__(self) -> None: self.feishu = FeishuClient() self.ai = AICleaner() async def run( self, db: Session, *, task_type: models.TaskType = models.TaskType.manual_scan, session_id: int | None = None, reprocess: bool = False, ) -> models.TaskRun: task = models.TaskRun(task_type=task_type, task_status=models.TaskStatus.running, started_at=utc_now()) db.add(task) db.commit() db.refresh(task) try: sessions = self._resolve_sessions(db, session_id=session_id) if not sessions and self.feishu.is_mock_mode and session_id is None: sessions = [create_mock_session(db)] task.sessions_scanned = len(sessions) for session in sessions: try: created_count = await self._process_session(db, session, reprocess=reprocess) task.sessions_processed += 1 task.qa_created += created_count except Exception as exc: # noqa: BLE001 task.qa_failed += 1 session.process_status = models.ProcessStatus.failed session.failed_reason = str(exc) task.error_message = str(exc) db.add(session) db.commit() self.feishu.update_session_status(session, session.process_status.value) task.task_status = ( models.TaskStatus.success if task.qa_failed == 0 else models.TaskStatus.partial_success if task.sessions_processed > 0 else models.TaskStatus.failed ) except Exception as exc: # noqa: BLE001 task.task_status = models.TaskStatus.failed task.error_message = str(exc) finally: task.ended_at = utc_now() db.add(task) db.commit() db.refresh(task) return task def _resolve_sessions(self, db: Session, session_id: int | None) -> list[models.FeishuSession]: if session_id is not None: session = db.get(models.FeishuSession, session_id) return [session] if session else [] return self.feishu.scan_unprocessed_sessions(db) async def _process_session(self, db: Session, session: models.FeishuSession, *, reprocess: bool = False) -> int: if reprocess: db.query(models.StandardQAItem).filter(models.StandardQAItem.session_id == session.id).delete() db.query(models.RawQAItem).filter(models.RawQAItem.session_id == session.id).delete() db.commit() session.process_status = models.ProcessStatus.processing session.failed_reason = None db.add(session) db.commit() self.feishu.update_session_status(session, session.process_status.value) transcript = self.feishu.fetch_transcript(session) session.source_text = transcript ai_items = await self.ai.clean_transcript(session.id, transcript) created: list[models.RawQAItem] = [] for index, item in enumerate(ai_items, start=1): raw = models.RawQAItem( session_id=session.id, qa_code=f"{session.session_code}-QA-{index:03d}", raw_question=item["raw_question"], normalized_question=item.get("normalized_question"), raw_answer=item["raw_answer"], normalized_answer=item.get("normalized_answer"), suggested_standard_question=item.get("suggested_standard_question"), suggested_standard_answer=item.get("suggested_standard_answer"), answer_person=item.get("answer_person"), primary_topic=item.get("primary_topic", "其他"), problem_tags=item.get("problem_tags", []), course_stage=item.get("course_stage", "不确定"), audience_tags=item.get("audience_tags", []), emotion_intensity=item.get("emotion_intensity"), risk_level=item.get("risk_level", "medium"), risk_types=item.get("risk_types", []), risk_notes=item.get("risk_notes"), need_desensitization=item.get("need_desensitization", False), desensitization_status=item.get("desensitization_status", "unknown"), review_status=models.ReviewStatus.pending, review_notes=item.get("review_notes"), suggested_to_standard_qa=item.get("suggested_to_standard_qa", True), source_timestamp=item.get("source_timestamp"), ) db.add(raw) created.append(raw) session.process_status = models.ProcessStatus.pending_review db.add(session) db.commit() refresh_session_counts(db, session.id) db.commit() self.feishu.write_raw_qa_items(session, created) self.feishu.update_session_status(session, session.process_status.value) return len(created)