Movie Finder Agent

July 11, 2025 ยท View on GitHub

Build

Kotlin Java Spring Apache Tomcat Apache Maven ChatGPT JSON GitHub Actions Docker IntelliJ IDEA

ย ย ย ย 

ย ย ย ย 

Movie Finder Agent

An intelligent movie recommendation agent that analyzes taste profiles and suggests streaming-available movies.

What It Teaches:

  • ๐Ÿ—๏ธ Domain-Driven Design with rich domain models
  • ๐Ÿ”„ Complex workflows with conditions and retries
  • ๐Ÿ“Š Spring Data integration with repositories
  • ๐ŸŽญ Persona-based prompting for creative content
  • ๐Ÿ› ๏ธ Multiple API integration (OMDB, streaming services)
  • ๐Ÿ“ˆ Progress tracking and event publishing
  • ๐Ÿค Human-in-the-loop confirmations

API keys you'll need

Besides your LLM keys such as as OPENAI_API_KEY, you will need to set the following environment variables:

  • export OMDB_API_KEY=<your_omdb_key>
  • export X_RAPIDAPI_KEY=<your_rapidapi_key>

See Open Movie Database and Rapid API Hub for information about required integrations, and to obtain API keys.

Domain Model

data class MovieBuff(
    override val name: String,
    val movieRatings: List<MovieRating>,
    val countryCode: String,
    val streamingServices: List<String>
) : Person

data class DecoratedMovieBuff(
    val movieBuff: MovieBuff,
    val tasteProfile: String  // AI-generated analysis
)

How It Works

  1. Find MovieBuff from repository (with confirmation)
  2. Analyze their taste profile using AI
  3. Research current news for inspiration
  4. Generate movie suggestions (excluding seen movies)
  5. Filter by streaming availability
  6. Create Roger Ebert-style writeup

Running

First, start the PostgresSQL database using Docker with:

docker compose up

Start the application under your IDE or by navigating to the scripts directory and typing ./run.sh.

You will find the app at http://localhost:2001. Thanks to Stanley Kubrick.

The logging will channel Severance.

Key Patterns

Spring Configuration

@ConfigurationProperties(prefix = "embabel.examples.moviefinder")
data class MovieFinderConfig(
    val suggestionCount: Int = 5,
    val suggesterPersona: Persona = Roger,
    val model: String = OpenAiModels.GPT_41_MINI
)

interface MovieBuffRepository : CrudRepository<MovieBuff, String>

Advanced Workflow Control

@Action(
    post = [HAVE_ENOUGH_MOVIES],  // Condition check
    canRerun = true               // Retry if needed
)
fun suggestMovies(/* params */): StreamableMovies

@Condition(name = HAVE_ENOUGH_MOVIES)
fun haveEnoughMovies(context: OperationContext): Boolean