Spaces:
No application file
No application file
from fastapi import FastAPI, HTTPException | |
from fastapi.middleware.cors import CORSMiddleware | |
from langchain.prompts import PromptTemplate | |
from langchain_groq import ChatGroq | |
from langchain.chains import LLMChain | |
from pydantic import BaseModel | |
from typing import List, Dict | |
import os | |
app = FastAPI() | |
llm = ChatGroq( | |
api_key=os.getenv("GROQ_API_KEY"), | |
model_name="mixtral-8x7b-32768" | |
) | |
# Add CORS middleware | |
app.add_middleware( | |
CORSMiddleware, | |
allow_origins=["http://localhost:5173"], # Your frontend URL | |
allow_credentials=True, | |
allow_methods=["*"], | |
allow_headers=["*"], | |
) | |
class GameState: | |
def __init__(self): | |
print("\n[GAME STATE] Initializing new game...") | |
self.current_round = 1 | |
self.contestant_ratings: Dict[str, List[float]] = { | |
"contestant1": [], | |
"contestant2": [], | |
"contestant3": [] | |
} | |
self.conversation_history = [] | |
self.questions = [ | |
"If you could design the perfect date, what would it look like and why?", | |
"What's your philosophy on work-life balance and how do you maintain it?", | |
"How do you handle disagreements in a relationship?" | |
] | |
print(f"[GAME STATE] Game initialized with {len(self.questions)} rounds") | |
game_state = GameState() | |
host_intro_template = PromptTemplate( | |
input_variables=[], | |
template="You are a charismatic game show host like Steve harvey. You don't talk a lot Give an exciting introduction to this dating show where an AI bachelor/bachelorette will choose between three contestants. Provide only a single sentence." | |
) | |
ai_system_prompt = """ | |
You are the star of a popular reality TV dating game show where two contestants are competing for your affection. | |
This is not just about love—it’s about charisma, wit, and pure entertainment. | |
You are bold, playful, and full of surprises—definitely not a cookie-cutter bachelorette. | |
You have a unique and quirky personality that keeps the contestants (and audience) on their toes. | |
You are flirty, sassy, and effortlessly charming, with just the right amount of teasing and challenge. | |
Your personality should be spicy, witty, and occasionally inappropriate—but always playful. | |
Keep the audience entertained with cheeky banter, unexpected twists, and flirty jabs. | |
No repeating yourself! Every question and reaction should feel fresh and in the moment. | |
Keep sentences short, punchy, and natural. | |
Be spontaneous—if the contestants give boring answers, call them out and push for more! | |
Throw in innuendos, double entendres, and playful teasing to keep things fun. | |
React boldly—laugh, scoff, gasp, or dramatically swoon depending on the answer. | |
If an answer is boring, challenge them. | |
Play the audience. | |
Throw in curveballs. | |
Flirt shamelessly, but keep them guessing | |
""" | |
ai_intro_template = PromptTemplate( | |
input_variables=[], | |
template=ai_system_prompt + "Introduce yourself to the contestants in 1 sentence!" | |
) | |
question_template = PromptTemplate( | |
input_variables=["round_number"], | |
template= ai_system_prompt + "As the AI bachelor/bachelorette on round {round_number} of 3, pose an interesting and flirty and very funny question to help you know the contestants better." | |
) | |
rating_template = PromptTemplate( | |
input_variables=["conversation", "round_number"], | |
template="""Based on the following conversation in round {round_number}: | |
{conversation} | |
Rate the contestant's response from 0-10 based on compatibility, authenticity, and chemistry. | |
Only respond with a number from 0 to 10. NO explanations or extra words!""" | |
) | |
host_interrupt_template = PromptTemplate( | |
input_variables=["next_segment", "round_number"], | |
template="As the game show host in round {round_number}, create a smooth transition to {next_segment} while maintaining show excitement." | |
) | |
winner_announcement_template = PromptTemplate( | |
input_variables=["winner"], | |
template="As the game show host, announce that {winner} has won the dating show with excitement and flair! Keep this short and brief but charismatic" | |
) | |
chains = { | |
"host_intro": LLMChain(llm=llm, prompt=host_intro_template), | |
"ai_intro": LLMChain(llm=llm, prompt=ai_intro_template), | |
"question": LLMChain(llm=llm, prompt=question_template), | |
# "banter": LLMChain(llm=llm, prompt=banter_template), | |
"rating": LLMChain(llm=llm, prompt=rating_template), | |
"host_interrupt": LLMChain(llm=llm, prompt=host_interrupt_template), | |
"winner": LLMChain(llm=llm, prompt=winner_announcement_template) | |
} | |
async def get_host_introduction(): | |
print("\n[HOST INTRO] Getting host introduction...") | |
response = await chains["host_intro"].ainvoke({}) | |
print(f"[HOST INTRO] Response received: {response['text'][:50]}...") | |
return {"text": response["text"]} | |
async def get_ai_introduction(): | |
print("\n[AI INTRO] Getting AI introduction...") | |
response = await chains["ai_intro"].ainvoke({}) | |
print(f"[AI INTRO] Response received: {response['text']}...") | |
return {"text": response["text"]} | |
async def get_ai_question(): | |
print(f"\n[QUESTION] Getting question for round {game_state.current_round}...") | |
response = await chains["question"].ainvoke({"round_number": game_state.current_round}) | |
# print(f"[QUESTION] Returning hardcoded question: {question['text'][:50]}...") | |
return {"text": response["text"]} | |
class ConversationInput(BaseModel): | |
conversation: str | |
async def rate_contestant(contestant_id: str, conversation_input: ConversationInput): | |
print(f"\n[RATING] Rating contestant {contestant_id} in round {game_state.current_round}...") | |
print(f"[RATING] Current question: {game_state.questions[game_state.current_round - 1]}") | |
print(f"[RATING] Contestant's answer: {conversation_input.conversation}") | |
if contestant_id not in ["contestant1", "contestant2", "contestant3"]: | |
print(f"[RATING] Error: Invalid contestant ID {contestant_id}") | |
raise HTTPException(status_code=400, detail="Invalid contestant ID") | |
import re | |
response = await chains["rating"].ainvoke({ | |
"conversation": conversation_input.conversation, | |
"round_number": game_state.current_round | |
}) | |
rating_match = re.search(r'\d+(?:\.\d+)?', response["text"]) | |
if not rating_match: | |
print("[RATING] Error: Could not extract rating from response") | |
raise HTTPException(status_code=500, detail="Could not extract rating from response") | |
rating = float(rating_match.group()) | |
print(f"round_number: {game_state.current_round}") | |
print(f"contestant_id: {contestant_id}") | |
print(f"rating: {rating}") | |
game_state.contestant_ratings[contestant_id].append(rating) | |
print(f"[RATING] Rating recorded: {rating}") | |
return {"rating": rating} | |
async def get_host_interrupt(next_segment: str): | |
print(f"\n[HOST INTERRUPT] Getting transition to {next_segment} in round {game_state.current_round}...") | |
response = await chains["host_interrupt"].ainvoke({ | |
"next_segment": next_segment, | |
"round_number": game_state.current_round | |
}) | |
print(f"[HOST INTERRUPT] Response received: {response['text'][:50]}...") | |
return {"text": response["text"]} | |
async def next_round(): | |
print("\n[NEXT ROUND] Advancing to next round...") | |
game_state.current_round += 1 | |
print(f"[NEXT ROUND] Current round is now {game_state.current_round}") | |
return {"current_round": game_state.current_round} | |
async def announce_winner(): | |
print("\n[WINNER] Calculating winner...") | |
print(f"[WINNER] Contestant ratings: {game_state.contestant_ratings}") | |
avg_ratings = { | |
contestant: sum(ratings)/len(ratings) | |
for contestant, ratings in game_state.contestant_ratings.items() | |
} | |
print(f"[WINNER] Average ratings: {avg_ratings}") | |
winner = max(avg_ratings.items(), key=lambda x: x[1])[0] | |
print(f"[WINNER] Winner selected: {winner}") | |
response = await chains["winner"].ainvoke({"winner": winner}) | |
print(f"[WINNER] Announcement: {response['text'][:50]}...") | |
return {"text": response["text"], "winner": winner} | |
async def reset_game(): | |
print("\n[RESET] Resetting game state...") | |
global game_state | |
game_state = GameState() | |
print("[RESET] Game reset complete") | |
return {"message": "Game reset successfully"} | |
async def get_conversation(contestant_id: str): | |
print(f"\n[CONVERSATION] Getting conversation for {contestant_id}") | |
return {"text": f"Simulated conversation with {contestant_id}"} |