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 | |