cicboy commited on
Commit
8003083
·
1 Parent(s): 4d84497

update app.py and requirements.txt files

Browse files
Files changed (2) hide show
  1. app.py +48 -38
  2. requirements.txt +0 -1
app.py CHANGED
@@ -1,64 +1,74 @@
1
-
2
  from dataclasses import dataclass
3
- import imdb
4
- from pydantic import BaseModel
5
  from pydantic_ai import Agent, RunContext
6
  import gradio as gr
7
  import os
 
8
 
 
9
  OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
10
  if not OPENAI_API_KEY:
11
  raise RuntimeError("Missing OPENAI_API_KEY. Add it in Spaces → Settings → Secrets.")
12
 
 
 
 
 
 
13
  class Review(BaseModel):
14
  why: str
15
- rating: int
16
  recommended: bool
17
 
18
- class IMDbConnection:
19
- def __init__(self):
20
- self.ia = imdb.IMDb()
 
 
21
 
22
  async def get_movie_info(self, title: str) -> str:
23
  title = (title or "").strip()
24
  if not title:
25
  return "ERROR: No title provided."
26
 
27
- print(f"Searching for movie: {title}")
28
-
29
  try:
30
- movies = self.ia.search_movie(title)
 
 
 
31
  except Exception as e:
32
- return f"ERROR: IMDb search failed: {type(e).__name__}: {e}"
33
 
34
- if not movies:
 
 
35
  return (
36
- f"ERROR: No IMDb results found for: {title}\n"
37
- "Try including the year, e.g. 'The Conjuring (2013)'."
 
38
  )
39
 
40
- first = movies[0]
41
- movie_id = getattr(first, "movieID", None)
42
- if not movie_id:
43
- return f"ERROR: IMDb result had no movieID for: {title}"
44
-
45
- try:
46
- movie = self.ia.get_movie(movie_id)
47
- except Exception as e:
48
- return f"ERROR: IMDb fetch failed for '{title}' (id={movie_id}): {type(e).__name__}: {e}"
49
-
50
- return f"""Title: {movie.get("title")}
51
- IMDb Rating: {movie.get("rating")}
52
- Plot: {(movie.get("plot") or [None])[0]}
53
- Year: {movie.get("year")}
54
- Genres: {movie.get("genres")}
55
  """
 
56
 
 
57
  @dataclass
58
  class MovieData:
59
  title: str
60
- imdb_conn: IMDbConnection
61
 
 
62
  agent = Agent(
63
  "openai:gpt-4o-mini",
64
  deps_type=MovieData,
@@ -67,13 +77,13 @@ agent = Agent(
67
 
68
  @agent.system_prompt
69
  async def movie_system_prompt(ctx: RunContext[MovieData]) -> str:
70
- return await ctx.deps.imdb_conn.get_movie_info(ctx.deps.title)
71
 
72
  async def run_agent(user_query: str, movie_title: str):
73
- deps = MovieData(title=movie_title, imdb_conn=IMDbConnection())
74
 
75
- # Preflight IMDb so we show a clean error instead of generating nonsense
76
- preflight = await deps.imdb_conn.get_movie_info(movie_title)
77
  if preflight.startswith("ERROR:"):
78
  return {"Error": preflight.replace("ERROR:", "").strip()}
79
 
@@ -84,14 +94,14 @@ async def run_agent(user_query: str, movie_title: str):
84
  "Recommend": bool(result.output.recommended),
85
  }
86
 
 
87
  with gr.Blocks() as demo:
88
- gr.Markdown("## Movie Recommender Agent")
89
  user_query = gr.Textbox(label="What is your preference? (e.g. 'I like supernatural horror movies')")
90
- movie_title = gr.Textbox(label="Movie name (e.g. 'The Conjuring')")
91
  output = gr.JSON(label="Agent Recommendation")
92
- submit_btn = gr.Button("Check Movie")
93
 
94
- # IMPORTANT: call async fn directly (no asyncio.run)
95
  submit_btn.click(fn=run_agent, inputs=[user_query, movie_title], outputs=output)
96
 
97
  if __name__ == "__main__":
 
 
1
  from dataclasses import dataclass
2
+ from pydantic import BaseModel, Field
 
3
  from pydantic_ai import Agent, RunContext
4
  import gradio as gr
5
  import os
6
+ import httpx
7
 
8
+ # ---- Secrets ----
9
  OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
10
  if not OPENAI_API_KEY:
11
  raise RuntimeError("Missing OPENAI_API_KEY. Add it in Spaces → Settings → Secrets.")
12
 
13
+ OMDB_API_KEY = os.getenv("OMDB_API_KEY")
14
+ if not OMDB_API_KEY:
15
+ raise RuntimeError("Missing OMDB_API_KEY. Add it in Spaces → Settings → Secrets.")
16
+
17
+ # ---- Output schema ----
18
  class Review(BaseModel):
19
  why: str
20
+ rating: int = Field(ge=1, le=10)
21
  recommended: bool
22
 
23
+ # ---- OMDb connector ----
24
+ class OMDbConnection:
25
+ def __init__(self, api_key: str):
26
+ self.api_key = api_key
27
+ self.base_url = "https://www.omdbapi.com/"
28
 
29
  async def get_movie_info(self, title: str) -> str:
30
  title = (title or "").strip()
31
  if not title:
32
  return "ERROR: No title provided."
33
 
34
+ params = {"apikey": self.api_key, "t": title, "plot": "short"}
 
35
  try:
36
+ async with httpx.AsyncClient(timeout=15) as client:
37
+ r = await client.get(self.base_url, params=params)
38
+ r.raise_for_status()
39
+ data = r.json()
40
  except Exception as e:
41
+ return f"ERROR: OMDb request failed: {type(e).__name__}: {e}"
42
 
43
+ if not data or data.get("Response") != "True":
44
+ # OMDb returns Response=False with an Error message
45
+ msg = data.get("Error") if isinstance(data, dict) else None
46
  return (
47
+ f"ERROR: No OMDb results found for: {title}"
48
+ + (f" ({msg})" if msg else "")
49
+ + "\nTry adding the year, e.g. 'The Conjuring (2013)'."
50
  )
51
 
52
+ # Build system prompt from OMDb fields
53
+ system_prompt = f"""Title: {data.get("Title")}
54
+ Year: {data.get("Year")}
55
+ Rated: {data.get("Rated")}
56
+ Runtime: {data.get("Runtime")}
57
+ Genre: {data.get("Genre")}
58
+ Director: {data.get("Director")}
59
+ Actors: {data.get("Actors")}
60
+ IMDb Rating: {data.get("imdbRating")}
61
+ Plot: {data.get("Plot")}
 
 
 
 
 
62
  """
63
+ return system_prompt
64
 
65
+ # ---- Deps container ----
66
  @dataclass
67
  class MovieData:
68
  title: str
69
+ omdb_conn: OMDbConnection
70
 
71
+ # ---- Agent ----
72
  agent = Agent(
73
  "openai:gpt-4o-mini",
74
  deps_type=MovieData,
 
77
 
78
  @agent.system_prompt
79
  async def movie_system_prompt(ctx: RunContext[MovieData]) -> str:
80
+ return await ctx.deps.omdb_conn.get_movie_info(ctx.deps.title)
81
 
82
  async def run_agent(user_query: str, movie_title: str):
83
+ deps = MovieData(title=movie_title, omdb_conn=OMDbConnection(OMDB_API_KEY))
84
 
85
+ # Preflight so we return clean UI errors (and avoid LLM call on missing data)
86
+ preflight = await deps.omdb_conn.get_movie_info(movie_title)
87
  if preflight.startswith("ERROR:"):
88
  return {"Error": preflight.replace("ERROR:", "").strip()}
89
 
 
94
  "Recommend": bool(result.output.recommended),
95
  }
96
 
97
+ # ---- Gradio UI ----
98
  with gr.Blocks() as demo:
99
+ gr.Markdown("## Movie Recommender Agent (OMDb)")
100
  user_query = gr.Textbox(label="What is your preference? (e.g. 'I like supernatural horror movies')")
101
+ movie_title = gr.Textbox(label="Movie name (e.g. 'The Conjuring (2013)')")
102
  output = gr.JSON(label="Agent Recommendation")
 
103
 
104
+ submit_btn = gr.Button("Check Movie")
105
  submit_btn.click(fn=run_agent, inputs=[user_query, movie_title], outputs=output)
106
 
107
  if __name__ == "__main__":
requirements.txt CHANGED
@@ -1,4 +1,3 @@
1
- imdbpy
2
  python-dotenv
3
  pydantic
4
  pydantic-ai
 
 
1
  python-dotenv
2
  pydantic
3
  pydantic-ai