Spaces:
Sleeping
Sleeping
| """Feedback Crew for interview analysis using CrewAI.""" | |
| import json | |
| import logging | |
| from typing import Dict, Any, List | |
| from crewai import Agent, Crew, Process, Task | |
| from crewai.project import CrewBase, agent, task, crew | |
| from src.config import crew_openai | |
| from src.schemas.feedback_schemas import FeedbackOutput | |
| logger = logging.getLogger(__name__) | |
| class FeedbackCrew: | |
| """Crew for analyzing interview conversations and generating structured feedback.""" | |
| agents_config = "config/agents.yaml" | |
| tasks_config = "config/tasks.yaml" | |
| def __init__(self, job_offer: Dict[str, Any], cv_content: str, conversation_history: List[Dict[str, Any]], cheat_metrics: Dict[str, Any] = None, gap_analysis: Dict[str, Any] = None): | |
| self.job_offer = json.dumps(job_offer, ensure_ascii=False) | |
| self.cv_content = cv_content | |
| self.conversation_history = json.dumps(conversation_history, ensure_ascii=False) | |
| self.cheat_metrics = json.dumps(cheat_metrics or {}, ensure_ascii=False) | |
| self.gap_analysis = json.dumps(gap_analysis or {}, ensure_ascii=False) | |
| self._llm = crew_openai() | |
| # --- Agents --- | |
| def consistency_analyst(self) -> Agent: | |
| return Agent(config=self.agents_config["consistency_analyst"], llm=self._llm) | |
| def search_analyst(self) -> Agent: | |
| return Agent(config=self.agents_config["search_analyst"], llm=self._llm) | |
| def tech_expert(self) -> Agent: | |
| return Agent(config=self.agents_config["tech_expert"], llm=self._llm) | |
| def business_evaluator(self) -> Agent: | |
| return Agent(config=self.agents_config["business_evaluator"], llm=self._llm) | |
| def final_reporter(self) -> Agent: | |
| return Agent(config=self.agents_config["final_reporter"], llm=self._llm) | |
| # --- Tasks --- | |
| def consistency_task(self) -> Task: | |
| return Task(config=self.tasks_config["consistency_task"]) | |
| def search_task(self) -> Task: | |
| return Task(config=self.tasks_config["search_task"]) | |
| def tech_task(self) -> Task: | |
| return Task(config=self.tasks_config["tech_task"]) | |
| def business_task(self) -> Task: | |
| return Task(config=self.tasks_config["business_task"]) | |
| def reporting_task(self) -> Task: | |
| return Task( | |
| config=self.tasks_config["reporting_task"], | |
| output_pydantic=FeedbackOutput | |
| ) | |
| # --- Crew --- | |
| def crew(self) -> Crew: | |
| return Crew( | |
| agents=self.agents, | |
| tasks=self.tasks, | |
| process=Process.sequential, | |
| verbose=True | |
| ) | |
| # --- Public API --- | |
| def run(self) -> Dict[str, Any]: | |
| """Execute the feedback crew and return structured output.""" | |
| logger.info("Starting Feedback Crew analysis...") | |
| # Safe extraction of job_type from gap_analysis string or dict | |
| job_type = "GENERAL_TECH" | |
| try: | |
| ga_data = json.loads(self.gap_analysis) if isinstance(self.gap_analysis, str) else self.gap_analysis | |
| job_type = ga_data.get("job_type", "GENERAL_TECH") | |
| except: | |
| pass | |
| inputs = { | |
| "job_offer": self.job_offer, | |
| "cv_content": self.cv_content, | |
| "conversation_history": self.conversation_history, | |
| "cheat_metrics": self.cheat_metrics, | |
| "gap_analysis": self.gap_analysis, | |
| "job_type": job_type | |
| } | |
| result = self.crew().kickoff(inputs=inputs) | |
| # Handle structured output | |
| if result.pydantic: | |
| return result.pydantic.model_dump() | |
| elif result.json_dict: | |
| return result.json_dict | |
| else: | |
| logger.warning("No structured output, parsing raw result") | |
| try: | |
| raw_str = str(result.raw) | |
| start = raw_str.find('{') | |
| end = raw_str.rfind('}') + 1 | |
| if start != -1 and end > start: | |
| return json.loads(raw_str[start:end]) | |
| except json.JSONDecodeError as e: | |
| logger.error(f"JSON parsing failed: {e}") | |
| return {"error": "Could not parse output", "raw": str(result.raw)} | |