This project implements a personalized podcast recommendation solution with Neon, Azure OpenAI, and Azure Functions. The solution dynamically analyzes user preferences and podcast data to provide highly relevant suggestions in real-time. It uses the Generative Feedback Loops (GFL) mechanism to continuously learn from new user interactions and content updates. Read more on how to guide blog.
As vector search and Retrieval Augmented Generation(RAG) become mainstream for Generative AI (GenAI) use cases, we’re looking ahead to what’s next. GenAI primarily operates in a one-way direction, generating content based on input data. Generative Feedback Loops (GFL) are focused on optimizing and improving the AI’s outputs over time through a cycle of feedback and learnings based on the production data. In GFL, results generated from Large Language Models (LLMs) like GPT are vectorized, indexed, and saved back into vector storage for better-filtered semantic search operations. This creates a dynamic cycle that adapts LLMs to new and continuously changing data, and user needs. GFL offers personalized, up-to-date summaries and suggestions.
- Add New Podcasts:
- Automatically generates embeddings and summaries using Azure OpenAI and stores them in Neon.
- Update User Preferences:
- Updates user listening history and generates embeddings for personalization.
- Recommend Podcasts:
- Provides personalized podcast recommendations based on user preferences and podcast similarity using the Neon
pgvector
extension.
- Provides personalized podcast recommendations based on user preferences and podcast similarity using the Neon
- Feedback Loop:
- Continuously adapts recommendations by incorporating new user preferences and podcast data.
- Python: Backend implementation.
- Azure Functions: Expose APIs for podcast management and recommendations.
- Azure OpenAI: Generate embeddings and summaries using
text-embedding-ada-002
andgpt-4
. - Neon: Serverless PostgreSQL database with
pgvector
extension for storing embeddings and performing similarity queries.
- Add Podcast:
- Generates an embedding and summary using Azure OpenAI.
- Saves the podcast data, embedding, and summary in Neon.
- Update User History:
- Generates an embedding for the user's updated listening history.
- Saves the updated preferences and embedding in Neon.
- Recommend Podcasts:
- Fetches the user's embedding from Neon.
- Finds the most relevant podcasts using
pgvector
similarity. - Generates a short description for each recommendation using GPT.
- Stores the recommendation and GPT output in the
suggested_podcasts
table.
- Real-Time Updates:
- Each new podcast or updated user preference is reflected immediately in the system.
- Dynamic Recommendations:
- Recommendations evolve based on user interactions and new data.
- Adaptability:
- The system automatically scales with more users and podcasts.
generative-feedback-loops-example/
├── .env # Environment variables (Neon connection string, Azure OpenAI keys, etc.)
├── requirements.txt # Python dependencies
├── host.json
├── local.settings.json
├── function_app.py # Single file with all Azure Function definitions
├── utils/
│ ├── database.py # Database utilities for Neon
│ ├── openai_client.py # Azure OpenAI client utility
│ └── config.py # Configuration management
├── data/
│ └── sample_data.sql # Sample SQL data for podcasts and users
Create a Neon Project
- Navigate to the Neon Console
- Click "New Project"
- Select Azure as your cloud provider
- Choose East US 2 as your region
- Give your project a name (e.g., "generative-feedback-loop")
- Click "Create Project"
- Once the project is created successfully, copy the Neon connection string. You can find the connection details in the Connection Details widget on the Neon Dashboard.
Set Up Database Tables
Open the SQL editor in Neon and execute the following script to set up the schema:
-- Create a table to store vector embeddings
CREATE EXTENSION IF NOT EXISTS vector;
CREATE TABLE podcast_episodes (
id SERIAL PRIMARY KEY,
title TEXT NOT NULL,
description TEXT,
transcript TEXT NOT NULL,
embedding VECTOR(1536)
);
CREATE TABLE users (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
listening_history TEXT,
embedding VECTOR(1536)
);
CREATE TABLE suggested_podcasts (
id SERIAL PRIMARY KEY,
user_id INT NOT NULL,
podcast_id INT NOT NULL,
suggested_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
similarity_score FLOAT,
FOREIGN KEY (user_id) REFERENCES users (id) ON DELETE CASCADE,
FOREIGN KEY (podcast_id) REFERENCES podcast_episodes (id) ON DELETE CASCADE
);
Insert Sample Data
Add sample users:
INSERT INTO users (name, listening_history)
VALUES
('Alice', 'Interested in AI, deep learning, and neural networks.'),
('Bob', 'Enjoys podcasts about robotics, automation, and machine learning.'),
('Charlie', 'Fascinated by space exploration, astronomy, and astrophysics.'),
('Diana', 'Prefers topics on fitness, nutrition, and mental health.'),
('Eve', 'Likes discussions on blockchain, cryptocurrency, and decentralized finance.'),
('Frank', 'Follows podcasts about history, culture, and ancient civilizations.');
- Python 3.8 or later version
- Azure Functions Core Tools installed
- A free Neon account
- An Azure account with an active subscription
git clone https://github.com/neondatabase-labs/generative-feedback-loops-example
cd generative-feedback-loops-example
Create a .env
file in the root directory with the following:
DATABASE_URL=your-neon-database-connection-string
OPENAI_ENDPOINT=https://your-openai-resource.openai.azure.com/
OPENAI_API_KEY=your-azure-openai-key
EMBEDDING_MODEL=text-embedding-ada-002
GPT_MODEL=gpt-4
pip install -r requirements.txt
func start
-
Description: Add a new podcast episode.
-
Endpoint:
POST /add_podcast
-
Request Body:
{ "title": "Future of Robotics", "transcript": "This episode discusses robotics, AI, and automation..." }
-
Response:
{ "status": "Podcast 'Future of Robotics' added successfully." }
-
Description: Updates user listening history and generates embeddings.
-
Endpoint:
POST /update_user_history
-
Request Body:
{ "user_id": 1, "listening_history": "Exploring robotics, AI, and automation advancements." }
-
Response:
{ "status": "User 1's history updated." }
-
Description: Fetches personalized podcast recommendations.
-
Endpoint:
GET /recommend_podcasts?user_id=<user_id>
-
Response:
[ { "id": 1, "title": "AI and the Future", "original_description": "Full transcript about AI and its future...", "short_description": "AI shapes tomorrow.", "similarity": 0.123 } ]
- Enhanced User Analytics:
- Track user interactions (e.g., likes, skips) for better recommendations.
- Filter Expired Suggestions:
- Automatically expire old recommendations after a set period.
- Frontend Integration:
- Build a web or mobile app to provide an interactive UI for users.