Erstellen Sie Ihren eigenen Podcast RAG Chat mit Gemini API
Haben Sie sich jemals gewünscht, ein intelligentes Gespräch mit der Weisheit Ihrer Lieblingspodcasts führen zu können? Stellen Sie sich vor, Fragen zu stellen und kontextuelle Antworten mit direkten Zitaten und Episodenreferenzen zu erhalten.
In dieser Anleitung lernen Sie, wie Sie eine vollständige Retrieval-Augmented-Generation (RAG) Chat-Anwendung erstellen, die Podcast-Transkripte zum Leben erweckt und modernste KI-Technologie nutzt. Wir verwenden Google Gemini AI sowohl für die Generierung von Embeddings als auch für konversationelle Antworten, Qdrant für die Vektorähnlichkeitssuche und ein modernes React-Frontend.
Was ist RAG und warum es für Podcasts wichtig ist
Retrieval-Augmented-Generation (RAG) kombiniert die Leistungsfähigkeit großer Sprachmodelle mit der Informationsabfrage aus einer Wissensdatenbank. Für Podcasts bedeutet das:
- Semantische Suche: Relevante Inhalte über Hunderte von Stunden Audio-Transkripten finden
- Kontextuelle Antworten: Antworten, die auf tatsächlichen Podcast-Inhalten basieren
- Quellenangaben: Immer wissen, woher die Information stammt
- Skalierbarkeit: Effiziente Handhabung großer Textmengen
Tech-Stack Übersicht
Unsere Anwendung verwendet einen sorgfältig ausgewählten Stack moderner Technologien:
Frontend
- React 18 mit TypeScript für Typsicherheit
- Tailwind CSS für responsives, modernes UI
- React Query für effiziente Datenabfrage und Caching
- React Router für Navigation
Backend
- Node.js mit Express und TypeScript
- Qdrant Vektordatenbank für Ähnlichkeitssuche
- Google Gemini AI für Embeddings und Chat-Antworten
- Winston für strukturierte Protokollierung
Verarbeitungs-Pipeline
- Python-Skripte für Transkript-Verarbeitung
- LangChain für Text-Chunking und -Verarbeitung
- TikToken für intelligentes Text-Splitting
Voraussetzungen
Bevor wir beginnen, stellen Sie sicher, dass Sie haben:
- Node.js (v18 oder höher)
- Python 3.8+
- Docker & Docker Compose (für lokale Entwicklung)
- Google Gemini API-Schlüssel
Schritt 1: Projekt-Setup
Beginnen wir mit dem Klonen und Einrichten der Projektstruktur:
git clone https://github.com/TMFNK/Founders-Podcast-RAG-Chat-Gemini.git
cd Founders-Podcast-RAG-Chat-Gemini
Erstellen Sie Umgebungsvariablen:
cp .env.example .env
Bearbeiten Sie .env mit Ihrer Konfiguration:
# Google Gemini API-Schlüssel
GOOGLE_GEMINI_API_KEY=your-gemini-api-key-here
VITE_GOOGLE_GEMINI_API_KEY=your-gemini-api-key-here
# Qdrant-Konfiguration
QDRANT_URL_LOCAL=http://localhost:6333
QDRANT_URL_PRODUCTION=https://your-qdrant-instance.onrender.com
# Umgebung
NODE_ENV=development
Schritt 2: Einrichten der Vektordatenbank
Qdrant ist unsere Vektordatenbank, die Podcast-Transkript-Embeddings speichert. Für die lokale Entwicklung:
docker run -p 6333:6333 -v qdrant_storage:/qdrant/storage qdrant/qdrant:v1.7.4
Installieren Sie Python-Abhängigkeiten und richten Sie die Sammlung ein:
pip install -r requirements.txt
python scripts/setup_qdrant.py
Schritt 3: Verarbeiten von Podcast-Transkripten
Die Magie geschieht in der Verarbeitungs-Pipeline. Schauen wir uns die Schlüsselkomponenten an:
Transkript-Verarbeitungs-Skript
Das process_transcripts.py Skript übernimmt die schwere Arbeit:
import os
from qdrant_client import QdrantClient
from google.generativeai import configure, embed_content
import json
# Konfiguriere Gemini AI
configure(api_key=os.getenv('GOOGLE_GEMINI_API_KEY'))
def process_transcript(file_path):
"""Verarbeite ein einzelnes Podcast-Transkript"""
with open(file_path, 'r', encoding='utf-8') as f:
content = f.read()
# Extrahiere Metadaten aus dem Dateinamen
filename = os.path.basename(file_path)
episode_num = extract_episode_number(filename)
title = extract_title(filename)
# Teile in Chunks auf
chunks = split_into_chunks(content)
# Generiere Embeddings und speichere
for i, chunk in enumerate(chunks):
embedding = embed_content(
model="models/embedding-001",
content=chunk,
task_type="retrieval_document"
)
# Speichere in Qdrant
client.upsert(
collection_name="podcast_transcripts",
points=[{
"id": f"{episode_num}_{i}",
"vector": embedding['embedding'],
"payload": {
"episode": episode_num,
"title": title,
"chunk": chunk,
"chunk_id": i
}
}]
)
Chunking-Strategie
Effektives Text-Chunking ist entscheidend für die RAG-Leistung:
import tiktoken
def split_into_chunks(text, chunk_size=1000, overlap=200):
"""Teile Text in überlappende Chunks mit Token-Zählung"""
encoding = tiktoken.get_encoding("cl100k_base")
tokens = encoding.encode(text)
chunks = []
start = 0
while start < len(tokens):
end = min(start + chunk_size, len(tokens))
chunk_tokens = tokens[start:end]
chunk_text = encoding.decode(chunk_tokens)
chunks.append(chunk_text)
start = end - overlap
return chunks
Schritt 4: Erstellen der Chat-API
Die Backend-API verarbeitet Chat-Anfragen und semantische Suche:
Such-Endpunkt
// api/search.ts
import { Request, Response } from "express";
import { QdrantClient } from "@qdrant/js-client-rest";
import { GoogleGenerativeAI } from "@google/generative-ai";
const genAI = new GoogleGenerativeAI(process.env.GOOGLE_GEMINI_API_KEY!);
const qdrant = new QdrantClient({ url: process.env.QDRANT_URL_LOCAL });
export const searchTranscripts = async (req: Request, res: Response) => {
const { query, limit = 5 } = req.body;
// Generiere Embedding für die Abfrage
const embeddingModel = genAI.getGenerativeModel({ model: "embedding-001" });
const result = await embeddingModel.embedContent(query);
const queryEmbedding = result.embedding.values;
// Suche in Qdrant
const searchResults = await qdrant.search("podcast_transcripts", {
vector: queryEmbedding,
limit,
with_payload: true,
});
res.json(searchResults);
};
Chat-Endpunkt
// api/chat.ts
export const chatWithAI = async (req: Request, res: Response) => {
const { question, context } = req.body;
// Hole relevanten Kontext
const searchResults = await qdrant.search("podcast_transcripts", {
vector: await generateEmbedding(question),
limit: 5,
});
const contextText = searchResults
.map((result) => result.payload?.chunk)
.join("\n\n");
// Generiere Antwort mit Gemini
const model = genAI.getGenerativeModel({ model: "gemini-pro" });
const prompt = `Kontext aus Podcast-Transkripten:\n${contextText}\n\nFrage: ${question}\n\nAntworte basierend auf dem bereitgestellten Kontext:`;
const result = await model.generateContent(prompt);
const response = result.response.text();
res.json({
response,
sources: searchResults.map((r) => ({
episode: r.payload?.episode,
title: r.payload?.title,
score: r.score,
})),
});
};
Schritt 5: Erstellen des Frontends
Das React-Frontend bietet eine intuitive Chat-Schnittstelle:
// src/components/ChatInterface.tsx
import { useState } from "react";
import { useMutation } from "@tanstack/react-query";
export const ChatInterface = () => {
const [messages, setMessages] = useState([]);
const [input, setInput] = useState("");
const chatMutation = useMutation({
mutationFn: async (question: string) => {
const response = await fetch("/api/chat", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ question }),
});
return response.json();
},
onSuccess: (data) => {
setMessages((prev) => [
...prev,
{ role: "user", content: input },
{ role: "assistant", content: data.response, sources: data.sources },
]);
setInput("");
},
});
const handleSubmit = (e) => {
e.preventDefault();
if (input.trim()) {
chatMutation.mutate(input);
}
};
return (
<div className="flex flex-col h-screen">
<div className="flex-1 overflow-y-auto p-4">
{messages.map((msg, idx) => (
<div
key={idx}
className={`mb-4 ${
msg.role === "user" ? "text-right" : "text-left"
}`}>
<div
className={`inline-block p-3 rounded-lg ${
msg.role === "user" ? "bg-blue-500 text-white" : "bg-gray-200"
}`}>
{msg.content}
{msg.sources && (
<div className="mt-2 text-sm">
{msg.sources.map((source, sidx) => (
<div key={sidx}>
Episode {source.episode}: {source.title}
</div>
))}
</div>
)}
</div>
</div>
))}
</div>
<form onSubmit={handleSubmit} className="p-4 border-t">
<div className="flex">
<input
type="text"
value={input}
onChange={(e) => setInput(e.target.value)}
className="flex-1 p-2 border rounded-l-lg"
placeholder="Fragen Sie nach Podcast-Inhalten..."
/>
<button
type="submit"
disabled={chatMutation.isPending}
className="px-4 py-2 bg-blue-500 text-white rounded-r-lg disabled:opacity-50">
{chatMutation.isPending ? "Denke nach..." : "Senden"}
</button>
</div>
</form>
</div>
);
};
Schritt 6: Ausführen der Anwendung
Starten Sie alle Dienste mit Docker Compose:
docker-compose up -d
Verarbeiten Sie Ihre Podcast-Transkripte:
docker-compose exec processor python scripts/process_transcripts.py --init
Starten Sie die Entwicklungsserver:
# Backend
cd api && npm start
# Frontend
npm run dev
Besuchen Sie http://localhost:5173, um mit Ihren Podcast-Transkripten zu chatten!
Verständnis der Architektur
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Frontend │ │ Backend API │ │ Vector DB │
│ (React/TS) │◄──►│ (Node/Express)│◄──►│ (Qdrant) │
│ │ │ │ │ │
│ • Chat UI │ │ • RAG Logic │ │ • Embeddings │
│ • Search UI │ │ • Rate Limiting │ │ • Similarity │
│ • Real-time │ │ • API Validation│ │ • Metadata │
└─────────────────┘ └─────────────────┘ └─────────────────┘
│ │ │
└───────────────────────┼───────────────────────┘
│
┌─────────────────┐
│ AI Models │
│ (Google Gemini)│
│ │
│ • Text Generation│
│ • Embeddings │
└─────────────────┘
Leistungsoptimierungstipps
- Inkrementelle Verarbeitung: Nur neue Transkripte verarbeiten, um Neuverarbeitung zu vermeiden
- Chunk-Größen-Anpassung: Experimentieren Sie mit verschiedenen Chunk-Größen (500-2000 Tokens)
- Embedding-Caching: Cachen Sie Embeddings, um Neuberechnung zu vermeiden
- Datenbank-Indizierung: Stellen Sie sicher, dass die Vektorindizierung in Qdrant korrekt ist
- Response-Streaming: Implementieren Sie Streaming für bessere UX bei langen Antworten
Bereitstellung in Produktion
Für die Produktionsbereitstellung:
- Datenbank: Stellen Sie Qdrant bei Render oder einem anderen Cloud-Anbieter bereit
- Backend: Stellen Sie die API mit Umgebungsvariablen bereit
- Frontend: Bauen und stellen Sie die statische Seite bereit
- Umgebungsvariablen: Setzen Sie Produktions-URLs und API-Schlüssel
Fehlerbehebung häufiger Probleme
- Qdrant-Verbindung fehlgeschlagen: Überprüfen Sie den Docker-Container-Status und Port-Mapping
- API-Schlüssel-Probleme: Überprüfen Sie die Gültigkeit des Gemini-API-Schlüssels und Kontingent
- Verarbeitungsfehler: Überprüfen Sie die Kodierung der Transkript-Dateien (sollte UTF-8 sein)
- Schlechte Suchergebnisse: Passen Sie Chunk-Größe oder Überlappungsparameter an
Erweitern der Anwendung
Ideen zur Verbesserung:
- Multi-Podcast-Unterstützung: Unterstützung für verschiedene Podcast-Serien hinzufügen
- Audio-Integration: Audio-Wiedergabe mit Zeitstempeln hinzufügen
- Benutzer-Authentifizierung: Benutzerkonten und Gesprächsverlauf hinzufügen
- Erweiterte Suche: Filter nach Episode, Thema oder Sprecher implementieren
- Export-Funktionen: Export von Chat-Gesprächen ermöglichen
Diese RAG-Chat-Anwendung zeigt die Leistungsfähigkeit der Kombination von Vektordatenbanken mit großen Sprachmodellen zur Erstellung intelligenter, kontextbewusster Anwendungen. Die gleichen Prinzipien können auf Dokumentation, Kundensupport oder jede Domäne mit großen Textmengen angewendet werden.