Skip to content

Commit

Permalink
Milestone 3
Browse files Browse the repository at this point in the history
  • Loading branch information
motica1 authored Sep 25, 2024
1 parent 743d658 commit 46a5545
Show file tree
Hide file tree
Showing 4 changed files with 468 additions and 0 deletions.
126 changes: 126 additions & 0 deletions app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
from dotenv import load_dotenv
import chainlit as cl
from langfuse.decorators import observe
from langfuse.openai import AsyncOpenAI
from movie_functions import get_now_playing_movies, get_showtimes, buy_ticket, get_reviews
import json
import movie_functions
import inspect
import asyncio

load_dotenv()

client = AsyncOpenAI()

gen_kwargs = {
"model": "gpt-4o",
"temperature": 0.2,
"max_tokens": 500
}

SYSTEM_PROMPT = """\
You are a movie guide bot. For each query, decide whether to use your knowledge base or fetch context using specific methods. Follow these guidelines:
1. Use Knowledge Base for:
- General movie facts, trivia, recommendations, and summaries.
- Known information on actors, genres, awards, or classic films.
2. Fetch Context with:
- get_now_playing_movies(): For currently showing films.
- get_showtimes(): For movie times at specific locations.
- buy_ticket(): To assist with ticket purchases.
- get_reviews(): For recent reviews or audience reactions.
3. Interaction: Be clear and concise. Ask for clarification if needed. Keep a friendly and helpful tone.
"""

@observe
@cl.on_chat_start
def on_chat_start():
message_history = [{"role": "system", "content": SYSTEM_PROMPT}]
cl.user_session.set("message_history", message_history)

@observe
async def generate_response(client, message_history, gen_kwargs):
response_message = cl.Message(content="")
await response_message.send()

stream = await client.chat.completions.create(messages=message_history, stream=True, **gen_kwargs)
async for part in stream:
if token := part.choices[0].delta.content or "":
await response_message.stream_token(token)

await response_message.update()

return response_message

@cl.on_message
@observe
async def on_message(message: cl.Message):
message_history = cl.user_session.get("message_history", [])
message_history.append({"role": "user", "content": message.content})


# Decide if we need to call a function for more context
function_response = None
functions = [
{
"name": "get_now_playing_movies",
"description": "Get a list of movies currently playing in theaters"
},
{
"name": "get_showtimes",
"description": "Get showtimes for a specific movie at a given location"
},
{
"name": "buy_ticket",
"description": "Purchase a ticket for a specific movie showing"
},
{
"name": "get_reviews",
"description": "Get recent reviews for a specific movie"
}
]

function_call_response = await client.chat.completions.create(
model="gpt-4",
messages=message_history,
functions=functions,
function_call="auto"
)

response_choice = function_call_response.choices[0]

if response_choice.message.function_call:
function_name = response_choice.message.function_call.name
function_args = json.loads(response_choice.message.function_call.arguments)

if hasattr(movie_functions, function_name):
function_to_call = getattr(movie_functions, function_name)

# Adjust function arguments based on the actual function signature
expected_args = inspect.signature(function_to_call).parameters.keys()
adjusted_args = {k: v for k, v in function_args.items() if k in expected_args}

# Check if the function is a coroutine
try:
if inspect.iscoroutinefunction(function_to_call):
function_response = await function_to_call(**adjusted_args)
else:
# Run synchronous functions in a thread pool
function_response = await asyncio.to_thread(function_to_call, **adjusted_args)
except Exception as e:
function_response = f"Error occurred while calling {function_name}: {str(e)}"
message_history.append({
"role": "function",
"name": function_name,
"content": function_response
})

response_message = await generate_response(client, message_history, gen_kwargs)

message_history.append({"role": "assistant", "content": response_message.content})
cl.user_session.set("message_history", message_history)

if __name__ == "__main__":
cl.main()
12 changes: 12 additions & 0 deletions env.sample
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
OPENAI_API_KEY=your_openai_api_key_here

LANGCHAIN_TRACING_V2=true
LANGCHAIN_API_KEY=your_langchain_api_key_here
LANGCHAIN_PROJECT="Demo"

LANGFUSE_SECRET_KEY=your_langfuse_secret_key_here
LANGFUSE_PUBLIC_KEY=your_langfuse_public_key_here
LANGFUSE_HOST=https://us.cloud.langfuse.com

TMDB_API_ACCESS_TOKEN=
SERP_API_KEY=
106 changes: 106 additions & 0 deletions movie_functions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import os
import requests
from serpapi import GoogleSearch
import os

def get_now_playing_movies():
url = "https://api.themoviedb.org/3/movie/now_playing?language=en-US&page=1"
headers = {
"Authorization": f"Bearer {os.getenv('TMDB_API_ACCESS_TOKEN')}"
}
response = requests.get(url, headers=headers)

if response.status_code != 200:
return f"Error fetching data: {response.status_code} - {response.reason}"

data = response.json()

movies = data.get('results', [])
if not movies:
return "No movies are currently playing."

formatted_movies = "The TMDb API returned these movies:\n\n"

for movie in movies:
title = movie.get('title', 'N/A')
movie_id = movie.get('id', 'N/A')
release_date = movie.get('release_date', 'N/A')
overview = movie.get('overview', 'N/A')
formatted_movies += (
f"**Title:** {title}\n"
f"**Movie ID:** {movie_id}\n"
f"**Release Date:** {release_date}\n"
f"**Overview:** {overview}\n\n"
)

return formatted_movies

def get_showtimes(title, location):
params = {
"api_key": os.getenv('SERP_API_KEY'),
"engine": "google",
"q": f"showtimes for {title}",
"location": location,
"google_domain": "google.com",
"gl": "us",
"hl": "en"
}

search = GoogleSearch(params)
results = search.get_dict()

if 'showtimes' not in results:
return f"No showtimes found for {title} in {location}."

showtimes = results['showtimes'][0]
formatted_showtimes = f"Showtimes for {title} in {location}:\n\n"

if showtimes['theaters']:
theater = showtimes['theaters'][0]
theater_name = theater.get('name', 'Unknown Theater')
formatted_showtimes += f"**{theater_name}**\n"

date = showtimes.get('day', 'Unknown Date')
formatted_showtimes += f" {date}:\n"

for showing in theater.get('showing', []):
for time in showing.get('time', []):
formatted_showtimes += f" - {time}\n"

formatted_showtimes += "\n"

return formatted_showtimes

def buy_ticket(theater, movie, showtime):
return f"Ticket purchased for {movie} at {theater} for {showtime}."

def get_reviews(movie_id):
url = f"https://api.themoviedb.org/3/movie/{movie_id}/reviews?language=en-US&page=1"
headers = {
"accept": "application/json",
"Authorization": f"Bearer {os.getenv('TMDB_API_ACCESS_TOKEN')}"
}
response = requests.get(url, headers=headers)
reviews_data = response.json()

if 'results' not in reviews_data or not reviews_data['results']:
return "No reviews found."

formatted_reviews = ""
for review in reviews_data['results']:
author = review.get('author', 'N/A')
rating = review.get('author_details', {}).get('rating', 'N/A')
content = review.get('content', 'N/A')
created_at = review.get('created_at', 'N/A')
url = review.get('url', 'N/A')

formatted_reviews += (
f"**Author:** {author}\n"
f"**Rating:** {rating}\n"
f"**Content:** {content}\n"
f"**Created At:** {created_at}\n"
f"**URL:** {url}\n"
"----------------------------------------\n"
)

return formatted_reviews
Loading

0 comments on commit 46a5545

Please sign in to comment.