from pydantic import BaseModel, Field, conlist from typing import List, Optional, Sequence, Annotated, Dict from langchain_core.messages import BaseMessage from langgraph.graph.message import add_messages class InitialInput(BaseModel): """Raw input from the user.""" resume_text: str = Field(default="", description="Raw text extracted from the resume") personal_text: Optional[str] = Field(default=None, description="Additional personal information provided by the user") job_text: Optional[str] = Field(default=None, description="Job description or position-related text") ### These are classes for the build_reference_material_node class PersonalStory(BaseModel): """Key moments that can be used as storytelling elements""" challenge: str = Field(description="Specific challenge or obstacle faced") action: str = Field(description="How they addressed the challenge") result: str = Field(description="Outcome and impact of their actions") lessons_learned: str = Field(description="Key takeaways from this experience") class MotivationalElements(BaseModel): """Core elements that drive the person""" key_values: List[str] = Field( description="Personal and professional values demonstrated in their history" ) proud_moments: List[str] = Field( description="Achievements they speak about with genuine enthusiasm" ) impact_areas: List[str] = Field( description="Areas where they've made meaningful differences" ) class RoleConnection(BaseModel): """Structured connection between experience and target role""" experience: str = Field(description="Relevant past experience") role_requirement: str = Field(description="Matching requirement in target role") strength_level: str = Field(description="How strongly this experience matches") class ReferenceMaterial(BaseModel): """Essential elements for creating a motivational speech""" core_narrative: str = Field( description="The main theme that emerges from their background and aspirations" ) compelling_stories: List[PersonalStory] = Field( default_factory=list, description="Key stories that can be used to illustrate their journey" ) motivation_profile: MotivationalElements = Field( description="Elements that genuinely motivate the person" ) role_summary: str = Field( description="A summary of the target role and its key requirements" ) target_role_connections: List[RoleConnection] = Field( default_factory=list, description="Clear connections between their experiences and the target role" ) authenticity_markers: List[str] = Field( description="Genuine aspects of their personality and experience that make their story unique" ) # class ReferenceMaterial(BaseModel): # """Structured analysis of candidate background and target position.""" # personal_history_summary: str = Field( # description="Summary of candidate's career background and key achievements" # ) # aspiring_position_summary: str = Field( # description="Overview of the target role and its key requirements" # ) # personal_focus_points: List[str] = Field( # default_factory=list, # description="Key points highlighting candidate's relevant experiences and skills" # ) # aspiring_position_focus_points: List[str] = Field( # default_factory=list, # description="Essential requirements and expectations of the target role" # ) ### These are the classes for the generate_questions_node class AnswerChoice(BaseModel): """Single answer choice for a question""" text: str = Field(description="The answer option text") category: str = Field(description="Simple category this answer aligns with") class Question(BaseModel): """Question with multiple choice options""" question_text: str = Field(description="The main question to be asked") context: str = Field(description="Brief context from their background") choices: Annotated[List[AnswerChoice], conlist(AnswerChoice, min_length=3, max_length=3) ] = Field(description="Three possible answer choices") user_answer: str = Field(description="The user's answer to the question", default="") # Make sure Question is properly defined as a Pydantic model class QuestionList(BaseModel): questions: List[Question] # class QAPair(BaseModel): # """Individual question-answer interaction during the interview process.""" # question_id: int = Field(description="Unique identifier for the Q&A pair") # question: str = Field(description="The question asked") # answer: Optional[str] = Field(default=None, description="The generated or provided answer") ## These are used for the transcript generation node class HypeCastTranscript(BaseModel): """Motivational speech transcript""" content: str = Field( description="The complete motivational speech as a single flowing conversation" ) ### This is the main state class class InterviewState(BaseModel): """Current state of the interview process.""" user_initial_input: InitialInput reference_material: Optional[ReferenceMaterial] = None qa_history: Optional[QuestionList] = None transcript: Optional[HypeCastTranscript] = None messages: Annotated[Sequence[BaseMessage], add_messages] = [] # Add this line audio_bytes: Optional[bytes] = None class Config: arbitrary_types_allowed = True # Enable arbitrary types for BaseMessage