paint-brush
Next.js, OpenAI, LangChain ve Supabase ile Web Sayfası Özetleme Uygulaması Nasıl Oluşturulurile@nassermaronie
6,084 okumalar
6,084 okumalar

Next.js, OpenAI, LangChain ve Supabase ile Web Sayfası Özetleme Uygulaması Nasıl Oluşturulur

ile Nasser Maronie13m2024/06/27
Read on Terminal Reader

Çok uzun; Okumak

Bu makalede size herhangi bir web sayfasının içeriğini özetleyebilecek kullanışlı bir web uygulamasının nasıl oluşturulacağını göstereceğiz. Sorunsuz ve hızlı bir web deneyimi için [Next.js], dili işlemek için [LangChain], özetler oluşturmak için [OpenAI](https://openai.com/) ve vektör verilerini yönetmek ve depolamak için [Supabase] kullanarak, birlikte güçlü bir araç oluşturacağız.
featured image - Next.js, OpenAI, LangChain ve Supabase ile Web Sayfası Özetleme Uygulaması Nasıl Oluşturulur
Nasser Maronie HackerNoon profile picture

Herhangi Bir Web Sayfasının İçeriğini Anlayabilen Bir Uygulama.

Bu makalede size herhangi bir web sayfasının içeriğini özetleyebilecek kullanışlı bir web uygulamasının nasıl oluşturulacağını göstereceğiz. Sorunsuz ve hızlı bir web deneyimi için Next.js'yi , dili işlemek için LangChain'i , özetler oluşturmak için OpenAI'yi ve vektör verilerini yönetmek ve depolamak için Supabase'i kullanarak birlikte güçlü bir araç oluşturacağız.



Neden İnşa Ediyoruz?

Çevrimiçi ortamda bu kadar çok içerik varken hepimiz aşırı bilgi yüklemesiyle karşı karşıyayız. Hızlı özetler veren bir uygulama yaparak insanların zamandan tasarruf etmesine ve bilgi sahibi olmasına yardımcı oluyoruz. İster yoğun bir çalışan, ister öğrenci, ister sadece haberleri ve makaleleri takip etmek isteyen biri olun, bu uygulama sizin için yararlı bir araç olacaktır.

Nasıl olacak

Uygulamamız, kullanıcıların herhangi bir web sitesi URL'sini girmesine ve sayfanın kısa bir özetini hızlı bir şekilde almasına olanak tanır. Bu, uzun makalelerin, blog yazılarının veya araştırma makalelerinin ana noktalarını, onları tam olarak okumadan anlayabileceğiniz anlamına gelir.

Potansiyel ve Etki

Bu özetleme uygulaması birçok yönden faydalı olabilir. Araştırmacıların akademik makalelere göz atmasına, haber severleri güncel tutmasına ve daha fazlasına yardımcı olabilir. Ayrıca geliştiriciler, daha da kullanışlı özellikler oluşturmak için bu uygulamayı geliştirebilirler.


Teknoloji yığınları

Next.js

Next.js, Vercel tarafından geliştirilen ve geliştiricilerin sunucu tarafı işleme (SSR) ve statik web uygulamalarını kolaylıkla oluşturmasına olanak tanıyan güçlü ve esnek bir React çerçevesidir. Optimize edilmiş ve ölçeklenebilir web uygulamaları oluşturmak için React'in en iyi özelliklerini ek yeteneklerle birleştirir.

OpenAI

Node.js'deki OpenAI modülü, OpenAI'nin API'si ile etkileşim kurmanın bir yolunu sağlayarak geliştiricilerin GPT-3 ve GPT-4 gibi güçlü dil modellerinden yararlanmasına olanak tanır. Bu modül, gelişmiş yapay zeka işlevlerini Node.js uygulamalarınıza entegre etmenizi sağlar.

LangChain.js

LangChain, dil modelleriyle uygulamalar geliştirmek için tasarlanmış güçlü bir çerçevedir. Başlangıçta Python için geliştirilen bu dil, daha sonra Node.js dahil diğer dillere de uyarlandı. Node.js bağlamında LangChain'e genel bir bakış:

LangChain nedir?

LangChain , büyük dil modellerini (LLM'ler) kullanarak uygulamaların oluşturulmasını kolaylaştıran bir kütüphanedir. LLM'leri uygulamalarınıza entegre etmek ve yönetmek, çağrıların bu modellere zincirlenmesini yönetmek ve karmaşık iş akışlarını kolaylıkla etkinleştirmek için araçlar sağlar.

Büyük Dil Modelleri (LLM) Nasıl Çalışır?

OpenAI'nin GPT-3.5'i gibi Büyük Dil Modelleri (LLM'ler), insan benzeri metinleri anlamak ve oluşturmak için çok miktarda metin verisi üzerinde eğitilir. Yanıtlar oluşturabilir, dilleri çevirebilir ve diğer birçok doğal dil işleme görevini gerçekleştirebilirler.

Supabaz

Supabase, geliştiricilerin ölçeklenebilir uygulamaları hızlı bir şekilde oluşturmasına ve dağıtmasına yardımcı olmak için tasarlanmış açık kaynaklı bir hizmet olarak arka uç (BaaS) platformudur. Tamamı PostgreSQL üzerine inşa edilmiş, veritabanı yönetimini, kimlik doğrulamayı, depolamayı ve gerçek zamanlı yetenekleri basitleştiren bir araç ve hizmet paketi sunar.


Önkoşullar

Başlamadan önce aşağıdakilere sahip olduğunuzdan emin olun:

  • Node.js ve npm yüklü
  • Bir Supabase hesabı
  • Bir OpenAI hesabı

Adım 1: Supabase'in Kurulumu

Öncelikle bir Supabase projesi kurup verilerimizi saklayacak gerekli tabloları oluşturmamız gerekiyor.

Supabase Projesi Oluşturun

  1. Supabase'e gidin ve bir hesaba kaydolun.


  2. Yeni bir proje oluşturun ve Supabase URL'nizi ve API anahtarınızı not edin. Bunlara daha sonra ihtiyacınız olacak.

Supabase için SQL Komut Dosyası

Supabase kontrol panelinizde yeni bir SQL sorgusu oluşturun ve gerekli tabloları ve işlevleri oluşturmak için aşağıdaki komut dosyalarını çalıştırın:

Öncelikle vektör mağazamız için mevcut değilse bir uzantı oluşturun:

 create extension if not exists vector;


Daha sonra "belgeler" adlı bir tablo oluşturun. Bu tablo, web sayfasının içeriğini vektör formatında depolamak ve gömmek için kullanılacaktır:

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


Şimdi gömülü verilerimizi sorgulamak için bir fonksiyona ihtiyacımız var:

 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; $$;


Daha sonra, web sayfasının ayrıntılarını saklamak için tablomuzu ayarlamamız gerekiyor:

 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 );

Adım 2: OpenAI'yi Ayarlama

OpenAI Projesi Oluşturun


  • API'ye gidin: Giriş yaptıktan sonra API bölümüne gidin ve yeni bir API anahtarı oluşturun. Buna genellikle kontrol panelinden erişilebilir.

3. Adım: Next.js'yi Kurma

Next.js uygulamasını oluşturun

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


Gerekli bağımlılıkları yükleyin:

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


Ardından arayüzümüzü oluşturmak için Material UI'yi kuracağız; başka bir kütüphaneyi kullanmaktan çekinmeyin:

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

Adım 4: OpenAI ve Supabase İstemcileri

Daha sonra OpenAI ve Supabase istemcilerini kurmamız gerekiyor. Projenizde bir libs dizini oluşturun ve aşağıdaki dosyaları ekleyin.

src/libs/openAI.ts

Bu dosya OpenAI istemcisini yapılandıracaktır.

 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 : Özetlerimizi oluşturacak dil modeli örneği.


  • embeddings : Bu, belgelerimiz için benzer içeriği bulmamıza yardımcı olacak yerleştirmeler oluşturacaktır.

src/libs/supabaseClient.ts

Bu dosya Supabase istemcisini yapılandıracaktır.

 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 : Supabase veritabanımızla etkileşime girecek Supabase istemci örneği.

Adım 5: İçerik ve Dosyalar için Hizmetler Oluşturma

Bir services dizini oluşturun ve içerik getirme ve dosyaları yönetme işlemlerini gerçekleştirmek için aşağıdaki dosyaları ekleyin.

src/services/content.ts

Bu hizmet web sayfası içeriğini getirecek ve HTML etiketlerini, komut dosyalarını ve stillerini kaldırarak temizleyecektir.

 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, " "); }

Bu işlev, belirli bir URL'nin HTML içeriğini getirir ve stilleri, komut dosyalarını ve HTML etiketlerini kaldırarak onu temizler.

src/services/file.ts

Bu hizmet web sayfası içeriğini Supabase'e kaydedecek ve özetleri alacaktır.

 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 : Dosyayı ve içeriğini Supabase'e kaydeder, içeriği yönetilebilir parçalara böler ve bunları vektör deposunda saklar.


  • getSummarization : Vektör deposundan ilgili belgeleri alır ve OpenAI kullanarak bir özet oluşturur.

Adım 6: API İşleyicisi Oluşturma

Şimdi içeriği işleyip özet oluşturacak bir API işleyicisi oluşturalım.

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 }); } }

Bu API işleyicisi bir URL alır, içeriği getirir, Supabase'e kaydeder ve bir özet oluşturur. Hizmetlerimizdeki hem saveFile hem de getSummarization işlevlerini yönetir.


Adım 7: Ön Uç Oluşturma

Son olarak, kullanıcıların URL'leri girmesine ve özetleri görüntülemesine olanak sağlamak için src/pages/index.tsx dosyasında ön uç oluşturalım.

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> ); }

Bu React bileşeni, kullanıcıların bir URL girmesine, göndermesine ve oluşturulan özeti görüntülemesine olanak tanır. Daha iyi bir kullanıcı deneyimi sağlamak için yükleme durumlarını ve hata mesajlarını yönetir.


Adım 8: Uygulamayı Çalıştırma

Ortam değişkenlerinizi depolamak için projenizin kökünde bir .env dosyası oluşturun:

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


Son olarak Next.js uygulamanızı başlatın:

 npm run dev


Artık web sayfasının URL'sini girebileceğiniz ve sayfanın özet yanıtlarını alabileceğiniz, çalışan bir uygulamanız olmalıdır.


Çözüm

Tebrikler! Next.js, OpenAI, LangChain ve Supabase'i kullanarak tamamen işlevsel bir web sayfası özetleme uygulaması oluşturdunuz. Kullanıcılar bir URL girebilir, içeriği alabilir, Supabase'de saklayabilir ve OpenAI'nin yeteneklerini kullanarak bir özet oluşturabilir. Bu kurulum, ihtiyaçlarınıza göre daha fazla geliştirme ve özelleştirme için sağlam bir temel sağlar.


Daha fazla özellik ekleyerek, kullanıcı arayüzünü iyileştirerek veya ek API'leri entegre ederek bu projeyi genişletmekten çekinmeyin.

Bu Repo'daki Kaynak Kodunu Kontrol Edin:

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


Mutlu kodlama!