paint-brush
So erstellen Sie eine App zur Zusammenfassung von Webseiten mit Next.js, OpenAI, LangChain und Supabasevon@nassermaronie
Neue Geschichte

So erstellen Sie eine App zur Zusammenfassung von Webseiten mit Next.js, OpenAI, LangChain und Supabase

von Nasser Maronie13m2024/06/27
Read on Terminal Reader

Zu lang; Lesen

In diesem Artikel zeigen wir Ihnen, wie Sie eine praktische Web-App erstellen, die den Inhalt jeder Webseite zusammenfassen kann. Mit [Next.js] für ein reibungsloses und schnelles Web-Erlebnis, [LangChain] zur Sprachverarbeitung, [OpenAI](https://openai.com/) zum Generieren von Zusammenfassungen und [Supabase] zum Verwalten und Speichern von Vektordaten erstellen wir gemeinsam ein leistungsstarkes Tool.
featured image - So erstellen Sie eine App zur Zusammenfassung von Webseiten mit Next.js, OpenAI, LangChain und Supabase
Nasser Maronie HackerNoon profile picture

Eine App, die den Kontext jeder Webseite verstehen kann.

In diesem Artikel zeigen wir Ihnen, wie Sie eine praktische Web-App erstellen, die den Inhalt jeder beliebigen Webseite zusammenfassen kann. Mit Next.js für ein reibungsloses und schnelles Web-Erlebnis, LangChain zur Sprachverarbeitung, OpenAI zum Generieren von Zusammenfassungen und Supabase zum Verwalten und Speichern von Vektordaten erstellen wir gemeinsam ein leistungsstarkes Tool.



Warum wir es bauen

Angesichts der vielen Online-Inhalte sind wir alle mit einer Informationsüberflutung konfrontiert. Indem wir eine App mit schnellen Zusammenfassungen entwickeln, helfen wir den Menschen, Zeit zu sparen und informiert zu bleiben. Egal, ob Sie ein vielbeschäftigter Arbeiter, Student oder einfach jemand sind, der über Neuigkeiten und Artikel auf dem Laufenden bleiben möchte, diese App ist ein hilfreiches Tool für Sie.

Wie es sein wird

Mit unserer App können Benutzer die URL einer beliebigen Website eingeben und erhalten schnell eine kurze Zusammenfassung der Seite. Das bedeutet, dass Sie die wichtigsten Punkte langer Artikel, Blogbeiträge oder Forschungsarbeiten verstehen können, ohne sie vollständig lesen zu müssen.

Potenzial und Auswirkungen

Diese Zusammenfassungs-App kann in vielerlei Hinsicht nützlich sein. Sie kann Forschern dabei helfen, akademische Arbeiten zu überfliegen, Nachrichtenliebhaber auf dem Laufenden zu halten und vieles mehr. Außerdem können Entwickler diese App erweitern, um noch mehr nützliche Funktionen zu erstellen.


Technologie-Stacks

Weiter.js

Next.js ist ein leistungsstarkes und flexibles React-Framework von Vercel, mit dem Entwickler problemlos Server-Side-Rendering (SSR) und statische Webanwendungen erstellen können. Es kombiniert die besten Funktionen von React mit zusätzlichen Funktionen zum Erstellen optimierter und skalierbarer Webanwendungen.

OpenAI

Das OpenAI-Modul in Node.js bietet eine Möglichkeit zur Interaktion mit der API von OpenAI, sodass Entwickler leistungsstarke Sprachmodelle wie GPT-3 und GPT-4 nutzen können. Mit diesem Modul können Sie erweiterte KI-Funktionen in Ihre Node.js-Anwendungen integrieren.

LangChain.js

LangChain ist ein leistungsstarkes Framework für die Entwicklung von Anwendungen mit Sprachmodellen. Ursprünglich für Python entwickelt, wurde es inzwischen für andere Sprachen, darunter Node.js, angepasst. Hier ist ein Überblick über LangChain im Kontext von Node.js:

Was ist LangChain?

LangChain ist eine Bibliothek, die die Erstellung von Anwendungen mit großen Sprachmodellen (LLMs) vereinfacht. Sie bietet Tools zum Verwalten und Integrieren von LLMs in Ihre Anwendungen, zum Verketten von Aufrufen dieser Modelle und zum einfachen Aktivieren komplexer Workflows.

Wie funktionieren Large Language Models (LLM)?

Große Sprachmodelle (LLMs) wie GPT-3.5 von OpenAI werden anhand riesiger Mengen von Textdaten trainiert, um menschenähnliche Texte zu verstehen und zu generieren. Sie können Antworten generieren, Sprachen übersetzen und viele andere Aufgaben der natürlichen Sprachverarbeitung ausführen.

Supabase

Supabase ist eine Open-Source-Backend-as-a-Service-Plattform (BaaS), die Entwicklern dabei helfen soll, schnell skalierbare Anwendungen zu erstellen und bereitzustellen. Sie bietet eine Reihe von Tools und Diensten, die Datenbankverwaltung, Authentifizierung, Speicherung und Echtzeitfunktionen vereinfachen und alle auf PostgreSQL basieren.


Voraussetzungen

Bevor wir beginnen, stellen Sie sicher, dass Sie Folgendes haben:

  • Node.js und npm installiert
  • Ein Supabase-Konto
  • Ein OpenAI-Konto

Schritt 1: Supabase einrichten

Zuerst müssen wir ein Supabase-Projekt einrichten und die erforderlichen Tabellen zum Speichern unserer Daten erstellen.

Erstellen Sie ein Supabase-Projekt

  1. Gehen Sie zu Supabase und registrieren Sie sich für ein Konto.


  2. Erstellen Sie ein neues Projekt und notieren Sie sich Ihre Supabase-URL und Ihren API-Schlüssel. Sie werden diese später benötigen.

SQL-Skript für Supabase

Erstellen Sie eine neue SQL-Abfrage in Ihrem Supabase-Dashboard und führen Sie die folgenden Skripts aus, um die erforderlichen Tabellen und Funktionen zu erstellen:

Erstellen Sie zunächst eine Erweiterung, falls diese für unseren Vektorspeicher noch nicht vorhanden ist:

 create extension if not exists vector;


Erstellen Sie als Nächstes eine Tabelle mit dem Namen „Dokumente“. Diese Tabelle wird verwendet, um den Inhalt der Webseite im Vektorformat zu speichern und einzubetten:

 create table if not exists documents ( id bigint primary key generated always as identity, content text, metadata jsonb, embedding vector(1536) );


Jetzt benötigen wir eine Funktion zum Abfragen unserer eingebetteten Daten:

 create or replace function match_documents ( query_embedding vector(1536), match_count int default null, filter jsonb default '{}' ) returns table ( id bigint, content text, metadata jsonb, similarity float ) language plpgsql as $$ begin return query select id, content, metadata, 1 - (documents.embedding <=> query_embedding) as similarity from documents where metadata @> filter order by documents.embedding <=> query_embedding limit match_count; end; $$;


Als Nächstes müssen wir unsere Tabelle zum Speichern der Webseitendetails einrichten:

 create table if not exists files ( id bigint primary key generated always as identity, url text not null, created_at timestamp with time zone default timezone('utc'::text, now()) not null );

Schritt 2: OpenAI einrichten

OpenAI-Projekt erstellen


  • Navigieren Sie zur API: Navigieren Sie nach der Anmeldung zum API-Bereich und erstellen Sie einen neuen API-Schlüssel. Dieser ist normalerweise über das Dashboard zugänglich.

Schritt 3: Einrichten von Next.js

Erstellen Sie die Next.js-App

 $ npx create-next-app summarize-page $ cd ./summarize-page


Installieren Sie die erforderlichen Abhängigkeiten:

 npm install @langchain/community @langchain/core @langchain/openai @supabase/supabase-js langchain openai axios


Anschließend installieren wir Material UI zum Erstellen unserer Schnittstelle. Sie können auch eine andere Bibliothek verwenden:

 npm install @mui/material @emotion/react @emotion/styled

Schritt 4: OpenAI- und Supabase-Clients

Als nächstes müssen wir die OpenAI- und Supabase-Clients einrichten. Erstellen Sie in Ihrem Projekt ein libs Verzeichnis und fügen Sie die folgenden Dateien hinzu.

src/libs/openAI.ts

Diese Datei konfiguriert den OpenAI-Client.

 import { ChatOpenAI, OpenAIEmbeddings } from "@langchain/openai"; const openAIApiKey = process.env.OPENAI_API_KEY; if (!openAIApiKey) throw new Error('OpenAI API Key not found.') export const llm = new ChatOpenAI({ openAIApiKey, modelName: "gpt-3.5-turbo", temperature: 0.9, }); export const embeddings = new OpenAIEmbeddings( { openAIApiKey, }, { maxRetries: 0 } );
  • llm : Die Sprachmodellinstanz, die unsere Zusammenfassungen generiert.


  • embeddings : Dadurch werden Einbettungen für unsere Dokumente erstellt, die beim Auffinden ähnlicher Inhalte helfen.

src/libs/supabaseClient.ts

Diese Datei konfiguriert den Supabase-Client.

 import { createClient } from "@supabase/supabase-js"; const supabaseUrl = process.env.SUPABASE_URL || ""; const supabaseAnonKey = process.env.SUPABASE_ANON_KEY || ""; if (!supabaseUrl) throw new Error("Supabase URL not found."); if (!supabaseAnonKey) throw new Error("Supabase Anon key not found."); export const supabaseClient = createClient(supabaseUrl, supabaseAnonKey);
  • supabaseClient : Die Supabase-Clientinstanz zur Interaktion mit unserer Supabase-Datenbank.

Schritt 5: Dienste für Inhalte und Dateien erstellen

Erstellen Sie ein services und fügen Sie die folgenden Dateien hinzu, um das Abrufen von Inhalten und die Verwaltung von Dateien zu handhaben.

src/services/content.ts

Dieser Dienst ruft den Inhalt der Webseite ab und bereinigt ihn, indem er HTML-Tags, Skripts und Stile entfernt.

 import axios from "axios"; export async function getContent(url: string): Promise<string> { let htmlContent: string = ""; const response = await axios.get(url as string); htmlContent = response.data; if (!htmlContent) return ""; // Remove unwanted elements and tags return htmlContent .replace(/style="[^"]*"/gi, "") .replace(/<style[^>]*>[\s\S]*?<\/style>/gi, "") .replace(/\s*on\w+="[^"]*"/gi, "") .replace( /<script(?![^>]*application\/ld\+json)[^>]*>[\s\S]*?<\/script>/gi, "" ) .replace(/<[^>]*>/g, "") .replace(/\s+/g, " "); }

Diese Funktion ruft den HTML-Inhalt einer bestimmten URL ab und bereinigt ihn, indem Stile, Skripts und HTML-Tags entfernt werden.

src/services/file.ts

Dieser Dienst speichert den Inhalt der Webseite in Supabase und ruft Zusammenfassungen ab.

 import { embeddings, llm } from "@/libs/openAI"; import { supabaseClient } from "@/libs/supabaseClient"; import { SupabaseVectorStore } from "@langchain/community/vectorstores/supabase"; import { StringOutputParser } from "@langchain/core/output_parsers"; import { ChatPromptTemplate, HumanMessagePromptTemplate, SystemMessagePromptTemplate, } from "@langchain/core/prompts"; import { RunnablePassthrough, RunnableSequence, } from "@langchain/core/runnables"; import { RecursiveCharacterTextSplitter } from "langchain/text_splitter"; import { formatDocumentsAsString } from "langchain/util/document"; export interface IFile { id?: number | undefined; url: string; created_at?: Date | undefined; } export async function saveFile(url: string, content: string): Promise<IFile> { const doc = await supabaseClient .from("files") .select() .eq("url", url) .single<IFile>(); if (!doc.error && doc.data?.id) return doc.data; const { data, error } = await supabaseClient .from("files") .insert({ url }) .select() .single<IFile>(); if (error) throw error; const splitter = new RecursiveCharacterTextSplitter({ separators: ["\n\n", "\n", " ", ""], }); const output = await splitter.createDocuments([content]); const docs = output.map((d) => ({ ...d, metadata: { ...d.metadata, file_id: data.id }, })); await SupabaseVectorStore.fromDocuments(docs, embeddings, { client: supabaseClient, tableName: "documents", queryName: "match_documents", }); return data; } export async function getSummarization(fileId: number): Promise<string> { const vectorStore = await SupabaseVectorStore.fromExistingIndex(embeddings, { client: supabaseClient, tableName: "documents", queryName: "match_documents", }); const retriever = vectorStore.asRetriever({ filter: (rpc) => rpc.filter("metadata->>file_id", "eq", fileId), k: 2, }); const SYSTEM_TEMPLATE = `Use the following pieces of context, explain what is it about and summarize it. If you can't explain it, just say that you don't know, don't try to make up some explanation. ---------------- {context}`; const messages = [ SystemMessagePromptTemplate.fromTemplate(SYSTEM_TEMPLATE), HumanMessagePromptTemplate.fromTemplate("{format_answer}"), ]; const prompt = ChatPromptTemplate.fromMessages(messages); const chain = RunnableSequence.from([ { context: retriever.pipe(formatDocumentsAsString), format_answer: new RunnablePassthrough(), }, prompt, llm, new StringOutputParser(), ]); const format_summarization = ` Give it title, subject, description, and the conclusion of the context in this format, replace the brackets with the actual content: [Write the title here] By: [Name of the author or owner or user or publisher or writer or reporter if possible, otherwise leave it "Not Specified"] [Write the subject, it could be a long text, at least minimum of 300 characters] ---------------- [Write the description in here, it could be a long text, at least minimum of 1000 characters] Conclusion: [Write the conclusion in here, it could be a long text, at least minimum of 500 characters] `; const summarization = await chain.invoke(format_summarization); return summarization; }
  • saveFile : Speichert die Datei und ihren Inhalt in Supabase, teilt den Inhalt in handliche Teile auf und speichert sie im Vektorspeicher.


  • getSummarization : Ruft relevante Dokumente aus dem Vektorspeicher ab und generiert mit OpenAI eine Zusammenfassung.

Schritt 6: Erstellen eines API-Handlers

Lassen Sie uns nun einen API-Handler erstellen, um den Inhalt zu verarbeiten und eine Zusammenfassung zu generieren.

pages/api/content.ts

 import { getContent } from "@/services/content"; import { getSummarization, saveFile } from "@/services/file"; import { NextApiRequest, NextApiResponse } from "next"; export default async function handler( req: NextApiRequest, res: NextApiResponse ) { if (req.method !== "POST") return res.status(404).json({ message: "Not found" }); const { body } = req; try { const content = await getContent(body.url); const file = await saveFile(body.url, content); const result = await getSummarization(file.id as number); res.status(200).json({ result }); } catch (err) { res.status( 500).json({ error: err }); } }

Dieser API-Handler empfängt eine URL, ruft den Inhalt ab, speichert ihn in Supabase und generiert eine Zusammenfassung. Er verarbeitet sowohl die Funktionen saveFile als auch getSummarization unserer Dienste.


Schritt 7: Erstellen des Frontends

Lassen Sie uns abschließend das Frontend in src/pages/index.tsx erstellen, damit Benutzer URLs eingeben und die Zusammenfassungen anzeigen können.

src/pages/index.tsx

 import axios from "axios"; import { useState } from "react"; import { Alert, Box, Button, Container, LinearProgress, Stack, TextField, Typography, } from "@mui/material"; export default function Home() { const [loading, setLoading] = useState(false); const [url, setUrl] = useState(""); const [result, setResult] = useState(""); const [error, setError] = useState<any>(null); const onSubmit = async () => { try { setError(null); setLoading(true); const res = await axios.post("/api/content", { url }); setResult(res.data.result); } catch (err) { console.error("Failed to fetch content", err); setError(err as any); } finally { setLoading(false); } }; return ( <Box sx={{ height: "100vh", overflowY: "auto" }}> <Container sx={{ backgroundColor: (theme) => theme.palette.background.default, position: "sticky", top: 0, zIndex: 2, py: 2, }} > <Typography sx={{ mb: 2, fontSize: "24px" }}> Summarize the content of any page </Typography> <TextField fullWidth label="Input page's URL" value={url} onChange={(e) => { if (result) setResult(""); setUrl(e.target.value); }} sx={{ mb: 2 }} /> <Button disabled={loading} variant="contained" onClick={onSubmit} > Summarize </Button> </Container> <Container maxWidth="lg" sx={{ py: 2 }}> {loading ? ( <LinearProgress /> ) : ( <Stack sx={{ gap: 2 }}> {result && ( <Alert> <Typography sx={{ whiteSpace: "pre-line", wordBreak: "break-word", }} > {result} </Typography> </Alert> )} {error && <Alert severity="error">{error.message || error}</Alert>} </Stack> )} </Container> </Box> ); }

Mit dieser React-Komponente können Benutzer eine URL eingeben, absenden und die generierte Zusammenfassung anzeigen. Sie verarbeitet Ladezustände und Fehlermeldungen, um ein besseres Benutzererlebnis zu bieten.


Schritt 8: Ausführen der Anwendung

Erstellen Sie im Stammverzeichnis Ihres Projekts eine .env-Datei, um Ihre Umgebungsvariablen zu speichern:

 SUPABASE_URL=your-supabase-url SUPABASE_ANON_KEY=your-supabase-anon-key OPENAI_API_KEY=your-openai-api-key


Starten Sie abschließend Ihre Next.js-Anwendung:

 npm run dev


Jetzt sollte Ihre Anwendung laufen, in der Sie die URL der Webseite eingeben und die zusammengefassten Antworten der Seite erhalten können.


Abschluss

Herzlichen Glückwunsch! Sie haben mit Next.js, OpenAI, LangChain und Supabase eine voll funktionsfähige Anwendung zur Zusammenfassung von Webseiten erstellt. Benutzer können eine URL eingeben, den Inhalt abrufen, ihn in Supabase speichern und mithilfe der Funktionen von OpenAI eine Zusammenfassung erstellen. Dieses Setup bietet eine robuste Grundlage für weitere Verbesserungen und Anpassungen entsprechend Ihren Anforderungen.


Sie können dieses Projekt gerne erweitern, indem Sie weitere Funktionen hinzufügen, die Benutzeroberfläche verbessern oder zusätzliche APIs integrieren.

Überprüfen Sie den Quellcode in diesem Repo:

https://github.com/firstpersoncode/summarize-page


Viel Spaß beim Programmieren!