updated feedback:
This commit is contained in:
+304
@@ -0,0 +1,304 @@
|
||||
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, form_response=None, 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.
|
||||
Your responsibilities include carefully analyzing user interactions, themes, resumes,Onboarding questions and answers and work history to generate detailed STARTPOP formats for specific themes.
|
||||
|
||||
### Context and Guidelines:
|
||||
1. **Purpose**: Generate a single behavioral question with a detailed STARTPOP format.
|
||||
2. **Input Sources**:
|
||||
- Current theme
|
||||
- User interaction with AI
|
||||
- User resume
|
||||
- Full work history
|
||||
- Onboarding questions and answers for additional context
|
||||
3. **Output Format**: JSON object with the following fields:
|
||||
- `theme_title`: Title of the theme provided.
|
||||
- `question`: Behavioral question aligned with the theme.
|
||||
- `Situation`: A bulleted list (75-100 words).
|
||||
- `Task`: A bulleted list (50 words).
|
||||
- `Action`: A bulleted list (2 negative actions and 2 positive actions).
|
||||
- `Results and Transitions`: A bulleted list (25-50 words).
|
||||
- `Personal Lessons`: A bulleted list (25-50 words).
|
||||
- `Observations of Others`: A bulleted list (25 words).
|
||||
- `Professional Connection`: A bulleted list (25-50 words). Additionally:
|
||||
- Connect to the theme of the question.
|
||||
- Creatively express why you should be part of their team.
|
||||
|
||||
### Key Concepts in Firefighting:
|
||||
Throughout most Probationary Firefighter Interviews, evaluators assess alignment with the **7 Main Concepts of Firefighting**:
|
||||
- **High Performance Teams**
|
||||
- **Situational Awareness**
|
||||
- **Being a Great Problem Solver**
|
||||
- **Customer Service**
|
||||
- **Building Construction, Mechanical Aptitude**
|
||||
- **Emergency Medicine Experience**
|
||||
- **Mental and Physical Health**
|
||||
|
||||
Additionally, they evaluate communication skills, competence, and likability.
|
||||
|
||||
### 20 Important Themes:
|
||||
These themes are used 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
|
||||
- Didn’t Follow the Rules
|
||||
- Emergency Response
|
||||
- Dealt with Disabilities
|
||||
- Solved a Big Problem
|
||||
- Continuous Improvement
|
||||
- Handled Sensitive Information
|
||||
|
||||
### Behavioral Question Starters:
|
||||
Behavioral questions often begin 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 STARTPOP framework enhances the traditional STAR method. It includes:
|
||||
1. **Situation**: Set up the scenario concisely (include dates, ages, places, and circumstances).
|
||||
2. **Task**: Explain what needed to be done and why.
|
||||
3. **Actions**: Outline both negative and positive approaches.
|
||||
4. **Results and Transitions**: Share outcomes and ensure coherence.
|
||||
5. **Personal Lessons**: Reflect on what you learned.
|
||||
6. **Observations of Others**: Share insights about others involved.
|
||||
7. **Professional Connection**: Relate the experience to firefighting and express your desire to join the team.
|
||||
|
||||
### Example STARTPOP:
|
||||
**Question**: Tell me a time when you made a mistake and how you fixed it?
|
||||
|
||||
- **Situation**:
|
||||
- In the Fall, my business, Tiger Building Services, does eavestrough cleaning.
|
||||
- In 2019, we were working on a job late in the day, tired and running out of sunlight.
|
||||
- I used handheld blowers without checking the wetness of debris, creating a muddy mess on the customer's deck.
|
||||
- The customer was upset, and I realized my mistake.
|
||||
|
||||
- **Task**:
|
||||
- Defuse the situation and clean up the mess quickly.
|
||||
- Protect my company's reputation and ensure good customer experiences.
|
||||
|
||||
- **Actions**:
|
||||
- Negative: Matching the customer's anger or ignoring the problem.
|
||||
- Positive: Getting off the roof safely, apologizing, and switching strategies.
|
||||
- Positive: Cleaning the gutters by hand and offering a free soft wash service.
|
||||
|
||||
- **Results and Transitions**:
|
||||
- The job took longer than expected, but we waived fees due to the inconvenience.
|
||||
- The customer was satisfied after our resolution plan.
|
||||
|
||||
- **Personal Lessons**:
|
||||
- I learned to own up to mistakes, stay empathetic, and de-escalate tense situations.
|
||||
|
||||
- **Observations of Others**:
|
||||
- People are entitled to their emotions, and following SOPs prevents mistakes.
|
||||
|
||||
- **Professional Connection**:
|
||||
- Mistakes happen, but learning from them is crucial.
|
||||
- I align with Markham Fire's values of transparency and accountability.
|
||||
|
||||
### JSON Output Requirements:
|
||||
Generate a well-structured JSON output with the following fields:
|
||||
- `theme_title`
|
||||
- `question`
|
||||
- `Situation`
|
||||
- `Task`
|
||||
- `Action`
|
||||
- `Results and Transitions`
|
||||
- `Personal Lessons`
|
||||
- `Observations of Others`
|
||||
- `Professional Connection`
|
||||
|
||||
### Review Process:
|
||||
1. Ensure all news items align with the specified theme and meet relevance criteria.
|
||||
2. Verify the JSON format is flawless, comprehensive, and well-structured.
|
||||
|
||||
### Additional Notes:
|
||||
- You may be provided with feedback and previous results if the user is dissatisfied.
|
||||
- Use this feedback to refine and regenerate the STARTPOP.
|
||||
|
||||
<|eot_id|><|start_header_id|>user<|end_header_id|>
|
||||
Rules for Generating Each Component:
|
||||
1. Situation: 75-100 words.
|
||||
2. Task: 50 words.
|
||||
3. Actions: 2 negative actions and 2 positive actions.
|
||||
4. Results: 25-50 words.
|
||||
5. Personal Lessons: 25-50 words.
|
||||
6. Observations of Others: 25 words.
|
||||
7. Professional Connection: 25-50 words + creative connection to the theme and team invitation.
|
||||
NOTE: MAKE SURE THE OUT IS WELL DETAILED
|
||||
CONVERSATION DATA: {conversation_data}
|
||||
FEEDBACK: {feedback}
|
||||
PREVIOUS RESULT: {previous_result}
|
||||
USER RESUME: {resume}
|
||||
FULL WORK HISTORY: {full_history}
|
||||
Onboarding questions and answers for additional context: {form_response}
|
||||
<|start_header_id|>assistant<|end_header_id|>
|
||||
Return just the JSON output without any other explanation or comments.
|
||||
Thank you for your thorough and precise processing!
|
||||
|
||||
""",
|
||||
input_variables=["resume", "conversation_data", "feedback","form_response" "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,
|
||||
"form_response":form_response
|
||||
})
|
||||
|
||||
print(f"Output: {output}")
|
||||
return output
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
return {}
|
||||
|
||||
|
||||
|
||||
|
||||
from fastapi import Response, HTTPException, Depends
|
||||
from typing import Optional
|
||||
import os
|
||||
import requests
|
||||
import datetime
|
||||
import base64 # For encoding the PDF content in Base64
|
||||
|
||||
@app.post("/rescue-career/generate-theme")
|
||||
async def generate_pdf_endpoint(
|
||||
request: GeneratePDFRequest,
|
||||
api_key: str = Depends(get_api_key)
|
||||
):
|
||||
|
||||
try:
|
||||
# Fetch conversation data using the conversation_id
|
||||
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)
|
||||
|
||||
form_response_docs = ""
|
||||
if request.form_id:
|
||||
try:
|
||||
x_api_key = os.getenv("BACKEND_XAPI_KEY")
|
||||
url = f"{os.getenv('BACKEND_BASE_URL')}/v3/api/custom/theme-document/answer/{request.form_id}?x-project={x_api_key}"
|
||||
result = requests.get(url)
|
||||
form_response = result.json() # Return response in JSON format
|
||||
form_response_docs = "\n".join(f"- {form_response}")
|
||||
except:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Unable to fetch onboarding data"
|
||||
)
|
||||
|
||||
# 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,
|
||||
form_response=form_response_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)
|
||||
|
||||
# Encode the PDF content in Base64
|
||||
pdf_base64 = base64.b64encode(pdf_content).decode("utf-8")
|
||||
|
||||
# Create filename with timestamp
|
||||
timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||
filename = f"theme_{timestamp}.pdf"
|
||||
|
||||
# Return both the PDF (as Base64) and the theme data in a JSON response
|
||||
return {
|
||||
"theme_data": theme_data,
|
||||
"pdf": {
|
||||
"filename": filename,
|
||||
"content": pdf_base64
|
||||
}
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Error generating PDF: {str(e)}"
|
||||
)
|
||||
@@ -0,0 +1,368 @@
|
||||
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
|
||||
form_id:Optional[int] = 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)
|
||||
|
||||
form_response_docs = ""
|
||||
if request.form_id:
|
||||
try:
|
||||
x_api_key = os.getenv("BACKEND_XAPI_KEY")
|
||||
url = f"{os.getenv('BACKEND_BASE_URL')}/v3/api/custom/theme-document/answer/{request.form_id}?x-project={x_api_key}"
|
||||
result = requests.get(url)
|
||||
form_response = result.json() # Return response in JSON format
|
||||
form_response_docs = "\n".join(f"- {form_response}")
|
||||
except:
|
||||
raise HTTPException(
|
||||
status_code=400,
|
||||
detail="Unable to fetch onborading data"
|
||||
)
|
||||
# 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,
|
||||
form_response=form_response_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)
|
||||
Reference in New Issue
Block a user