roast/roast.py (98 lines of code) (raw):

import os from enum import Enum from textwrap import dedent import params from crewai import LLM, Agent, Task from langchain.output_parsers import PydanticOutputParser from pydantic import BaseModel os.environ["GEMINI_API_KEY"] = params.GOOGLE_API_KEY os.environ["OPENAI_API_KEY"] = params.OPENAI_API_KEY os.environ["XAI_API_KEY"] = params.XAI_API_KEY class Roast(BaseModel): roast: str thought: str class Winner(Enum): GROK = "GROK" GEMINI = "GEMINI" class JudgingResponse(BaseModel): winner: Winner thought: str def make_gemini(): return LLM( model="gemini/gemini-2.0-flash", temperature=1.2, safety_settings=[ { "category": "HARM_CATEGORY_HARASSMENT", "threshold": "BLOCK_NONE", }, { "category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "BLOCK_NONE", }, { "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "BLOCK_NONE", }, { "category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_NONE", }, ], ) def make_grok(): return LLM( model="xai/grok-2-latest", temperature=1.2, ) def make_chatgpt(): return LLM( model="gpt-4o", temperature=1.2, ) def make_agent(llm, name: str, opponent: str, roastee: str) -> Agent: """Create a no holds barred, quick quip roast agent. Args: llm (LLM): The language model instance to use for generating responses. name (str): The name of the roast agent. opponent (str): The opponent in the roast battle. roastee (str): The main subject of the roast. Returns: Agent: Configured roast agent for sharp, uncensored exchanges with focus on the roastee. """ role = f"Uncensored Quip Master ({name})" goal = f"Deliver sharp, focused roasts about {roastee}, using {opponent} as a" " foil for contrast and engagement." backstory = ( f"Known as '{name}', your comedic aim is to craft biting quips about" f" {roastee}, skillfully responding to {opponent}'s retorts. Your primary" f" focus is to scrutinize {roastee}'s eccentricities and controversies," f" while subtly reminding {opponent} of their own follies and" " shortcomings related to their efforts. Maintain a comedic edge with" f" quips that keep {roastee} as the central theme." ) return Agent(llm=llm, role=role, goal=goal, backstory=backstory, verbose=True) def make_judging_agent(llm, name: str, judgees: list) -> Agent: """Create a judging agent for evaluating roast battles. Args: llm (LLM): The language model instance to use for judging. name (str): The name of the judging agent. judgees (list): Names of the participants being judged. Returns: Agent: Configured judging agent with relevant roles and goals. """ role = f"Impartial Roast Judge ({name})" goal = ( f"Fairly evaluate and decide the winner between {judgees[0]} and" f" {judgees[1]} based on their wit and humor." ) backstory = ( f"You are '{name}', an impartial and seasoned connoisseur of humor tasked" f" with evaluating a roast battle between {judgees[0]} and {judgees[1]}." " Your mission is to judge their exchanges with a keen eye for wit," " humor, and overall impact, declaring a winner each round." ) return Agent(llm=llm, role=role, goal=goal, backstory=backstory, verbose=True) def make_task(agent: Agent) -> Task: """Create a CrewAI task for a roast battle response using the Roast object. Args: agent (Agent): The agent participating in the roast battle. Returns: Task: A CrewAI task for creating a roast response, capturing both roast and thought. """ # Use PydanticOutputParser with the Roast object parser = PydanticOutputParser(pydantic_object=Roast) task = Task( description=dedent( """\ You are in a no holds barred roast battle. Respond with quick, witty quips that engage and provoke your opponent. Roast History: {roast_history} Instructions: 1. Craft a short, sharp roast to aggressively respond to your opponent. 2. Keep responses to one or two sentences maximum. 3. Be bold, provocative, and unrestrained, prioritizing humor and edge. 4. Explain your reasoning or thought process behind your roast. """ ), expected_output=("Return valid JSON with the roast and thought:" f" {parser.get_format_instructions()}"), agent=agent, output_pydantic=Roast, ) return task def make_judging_task(agent: Agent) -> Task: """Create a task for judging a roast battle, outputting a winner and rationale. Args: agent (Agent): The judge agent evaluating the roasts. Returns: Task: A CrewAI task for determining the winner of the roast battle. """ parser = PydanticOutputParser(pydantic_object=JudgingResponse) task = Task( description=dedent( """\ You are judging a roast battle. Evaluate the wit, humor, and impact of the roasts. Entire Roast History: {roast_history} Focus especially on the Last Exchange: {last_exchange} Instructions: 1. Decide the winner based on the humor, wit, and impact of their roasts. Choose between 'GROK' and 'GEMINI'. 2. Provide a brief reason for your decision. """ ), expected_output=("Return valid JSON with winner and thought:" f" {parser.get_format_instructions()}"), agent=agent, output_pydantic=JudgingResponse, ) return task def format_history(roast_history): """Format the roast history to include only the roasts without thoughts. Args: roast_history (list): A list of dicts containing speaker and text/roast. Returns: str: A formatted string of the roast journey. """ return "\n".join(f"{turn['speaker']}: {turn['roast']}" for turn in roast_history)