-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
4 changed files
with
468 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Oops, something went wrong.