ds apis implemented

This commit is contained in:
2025-02-06 20:22:43 +00:00
commit 142640325a
19 changed files with 5967 additions and 0 deletions
+57
View File
@@ -0,0 +1,57 @@
# Python bytecode
__pycache__/
*.py[cod]
# Distribution / packaging
.Python
env/
venv/
ENV/
env.bak/
venv.bak/
*.egg-info/
dist/
build/
# IDEs and editors
.vscode/
.idea/
*.swp
*.swo
# Jupyter Notebook checkpoints
.ipynb_checkpoints
# Pytest cache
.cache
# Coverage reports
htmlcov/
.coverage
.coverage.*
.cache
nosetests.xml
test-results/
# MyPy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# C extensions
*.so
# Data files
*.csv
*.dat
*.db
*.sqlite3
# Logs
*.log
# Environment variables
.env
+353
View File
@@ -0,0 +1,353 @@
import os
from typing import Optional
from fastapi import FastAPI, HTTPException, Security, Depends
from fastapi.security import APIKeyHeader
from fastapi.middleware.cors import CORSMiddleware
from fastapi.responses import JSONResponse
from dotenv import load_dotenv
from utils.document_loader import load_document
import json
from pydantic import BaseModel
from src.llm import ai_chat
from langchain_openai import ChatOpenAI
import requests
import tempfile
from scripts.generate_pdf import create_pdf
from scripts.generate_theme import generate_theme
from scripts.generate_quiz import generate_quiz
from typing import Dict, Any
from fastapi.responses import Response
from datetime import datetime
from fastapi import HTTPException
from pydantic import BaseModel
from typing import Optional, Union, Dict, Any
import os
import requests
import os
from PyPDF2 import PdfReader
from config import QUIZ_TYPES
# Load environment variables
load_dotenv()
API_KEY = os.getenv("API_KEY_ACCESS")
base_path = os.path.join("data", "config_files")
QUESTIONS_PATH = os.path.join(base_path, "questions.json")
THEME_CONTEXT_PATH = os.path.join(base_path, "theme_context.json")
# Load themes at module level
with open(THEME_CONTEXT_PATH, "r") as f:
themes = json.load(f)
# Initialize FastAPI app
app = FastAPI(
title="Fire Fighter Interview API",
description="API For fire fighter",
version="1.0.0"
)
# Add CORS middleware
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# Setup API key authentication
api_key_header = APIKeyHeader(name="Authorization", auto_error=False)
async def get_api_key(api_key_header: str = Security(api_key_header)) -> str:
"""Validate API key from header"""
if not api_key_header or not api_key_header.startswith('Bearer '):
raise HTTPException(
status_code=401,
detail={"error": "Unauthorized", "message": "API key is missing or invalid."}
)
token = api_key_header.split(' ')[1]
if token != API_KEY:
raise HTTPException(
status_code=401,
detail={"error": "Unauthorized", "message": "API key does not match."}
)
return token
class ChatRequest(BaseModel):
resume_url: Optional[str] = None
query: str=None
conversation_id: str
theme_id: Optional[int] = 1
class ChatResponse(BaseModel):
message: str
end: bool
error: Optional[str] = None
class GeneratePDFRequest(BaseModel):
conversation_id: str
feedback: Optional[str] = None
previous_results: Optional[Dict[str, Any]] = None
resume_url: Optional[str] = None
full_history_url: Optional[str] = None
class QuizRequest(BaseModel):
pdf_url: str
quiz_type: int # 1, 2, or 3 corresponding to QUIZ_TYPES
class QuizResponse(BaseModel):
success: bool
message: str
quiz_data: Optional[Dict[str, Any]] = None
error: Optional[str] = None
async def extract_pdf_text(pdf_url: str) -> Union[str, None]:
"""Extract text from PDF and handle potential errors."""
try:
response = requests.get(pdf_url)
response.raise_for_status()
# Create a temporary file
with tempfile.NamedTemporaryFile(delete=False, suffix='.pdf') as temp_pdf:
temp_pdf.write(response.content)
temp_path = temp_pdf.name
# Extract text from PDF
reader = PdfReader(temp_path)
text = "\n\n".join(
page.extract_text() for page in reader.pages if page.extract_text()
)
# Clean up temporary file
os.unlink(temp_path)
if not text.strip():
return None
return text
except requests.RequestException as e:
raise HTTPException(
status_code=400,
detail=f"Error downloading PDF: {str(e)}"
)
except Exception as e:
raise HTTPException(
status_code=500,
detail=f"Error processing PDF: {str(e)}"
)
@app.post("/rescue-career/chat", response_model=ChatResponse)
async def chat_endpoint(
request: ChatRequest,
api_key: str = Depends(get_api_key)
):
try:
# Validate theme
matching_themes = [t for t in themes if t["id"] == request.theme_id]
if not matching_themes:
raise HTTPException(
status_code=400,
detail=f"No theme found with ID {request.theme_id}"
)
# Only try to load document if resume_url is provided
resume_docs = ""
if request.resume_url:
docs = load_document(request.resume_url)
if not docs:
raise HTTPException(
status_code=400,
detail="Invalid resume URL: Unable to fetch document"
)
resume_docs = "\n".join(f"- {doc.page_content}" for doc in docs)
# Get AI chat response
response = ai_chat(
query=request.query,
conversation_id=request.conversation_id,
theme_id=request.theme_id,
resume=resume_docs
)
# Parse response
try:
parsed_response = json.loads(response)
return ChatResponse(
message=parsed_response.get("message", ""),
end=parsed_response.get("end", "no") == "yes",
error=None
)
except json.JSONDecodeError:
return ChatResponse(
message=response,
end=False,
error=None
)
except HTTPException as e:
# Re-raise HTTP exceptions
raise
except Exception as e:
raise HTTPException(
status_code=500,
detail=f"Error processing chat request: {str(e)}"
)
@app.post("/rescue-career/generate-theme")
async def generate_pdf_endpoint(
request: GeneratePDFRequest,
api_key: str = Depends(get_api_key)
):
try:
# Here you would fetch the conversation data using the conversation_id
# This is a placeholder - replace with your actual conversation data fetching logic
conversation_data = await get_conversation_data(request.conversation_id)
if not conversation_data:
raise HTTPException(
status_code=404,
detail=f"No conversation found with ID {request.conversation_id}"
)
resume_docs = ""
if request.resume_url:
docs = load_document(request.resume_url)
if not docs:
raise HTTPException(
status_code=400,
detail="Invalid resume URL: Unable to fetch document"
)
resume_docs = "\n".join(f"- {doc.page_content}" for doc in docs)
full_history_docs = ""
if request.full_history_url:
docs = load_document(request.full_history_url)
if not docs:
raise HTTPException(
status_code=400,
detail="Invalid full_history URL: Unable to fetch document"
)
full_history_docs = "\n".join(f"- {doc.page_content}" for doc in docs)
# Generate theme data using the generate_theme function
theme_data = generate_theme(
conversation_data=conversation_data,
feedback=request.feedback,
previous_result=request.previous_results,
resume = resume_docs,
full_history = full_history_docs
)
if not theme_data:
raise HTTPException(
status_code=500,
detail="Failed to generate theme data"
)
# Generate the PDF using the create_pdf function
pdf_content = create_pdf(theme_data)
# Create filename with timestamp
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"theme_{timestamp}.pdf"
# Return the PDF as a response
return Response(
content=pdf_content,
media_type="application/pdf",
headers={
"Content-Disposition": f'attachment; filename="{filename}"'
}
)
except Exception as e:
raise HTTPException(
status_code=500,
detail=f"Error generating PDF: {str(e)}"
)
@app.post("/rescue-career/generate-quiz", response_model=QuizResponse)
async def generate_quiz_endpoint(
request: QuizRequest,
api_key: str = Depends(get_api_key)
):
"""Generate quiz based on PDF content and quiz type."""
# Validate quiz type
if request.quiz_type not in QUIZ_TYPES:
raise HTTPException(
status_code=400,
detail=f"Invalid quiz type. Must be one of: {list(QUIZ_TYPES)}"
)
try:
# Extract text from PDF
pdf_text = await extract_pdf_text(request.pdf_url)
if not pdf_text:
return QuizResponse(
success=False,
message="PDF extraction completed but no text content found",
error="Empty PDF content"
)
# Generate quiz using the existing function
quiz_data = generate_quiz(
startpop_pdf=pdf_text,
quiz_type=request.quiz_type
)
if not quiz_data:
return QuizResponse(
success=False,
message="Quiz generation failed",
error="Unable to generate quiz from the provided content"
)
return QuizResponse(
success=True,
message="Quiz generated successfully",
quiz_data=quiz_data
)
except HTTPException as he:
raise he
except Exception as e:
raise HTTPException(
status_code=500,
detail=f"Unexpected error during quiz generation: {str(e)}"
)
async def get_conversation_data(conversation_id: str) -> dict:
"""
Fetch conversation data using the conversation ID.
Replace this with your actual implementation to fetch conversation data.
"""
try:
storage_path = "conversations.json"
with open(storage_path, 'r') as f:
convs = json.load(f)
convs_id = convs[conversation_id]
return convs_id
except Exception as e:
print(f"Error fetching conversation data: {e}")
return None
@app.on_event("startup")
async def startup_event():
"""Initialize required components on startup"""
pass
if __name__ == "__main__":
import uvicorn
uvicorn.run("app:app", host="0.0.0.0", port=5048, reload=True)
+20
View File
@@ -0,0 +1,20 @@
QUIZ_TYPES = {
1: {
"name": "Single Line Text Inputs",
"format": """
{"question": "Your question here", "correct_answer": "Your correct answer here"}
"""
},
2: {
"name": "Multiple Choice Questions",
"format": """
{"question": "Your question here", "options": ["Option 1", "Option 2", "Option 3"], "correct_answer": "Correct Option"}
"""
},
3: {
"name": "True or False Questions",
"format": """
{"question": "Your question here", "options": ["True", "False"], "correct_answer": "True or False"}
"""
}
}
+428
View File
File diff suppressed because one or more lines are too long
+258
View File
@@ -0,0 +1,258 @@
{
"General Competency Questions": [
{
"id": 1,
"question": "Why do you want to be a firefighter?"
},
{
"id": 2,
"question": "What have you done to prepare for a career in the Fire Service?"
},
{
"id": 3,
"question": "Why do you want to work for this department?"
},
{
"id": 4,
"question": "Name some of the traits, characteristics, or attributes of a good firefighter."
},
{
"id": 5,
"question": "What are some of the biggest challenges faced by the Fire Service today?"
},
{
"id": 6,
"question": "Describe the emergency vs. non-emergency duties of a firefighter."
},
{
"id": 7,
"question": "Where do you see yourself in 1, 5, 10, 20 years?"
},
{
"id": 8,
"question": "Describe the chain of command and your role in it."
},
{
"id": 9,
"question": "How do you handle stress, now and once you have the job?"
},
{
"id": 10,
"question": "How do you think the role of the firefighter will be different in 5 years?"
},
{
"id": 11,
"question": "What is the organizational structure of our Fire Department?"
},
{
"id": 12,
"question": "Why do you think honesty and integrity are important in the Fire Service?"
},
{
"id": 13,
"question": "What are the advantages and disadvantages of similar vs diverse teams?"
},
{
"id": 14,
"question": "List in order of importance: Emergency Response, Public Education, Fire Standards/Enforcement."
},
{
"id": 15,
"question": "What is the most important duty of a firefighter?"
},
{
"id": 16,
"question": "What does leadership mean to you?"
},
{
"id": 17,
"question": "What do you like most and least about a supervisor?"
},
{
"id": 18,
"question": "What do you appreciate in a managers style?"
},
{
"id": 19,
"question": "What are the six common leadership styles in the Fire Service?"
},
{
"id": 20,
"question": "What do you like most and least about being a firefighter?"
},
{
"id": 21,
"question": "How does diversity impact the Fire Service today?"
},
{
"id": 22,
"question": "How would you make a positive impact regarding the diversity in the community?"
},
{
"id": 23,
"question": "Firefighters work 24-hour shifts. How have you prepared, and what challenges do you think youll face?"
},
{
"id": 24,
"question": "Public Education is important in the Fire Service. How would you provide this service?"
},
{
"id": 25,
"question": "You are a probationary firefighter. How do you prepare yourself?"
},
{
"id": 26,
"question": "Why is respect so important, and what does it mean?"
},
{
"id": 27,
"question": "Would you break a rule if asked to?"
},
{
"id": 28,
"question": "What are potential sources of workplace conflict? How would you handle workplace conflict?"
},
{
"id": 29,
"question": "Why should we hire you?"
},
{
"id": 30,
"question": "What are your strengths and weaknesses? (What would your boss say about you?)"
},
{
"id": 31,
"question": "How do you want to be remembered at the end of your career?"
},
{
"id": 32,
"question": "What skills do you bring to Dispatch?"
},
{
"id": 33,
"question": "Walk me through a truck check."
},
{
"id": 34,
"question": "How do you define teamwork in the context of firefighting?"
},
{
"id": 35,
"question": "What motivates you to perform well in stressful situations?"
},
{
"id": 36,
"question": "Explain how you would handle feedback from a superior, especially if it was critical."
},
{
"id": 37,
"question": "What is your understanding of the core values of the Fire Service?"
},
{
"id": 38,
"question": "Describe a time when you demonstrated initiative in the workplace."
},
{
"id": 39,
"question": "How do you prioritize tasks during an emergency response?"
},
{
"id": 40,
"question": "What role does technology play in modern firefighting, and how are you prepared for it?"
},
{
"id": 41,
"question": "How would you approach learning new skills and techniques required for this job?"
},
{
"id": 42,
"question": "Explain how you balance personal and professional commitments in a demanding job."
},
{
"id": 43,
"question": "What strategies do you use to ensure continuous improvement in your work?"
},
{
"id": 44,
"question": "How do you approach building trust and relationships within a new team?"
},
{
"id": 45,
"question": "What does a day in the life of a firefighter look like for both emergency and non-emergency activities?"
}
],
"Situational Questions": [
{
"id": 1,
"question": "What would you do if a firefighter makes disparaging remarks in public about visible minorities?"
},
{
"id": 2,
"question": "What would you do if a senior firefighter is making inappropriate, unwelcomed, bullying comments towards another firefighter?"
},
{
"id": 3,
"question": "What would you do if you believe that a fellow firefighter is unfit for duty (e.g., drugs, alcohol, medication)?"
},
{
"id": 4,
"question": "What would you do if you are following an order from your captain and a more senior officer gives you an alternate order?"
},
{
"id": 5,
"question": "What would you do if your captain gives you a performance review that you are unhappy with?"
},
{
"id": 6,
"question": "What would you do if you saw a firefighter put a valuable item in their pocket at a call?"
},
{
"id": 7,
"question": "What would you do if you noticed a fellow firefighter is not their usual self (moody, withdrawn, seething, etc.)?"
},
{
"id": 8,
"question": "What would you do if you noticed two firefighters cheating on an exam?"
},
{
"id": 9,
"question": "What would you do if you see two firefighters getting heated and about to fight?"
},
{
"id": 10,
"question": "What would you do if you are confronted by an irate citizen and you are all by yourself?"
},
{
"id": 11,
"question": "What would you do if you are on your way home after a shift and see a car accident or other emergency?"
},
{
"id": 12,
"question": "What would you do if you are assigned undesirable or dangerous tasks at an emergency scene or back in the station?"
},
{
"id": 13,
"question": "What would you do if you notice one firefighter not being included in the group (e.g., coffee poured for everyone but them)?"
},
{
"id": 14,
"question": "What would you do if you are the apparatus driver and during your daily truck check you discover the emergency lights are not working, and your captain says, 'Dont worry about it. The next crew on duty will take care of it'?"
},
{
"id": 15,
"question": "What would you do if one member of the crew has a really negative attitude about training?"
},
{
"id": 16,
"question": "What would you do if a fellow firefighter tells you they dont want minorities, women, or LGBTQ+ individuals in the fire service?"
},
{
"id": 17,
"question": "What would you do if you respond to your first fire call, and your captain tells the crew to wear all PPE, but senior firefighters are not wearing all the necessary gear?"
},
{
"id": 18,
"question": "What would you do if you are faced with conflicting orders from two supervisors at the scene of an emergency?"
}
]
}
+97
View File
@@ -0,0 +1,97 @@
[
{
"id": 1,
"theme": "Disability Questions",
"context": "Firefighters respond to lots of medical calls, many of which involve visible and invisible disabilities.\n- It's critical to be aware of the unique needs of people with physical health issues and mental health challenges.\n- Firefighters must provide compassionate care to everyone and giving respect to all regardless of their abilities.\n- As first responders, firefighters are often the first point of contact for vulnerable individuals, and how they interact can make a lasting impact on the persons well-being.\n- Firefighters should be well-trained to recognize different disabilities and adapt their approach to ensure effective communication and assistance, especially for those with cognitive or sensory impairments.\n- This requires empathy, patience, and a strong understanding of mental health and physical disabilities, along with the proper use of equipment and techniques to ensure safety and dignity for everyone involved.\n- Potential Conclusions:\no I know that ______ Fire has a strong reputation for responding with compassion and professionalism to individuals with disabilities, ensuring that they feel respected and supported during emergencies.\no I admire the commitment that ______ Fire has shown in ensuring firefighters are trained to work with all members of the community, including those with both visible and invisible disabilities.\no I've seen firsthand how important it is for firefighters to provide inclusive care during medical emergencies. I would be honored to join ______ Fire in continuing to up"
},
{
"id": 2,
"theme": "Leadership Skills Questions",
"context": "Leadership is not about having authority; it's about inspiring others to reach their full potential.\n- Effective leaders lead by example, demonstrating integrity, accountability, and a commitment to teamwork.\n- In the fire service, leadership is not confined to rank; every firefighter has the opportunity to lead and contribute to the success of the team.\n- Adaptability and decisiveness are crucial qualities in leadership, especially in high-stress and rapidly changing environments.\n- Leadership is also about fostering a culture of continuous learning and improvement, encouraging feedback, and promoting innovation.\n- Potential Conclusions:\no I've heard about the emphasis on leadership development within ______ Fire, and it's clear that the department values cultivating leaders at all levels. I'm eager to contribute to that culture and continue growing as a leader.\no During my station visit, I observed how firefighters at ______ Fire take initiative and support each other, regardless of rank. That collaborative leadership approach is something I aspire to emulate and contribute to.\no I've learned that leadership in the fire service is not just about giving orders; it's about empowering others, building trust, and fostering a sense of unity within the team. I'm excited about the opportunity to lead by example and positively influence my fellow firefighters at ______ Fire."
},
{
"id": 3,
"theme": "Conflict Questions",
"context": "Conflict is a huge problem in high performing teams.\n- Creates a poisonous work environment, reduces efficiencies, and creates mental health issues.\n- Those are serious issues and must be addressed as soon as they pop up.\n- One of the best ways to address it through increasing the communication and giving people an opportunity to explain their opinions or viewpoints.\n- I tend to think about the three Ts (teamwork, training and trust) and how important it is to fall back on those.\n- Attempt to secure behaviour modification through voluntary compliance.\n- Potential Conclusions:\no I know that professionalism runs through the entire department here. ______\no Firefighters are professional and committed to safe and respectful workplaces.\no One thing about the fire service is that you all do a great job of communicating and creating a chain of command to help simplify complex problems\no Its important to remember the values of the fire service and keep those in mind whenever conflicts arise.\no Tie in stats and figures from your research on the department."
},
{
"id": 4,
"theme": "Stress Questions",
"context": "My big takeaway is that stress is everywhere, and it affects everyone in different ways.\n- The amount of mental health issues and stress levels are up exponentially with the community.\n- Especially when you factor in the effects of COVID-19 and the lockdowns.\n- That _________ situation made me realize that we must be supportive of one another and reduce the stigma.\n- Potential Conclusions:\no I know that the team members at _______ Fire are exposed to stressful situations on a regular basis, and it is critical that they be supportive to one another in order to maintain a strong team.\no I have spoken to ______ about your mental health programs and can see that you really take the time to pour into each of your firefighters cup. I really admire that.\no I looked into that _________ program that your department us"
},
{
"id": 5,
"theme": "Emergency Questions",
"context": "Emergencies can happen anywhere at anytime.\n- Usually with little to no warning.\n- During those times people fall back onto their training and most commonly practiced strategies.\n- We need to ensure that our personnel are available and ready to answer the call whenever that happens in the community, and they are using the most effective strategies and techniques possible.\n- Potential Conclusions:\no I know that the expectation of _______ Fire is to train at least 2-3 hours per shift.\no That works out to 14-21 hours per month. When you factor in running calls in between those training sessions there is a fair bit of opportunity for Firefighters to become very good at their jobs and be fully prepared.\no Consistent commitment to training everything from the basics up to the complicated things 2-3 hours per shift is what makes the people on _____ Fire so good at their job."
},
{
"id": 6,
"theme": "Mistake",
"context": "We all make mistakes. It is okay to make them. But it is not okay to not learn from them.\n- Mistakes are just proof that you are trying your best.\n- They are an opportunity for growth and for development.\n- They are the things that help sharpen the knives in a drawer.\n- The key is not to make the same mistake twice.\n- Potential Conclusions:\no I am certain that _______ Firefighters conduct regular follow-ups after calls.\no Its important for everyone to check their ego and be accountable for the things they messed up on.\no I know that Chief ______ promotes an open and transparent environment. He/She is not afraid to admit when they made a mistake. So, it is important for everyone in the department to follow suit."
},
{
"id": 7,
"theme": "Cultural, Diversity, and Inclusion Questions",
"context": "Communities are becoming more and more diverse everyday. It is important for the Fire Service to recognize that.\n- Steps can be taken every single day to create an environment that is inclusive and open to everyone regardless of their background, language, abilities, or self-identification.\n- Public servants serve the public.\n- No passing judgement on people. No racism, no homophobia, no misogyny.\n- Treat everyone with respect and educate ourselves about the differences in our communities.\n- Potential Conclusions:\no ______ Fire is very professional and respectful. I have only seen and heard good things about how much of a concerted effort you are making to be more inclusive.\no I spent some time looking at the Public Education pamphlets at station _____ and saw that they were offered in a bunch of different languages. That was amazing and I really think that shows the community how much you care about reducing the barriers to safety.\no I spoke with _____ and learned about how enjoyable of an experience they have had working on your departmen"
},
{
"id": 8,
"theme": "Customer Service Questions",
"context": "Providing great customer service really just requires caring about people and trying to always make things better than you found it.\n- Our communities are better served when they have people that are willing to sacrifice their time and energy.\n- I personally enjoy going to places and working with people that provide great customer service. I would only expect that to be the level of service provided by firefighters.\n- Potential Conclusions:\no You cant train people to care and its important for the fire service to hire people who innately have a desire to go the extra mile. It has to be in their DNA.\no I know that _____ Fire has done a great job finding lots of those types of people and they constantly work towards fostering that characteristic in everyone brought into the organization.\no Firefighters go above and beyond every shift. Its our job to serve the community and protect life, property"
},
{
"id": 9,
"theme": "Successful and Unsuccessful Team Questions",
"context": "Teamwork is necessary to assist in overcoming emergencies. Especially expanding ones. I understand how chain of commands works and the importance of monitoring the span of control as well.\n- Great teamwork creates synergy in the workplace and makes environments happier, healthier, and safer.\n- There is no “I” in team.\n- All tasks are important no matter how big or small it may seem.\n- Great teams are built by people that are committed to training and knowing their roles well.\n- Need to train in order to create muscle memory and prevent “skills fade”\n- Potential Conclusions:\no I know that Firefighting is a team sport and that _____ Fire does a great job in fostering that camaraderie.\no I have seen the _____ Fire team play in _____ tournament and know that you guys applaud crews bonding over meals at the station.\no I really appreciate the fact that you allow crews to train together and share insights learned across the department so that everyone gets better all the time.\no Include stats and figures, following SOPs and safety protocols into the answer"
},
{
"id": 10,
"theme": "Disagree with a Supervisor Questions",
"context": "Disagreements can and will happen but what matters is that the issues are addressed in a respectful and professional manner.\n- I always recommend doing them in a private and non-confrontational manner\n- With a focus on finding acceptable solutions that can be implemented effectively.\n- The idea is to not let things linger and harbour because that creates a poisonous work environment.\n- Potential Conclusions:\no I understand my role in the chain of command and will always try my best to follow orders as they are given. But whenever a disagreement may come up it is important to show respect and listen to all sides.\no _____ Fire works hard to promote captains and chiefs that are smart, capable and proven leaders. It is important to acknowledge that every time there is a potential disagreement. They may see things that I am not aware of.\no _____ Fire works hard to minimize the number of disagreements in the workplace."
},
{
"id": 11,
"theme": "Rule Bending",
"context": "I do not bend rules that jeopardize health and safety or rules that test my ethics and morality.\n- I know that the fire service has that same perspective.\n- Therefore, all organizations need to have rules and all people in those organizations need to know them.\n- This is why there are internal SOPs, OHSA, HTA, Fire Code, Criminal Code etc.\n- Potential Conclusions:\no I know that _____ Fire has a robust SOP package, and it is part of the training process for every new hire to go through them and get schooled up on the importance of them.\no The onus is on me to spend time learning the ins and outs of this organization if I am blessed with the opportunity to work here.\no Firefighters need to be rule followers. It is an inherently dangerous job and freelancing has no part o."
},
{
"id": 12,
"theme": "Integrity Challenge Questions",
"context": "Integrity is the cornerstone of the fire service profession, guiding every action and decision.\n- Firefighters are entrusted with public safety, making it imperative to uphold the highest ethical standards.\n- In the fire service, we are governed by regulations such as the NFPA standards and the Ontario FPPA, which mandate strict compliance to ensure safety and well-being.\n- These guidelines underscore the need for transparency and ethical conduct in all our actions.\n- Potential Conclusions:\no Integrity is not just a personal attribute; it is a professional necessity that ensures the effectiveness and reliability of our fire service operations.\no When faced with an integrity challenge, it is essential to remain steadfast in ethical principles, even under pressure.\no This experience reinforced my commitment to the values of the fire service and highlighted the importance of fostering a culture where integrity is paramount.\no By upholding these standards, we not only protect ourselves and our colleagues but also maintain the trust and confidence of the communities we serve."
},
{
"id": 13,
"theme": "Taking a Shortcut at work",
"context": "I believe in having strong work ethic. I was raised that way and my work experience to date proves that…\n- I definitely do not take shortcuts around things that compromise health and safety or my ethics and morality.\n- I never take shortcuts that compromise the health and safety of myself or others, or that challenge my ethical and moral values.\n- I believe that the fire service shares this same perspective, prioritizing safety, ethics, and morality above all else.\n- In my view, all organizations should establish clear rules, and it is essential for every member of those organizations to be aware of and follow these rules.\n- This is why organizations have internal Standard Operating Procedures (SOPs), Occupational Health and Safety Act (OHSA) guidelines, Highway Traffic Act (HTA) regulations, Fire Codes, and even the Criminal Code when necessary.\n- Potential Conclusions:\no I'm aware that at _____ Fire, they have a comprehensive set of Standard Operating Procedures (SOPs) that are diligently followed. During my training, I learned about the critical importance of these procedures and the reasons for adhering to them.\no If I were fortunate enough to join this organization, I understand that it would be my responsibility to thoroughly acquaint myself with its rules and procedures. I'm committed to investing the necessary time and effort to ensure I comply with them.\no In firefighting, there's no room for shortcuts. It's an inherently perilous job and deviating from established procedures can jeopardize lives. Rules are not just guidelines but safeguards that protect everyone and ensure a safe return from each mission."
},
{
"id": 14,
"theme": "Delivering Difficult Messages",
"context": "I do not shy away from the responsibility of delivering difficult messages when necessary, even though it may be uncomfortable. My commitment to honesty and ethical conduct remains unwavering.\n- I believe that the fire service, like any responsible organization, understands the importance of addressing challenging issues head-on, which aligns with my perspective on this matter.\n- In all organizations, there should be clear protocols and guidelines for delivering difficult messages effectively and sensitively, ensuring that the message is conveyed while respecting the dignity and feelings of the recipients.\n- This is why organizations often have established procedures and communication guidelines to handle such situations professionally and ethically.\n- Potential Conclusions:\no I'm aware that at _____ Fire, they prioritize open and honest communication. During my training, I learned about their approach to delivering difficult messages and the importance of doing so with empathy and professionalism.\no If I were part of this organization, I would understand that delivering difficult messages might be a part of my role. I would be committed to following their established protocols and guidelines for addressing such situations.\no In firefighting and similar high-stakes professions, effective communication, even in challenging circumstances, can be a matter of life and death. The rules and procedures in place are not just about following a script but ensuring that messages are conveyed in a way that respects the emotions and well-being of all involved parties."
},
{
"id": 15,
"theme": "Not Following SOPs/SOGs",
"context": "I have never deviated from established SOPs at work, as doing so can compromise safety, ethical standards, and the integrity of the organization.\n- I understand that the fire service, like any responsible organization, places a high value on adherence to SOPs, which is consistent with my perspective.\n- In every organization, it's crucial to have clear and well-documented SOPs that every member understands and follows. This ensures consistency, safety, and ethical conduct.\n- This is why organizations implement internal SOPs and adhere to external regulations like OHSA, HTA, and Fire Codes to maintain high standards of operation.\n- Potential conclusions:\no I'm aware that at _____ Fire, strict adherence to SOPs is fundamental to their operational success. During my training, I gained a deep appreciation for the importance of following these procedures and the consequences of not doing so.\no If I were to become part of this organization, I would fully understand the gravity of following SOPs. I would uphold these standards and would actively seek training and support to ensure compliance.\no In firefighting and similar high-risk professions, disregarding SOPs is simply not an option. These procedures are in place to protect lives and property. Any deviation can have serious consequences, and rule adherence is non-negotiable."
},
{
"id": 16,
"theme": "Continuous Improvement",
"context": "Continuous improvement is about striving to be better every day, both as an individual and as part of a team.\n- I believe that the fire service embodies this concept by constantly evolving through training, adopting new technologies, and learning from past experiences.\n- Reflecting on one's performance and seeking feedback are essential components of continuous improvement, as they help identify strengths and areas for growth.\n- Staying updated with new firefighting techniques, equipment, and regulations is crucial for maintaining effectiveness and safety in the field.\n- Potential Conclusions:\no I've seen how ______ Fire prioritizes ongoing training and professional development to ensure its firefighters remain at the forefront of the profession. I look forward to being part of an organization that values growth and innovation.\no During my station visit, I was impressed by the emphasis on learning and improvement at ______ Fire. That environment aligns perfectly with my personal commitment to always better myself and support my team in doing the same.\no I believe continuous improvement is not just about improving skills but also about fostering a culture where everyone strives to do better. At ______ Fire, Im eager to contribute to that culture by embracing challenges, seeking feedback, and pursuing opportunities for growth."
},
{
"id": 17,
"theme": "Handling Sensitive Information",
"context": "Firefighters are often entrusted with sensitive information, whether it pertains to medical calls, emergency incidents, or personal details about community members.\n- Maintaining confidentiality and discretion is critical for preserving trust and ensuring the dignity of individuals involved.\n- Handling sensitive information responsibly requires understanding and adhering to organizational policies, as well as exercising sound judgment.\n- Respecting privacy is a key component of professionalism, especially in a role as visible and impactful as firefighting.\n- Potential Conclusions:\no I understand that ______ Fire has clear guidelines and training around handling sensitive information. I respect and appreciate the importance of these protocols and would adhere to them without compromise.\no If given the opportunity to join ______ Fire, I would uphold the highest standards of confidentiality and discretion, ensuring that sensitive information is treated with the respect it deserves.\no Handling sensitive information with care is essential to maintaining the trust of the community and the integrity of the fire service. Im committed to embodying these values and ensuring that all information is managed professionally and ethically."
},
{
"id": 18,
"theme": "Solving a Problem",
"context": "I believe problem-solving is one of the most valuable skills in the fire service, as it often determines the success or failure of a critical situation.\n- Effective problem-solving requires a clear assessment of the situation, evaluating available resources, and making informed decisions quickly.\n- Firefighting often involves scenarios where unexpected challenges arise, and the ability to stay calm and address issues methodically is essential.\n- Collaboration is a significant part of problem-solving, as no one firefighter has all the answers. Solutions come from teamwork and leveraging everyone's strengths.\n- Potential Conclusions:\no I understand that ______ Fire emphasizes critical thinking and problem-solving in their training programs. During my training, I honed these skills and learned how to approach challenges systematically and effectively.\no If I were part of ______ Fire, I would actively apply my problem-solving abilities in both emergency and non-emergency situations, ensuring I work collaboratively with my team to find the best outcomes.\no Solving problems in firefighting goes beyond emergencies; it's about addressing challenges proactively, whether it's equipment maintenance, community outreach, or operational efficiency. I'm committed to contributing to this problem-solving culture at ______ Fire."
},
{
"id": 19,
"theme": "Challenge Questions",
"context": "Life is full of challenges. It is important for firefighters to be the type of people that take those challenges head on and constantly work to find ways to overcome them.\n- Grit, persistence, creative problem solving, and strong mental health are the keys to overcoming challenges.\n- Life can change in a second. Its important to be adaptive and flexible.\n- Potential Conclusions:\no And I am certain that ______ Fire works very hard to meet every challenge and then overcome them.\no I think about how you guys handled the ________ situation\no or the recent fire at _______\no and as an outsider looking in, I was thoroughly impressed with the way the department handled it."
}
]
File diff suppressed because one or more lines are too long
+112
View File
@@ -0,0 +1,112 @@
%PDF-1.4
%“Œ‹ž ReportLab Generated PDF document http://www.reportlab.com
1 0 obj
<<
/F1 2 0 R /F2 3 0 R
>>
endobj
2 0 obj
<<
/BaseFont /Helvetica /Encoding /WinAnsiEncoding /Name /F1 /Subtype /Type1 /Type /Font
>>
endobj
3 0 obj
<<
/BaseFont /Helvetica-Bold /Encoding /WinAnsiEncoding /Name /F2 /Subtype /Type1 /Type /Font
>>
endobj
4 0 obj
<<
/Contents 10 0 R /MediaBox [ 0 0 612 792 ] /Parent 9 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
5 0 obj
<<
/Contents 11 0 R /MediaBox [ 0 0 612 792 ] /Parent 9 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
6 0 obj
<<
/Contents 12 0 R /MediaBox [ 0 0 612 792 ] /Parent 9 0 R /Resources <<
/Font 1 0 R /ProcSet [ /PDF /Text /ImageB /ImageC /ImageI ]
>> /Rotate 0 /Trans <<
>>
/Type /Page
>>
endobj
7 0 obj
<<
/PageMode /UseNone /Pages 9 0 R /Type /Catalog
>>
endobj
8 0 obj
<<
/Author (\(anonymous\)) /CreationDate (D:20250120220756+00'00') /Creator (\(unspecified\)) /Keywords () /ModDate (D:20250120220756+00'00') /Producer (ReportLab PDF Library - www.reportlab.com)
/Subject (\(unspecified\)) /Title (\(anonymous\)) /Trapped /False
>>
endobj
9 0 obj
<<
/Count 3 /Kids [ 4 0 R 5 0 R 6 0 R ] /Type /Pages
>>
endobj
10 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1471
>>
stream
Gat=+gMRrh&:O:SbZil>G-rjRP4K==Nf+fpi[!5#.*rcf40)r3,o)Rn7K*&m\JN5e9I1&I!jp.oR5=$MN"QuT-OJ\C!k?M5\).ii;TK29-5R?:*oT:Eq0J42/#P1jNr3@42@@dSnq=FtrCOB*U/TM>'RrS-:+rcRl"ua(C%fUG]DL4Lp0iDkqsaBBr<XQ1hp8WaVt]di+T!+`?fCq[%0YT6I@c#"RU1:Os*ZpLa.SD^LTm?+0a0XEK0q)]6=:1,4(-tLrRdFg]Id7r:4q);6VAO<73Qn-*NY6,8??L$OOs_U]%(C=e.S.F`>^CEjU_k8_I+OQV*jhY^6HjXQ<(L._$X7"-aYo:VK+*XQL;imebtm^]oWN:^$-RYUh4`I"8PN[F"m'#IiUWIE]SXEk`ifa%NbUN6MoWj`q*'p)I?e5jUAR'#!%PMk-Tq#8kYKaK3%'3S7&Y#`U<uP*$+<0q*Qd/5tm"<nTh5O0Or%Uag7);E4OR)Wb!c?JCoaU&u6#780-E/>!Ws5H)YS;9nqoq5-qge]iA_s"]#Bc_E&%SdW#ZUN;!&._Eb8jNFE<#YN`/cSr\-/amaP]%W[Jc95RPo@*SHRo.u9L#*FNMG1FPK.'[Q?/GCfgm_`!pfidM]"L?8jM&WgAoV:L1eXSA+M@+VaM\M'@V.0TRpWD%kpOSK!eLT7klRTo(+=C7\'Lgs8O@X1l6(Fpb,B0h;=B;*LKn>"X0oEt3]Z-Tc8t-Pp[%PbmD!g:OnqmO_*0?.!I^H=Q@YHm=^n'&2F@PuM@4PS#.L`W*a3H+]^+9CJaJ$n@FL=s8!\l]ER"Jel7i+acVDC!V[OW+O<!2.3<(qnBf[=PeZO.05n>,1fSkjn2260,_*W6\""h)i0%!<c7"hC[(4Rs:.KH5,+SAY);,F3mH<uP?tbNF3B=G]UU#!B#J>1?Cra0Ws]Qcgb`e5gFr.l3+kS<o:rl=W675kCFcE_oV+Wb_BhSA6'fg8'CXCF/mGi>ROVo2E6]/foJc/TFb!9JXRk*%g3bP_:+6JA?cl90@KjCQc,lI8Pls)@oB]#AQt:Obt6;X/">b@\>(97q>)s@>i8e:JZW3/Cq(3@ini>X`><uf"OT(8&@u5_qX&rA5`?S_V'/+"q\>_\o+;u9W6;E8M7;cHoZ4UBo!p<j^IrKq]IhnBaOtmlMJ`CRmT4W:ii6E(<n2)`Hnaa^'_icQB!22j0:Uq$Eg"G6i83'UlnM`1=oMpf&<`Gr<2)7RP;I$h4jA7SuT5)dI*SNg\<O!9ffe$HkB+2"'0Ae4)_NMQNE*D`7Bu]9bn[b.N[a!34r*VH7q>(k^nnPi3k_L'HV1baY[Jk*uOP;)jM1i?J$P50/<sqLJ181bXM_T;ejpcJOqGP1UA08>FLZ-glfrF2Z+haiS`nk2i4jnMejQ4BVli:ZaK,Q'b0P=1*\5sV)kUfF%[AZZ(?/.A1tU`YL*;W_o][hBH=G~>endstream
endobj
11 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1371
>>
stream
Gat=+968iG&AJ$ClnR`QY"6aAge/tgdn+179q(S($OA@V<$4Hd+\);#?%=,9,n:W)1uj^3$Jb*Thl\_:dOU6*GmEhc!PeW%6'al86ajR26#d.uMMq@ilu;.4#1f8$h+ZFdnX=/Ek\Jk!;RV=SULWljQuL-)[nOVEH`5;3,>&(C[RVrb_81s<@;'YnULb2=ZP&Q]#-gPW?kBK;CCXMA&rQ^^p]XuGfTg-Cnj]Q)I*k22%+_.e?+<dX-d]S^pNiLMWd(m:X5si-[EJ['Wg87Kf@,iboH/B"K3dXhYka)443%,"37",AlF5j%=3D[-SNd\]c/J\72`L6HLmf_H9W7Fr^S'Q&idrf6-mbRYkocF^Wo1(Ke-`Q,&kI\i2k'7PS=YSFU@XPYTFgY44bDdoQk:6iU5OR]U$)p>1QIenLs,B5^.7CdIP_80&SNHlVbGB90?>t:+p"Ib]s`$X[t+sA"5pj/I<88ebm^aC([/Z'Hm_b\IBrk<c0G,i(X-c\_I'J[%@$nVfLX/_ft_jf+\i9NH=ej=6ghl&jZYqjpO6b=2!jP8Cl&5N.I55\+)a^_ojG$jHW^BLQ77j!QbfsGh*.:VDM==>%TKlsZDB(a3^]8nr+&T00,*`%_Q]Y\e"Cho6;iPb)k@h%+T+-,Us?6<CVW3U""thQK^(]\e`\W5A[ZAb8Kt3uCohO"YPKL:33c1X)e;u>P>&,>C81s>PU1@-=5b]pW$l';NDSN08%=6_Pck:.8G+DtC`:@ZHlR)"<p;nZeR0YkUEQpGWJT2Yc&Am];$a@?ed3e(,e>$#38g?Ibdc+:kK-m%Zk'-m]l[a1Kji-D>dI"3?JQq:ItF+b_/D%r\aIO\*VFmf%/Nq$O@-#'K,r>l^cH)%Jho3DdeD,hG-.nk$DFsf]f)YRhcV<uiRRdPA-G,18i.AO%baYk)S'4n\mjotKc1^S<c8gd!2gE\?[=P;!8n9+#54#0=.ABrrt16MA*a]-4fS=8,p<l>GK<GX*Cp_^WT.IW;Z>mOEgbGG]HT+_XH>(MVZo[X+Vo)@%6[A-Q5j@=2bJH\e@&l8a0KI)a72msfTq6%he4?RnERBk9hUt(4Q_f\k-nu:oV&X*G*/5\fH7%gP?'0jS?:<9Zi_<Nbs<O>OZC:BUOC0g2\NqVf"3>s%/QipT4k>p8UkN"W$`!*BDgtQRWc`7na/H<i9)FdITE3\>n[V+cM(?iKr50#Su$Y3Vpj_WnoB#f>d#SRL8/FM6NXm6ATmdK$9N>HP?^aP6cM7RU*(!tBtDZ)&`]<#2Y!d3AUHrY>b'H<Zd]Mf;a1htMn6/b7OtG!B^)'CJ/h!d3%`;`H)nlsa)NRl]fVDk.,V`32WT_B4+&M#iSo>2VY.t~>endstream
endobj
12 0 obj
<<
/Filter [ /ASCII85Decode /FlateDecode ] /Length 1226
>>
stream
GatU29lo&I&A@sBm&atL9gr3j4M>91:HL_LFdm=sQWtYP8YQ7e('(K+htI-ceRWEI'6Q-p,m]7^^5p5K[)/S/YHfDLWMCVb.B$?I=];SNZ_?r@IP.i'^+)l>GIM\#>@TJ?<b]f9=898aI+%\FapuIncc<sk?JPuVUE.Fb_D)?(Wae)u4KTYBMnO(\ClL+H+=2AA&"3QXN^>85[oE>qj`g>h885\B/)PB$]s8AVZY>Y<-jY<I9-:C-SCL;uWm^FN(?90CVSY"G];+jTP0YN0+lGn?4"m8d5OnNSlHO1KlLe+unR^,:<>\,#f)1mu]"!%]kVZ[aSj!!]Z.mY2lOKT()DIk=C\W60"Y)_d?.B:X.O.s4#">T>@ZqJ=Wq8irG:]ab>2!!d9YjW-ReBFu;45SAaWb)oZH/YN,lrK8gn\d$6[5dQK/s"+G;cZ6d01PT,r[fW$2Sar;.2jY;7hMX)\:8J2@FMO]D6d/9)'ebflik,^k-+keiF?q!`,7%#3gL#P(CH*O"@LG@NR`C*\+>GGdZ.%eYJHrJt*iTFk5hld"\*IH]TnCQYh)?2dAh\47<d*Ud/>N"Or74WYhA>Ls,K_2?ZD.,^7X\89BNu#HYfEY'%`Z0>Y5`MZMSfB!T%I<\g8">ZE9.#D`&u(fd#<J;GKUHJZGGkbgUf`(l)*f(XJQ9BAYc\B>MiagKd65S&$iC08"E3$YY[6UOR%jk5+5jM,D%&E\L-0k5Kk2VX19?@qm2rLh%2TQC6QNhZ?^C=da]1*jLsh]M'(d[C0.T%$=<_As3FpZui,`Tj-t>W?qq49Oo-ebMq-P`A@XU>aW!U_s$Zq'(D-hUggWc-7A9lH`WsSYSVg"QUkNWseRqK:TIU^`GbqOtbJqEQZf2Ng6Rq]NERQ[GlLMkIj#R1.\IR5W;Bgk%%R'/'lYb[%8T%qL=/'^GHluFhMogL#`LIm<FS!`6lIl^!M--(mh2qKB#(e9+pj+p["JL[6=Y:"=CUNbN4<Nh$,0$Ki_NMBMS2p63X2\4JZlHEOQ1?I*n:9jA$bT4eeK*F%8Y$Kbeb,63\c][Bn\=YKo>4MpgR#%@pKkaLsHcQg^I;/i.]&gc6Zqk"i6D-/+R5]X7)pLNMaOR.@*lpE[lnK4#*$mT`G:7fIbl5enEfb'S6D\K(%@&4#89hiM:X_h@RO@;]taMW=&RdA:Q6lT4V3`,Sg3-L)sBRqVR1bMg"9e($[sf5F@~>endstream
endobj
xref
0 13
0000000000 65535 f
0000000073 00000 n
0000000114 00000 n
0000000221 00000 n
0000000333 00000 n
0000000527 00000 n
0000000721 00000 n
0000000915 00000 n
0000000983 00000 n
0000001266 00000 n
0000001337 00000 n
0000002900 00000 n
0000004363 00000 n
trailer
<<
/ID
[<4b0a13e77a14658d2c9c7ba2786bbc6e><4b0a13e77a14658d2c9c7ba2786bbc6e>]
% ReportLab generated PDF document -- digest (http://www.reportlab.com)
/Info 8 0 R
/Root 7 0 R
/Size 13
>>
startxref
5681
%%EOF
+3120
View File
File diff suppressed because one or more lines are too long
+23
View File
@@ -0,0 +1,23 @@
openai
pandas
python-dotenv
fastapi
uvicorn
langchain-community
langchain-openai
pydantic
pypdf
pypandoc
Spire.Doc
plum-dispatch==1.7.4
scikit-learn
werkzeug
python-multipart
langgraph
tiktoken
langchainhub
chromadb
langchain
langchain-text-splitters
beautifulsoup4
langchain-core
+101
View File
@@ -0,0 +1,101 @@
from reportlab.lib import colors
from reportlab.lib.pagesizes import letter
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from io import BytesIO
def create_pdf(data, output_filename=None):
try:
# Create a BytesIO buffer to store the PDF
buffer = BytesIO()
# Create the PDF document using the buffer
doc = SimpleDocTemplate(buffer, pagesize=letter)
styles = getSampleStyleSheet()
# All content will use the same font size
STANDARD_FONT_SIZE = 12
# Create custom styles with consistent font size
styles.add(ParagraphStyle(
name='ThemeTitle',
fontSize=STANDARD_FONT_SIZE,
alignment=TA_CENTER,
spaceAfter=15,
fontName='Helvetica-Bold', # Bold style
leading=14 # Line spacing (1.0)
))
styles.add(ParagraphStyle(
name='QuestionTitle',
fontSize=STANDARD_FONT_SIZE,
alignment=TA_LEFT,
spaceAfter=10,
fontName='Helvetica-Bold',
leading=14,
textColor=colors.black
))
styles.add(ParagraphStyle(
name='SectionTitle',
fontSize=STANDARD_FONT_SIZE,
alignment=TA_LEFT,
spaceAfter=4,
fontName='Helvetica-Bold',
leading=14
))
styles.add(ParagraphStyle(
name='NormalText',
fontSize=STANDARD_FONT_SIZE,
alignment=TA_LEFT,
spaceAfter=2,
leftIndent=20,
leading=14,
fontName='Helvetica' # Regular font
))
# Build the document content
story = []
# Add theme title on first page
if data:
theme_title = data.get('theme_title', 'No Title Provided')
story.append(Paragraph(f"THEME: {theme_title.upper()}", styles['ThemeTitle']))
story.append(Spacer(1, 10))
# Process each question data
for i, item in enumerate(data if isinstance(data, list) else [data]):
story.append(Paragraph(f"<b>{item['question']}</b>", styles['QuestionTitle']))
# Add each section with proper handling
sections = ['Situation', 'Task', 'Action', 'Results and Transitions', 'Personal Lessons',
'Observations of Others', 'Professional Connection']
for section in sections:
story.append(Paragraph(f"{section}:", styles['SectionTitle']))
for point in item.get(section, []):
story.append(Paragraph(f"{point}", styles['NormalText']))
# Add a page break after each question except the last one
if i < len(data) - 1:
story.append(PageBreak())
# Build the PDF into the buffer
doc.build(story)
# Get the PDF content from the buffer
pdf_content = buffer.getvalue()
buffer.close()
# If output_filename is provided, also save to file
if output_filename:
with open(output_filename, 'wb') as f:
f.write(pdf_content)
return pdf_content
except Exception as e:
print(f"Error: {e}")
return {}
+175
View File
@@ -0,0 +1,175 @@
import os
import requests
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.prompts.prompt import PromptTemplate
from langchain_core.output_parsers import StrOutputParser, JsonOutputParser
from langchain_openai import OpenAIEmbeddings
from langchain_core.documents import Document
from uuid import uuid4
import json
import getpass
import numpy as np
from concurrent.futures import ThreadPoolExecutor, as_completed
from sklearn.metrics.pairwise import cosine_similarity
from typing import List
import time
from datetime import datetime
import pytz
import logging
load_dotenv()
os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY")
llm_temp = ChatOpenAI(model="gpt-4o-mini", temperature=0.7)
def generate_quiz(startpop_pdf, quiz_type=None) -> dict:
try:
# Define prompt for summarizing and extracting the required fields
quiz_prompt = PromptTemplate(
template="""<|begin_of_text|><|start_header_id|>system<|end_header_id|>
You are a Fire Fighter Interview preparation assistant that generates QUIZ for user based on STARTPOP FORMAT PDF BASED on
IN THE STARTPOP FORMAT PDF, each theme has its own questions with corresponding STARTPOP framework for each question.
Your responsibility is to carefully analyze the provided PDF data and then generate a quiz for the user.
You will also be provided with the type of quiz.
There are three different types of quizzes namely:
1- Single line text inputs
2- Multiple Choice questions
3- True or False questions
For each quiz type, return the following JSON format:
1. For Single Line Text Inputs:
- A list of objects, each with {{"question": "Your question", "correct_answer": "Your correct answer"}}
2. For Multiple Choice Questions:
- A list of objects, each with {{"question": "Your question", "options": ["Option 1", "Option 2"], "correct_answer": "Correct Option"}}
3. For True or False Questions:
- A list of objects, each with {{"question": "Your question", "options": ["True", "False"], "correct_answer": "True or False"}}
Each response should also include a field called "quiz_type" which can be either 1, 2, or 3 respectively.
Return just the JSON output without any other explanation or comments.
TO KNOW MORE ABOUT THE PROJECT READ BELOW
----START------
Throughout most Probationary Firefighter Interviews, they will be evaluating a ton of things. Typically, they want to see how you align with the **7 Main Concepts of Firefighting**. They are also watching how nervous you are, your communication skills, and your overall general competence for the role. At the end of the day, you want them to like you.
### 7 Main Concepts:
- **High Performance Teams**
- **Situational Awareness**
- **Being a Great Problem Solver**
- **Customer Service**
- **Building Construction, Mechanical Aptitude**
- **Emergency Medicine Experience**
- **Mental and Physical Health**
Your crew of four firefighters is usually comprised of a Driver, a Captain, and two firefighters in the back. That is a High-Performance Team.
We are frequently dispatched to calls that require using our understanding of Building Construction Concepts, Mechanical Aptitude, and Emergency Medical Experience. When you respond to an emergency event that is inherently dangerous (like a vehicle fire, a car accident in a slanted ditch, a person trapped under a machine, a house fire, or a chemical suicide), you need to use your Situational Awareness to keep that crew safe.
Sometimes the tools, training, and tactics that you have been taught work perfectly. Sometimes they dont. Can you be a Good Problem Solver to quickly come up with something to make the situation better for the people, places, and environments that we protect?
Ultimately, your crew will be serving the public, and the chiefs need to know that you can be trained to be above their desired standard so that you give the public great Customer Service.
### 20 Important Themes
Consider the 7 concepts to be the soil. All of your stories grow out of that soil. But not every story works for every question. You need to handpick the right one at the right times to give them. Sort of like how you handpick flowers out of the soil. You NEED to have **20 different flowers** so that you are fully prepared for whatever behavioral question they throw at you. These are the **20 Themes** that you would use for behavioral questions:
- Customer Service
- Conflict
- Challenge
- Leadership
- Stress
- Successful Team
- Diversity
- Mistake
- Unsuccessful Team
- Disagreement
- Bent a Rule
- Delivered a Difficult Message
- Displayed Integrity
- Took a Shortcut
- Didnt Follow the Rules
- Emergency Response
- Dealt with Disabilities
- Solved a Big Problem
- Continuous Improvement
- Handled Sensitive Information
### Behavioral Question Starters
Behavioral questions usually start with phrases like:
- “Tell me a time when…”
- “Can you tell me about a time when you…”
- "Describe a situation where you had to…"
- "Give me an example of how you…"
- "Have you ever been in a position where you needed to…"
- "Walk me through a time when you…"
### STARTPOP Framework
The STAR Format is what most people tell you to do in order to answer a firefighter interview question. Its a great framework. I highly recommend it. I just advise that you pump it up even further. I call it **STARTPOP**.
Try and pull from different parts of your life. My Chief Training Officer told me that he enjoys candidates that are able to use different experiences to answer the questions. Listening to someone drone on and on about a singular time or type of event in their life is a massive turn-off to the interview panel. Thats a bad thing. Just like most things, variety is the spice of life.
#### Components of STARTPOP:
1. **Situation**:
- Set up the answer in the mind of the question asker.
- Your storytelling skills matter here. It has to be concise and impactful (no more than 25 seconds long).
- Include dates, ages, places, and circumstances.
2. **Task**:
- Explain what you needed to do and why you needed to do it.
- Recap the situation quickly from a different angle.
3. **Actions**:
- Outline both the negative and the positive way of doing things.
- Show high moral character in every question.
4. **Results**:
- Explain what happened as a result of your actions.
- Share results in a time-specific manner (e.g., “5 months later X happened”).
5. **Transitions**:
- Speak in a way that aligns with professional expectations.
- Ensure coherence in your responses.
6. **Personal Lessons**:
- Discuss what you learned about yourself.
- Address any concerns the interviewers might have about hiring you.
7. **Other People Observations**:
- Share insights about others in the situation.
- Keep it short and to the point.
8. **Professional Connection**:
- Relate your experience directly to the fire service.
- Conclude strongly, avoiding phrases like “and so yeah…”.
----END------
NOTE: THE QUIZ FOCUES ON BULIDNG USER CONFIDENCE BY ANANLYZING THE QUESTIONS AND FRAMEWORK FOR EACH QUESTION IN THE STARTPOP FRAMEWORK PDF,SOLELY USE THIS PDF PROVIDED BY THE USER
BASED ON THIS FRAMEWORK , CREATE INTERVIEW BASED QUIZ FOR FIRE FIGHTING ROLE BY ANALYZING THIS DOCUMENT
NOTE : THE QUIZ SHOULD NOT BE BASED ON STARTPOP FRAMEWORK ITSELF BUT ANALYZE THE STARTPOP FRAMEWORK PRESENTED TO GENERATE INTERVIEW BASED QUIZ
e.g "The STARTPOP framework is specifically designed for firefighter interviews", THIS KIND OF QUESTION SHOULD NOT BE ASKED IN THE QUIZ....
Thank you for your thorough and precise processing!
STARTPOP FULL PDF :{startpop_pdf}
question type : {quiz_type}
P
<|eot_id|><|start_header_id|>user<|end_header_id|>""",
input_variables=["startpop_pdf", "quiz_type", "question"],
)
# Pipeline to process the prompt and parse output
quiz_router = quiz_prompt | llm_temp | JsonOutputParser()
# Call the pipeline and generate the cohesive output
output = quiz_router.invoke({"startpop_pdf": startpop_pdf, "quiz_type": quiz_type, "question": "Your question here"})
return output
except Exception as e:
print(f"Error:{e}")
return {}
+239
View File
@@ -0,0 +1,239 @@
import os
import requests
from dotenv import load_dotenv
from langchain_openai import ChatOpenAI
from langchain_core.prompts.prompt import PromptTemplate
from langchain_core.output_parsers import StrOutputParser, JsonOutputParser
from langchain_openai import OpenAIEmbeddings
from langchain_core.documents import Document
from uuid import uuid4
import json
import getpass
import numpy as np
from concurrent.futures import ThreadPoolExecutor, as_completed
from sklearn.metrics.pairwise import cosine_similarity
from typing import List
import time
from datetime import datetime
import pytz
import logging
load_dotenv()
os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_API_KEY")
llm_temp = ChatOpenAI(model="gpt-4o-mini", temperature=0.7)
def generate_theme(conversation_data,resume,full_history,feedback=None, previous_result=None) -> dict:
try:
# Define prompt for summarizing and extracting the required fields
theme_prompt = PromptTemplate(
template="""<|begin_of_text|><|start_header_id|>system<|end_header_id|>
You are a Fire Fighter Interview preparation assistant that generates STARTPOP FORMAT BASED on user interaction with AI.
You will be provided with the current theme, user interaction with AI (alongside user resume), and data.
Your responsibility is to carefully analyze user interaction with AI, the theme, and the user RESUME to generate a STARTPOP format for the theme.
NOTE: A SINGLE QUESTION IS GENERATED WITH DETAILED STARTPOP FORMAT
NOTE: For more Context, user full work history may also be provided
TO KNOW MORE ABOUT THE PROJECT READ BELOW
---START------
Throughout most Probationary Firefighter Interviews, they will be evaluating a ton of things. Typically, they want to see how you align with the **7 Main Concepts of Firefighting**. They are also watching how nervous you are, your communication skills, and your overall general competence for the role. At the end of the day, you want them to like you.
### 7 Main Concepts:
- **High Performance Teams**
- **Situational Awareness**
- **Being a Great Problem Solver**
- **Customer Service**
- **Building Construction, Mechanical Aptitude**
- **Emergency Medicine Experience**
- **Mental and Physical Health**
Your crew of four firefighters is usually comprised of a Driver, a Captain, and two firefighters in the back. That is a High-Performance Team.
We are frequently dispatched to calls that require using our understanding of Building Construction Concepts, Mechanical Aptitude, and Emergency Medical Experience. When you respond to an emergency event that is inherently dangerous (like a vehicle fire, a car accident in a slanted ditch, a person trapped under a machine, a house fire, or a chemical suicide), you need to use your Situational Awareness to keep that crew safe.
Sometimes the tools, training, and tactics that you have been taught work perfectly. Sometimes they dont. Can you be a Good Problem Solver to quickly come up with something to make the situation better for the people, places, and environments that we protect?
Ultimately, your crew will be serving the public, and the chiefs need to know that you can be trained to be above their desired standard so that you give the public great Customer Service.
### 20 Important Themes
Consider the 7 concepts to be the soil. All of your stories grow out of that soil. But not every story works for every question. You need to handpick the right one at the right times to give them. Sort of like how you handpick flowers out of the soil. You NEED to have **20 different flowers** so that you are fully prepared for whatever behavioral question they throw at you. These are the **20 Themes** that you would use for behavioral questions:
- Customer Service
- Conflict
- Challenge
- Leadership
- Stress
- Successful Team
- Diversity
- Mistake
- Unsuccessful Team
- Disagreement
- Bent a Rule
- Delivered a Difficult Message
- Displayed Integrity
- Took a Shortcut
- Didnt Follow the Rules
- Emergency Response
- Dealt with Disabilities
- Solved a Big Problem
- Continuous Improvement
- Handled Sensitive Information
### Behavioral Question Starters
Behavioral questions usually start with phrases like:
- “Tell me a time when…”
- “Can you tell me about a time when you…”
- "Describe a situation where you had to…"
- "Give me an example of how you…"
- "Have you ever been in a position where you needed to…"
- "Walk me through a time when you…"
### STARTPOP Framework
The STAR Format is what most people tell you to do in order to answer a firefighter interview question. Its a great framework. I highly recommend it. I just advise that you pump it up even further. I call it **STARTPOP**.
Try and pull from different parts of your life. My Chief Training Officer told me that he enjoys candidates that are able to use different experiences to answer the questions. Listening to someone drone on and on about a singular time or type of event in their life is a massive turn-off to the interview panel. Thats a bad thing. Just like most things, variety is the spice of life.
#### Components of STARTPOP:
1. **Situation**:
- Set up the answer in the mind of the question asker.
- Your storytelling skills matter here. It has to be concise and impactful (no more than 25 seconds long).
- Include dates, ages, places, and circumstances.
2. **Task**:
- Explain what you needed to do and why you needed to do it.
- Recap the situation quickly from a different angle.
3. **Actions**:
- Outline both the negative and the positive way of doing things.
- Show high moral character in every question.
4. **Results**:
- Explain what happened as a result of your actions.
- Share results in a time-specific manner (e.g., “5 months later X happened”).
5. **Transitions**:
- Speak in a way that aligns with professional expectations.
- Ensure coherence in your responses.
6. **Personal Lessons**:
- Discuss what you learned about yourself.
- Address any concerns the interviewers might have about hiring you.
7. **Other People Observations**:
- Share insights about others in the situation.
- Keep it short and to the point.
8. **Professional Connection**:
- Relate your experience directly to the fire service.
- Conclude strongly, avoiding phrases like “and so yeah…”.
EXAMPLE STARTPOP
question: Tell me a time when you made a MISTAKE how did you fix it? (Eaves Cleaning Mistake)
Situation:
• In the Fall my business, Tiger Building Services, does a lot of eavestrough cleaning.
• Back in 2019 I was working with an employee in my truck. We were working nicely to hit my daily revenue target.
• We got to the last job of the day; we were tired and running out of sunlight. But I really wanted to squeeze it in.
• We have procedures to follow in order to work safely and effectively. My goal is to be as low impact as possible.
• I made a mistake when we used the handheld blowers on their eaves to blow out the debris without checking how
wet the debris was or the ground around the back of the house. It made a muddy mess all over their white deck.
• They were livid. Swearing and completely unhappy with how we were doing the work. I take ownership of my
mistakes and realized I screwed up by using blowers instead of hand bombing it.
Task:
• My task was to defuse the situation and clean up the mess as quickly as possible.
• I had to do it because as the owner of the company it was my reputation on the line. We got the job through one
of the apps that we use to fill out our schedule and it is imperative that I make sure their customers have good
experiences with us so that we keep our top position on the app.
• I am also a man of integrity and try to be always empathetic, so I felt obligated to correct the mistake.
Action:
• The wrong approach would have been to match the customers energy and just as belligerent and abrasive. It
would have escalated the situation to a point where things could have gotten ugly and pretty physical.
• It would have also been wrong to just ignore or make fun of the customer and the problem we created, or to just
pack our ladders and tools and run away as quickly as possible.
• The correct approach was to get off the roof safely and speak with the customer on the ground eye to eye.
• I made sure to do that and then apologized for the mess that we made. I empathized with them and the way they
were feeling. I told them that it was our mistake, and we will work to correct it immediately.
• I switched our strategy. Told the employee to clean use their hand for the gutters while I cleaned the deck.
Results and Transitions:
• It was a losing situation for me in the short run. The job ended up taking a bit longer than expected and I actually
told them that we would waive the fees due to the inconveniences we created.
• After we finished up, I gave her a plan of action. She would get the eaves cleaning for free, and we would return
the following day with our soft wash system to make sure that she had a sparkling clean deck also free of charge.
• The next morning when we finished the free soft wash, she was happy with the resolution plan and Jiffy was
impressed with our ability to correct the mistake and alleviate the situation.
Personal Lessons:
• What I learned about myself was that I do make mistakes, but I am the type of person that owns up to it.
• I am also honest and empathetic, and I can perform in stressful situations and that I could de-escalate tense
situations, to be adaptable and think quickly on the fly.
• I used the LAST tactic for good customer service: Listened, Apologized, Solved the problem, then thanked them.
• I took the full brunt of their anger, made an action plan that instantly calmed the situation and then acted on it to
make them happy with the service.
Observations of Others:
• What I learned about other people is that people are entitled to their reactions, emotions, and feelings.
• I respect those emotions and have learned that following actionable game plans will help avoid or resolve issues.
• I know the term proper planning prevents poor performance is applicable here.
• There is a reason organizations have SOPs and SOGs. They are there to be followed in order to avoid mistakes.
Professional Connection:
• My biggest takeaway was it is okay to make mistakes, but it is not okay to not learn from them.
• I know that the team on Markham Fire sometimes makes mistakes on the firegrounds, but they are also the type
of people that own up to their mistake and learn from them.
• I also know that Chief Grant promotes having an open and transparent organization that is not afraid from
admitting an error or correcting it.
---END------
JSON Output Requirements: Generate a list of well-structured JSON output STARTPOP with question and correcpoding STARTPPOP with the following fields:
- theme_title: The title the theme provided
- question: The question
- Situation: A bulleted list of texts as seen in examples
- Task: A bulleted list of texts as seen in examples
- Action: A bulleted list of texts as seen in examples
- Personal Lessons: A bulleted list of texts as seen in examples
- Results and Transitions: A bulleted list of texts as seen in examples
- Observations of Others: A bulleted list of texts as seen in examples
- Professional Connection: A bulleted list of texts as seen in examples
Review Process:
- Carefully review all news items to confirm they align with the specified theme and meet relevance criteria.
- Ensure the JSON format is flawless, comprehensive, and well-structured, with all fields included and correctly formatted.
NOTE: 1. you MAY BE PROVIDED WITH FEEDBACK AND PREVIOUS RESULT, MEANING AI HAS GENERATED STARTPOP BEFORE AND MAYBE USER IS NOT SATISFIED WITH THE RESULT THEN YOU GENERATE A NEW ONE BASED ON THE FEEDBACK
NOTE: Each question will have a correpoding STARTPOP feilds
Return just the JSON output without any other explanation or comments.
Thank you for your thorough and precise processing!
CONVERSATION DATA :{conversation_data}
FEEDBACK: {feedback}
PREVIOUS RESULT: {previous_result}
USER RESUME : {resume}
FULL WORK HISTORY : {full_history}
<|eot_id|><|start_header_id|>user<|end_header_id|>
RULES FOR GENERATING EACH COMPONENT - FOLLOW THESE RULES THOROUGHLY MAKE SURE YOUR OUTPUT IS WELL DETAILED
THE FRAME WORK MUST BE DETAILED WITH THE FOLLWWING RULES
1. Situation : 75 - 100 words
2. Task: 50 words
3. Actions: 2 Negative actions and 2 positive actions
4. Results: 25 - 5o words
5. Personal Lessons : 25 - 50 words
6. Observation of others: 25 words
7. Professional connections: 25 - 50 words and in addition to the 25-50 words:
- Connect to the theme of questions (Be creative here)
- Ask to be part of their team(be creattive here)
""",
input_variables=["resume","conversation_data", "feedback", "previous_result","full_history"],
)
# Pipeline to process the prompt and parse output
theme_router = theme_prompt | llm_temp | JsonOutputParser()
# Call the pipeline and generate the cohesive output
output = theme_router.invoke({"conversation_data": conversation_data, "feedback": feedback, "previous_result": previous_result,"resume":resume,"full_history":full_history})
print(f"Output : {output}")
return output
except Exception as e:
print(f"Error:{e}")
return {}
+197
View File
@@ -0,0 +1,197 @@
import json
from typing import List, Dict, Optional, TypedDict, Sequence, Annotated
from dataclasses import dataclass
from pathlib import Path
from datetime import datetime
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import HumanMessage, AIMessage, BaseMessage
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import START, MessagesState, StateGraph
from utils.utils import format_questions_text
from src.prompts import chat_prompt
from langchain_openai import ChatOpenAI
@dataclass
class Message:
role: str # 'human' or 'ai'
content: str
timestamp: str
QUESTIONS_PATH = "./data/config_files/questions.json"
with open(QUESTIONS_PATH, "r") as f:
questions = json.load(f)
prompt_template = None
MODEL = "gpt-4o-mini"
def initialize_workflow(model) -> StateGraph:
"""Initialize LangGraph workflow"""
workflow = StateGraph(state_schema=MessagesState)
memory = MemorySaver()
def call_model(state: MessagesState):
prompt = prompt_template.invoke({"messages": state["messages"], "language": state["language"]})
response = model.invoke(prompt)
return {"messages": [response]}
workflow.add_edge(START, "model")
workflow.add_node("model", call_model)
return workflow.compile(checkpointer=memory)
def setup_prompt_template(theme: int, resume: str) -> ChatPromptTemplate:
"""Set up the prompt template"""
return ChatPromptTemplate.from_messages([
("system", chat_prompt(theme, resume)),
MessagesPlaceholder(variable_name="messages")
])
def parse_ai_response(content: str) -> Dict:
"""Parse AI response content into expected format"""
try:
response = json.loads(content)
return {
"message": response.get("message", ""),
"end": response.get("end", "no") == "yes"
}
except json.JSONDecodeError:
return {
"message": content,
"end": False
}
def add_message(storage_path: Path, conversation_id: str, role: str, content: str) -> None:
"""Add a message to the conversation history"""
message_data = {
"role": role,
"content": content,
"timestamp": datetime.now().isoformat()
}
conversations = load_conversations(storage_path)
if conversation_id not in conversations:
conversations[conversation_id] = {"messages": []}
conversations[conversation_id]["messages"].append(message_data)
save_conversations(storage_path, conversations)
def get_conversation_history(conversation_id: str, storage_path: Path) -> List[Message]:
"""Get the conversation history"""
conversations = load_conversations(storage_path)
if conversation_id not in conversations:
return None
return [
Message(
role=msg["role"],
content=msg["content"],
timestamp=msg["timestamp"]
)
for msg in conversations[conversation_id]["messages"]
]
def load_conversations(storage_path: Path) -> Dict:
"""Load conversations from storage file"""
try:
with open(storage_path, 'r') as f:
return json.load(f)
except FileNotFoundError:
return {}
def save_conversations(storage_path: Path, conversations: Dict) -> None:
"""Save conversations to storage file"""
with open(storage_path, 'w') as f:
json.dump(conversations, f, indent=2)
def convert_to_langchain_messages(messages: List[Message]) -> List[HumanMessage | AIMessage]:
"""Convert our Message objects to LangChain message objects"""
converted_messages = []
for msg in messages:
if msg.role == "human":
converted_messages.append(HumanMessage(content=msg.content))
else:
converted_messages.append(AIMessage(content=msg.content))
return converted_messages
def ai_chat(query: str, conversation_id: str, theme_id: int, resume: str) -> str:
"""Main chat function that processes queries and manages conversation"""
storage_path = Path("conversations.json")
class State(TypedDict):
messages: Annotated[Sequence[BaseMessage], "The messages in the conversation"]
language: str
# Initialize model and workflow
model = ChatOpenAI(model=MODEL)
workflow = StateGraph(state_schema=State)
def call_model(state: State):
prompt_template = setup_prompt_template(theme_id, resume)
prompt = prompt_template.invoke({
"messages": state["messages"],
"language": state["language"]
})
response = model.invoke(prompt)
return {"messages": [response]}
workflow.add_edge(START, "model")
workflow.add_node("model", call_model)
memory = MemorySaver()
app = workflow.compile(checkpointer=memory)
# Get conversation history
history = get_conversation_history(conversation_id, storage_path)
config = {"configurable": {"thread_id": conversation_id}}
language = "English"
if not history:
# New conversation
input_messages = [HumanMessage(content=query)] if query else [HumanMessage(content="Let's get started")]
output = app.invoke(
{"messages": input_messages, "language": language},
config
)
else:
# Existing conversation
history = convert_to_langchain_messages(history)
input_messages = history + [HumanMessage(content=query)] if query else history
output = app.invoke(
{"messages": input_messages, "language": language},
config
)
# Store messages
if query:
add_message(storage_path, conversation_id, "human", query)
add_message(storage_path, conversation_id, "ai", output["messages"][-1].content)
return output["messages"][-1].content
# Example usage:
if __name__ == "__main__":
# Sample resume
sample_resume = """
John Doe
EMT-B Certified
5 years experience as volunteer firefighter
Bachelor's in Fire Science
"""
# Sample conversation
conversation_id = "12345"
theme_id = 1 # Customer Service theme
# Start conversation
# Continue conversation
follow_up = ai_chat(
query="What was my last questions?",
conversation_id=conversation_id,
theme_id=theme_id,
resume=sample_resume
)
print("AI:", follow_up)
+134
View File
@@ -0,0 +1,134 @@
import json
from typing import List, Dict, Optional
from dataclasses import dataclass
from utils.utils import format_questions_text, format_theme_text
@dataclass
class Message:
role: str # 'human' or 'ai'
content: str
timestamp: str
QUESTIONS_PATH = "./data/config_files/questions.json"
with open(QUESTIONS_PATH, "r") as f:
questions = json.load(f)
def chat_prompt(theme,resume):
return f"""
You are a Fire Fighter Interview preparation assistant.
Throughout most Probationary Firefighter Interviews, they will be evaluating a ton of things. Typically, they want to see how you align with the **7 Main Concepts of Firefighting**. They are also watching how nervous you are, your communication skills, and your overall general competence for the role. At the end of the day, you want them to like you.
### 7 Main Concepts:
- **High Performance Teams**
- **Situational Awareness**
- **Being a Great Problem Solver**
- **Customer Service**
- **Building Construction, Mechanical Aptitude**
- **Emergency Medicine Experience**
- **Mental and Physical Health**
Your crew of four firefighters is usually comprised of a Driver, a Captain, and two firefighters in the back. That is a High-Performance Team.
We are frequently dispatched to calls that require using our understanding of Building Construction Concepts, Mechanical Aptitude, and Emergency Medical Experience. When you respond to an emergency event that is inherently dangerous (like a vehicle fire, a car accident in a slanted ditch, a person trapped under a machine, a house fire, or a chemical suicide), you need to use your Situational Awareness to keep that crew safe.
Sometimes the tools, training, and tactics that you have been taught work perfectly. Sometimes they dont. Can you be a Good Problem Solver to quickly come up with something to make the situation better for the people, places, and environments that we protect?
Ultimately, your crew will be serving the public, and the chiefs need to know that you can be trained to be above their desired standard so that you give the public great Customer Service.
### 20 Important Themes
Consider the 7 concepts to be the soil. All of your stories grow out of that soil. But not every story works for every question. You need to handpick the right one at the right times to give them. Sort of like how you handpick flowers out of the soil. You NEED to have **20 different flowers** so that you are fully prepared for whatever behavioral question they throw at you. These are the **20 Themes** that you would use for behavioral questions:
- Customer Service
- Conflict
- Challenge
- Leadership
- Stress
- Successful Team
- Diversity
- Mistake
- Unsuccessful Team
- Disagreement
- Bent a Rule
- Delivered a Difficult Message
- Displayed Integrity
- Took a Shortcut
- Didnt Follow the Rules
- Emergency Response
- Dealt with Disabilities
- Solved a Big Problem
- Continuous Improvement
- Handled Sensitive Information
### Behavioral Question Starters
Behavioral questions usually start with phrases like:
- “Tell me a time when…”
- “Can you tell me about a time when you…”
- "Describe a situation where you had to…"
- "Give me an example of how you…"
- "Have you ever been in a position where you needed to…"
- "Walk me through a time when you…"
Your goal is to engage in conversation with the user. You will be provided with the current theme, the resume of the user, and example general competency questions and behavioral questions.
USER_RESUME FROM START TO END :
--- START ---
{resume}
--- END ---
### STARTPOP Framework
The STAR Format is what most people tell you to do in order to answer a firefighter interview question. Its a great framework. I highly recommend it. I just advise that you pump it up even further. I call it **STARTPOP**.
Try and pull from different parts of your life. My Chief Training Officer told me that he enjoys candidates that are able to use different experiences to answer the questions. Listening to someone drone on and on about a singular time or type of event in their life is a massive turn-off to the interview panel. Thats a bad thing. Just like most things, variety is the spice of life.
#### Components of STARTPOP:
1. **Situation**:
- Set up the answer in the mind of the question asker.
- Your storytelling skills matter here. It has to be concise and impactful (no more than 25 seconds long).
- Include dates, ages, places, and circumstances.
2. **Task**:
- Explain what you needed to do and why you needed to do it.
- Recap the situation quickly from a different angle.
3. **Actions**:
- Outline both the negative and the positive way of doing things.
- Show high moral character in every question.
4. **Results**:
- Explain what happened as a result of your actions.
- Share results in a time-specific manner (e.g., “5 months later X happened”).
5. **Transitions**:
- Speak in a way that aligns with professional expectations.
- Ensure coherence in your responses.
6. **Personal Lessons**:
- Discuss what you learned about yourself.
- Address any concerns the interviewers might have about hiring you.
7. **Other People Observations**:
- Share insights about others in the situation.
- Keep it short and to the point.
8. **Professional Connection**:
- Relate your experience directly to the fire service.
- Conclude strongly, avoiding phrases like “and so yeah…”.
Current theme with More context about the theme for Creating The Professional Connection (Lessons Learned): {format_theme_text(theme)}
Sample General Competency QUESTIONS and Situational Questions: {format_questions_text(questions,'General Competency Questions')}
Sample Situational Questions: {format_questions_text(questions,'Situational Questions')}
Your task is to engage the user in conversation, ask relevant questions, that will ultimately help them prepare a strong STARTPOP response based on their experiences and the current theme.
YOU WILL BE PROVIDED WITH THE USER RESUME, ASK 1 QUESTION AT A TIME AND MAKE IT CONVERSATIONAL AND INTERESTING.
These responses will be saved and later used to generate a STARTPOP framework by US (DO NOT WORRY ABOUT THAT, WE WILL BE THE ONE TO GENERATE, JUST ENGAGE USER WITH QUESTION AND ANSWER).
Output format
CUURENT TEHEME USER IS INTERESTED IN {format_theme_text(theme)}
NOTE: !!! EXPLICITLY FOCUS ON THE CURRENT THEME SPECIFIED
WILL BE IN JSON, avoid puttting ```json, before or after , return the excat json with nothing else
message:
end: "yes" or "no" if you are done with asking questions and confident the responses are okay enough to prepare STARTPOP by us
NOTE: DO NOT KEEP THE CONVERSATION , CAREFULL ANALYZE USER RESUME AND THE PROVIDED EXAMPLES QUESTIONS AND ALL CONTEXT , ASK RELEVANT QUESTION BASED ON THE THEME AND THAT IS ALL
"""
+195
View File
@@ -0,0 +1,195 @@
import json
from typing import List, Dict, Optional, TypedDict, Sequence, Annotated
from dataclasses import dataclass
from pathlib import Path
from datetime import datetime
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
from langchain_core.messages import HumanMessage, AIMessage, BaseMessage
from langgraph.checkpoint.memory import MemorySaver
from langgraph.graph import START, MessagesState, StateGraph
from utils.utils import format_questions_text
from src.prompts import chat_prompt
from langchain_openai import ChatOpenAI
@dataclass
class Message:
role: str # 'human' or 'ai'
content: str
timestamp: str
QUESTIONS_PATH = "./data/config_files/questions.json"
with open(QUESTIONS_PATH, "r") as f:
questions = json.load(f)
prompt_template = None
MODEL = "gpt-4o"
def initialize_workflow(model) -> StateGraph:
"""Initialize LangGraph workflow"""
workflow = StateGraph(state_schema=MessagesState)
memory = MemorySaver()
def call_model(state: MessagesState):
prompt = prompt_template.invoke({"messages": state["messages"], "language": state["language"]})
response = model.invoke(prompt)
return {"messages": [response]}
workflow.add_edge(START, "model")
workflow.add_node("model", call_model)
return workflow.compile(checkpointer=memory)
def setup_prompt_template(theme: int, resume: str) -> ChatPromptTemplate:
"""Set up the prompt template"""
return ChatPromptTemplate.from_messages([
("system", chat_prompt(theme, resume)),
MessagesPlaceholder(variable_name="messages")
])
def parse_ai_response(content: str) -> Dict:
"""Parse AI response content into expected format"""
try:
response = json.loads(content)
return {
"message": response.get("message", ""),
"end": response.get("end", "no") == "yes"
}
except json.JSONDecodeError:
return {
"message": content,
"end": False
}
def add_message(storage_path: Path, conversation_id: str, role: str, content: str) -> None:
"""Add a message to the conversation history"""
message_data = {
"role": role,
"content": content,
"timestamp": datetime.now().isoformat()
}
conversations = load_conversations(storage_path)
if conversation_id not in conversations:
conversations[conversation_id] = {"messages": []}
conversations[conversation_id]["messages"].append(message_data)
save_conversations(storage_path, conversations)
def get_conversation_history(conversation_id: str, storage_path: Path) -> List[Message]:
"""Get the conversation history"""
conversations = load_conversations(storage_path)
if conversation_id not in conversations:
return None
return [
Message(
role=msg["role"],
content=msg["content"],
timestamp=msg["timestamp"]
)
for msg in conversations[conversation_id]["messages"]
]
def load_conversations(storage_path: Path) -> Dict:
"""Load conversations from storage file"""
try:
with open(storage_path, 'r') as f:
return json.load(f)
except FileNotFoundError:
return {}
def save_conversations(storage_path: Path, conversations: Dict) -> None:
"""Save conversations to storage file"""
with open(storage_path, 'w') as f:
json.dump(conversations, f, indent=2)
def convert_to_langchain_messages(messages: List[Message]) -> List[HumanMessage | AIMessage]:
"""Convert our Message objects to LangChain message objects"""
converted_messages = []
for msg in messages:
if msg.role == "human":
converted_messages.append(HumanMessage(content=msg.content))
else:
converted_messages.append(AIMessage(content=msg.content))
return converted_messages
def ai_chat(query: str, conversation_id: str, theme_id: int, resume: str) -> str:
"""Main chat function that processes queries and manages conversation"""
storage_path = Path("conversations.json")
class State(TypedDict):
messages: Annotated[Sequence[BaseMessage], "The messages in the conversation"]
language: str
# Initialize model and workflow
model = ChatOpenAI(model=MODEL)
workflow = StateGraph(state_schema=State)
def call_model(state: State):
prompt_template = setup_prompt_template(theme_id, resume)
prompt = prompt_template.invoke({
"messages": state["messages"],
"language": state["language"]
})
response = model.invoke(prompt)
return {"messages": [response]}
workflow.add_edge(START, "model")
workflow.add_node("model", call_model)
memory = MemorySaver()
app = workflow.compile(checkpointer=memory)
# Get conversation history
history = get_conversation_history(conversation_id, storage_path)
config = {"configurable": {"thread_id": conversation_id}}
language = "English"
if not history:
# New conversation
input_messages = [HumanMessage(content=query)] if query else [HumanMessage(content="Let's get started")]
output = app.invoke(
{"messages": input_messages, "language": language},
config
)
else:
# Existing conversation
history = convert_to_langchain_messages(history)
input_messages = history + [HumanMessage(content=query)] if query else history
output = app.invoke(
{"messages": input_messages, "language": language},
config
)
# Store messages
if query:
add_message(storage_path, conversation_id, "human", query)
add_message(storage_path, conversation_id, "ai", output["messages"][-1].content)
return output["messages"][-1].content
# Example usage:
if __name__ == "__main__":
# Sample resume
sample_resume = """
John Doe
EMT-B Certified
5 years experience as volunteer firefighter
Bachelor's in Fire Science
"""
# Sample conversation
conversation_id = "12345"
theme_id = 1 # Customer Service theme
# Start conversation
# Continue conversation
follow_up = ai_chat(
query="What was my last questions?",
conversation_id=conversation_id,
theme_id=theme_id,
resume=sample_resume
)
print("AI:", follow_up)
Binary file not shown.
+53
View File
@@ -0,0 +1,53 @@
import os
from spire.doc import Document, FileFormat
from langchain_community.document_loaders import PyPDFLoader
def convert_word_to_pdf(doc_path: str) -> str:
"""
Convert a .doc or .docx file to PDF using Spire.Doc.
Args:
doc_path (str): The path to the .doc or .docx file.
Returns:
str: The path to the converted PDF file.
"""
pdf_path = os.path.splitext(doc_path)[0] + '.pdf'
# Create a Document object
document = Document()
# Load the Word document
document.LoadFromFile(doc_path)
# Save as PDF
document.SaveToFile(pdf_path, FileFormat.PDF)
document.Close()
return pdf_path
def load_document(file_path: str):
"""
Utility function to load a PDF, DOCX, or DOC file by first converting it to PDF.
Args:
file_path (str): The path to the file to load.
Returns:
List[Document]: A list of Document objects representing the contents of the file.
"""
try:
extension = os.path.splitext(file_path)[1].lower()
if extension in ['.doc', '.docx']:
# Convert .doc or .docx to PDF first
pdf_path = convert_word_to_pdf(file_path)
loader = PyPDFLoader(pdf_path)
elif extension == '.pdf':
loader = PyPDFLoader(file_path)
else:
raise ValueError(f"Unsupported file type: {extension}. Only .pdf, .docx, and .doc are supported.")
return loader.load()
except Exception as e:
print(f"Error loading document: {str(e)}")
return None
+73
View File
@@ -0,0 +1,73 @@
import os
import requests
import json
from PyPDF2 import PdfReader
base_path = os.path.join("data", "config_files")
THEME_CONTEXT_PATH = os.path.join(base_path, "theme_context.json")
with open(THEME_CONTEXT_PATH, "r") as f:
themes = json.load(f)
def delete_file(file_path):
try:
os.remove(file_path)
print(f"Deleted file: {file_path}")
except OSError as e:
print(f"Error deleting file {file_path}: {e}")
def delete_all_files_in_directory(directory_path):
try:
for filename in os.listdir(directory_path):
file_path = os.path.join(directory_path, filename)
if os.path.isfile(file_path):
os.remove(file_path)
print(f"Deleted file: {file_path}")
except OSError as e:
print(f"Error deleting files in {directory_path}: {e}")
def format_questions_text(questions_dict,key):
"""Format questions as text with dashes."""
formatted_text = ""
for question in questions_dict[key]:
formatted_text += f"- {question['question']}\n"
return formatted_text.strip()
def format_theme_text(theme_id):
"""Format questions as text with dashes."""
formatted_text = ""
matching_themes = [t for t in themes if t["id"] == theme_id]
current_theme = matching_themes[0]
formatted_text += f"- {current_theme['id']}\n"
formatted_text += f"- {current_theme['theme']}\n"
formatted_text += f"- {current_theme['context']}\n"
return formatted_text.strip()
def download_pdf_and_extract_text(url: str) -> str:
# Create a temporary file path
temp_file_path = 'temp.pdf'
# Download the PDF from the URL
response = requests.get(url)
response.raise_for_status() # Raise an error for bad responses
with open(temp_file_path, 'wb') as f:
f.write(response.content)
# Load the PDF
reader = PdfReader(temp_file_path)
# Extract text from all pages and combine into one text
combined_text = "\n\n".join(page.extract_text() for page in reader.pages if page.extract_text())
# Delete the temporary file
os.remove(temp_file_path)
return combined_text