Spaces:
Running
Running
| from datetime import datetime | |
| from pydantic import Field, model_validator, BaseModel | |
| from typing import List, Optional, Union,Type, TypeVar | |
| from bson import ObjectId | |
| import openai | |
| from google import genai | |
| from google.genai import types | |
| import os | |
| from dotenv import load_dotenv | |
| load_dotenv() | |
| GOOGLE_API_KEY=os.getenv("GEMINI_API_KEY") | |
| OPENAI_API_KEY=os.getenv("OPENAI_API_KEY") | |
| T = TypeVar("T", bound=BaseModel) | |
| class AIWrapper: | |
| def __init__(self, provider='openai'): | |
| self.provider = provider.lower() | |
| if self.provider == 'openai': | |
| openai.api_key = OPENAI_API_KEY | |
| elif self.provider == 'gemini': | |
| self.gemini_client = genai.Client( | |
| api_key=GOOGLE_API_KEY, | |
| http_options=types.HttpOptions(api_version='v1alpha') | |
| ) | |
| else: | |
| raise ValueError("Provider must be 'openai' or 'gemini'") | |
| def chat(self, prompt: str,output_schema:Type[T]) -> T: | |
| """ | |
| Generate a response from the AI provider and return it parsed into the specified schema. | |
| Args: | |
| prompt (str): The input prompt. | |
| output_schema (Type[T]): A Pydantic model representing the output schema. | |
| Returns: | |
| T: Parsed AI response as an instance of the output_schema. | |
| """ | |
| if self.provider == 'openai': | |
| return self._openai_chat(prompt) | |
| elif self.provider == 'gemini': | |
| return self._gemini_chat(prompt,output_schema=output_schema) | |
| def _openai_chat(self, prompt: str) -> str: | |
| response = openai.ChatCompletion.create( | |
| model="gpt-4", | |
| messages=[ | |
| {"role": "user", "content": prompt} | |
| ] | |
| ) | |
| return response['choices'][0]['message']['content'] | |
| def _gemini_chat(self, prompt: str, output_schema: Type[T]) -> T: | |
| response = self.gemini_client.models.generate_content( | |
| model='gemini-2.0-flash-001', | |
| contents=prompt, | |
| config=types.GenerateContentConfig( | |
| response_mime_type='application/json', | |
| response_schema=output_schema, | |
| ), | |
| ) | |
| return response.parsed | |
| ai = AIWrapper(provider='gemini') | |
| class UserResilienceScoreCreate(BaseModel): | |
| overallScore: float | |
| userId: str | |
| BreakDownByDomainId: str | |
| FlaggedRiskAreasId: str | |
| BoostSuggestionsId: str | |
| class UserResilienceScoreUpdate(BaseModel): | |
| overallScore: Optional[float]=None | |
| BreakDownByDomainId: Optional[str]=None | |
| FlaggedRiskAreasId: Optional[str]=None | |
| BoostSuggestionsId: Optional[str]=None | |
| class BreakDownByDomainCreate(BaseModel): | |
| userId:str | |
| Technical:float | |
| Creative:float | |
| Strategy:float | |
| Collaboration:float | |
| class BreakDownByDomainUpdate(BaseModel): | |
| Technical:Optional[float]=None | |
| Creative:Optional[float]=None | |
| Strategy:Optional[float]=None | |
| Collaboration:Optional[float]=None | |
| class FlaggedRiskAreasCreate(BaseModel): | |
| userId:str | |
| risk_areas:List[str] | |
| class FlaggedRiskAreasUpdate(BaseModel): | |
| risk_areas:Optional[List[str]]=None | |
| class BoostSuggestionsCreate(BaseModel): | |
| boost_suggestions:List[str] | |
| class ProjectExperienceDetails(BaseModel): | |
| ProjectTitles: str = Field(..., description="The title(s) of the project(s) involved in.") | |
| descriptions: str = Field(..., description="Detailed description of the project and what it entailed.") | |
| RoleInTheProject: str = Field(..., description="The specific role played within the project.") | |
| class WorkExperienceDetails(BaseModel): | |
| JobTitles: str = Field(..., description="The job titles held in past employment.") | |
| JobDescriptions: str = Field(..., description="Summary of responsibilities and duties in these jobs.") | |
| class SoftTransferableSkills(BaseModel): | |
| LeadershipAndCollaborationIndicators: str = Field(..., description="Evidence or examples demonstrating leadership and teamwork.") | |
| CriticalThinkingOrProblemSolvingVerb: str = Field(..., description="Examples of critical thinking or problem solving performed.") | |
| CommunicationSkills: str = Field(None, description="Description of communication skills and contexts.") | |
| CrossFunctionalOrInterdisciplinaryExperience: str = Field(..., description="Experience working across teams or disciplines.") | |
| InitiativeAndAdaptabilityLanguage: str = Field(..., description="Examples of taking initiative and adapting to change.") | |
| class CareerPathInformation(BaseModel): | |
| CurrentOrIntendedRoleOrField: str = Field(..., description="Current or intended professional role or field of work.") | |
| IndustryAndSectorContext: str = Field(..., description="Context about the industry and sector related to the career path.") | |
| CareerTrajectoryTrends: str = Field(..., description="Observed or expected trends in the career trajectory or sector.") | |
| class EvidenceOfUpskillingAndLifelongLearning(BaseModel): | |
| CertificationsCoursesOrBootcampsListed: Optional[List[str]] = Field(None, description="List of certifications, courses, or bootcamps completed.") | |
| SelfInitiatedLearningProjectsOrNonDegreeEducationalAchievements: Optional[List[str]] = Field(None, description="List of personal projects or non-degree achievements.") | |
| ParticipationInHackathonsClubsOrProfessionalCommunities: Optional[List[str]] = Field(None, description="Involvement in hackathons, clubs, or professional groups.") | |
| class AIRelatedKeywords(BaseModel): | |
| AiToolsAndTechnologies: Optional[List[str]] = Field( | |
| None, | |
| description="List of AI tools and technologies mentioned in the resume, e.g., ChatGPT, TensorFlow." | |
| ) | |
| conceptsAndTechniques: Optional[List[str]] = Field( | |
| None, | |
| description="AI concepts or techniques like NLP, computer vision, or reinforcement learning." | |
| ) | |
| aiIntegratedProjectsMentioned: Optional[List[str]] = Field( | |
| None, | |
| description="Names or descriptions of projects where AI was applied." | |
| ) | |
| usageContextDescriptions: Optional[List[str]] = Field( | |
| None, | |
| description="Sentences or phrases describing how AI was used in projects or tasks." | |
| ) | |
| class ResumeData(BaseModel): | |
| workExperienceDetails:Optional[List[WorkExperienceDetails]]=None | |
| listOfExplicitTechnicalSkills:Optional[List[str]]=None | |
| softTransferableSkills:List[SoftTransferableSkills] | |
| projectExperienceDetails:Optional[List[ProjectExperienceDetails]]=None | |
| careerPathInformation:CareerPathInformation | |
| evidenceOfUpskillingAndLifelongLearning:Optional[EvidenceOfUpskillingAndLifelongLearning]=None | |
| aiRelatedKeywords:AIRelatedKeywords | |
| class RealWorldQuestion(BaseModel): | |
| question:str | |
| class AutomationRiskInput(BaseModel): | |
| # Resume background fields | |
| job_title: str = Field(..., description="Most recent job title") | |
| industry: str = Field(..., description="Industry sector (e.g., finance, education, manufacturing)") | |
| years_experience: int = Field(..., ge=0, description="Years of professional experience") | |
| education_level: str = Field(..., description="Highest education level (e.g., Bachelors, Masters, PhD)") | |
| technical_skills: List[str] = Field(default_factory=list, description="List of technical skills") | |
| soft_skills: List[str] = Field(default_factory=list, description="List of soft skills") | |
| managerial_experience: bool = Field(..., description="Has managed teams or projects") | |
| customer_facing_roles: bool = Field(..., description="Has held customer-facing roles") | |
| domain_specialization: Optional[str] = Field(None, description="Specialized domain (e.g., legal, medical)") | |
| recent_certifications: List[str] = Field(default_factory=list, description="Certifications obtained recently") | |
| # Scored traits (all int 0-5) | |
| repetitiveness_score: int = Field(..., ge=0, le=5, description="Repetitiveness of the tasks performed") | |
| creativity_score: int = Field(..., ge=0, le=5, description="Creativity required in the role") | |
| emotional_intelligence_score: int = Field(..., ge=0, le=5, description="Importance of emotional intelligence") | |
| data_driven_tasks_score: int = Field(..., ge=0, le=5, description="Dependence on data-driven tasks") | |
| physical_task_score: int = Field(..., ge=0, le=5, description="Amount of physical/manual work") | |
| decision_making_level: int = Field(..., ge=0, le=5, description="Level of autonomous decision-making") | |
| strategic_thinking_score: int = Field(..., ge=0, le=5, description="Need for strategic thinking") | |
| collaboration_score: int = Field(..., ge=0, le=5, description="Collaboration required in the role") | |
| ai_dependency_score: int = Field(..., ge=0, le=5, description="How much AI tools are already used") | |
| upskilling_index: int = Field(..., ge=0, le=5, description="Recent evidence of upskilling/adaptability") | |
| class AutomationRiskResult(AutomationRiskInput): | |
| result: Optional[int] =0 | |
| def calculate_result(self,cls) -> int: | |
| """ | |
| Calculate the overall automation risk score (0-100) | |
| based on the scored traits. | |
| """ | |
| # Weights for each scored trait (example weights; you can tune these) | |
| weights = { | |
| "repetitiveness_score": 15, | |
| "creativity_score": -10, | |
| "emotional_intelligence_score": -10, | |
| "data_driven_tasks_score": 10, | |
| "physical_task_score": 10, | |
| "decision_making_level": -10, | |
| "strategic_thinking_score": -10, | |
| "collaboration_score": -5, | |
| "ai_dependency_score": 5, | |
| "upskilling_index": -5, | |
| } | |
| # Sum weighted scores | |
| score = 0 | |
| for field, weight in weights.items(): | |
| value = getattr(self, field) | |
| score += value * weight | |
| # Normalize score to 0-100 range | |
| # Minimum possible score | |
| min_score = sum(0 * w for w in weights.values()) | |
| # Maximum possible score | |
| max_score = sum(5 * w if w > 0 else 0 for w in weights.values()) + \ | |
| sum(0 * w if w < 0 else 0 for w in weights.values()) | |
| # Because some weights are negative, min/max can be tricky. | |
| # Let's compute min and max more precisely: | |
| min_score = sum(0 * w if w > 0 else 5 * w for w in weights.values()) | |
| max_score = sum(5 * w if w > 0 else 0 * w for w in weights.values()) | |
| # Clamp the score between min and max | |
| score = max(min_score, min(max_score, score)) | |
| # Map score linearly to 0-100 | |
| normalized_score = int((score - min_score) / (max_score - min_score) * 100) | |
| self.result = normalized_score | |
| return self | |
| class SkillDepthInput(BaseModel): | |
| # Core scoring fields (all 0-5 integers) | |
| years_experience_per_skill: int = Field(..., ge=0, le=5, description="Depth of years experience per skill") | |
| seniority_level: int = Field(..., ge=0, le=5, description="Seniority level in roles held") | |
| certification_presence: int = Field(..., ge=0, le=5, description="Number and relevance of certifications") | |
| breadth_of_skills: int = Field(..., ge=0, le=5, description="Variety and diversity of skills") | |
| technical_skill_depth: int = Field(..., ge=0, le=5, description="Depth in core technical skills") | |
| leadership_skill_depth: int = Field(..., ge=0, le=5, description="Depth in leadership or management skills") | |
| complex_projects_involvement: int = Field(..., ge=0, le=5, description="Involvement in complex projects") | |
| strategic_initiatives_contribution: int = Field(..., ge=0, le=5, description="Contributions to strategic initiatives") | |
| recent_skill_usage_frequency: int = Field(..., ge=0, le=5, description="Frequency of skill usage in recent roles") | |
| continuous_learning_evidence: int = Field(..., ge=0, le=5, description="Evidence of continuous learning or upskilling") | |
| cross_functional_collaboration: int = Field(..., ge=0, le=5, description="Cross-functional collaboration skills") | |
| recognition_awards: int = Field(..., ge=0, le=5, description="Recognition or awards related to skills") | |
| public_speaking_training: int = Field(..., ge=0, le=5, description="Public speaking or training experience") | |
| publications_patents: int = Field(..., ge=0, le=5, description="Publications or patents (if any)") | |
| industry_expertise_depth: int = Field(..., ge=0, le=5, description="Industry-specific expertise depth") | |
| mentoring_coaching_experience: int = Field(..., ge=0, le=5, description="Mentoring or coaching experience") | |
| innovation_ability: int = Field(..., ge=0, le=5, description="Ability to innovate using skills") | |
| adaptability_to_technologies: int = Field(..., ge=0, le=5, description="Adaptability to new technologies") | |
| problem_solving_depth: int = Field(..., ge=0, le=5, description="Problem-solving skills depth") | |
| technical_communication_skills: int = Field(..., ge=0, le=5, description="Communication skills related to technical content") | |
| class SkillDepthResult(SkillDepthInput): | |
| result: Optional[int] =0 | |
| def calculate_result(self) -> None: | |
| fields = [ | |
| self.years_experience_per_skill, | |
| self.seniority_level, | |
| self.certification_presence, | |
| self.breadth_of_skills, | |
| self.technical_skill_depth, | |
| self.leadership_skill_depth, | |
| self.complex_projects_involvement, | |
| self.strategic_initiatives_contribution, | |
| self.recent_skill_usage_frequency, | |
| self.continuous_learning_evidence, | |
| self.cross_functional_collaboration, | |
| self.recognition_awards, | |
| self.public_speaking_training, | |
| self.publications_patents, | |
| self.industry_expertise_depth, | |
| self.mentoring_coaching_experience, | |
| self.innovation_ability, | |
| self.adaptability_to_technologies, | |
| self.problem_solving_depth, | |
| self.technical_communication_skills, | |
| ] | |
| max_total = 5 * len(fields) | |
| total_score = sum(fields) | |
| self.result = int((total_score / max_total) * 100) | |
| return self | |
| class AICollabReadinessInput(BaseModel): | |
| ai_tool_familiarity: int = Field(..., ge=0, le=5, description="Familiarity with AI tools and platforms") | |
| adaptability_to_ai_workflows: int = Field(..., ge=0, le=5, description="Ability to adapt to AI-enhanced workflows") | |
| willingness_to_learn_ai_skills: int = Field(..., ge=0, le=5, description="Motivation and willingness to learn AI skills") | |
| ai_ethics_understanding: int = Field(..., ge=0, le=5, description="Understanding of AI ethics and responsible use") | |
| collaboration_with_ai: int = Field(..., ge=0, le=5, description="Experience or mindset to collaborate effectively with AI systems") | |
| problem_solving_with_ai: int = Field(..., ge=0, le=5, description="Skill in using AI to solve complex problems") | |
| creativity_in_ai_use: int = Field(..., ge=0, le=5, description="Creativity in leveraging AI capabilities") | |
| ai_learning_speed: int = Field(..., ge=0, le=5, description="Speed of learning new AI technologies") | |
| communication_about_ai: int = Field(..., ge=0, le=5, description="Ability to communicate AI concepts effectively") | |
| ai_tool_integration: int = Field(..., ge=0, le=5, description="Skill in integrating AI tools into existing workflows") | |
| class AICollabReadiness(AICollabReadinessInput): | |
| result: Optional[int] =0 | |
| def calculate_result(self) -> None: | |
| fields = [ | |
| self.ai_tool_familiarity, | |
| self.adaptability_to_ai_workflows, | |
| self.willingness_to_learn_ai_skills, | |
| self.ai_ethics_understanding, | |
| self.collaboration_with_ai, | |
| self.problem_solving_with_ai, | |
| self.creativity_in_ai_use, | |
| self.ai_learning_speed, | |
| self.communication_about_ai, | |
| self.ai_tool_integration, | |
| ] | |
| max_total = 5 * len(fields) | |
| total_score = sum(fields) | |
| self.result = int((total_score / max_total) * 100) | |
| return self | |
| class BoostSuggestionsUpdate(BaseModel): | |
| boost_suggestions:List[str] | |
| class UserResilienceScoreOut(UserResilienceScoreCreate): | |
| _id: Optional[ObjectId]=None # Make sure _id can be Optional | |
| id:Optional[str]=None | |
| # To convert MongoDB ObjectId to string | |
| class Config: | |
| json_encoders = { | |
| ObjectId: str | |
| } | |
| # Custom validator to handle the ObjectId conversion if needed | |
| def handle_objectid(cls, values): | |
| if '_id' in values and isinstance(values['_id'], ObjectId): | |
| values['id'] = str(values['_id']) # Convert ObjectId to string | |
| return values | |
| class BreakDownByDomainOut(BreakDownByDomainCreate): | |
| _id: Optional[ObjectId]=None # Make sure _id can be Optional | |
| id:Optional[str]=None | |
| # To convert MongoDB ObjectId to string | |
| class Config: | |
| json_encoders = { | |
| ObjectId: str | |
| } | |
| # Custom validator to handle the ObjectId conversion if needed | |
| def handle_objectid(cls, values): | |
| if '_id' in values and isinstance(values['_id'], ObjectId): | |
| values['id'] = str(values['_id']) # Convert ObjectId to string | |
| return values | |
| class FlaggedRiskAreasOut(FlaggedRiskAreasCreate): | |
| _id: Optional[ObjectId]=None # Make sure _id can be Optional | |
| id:Optional[str]=None | |
| class Config: | |
| json_encoders = { | |
| ObjectId: str | |
| } | |
| # Custom validator to handle the ObjectId conversion if needed | |
| def handle_objectid(cls, values): | |
| if '_id' in values and isinstance(values['_id'], ObjectId): | |
| values['id'] = str(values['_id']) # Convert ObjectId to string | |
| return values | |
| class BoostSuggestionsOut(BoostSuggestionsCreate): | |
| _id: Optional[ObjectId]=None # Make sure _id can be Optional | |
| id:Optional[str]=None | |
| class Config: | |
| json_encoders = { | |
| ObjectId: str | |
| } | |
| # Custom validator to handle the ObjectId conversion if needed | |
| def handle_objectid(cls, values): | |
| if '_id' in values and isinstance(values['_id'], ObjectId): | |
| values['id'] = str(values['_id']) # Convert ObjectId to string | |
| return values | |