Skip to content

Commit

Permalink
trunk formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
johnymontana committed Dec 20, 2024
1 parent 7cbd13d commit 8e851a9
Show file tree
Hide file tree
Showing 11 changed files with 175 additions and 203 deletions.
37 changes: 25 additions & 12 deletions dgraph-modus-example/README.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,22 @@
# Movie Recommendation App

This project demonstrates the power of **Modus** and **Dgraph** by integrating a graph database with a large language model (LLM) to provide AI-driven movie recommendations. The app consists of a backend (powered by Modus and Dgraph) and a frontend (built with Next.js and tailwind).
This project demonstrates the power of **Modus** and **Dgraph** by integrating a graph database with
a large language model (LLM) to provide AI-driven movie recommendations. The app consists of a
backend (powered by Modus and Dgraph) and a frontend (built with Next.js and tailwind).

## Why Use Modus with Dgraph?

**Modus** simplifies the integration of internal data (from sources like Dgraph) with cutting-edge LLMs. Here's why this combination is powerful:
**Modus** simplifies the integration of internal data (from sources like Dgraph) with cutting-edge
LLMs. Here's why this combination is powerful:

- **Rich Data Queries**: Dgraph enables complex queries across interconnected datasets like movies, genres, actors, and directors. This makes it ideal for graph-based recommendations.
- **Seamless AI Integration**: Modus abstracts the complexity of using LLMs, allowing you to feed internal data into models and retrieve actionable insights tailored to your data.
- **Rapid Prototyping**: With Modus, you can quickly build and test serverless functions that combine graph-based querying and AI recommendations.
- **Customizability**: Dynamically construct prompts for LLMs using Dgraph's query results to generate personalized outputs, such as movie recommendations.
- **Rich Data Queries**: Dgraph enables complex queries across interconnected datasets like movies,
genres, actors, and directors. This makes it ideal for graph-based recommendations.
- **Seamless AI Integration**: Modus abstracts the complexity of using LLMs, allowing you to feed
internal data into models and retrieve actionable insights tailored to your data.
- **Rapid Prototyping**: With Modus, you can quickly build and test serverless functions that
combine graph-based querying and AI recommendations.
- **Customizability**: Dynamically construct prompts for LLMs using Dgraph's query results to
generate personalized outputs, such as movie recommendations.

---

Expand All @@ -19,14 +26,18 @@ The backend is written in Go using **Modus** and **Dgraph**.

### Features

- Functions powered by Modus are integrated with a read-only Dgraph database and an LLM from Hugging Face.
- Functions powered by Modus are integrated with a read-only Dgraph database and an LLM from Hugging
Face.
- Provides a GraphQL endpoint for querying data locally.
- Demonstrates how to use Modus to create powerful, serverless APIs that leverage Dgraph's capabilities and LLM-driven insights.
- Demonstrates how to use Modus to create powerful, serverless APIs that leverage Dgraph's
capabilities and LLM-driven insights.

### Prerequisites

- Install **Modus CLI**: Follow the [Modus installation guide](https://docs.hypermode.com/modus/installation).
- Ensure **Dgraph** is available or connected to the backend (the project uses a read-only Dgraph database).
- Install **Modus CLI**: Follow the
[Modus installation guide](https://docs.hypermode.com/modus/installation).
- Ensure **Dgraph** is available or connected to the backend (the project uses a read-only Dgraph
database).

### Running Locally

Expand Down Expand Up @@ -119,10 +130,12 @@ The frontend is built with **Next.js** and **Tailwind**.
## Learning More
- Modus Documentation: [https://docs.hypermode.com/modus/overview](https://docs.hypermode.com/modus/overview)
- Modus Documentation:
[https://docs.hypermode.com/modus/overview](https://docs.hypermode.com/modus/overview)
- Dgraph Documentation: [https://dgraph.io/docs](https://dgraph.io/docs)
- Next.js Documentation: [https://nextjs.org/docs](https://nextjs.org/docs)
---
This project is an excellent starting point for understanding how to combine the strengths of Dgraph, Modus, and LLMs to create powerful, data-driven applications. 🚀
This project is an excellent starting point for understanding how to combine the strengths of
Dgraph, Modus, and LLMs to create powerful, data-driven applications. 🚀
5 changes: 2 additions & 3 deletions dgraph-modus-example/backend/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import (
"fmt"
"strings"

"github.com/hypermodeinc/modus/sdk/go/pkg/http" // Modus HTTP library for making API requests
"github.com/hypermodeinc/modus/sdk/go/pkg/models" // Modus models library for AI models
"github.com/hypermodeinc/modus/sdk/go/pkg/http" // Modus HTTP library for making API requests
"github.com/hypermodeinc/modus/sdk/go/pkg/models" // Modus models library for AI models
"github.com/hypermodeinc/modus/sdk/go/pkg/models/openai" // Modus OpenAI model integration
)

Expand Down Expand Up @@ -177,7 +177,6 @@ func generatePrompt(movieName string, searchQuery string) string {
return prompt
}


// executeDgraphQuery performs the actual query against the Dgraph database
func executeDgraphQuery(query string) (string, error) {
queryPayload := map[string]string{"query": query}
Expand Down
21 changes: 15 additions & 6 deletions dgraph-modus-example/frontend/README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).
This is a [Next.js](https://nextjs.org) project bootstrapped with

Check notice on line 1 in dgraph-modus-example/frontend/README.md

View check run for this annotation

Trunk.io / Trunk Check

markdownlint(MD041)

[new] First line in a file should be a top-level heading
[`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app).

## Getting Started

Expand All @@ -16,9 +17,12 @@ bun dev

Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.

You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file.
You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the
file.

This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.
This project uses
[`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to
automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel.

## Learn More

Expand All @@ -27,10 +31,15 @@ To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.

You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome!
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback
and contributions are welcome!

## Deploy on Vercel

The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
The easiest way to deploy your Next.js app is to use the
[Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme)
from the creators of Next.js.

Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details.
Check out our
[Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying)
for more details.
100 changes: 43 additions & 57 deletions dgraph-modus-example/frontend/app/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -1,69 +1,62 @@
import { Suspense } from "react";
import { fetchMovieDetailsAndRecommendations } from "@/app/actions";
import Link from "next/link";
import { Suspense } from "react"
import { fetchMovieDetailsAndRecommendations } from "@/app/actions"
import Link from "next/link"

function Loading() {
return (
<div className="flex items-center justify-center">
<p className="text-lg text-white/60 animate-pulse">
Fetching movie details and personalized recommendations from our AI
system, please be patient...
Fetching movie details and personalized recommendations from our AI system, please be
patient...
</p>
</div>
);
)
}

type Movie = {
"name@en": string;
initial_release_date?: string;
genre?: { "name@en": string }[];
starring?: { "performance.actor": { "name@en": string }[] }[];
};
"name@en": string
initial_release_date?: string
genre?: { "name@en": string }[]
starring?: { "performance.actor": { "name@en": string }[] }[]
}

type Recommendations = string;
type Recommendations = string

type MovieDetailsResponse = {
movieDetails: string;
recommendations: Recommendations;
};
movieDetails: string
recommendations: Recommendations
}

async function MovieDetails({
movieId,
searchQuery,
}: {
movieId: string;
searchQuery: string;
}) {
const recommendations: MovieDetailsResponse =
await fetchMovieDetailsAndRecommendations(movieId, searchQuery);
const movieParsed = JSON.parse(recommendations.movieDetails);
const movie: Movie | undefined = movieParsed.data.movie[0];
async function MovieDetails({ movieId, searchQuery }: { movieId: string; searchQuery: string }) {
const recommendations: MovieDetailsResponse = await fetchMovieDetailsAndRecommendations(
movieId,
searchQuery,
)
const movieParsed = JSON.parse(recommendations.movieDetails)
const movie: Movie | undefined = movieParsed.data.movie[0]

if (!movie) {
return (
<div className="flex items-center justify-center min-h-screen bg-neutral-100 text-red-500 text-xl">
Movie not found
</div>
);
)
}

return (
<div className="space-y-6">
<MovieCard movie={movie} />
<h2 className="text-3xl font-semibold mb-6">Recommendations</h2>
<div className="my-4">
These recommendations are based on your interest in{" "}
<strong>{movie["name@en"]}</strong>
{searchQuery
? " and your search query '" + searchQuery + "'"
: ""}. <strong>Modus</strong> combines internal data from{" "}
<strong>Dgraph</strong> with a{" "}
<strong>large language model (LLM)</strong>, making it easy to generate
AI-driven insights tailored to your data.
These recommendations are based on your interest in <strong>{movie["name@en"]}</strong>
{searchQuery ? " and your search query '" + searchQuery + "'" : ""}. <strong>Modus</strong>{" "}
combines internal data from <strong>Dgraph</strong> with a{" "}
<strong>large language model (LLM)</strong>, making it easy to generate AI-driven insights
tailored to your data.
</div>
<Recommendations recommendations={recommendations.recommendations} />
</div>
);
)
}

function MovieCard({ movie }: { movie: Movie }) {
Expand All @@ -73,32 +66,28 @@ function MovieCard({ movie }: { movie: Movie }) {
<div className="text-lg space-y-2">
<p>
<strong>Release Year:</strong>{" "}
{movie.initial_release_date
? new Date(movie.initial_release_date).getFullYear()
: "N/A"}
{movie.initial_release_date ? new Date(movie.initial_release_date).getFullYear() : "N/A"}
</p>
<p>
<strong>Genre:</strong>{" "}
{movie.genre?.map((genre) => genre["name@en"]).join(", ") ||
"No genres listed"}
{movie.genre?.map((genre) => genre["name@en"]).join(", ") || "No genres listed"}
</p>
<p>
<strong>Starring:</strong>{" "}
{getStarringActors(movie.starring) || "No actors listed"}
<strong>Starring:</strong> {getStarringActors(movie.starring) || "No actors listed"}
</p>
</div>
</div>
);
)
}

function getStarringActors(starring?: Movie["starring"]): string | null {
if (!starring) return null;
if (!starring) return null

const actors = starring
.flatMap((s) => s["performance.actor"]?.map((actor) => actor["name@en"]))
.filter(Boolean);
.filter(Boolean)

return actors.length > 0 ? actors.slice(0, 5).join(", ") : null;
return actors.length > 0 ? actors.slice(0, 5).join(", ") : null
}

function Recommendations({ recommendations }: { recommendations: string }) {
Expand All @@ -107,30 +96,27 @@ function Recommendations({ recommendations }: { recommendations: string }) {
className="prose prose-invert max-w-none bg-white/10 p-6 rounded"
dangerouslySetInnerHTML={{ __html: recommendations }}
/>
);
)
}

export default function MoviePage({
params,
searchParams,
}: {
params: { id: string };
searchParams: { [key: string]: string | undefined };
params: { id: string }
searchParams: { [key: string]: string | undefined }
}) {
const movieId = params.id;
const searchQuery = searchParams.search || "";
const movieId = params.id
const searchQuery = searchParams.search || ""

return (
<div className="max-w-5xl mx-auto space-y-12">
<Link
href="/"
className="bg-blue-500 p-2 rounded text-white hover:bg-blue-400"
>
<Link href="/" className="bg-blue-500 p-2 rounded text-white hover:bg-blue-400">
← Back to Movies
</Link>
<Suspense fallback={<Loading />}>
<MovieDetails movieId={movieId} searchQuery={searchQuery} />
</Suspense>
</div>
);
)
}
Loading

0 comments on commit 8e851a9

Please sign in to comment.