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
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.
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
)- Find MovieBuff from repository (with confirmation)
- Analyze their taste profile using AI
- Research current news for inspiration
- Generate movie suggestions (excluding seen movies)
- Filter by streaming availability
- Create Roger Ebert-style writeup
First, start the PostgresSQL database using Docker with:
docker compose upStart 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.
@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>@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