top of page

Crea il tuo ChatGPT per i PDF con Langchain

In soli sei mesi, ChatGPT di OpenAI è diventato parte integrante delle nostre vite. Non è più solo limitato alla tecnologia; persone di tutte le età e professioni, dagli studenti agli scrittori, lo utilizzano ampiamente. Questi modelli di chat eccellono per accuratezza, velocità e conversazioni simili a quelle umane. Sono pronti a svolgere un ruolo significativo in vari campi, non solo nella tecnologia.


Crea il tuo ChatGPT per i PDF con Langchain
Crea il tuo ChatGPT per i PDF con Langchain

Sono emersi strumenti open source come AutoGPTs, BabyAGI e Langchain, sfruttando la potenza dei modelli linguistici. Automatizza le attività di programmazione con i prompt, collega i modelli linguistici alle origini dati e crea applicazioni AI più velocemente che mai. Langchain è uno strumento di domande e risposte abilitato per ChatGPT per i PDF, che lo rende uno sportello unico per la creazione di applicazioni AI.

Obiettivi formativi

  • Crea un'interfaccia chatbot utilizzando Gradio

  • Estrai testi da pdf e crea embedding

  • Memorizza gli embedding nel database dei vettori Chroma

  • Invia query al back-end (catena Langchain)

  • Esegui ricerche semantiche sui testi per trovare fonti di dati pertinenti

  • Invia dati a LLM (ChatGPT) e ricevi risposte sul chatbot

Il Langchain semplifica l'esecuzione di tutti questi passaggi in poche righe di codice. Dispone di wrapper per più servizi, inclusi modelli di embedding, modelli di chat e database vettoriali.


Cos'è Langchain?

Langchain è uno strumento open source scritto in Python che aiuta a connettere dati esterni a Large Language Models. Rende i modelli di chat come GPT-4 o GPT-3.5 più agentici e sensibili ai dati. Quindi, in un certo senso, Langchain fornisce un modo per fornire agli LLM nuovi dati su cui non è stato addestrato. Langchain fornisce molte catene che astraggono le complessità nell'interazione con i modelli linguistici. Abbiamo anche bisogno di molti altri strumenti, come i modelli per la creazione di incorporamenti di vettori e database di vettori per memorizzare i vettori. Prima di procedere oltre, diamo una rapida occhiata agli Embedding di testo. Cosa sono e perché sono importanti?




Embedding di testo.

Gli Embedding di testo sono il cuore e l'anima di Large Language Operations. Tecnicamente, possiamo lavorare con i modelli linguistici con il linguaggio naturale, ma l'archiviazione e il recupero del linguaggio naturale è altamente inefficiente. Ad esempio, in questo progetto, dovremo eseguire operazioni di ricerca ad alta velocità su grandi blocchi di dati. È impossibile eseguire tali operazioni sui dati in linguaggio naturale. Per renderlo più efficiente, dobbiamo trasformare i dati di testo in forme vettoriali. Esistono modelli ML dedicati per la creazione di incorporamenti o embedding da testi. I testi vengono convertiti in vettori multidimensionali. Una volta incorporati, possiamo raggruppare, ordinare, cercare e altro su questi dati. Possiamo calcolare la distanza tra due frasi per sapere quanto sono strettamente correlate. E la parte migliore è che queste operazioni non si limitano solo a parole chiave come le tradizionali ricerche nel database, ma catturano piuttosto la vicinanza semantica di due frasi. Questo lo rende molto più potente, grazie al Machine Learning.



Crea il tuo ChatGPT per i PDF con Langchain
Crea il tuo ChatGPT per i PDF con Langchain


Strumenti Langchain

Langchain ha wrapper per tutti i principali database vettoriali come Chroma, Redis, Pinecone, Alpine db e altri. E lo stesso vale per gli LLM, insieme ai modelli OpeanAI, supporta anche i modelli di Cohere, GPT4ALL, un'alternativa open source per i modelli GPT. Per gli incorporamenti, fornisce wrapper per gli incorporamenti OpeanAI, Cohere e HuggingFace. Puoi anche utilizzare i tuoi modelli di incorporamento personalizzati.


Quindi, in breve, Langchain è un meta-strumento che elimina molte complicazioni dell'interazione con le tecnologie sottostanti, il che rende più facile per chiunque creare rapidamente applicazioni AI.


In questo articolo, utilizzeremo il modello di incorporamento OpeanAI per la creazione di incorporamenti. Se desideri distribuire un'app AI per gli utenti finali, considera l'utilizzo di qualsiasi modello Opensource, come i modelli Huggingface o il codificatore di frasi universale di Google.


Per archiviare i vettori, utilizzeremo Chroma DB , un database di archiviazione di vettori open source. Sentiti libero di esplorare altri database come Alpine, Pinecone e Redis. Langchain ha wrapper per tutti questi negozi vettoriali.


Per creare una catena Langchain, utilizzeremo ConversationalRetrievalChain (), ideale per conversazioni con modelli di chat con cronologia (per mantenere il contesto della conversazione). Controlla la loro documentazione ufficiale relativa alle diverse catene LLM.






Configurare l'ambiente di sviluppo per langchain

Ci sono parecchie librerie che useremo. Quindi, installali in anticipo. Per creare un ambiente di sviluppo fluido e ordinato, utilizza gli ambienti virtuali o Docker .

gradio = "^3.27.0"
openai = "^0.27.4"
langchain = "^0.0.148"
chromadb = "^0.3.21"
tiktoken = "^0.3.3"
pypdf = "^3.8.1"
pymupdf = "^1.22.2"



Ora, importa queste librerie


import gradio as gr
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores import Chroma

from langchain.chains import ConversationalRetrievalChain
from langchain.chat_models import ChatOpenAI

from langchain.document_loaders import PyPDFLoader
import os

import fitz
from PIL import Image


Costruisci l'interfaccia di chat

L'interfaccia dell'applicazione avrà due funzionalità principali, una è un'interfaccia di chat e l'altra rende la pagina pertinente del PDF come un'immagine. Oltre a questo, una casella di testo per accettare le chiavi API OpenAI dagli utenti finali. L'articolo discute gli aspetti fondamentali di Gradio. Prenderemo in prestito molte cose da questo articolo.

La classe Gradio Blocks ci consente di creare un'app Web. Le classi Row e Columns consentono di allineare più componenti nell'app Web. Li useremo per personalizzare l'interfaccia web.

with gr.Blocks() as demo:
    # Create a Gradio block
    with gr.Column():
        with gr.Row():
            with gr.Column(scale=0.8):
                api_key = gr.Textbox(
                    placeholder='Enter OpenAI API key',
                    show_label=False,
                    interactive=True
                ).style(container=False)
            with gr.Column(scale=0.2):
                change_api_key = gr.Button('Change Key')
        with gr.Row():
            chatbot = gr.Chatbot(value=[], elem_id='chatbot').style(height=650)
            show_img = gr.Image(label='Upload PDF', tool='select').style(height=680)
    with gr.Row():
        with gr.Column(scale=0.70):
            txt = gr.Textbox(
                show_label=False,
                placeholder="Enter text and press enter"
            ).style(container=False)
        with gr.Column(scale=0.15):
            submit_btn = gr.Button('Submit')
        with gr.Column(scale=0.15):
            btn = gr.UploadButton("📁 Upload a PDF", file_types=[".pdf"]).style()

L'interfaccia è semplice con pochi componenti.




Esso ha:

  • Un'interfaccia di chat per comunicare con il PDF.

  • Un componente per il rendering di pagine PDF pertinenti.

  • Una casella di testo per accettare la chiave API e un pulsante di modifica della chiave.

  • Una casella di testo per porre domande e un pulsante di invio.

  • Un pulsante per caricare i file.

Ecco uno screshot di come dovresti vederel 'interfaccia utente web.


Crea il tuo ChatGPT per i PDF con Langchain
Crea il tuo ChatGPT per i PDF con Langchain

La parte frontend della nostra applicazione è completa. Passiamo al backend.



Backend di ChatGPT per i PDF con Langchain

Innanzitutto, delineamo i processi con cui ci occuperemo.

  • Gestisci il PDF caricato e la chiave API OpenAI

  • Estrai testi da PDF e crea incorporamenti di testo utilizzando gli incorporamenti OpenAI.

  • Memorizza gli incorporamenti vettoriali nell'archivio vettoriale ChromaDB.

  • Crea una catena di recupero conversazionale con Langchain.

  • Crea incorporamenti di testo interrogato ed esegui una ricerca per somiglianza su documenti incorporati.

  • Invia i documenti pertinenti al modello di chat OpenAI (gpt-3.5-turbo).

  • Recupera la risposta e riproducila in streaming sull'interfaccia utente della chat.

  • Renderizza la pagina PDF pertinente sull'interfaccia utente Web.

Queste sono la panoramica della nostra applicazione. Iniziamo a costruirlo.



Gestione eventi principali di ChatGPT per i PDF con Langchain

Quando viene eseguita un'azione specifica sull'interfaccia utente Web, questi eventi vengono attivati. Quindi, gli eventi rendono la web app interattiva e dinamica. Gradio ci permette di definire eventi con codici Python.


Gradio Events utilizza le variabili dei componenti che abbiamo definito in precedenza per comunicare con il backend. Definiremo alcuni eventi di cui abbiamo bisogno per la nostra applicazione. Questi sono

  • Invia evento chiave API : premendo Invio dopo aver incollato la chiave API si attiverà questo evento.

  • Cambia chiave : questo ti permetterà di fornire una nuova chiave API

  • Inserisci query : invia query di testo al chatbot

  • Carica file : consente all'utente finale di caricare un file PDF

with gr.Blocks() as demo:
    # Create a Gradio block
    with gr.Column():
        with gr.Row():
            with gr.Column(scale=0.8):
                api_key = gr.Textbox(
                    placeholder='Enter OpenAI API key',
                    show_label=False,
                    interactive=True
                ).style(container=False)
            with gr.Column(scale=0.2):
                change_api_key = gr.Button('Change Key')
        with gr.Row():
            chatbot = gr.Chatbot(value=[], elem_id='chatbot').style(height=650)
            show_img = gr.Image(label='Upload PDF', tool='select').style(height=680)
    with gr.Row():
        with gr.Column(scale=0.70):
            txt = gr.Textbox(
                show_label=False,
                placeholder="Enter text and press enter"
            ).style(container=False)
        with gr.Column(scale=0.15):
            submit_btn = gr.Button('Submit')
        with gr.Column(scale=0.15):
            btn = gr.UploadButton("📁 Upload a PDF", file_types=[".pdf"]).style()
    # Set up event handlers
    # Event handler for submitting the OpenAI API key
    api_key.submit(fn=set_apikey, inputs=[api_key], outputs=[api_key])
    # Event handler for changing the API key
    change_api_key.click(fn=enable_api_box, outputs=[api_key])
    # Event handler for uploading a PDF
    btn.upload(fn=render_first, inputs=[btn], outputs=[show_img])
    # Event handler for submitting text and generating response
    submit_btn.click(
        fn=add_text,
        inputs=[chatbot, txt],
        outputs=[chatbot],
        queue=False
    ).success(
        fn=generate_response,
        inputs=[chatbot, txt, btn],
        outputs=[chatbot, txt]
    ).success(
        fn=render_file,
        inputs=[btn],
        outputs=[show_img]
    )

Finora non abbiamo definito le nostre funzioni chiamate all'interno dei gestori di eventi di cui sopra. Successivamente, definiremo tutte queste funzioni per creare un'app Web funzionale.




Gestisci le chiavi API

La gestione delle chiavi API di un utente è importante poiché l'intera cosa funziona secondo il principio BYOK (Bring Your Own Key). Ogni volta che un utente invia una chiave, la casella di testo deve diventare immutabile con un prompt che suggerisce che la chiave è impostata. E quando viene attivato l'evento "Cambia chiave", la scatola deve essere in grado di ricevere input.


Per fare ciò, definire due variabili globali.

enable_box = gr.Textbox.update(value=None,placeholder= 'Upload your OpenAI API key',interactive=True)
disable_box = gr.Textbox.update(value = 'OpenAI API key is Set',interactive=False)

Definiamo le funzioni

def set_apikey(api_key):
    os.environ['OPENAI_API_KEY'] = api_key
    return disable_box
def enable_api_box():
    return enable_box

La funzione set_apikey accetta un input di stringa e restituisce la variabile disable_box, che rende la casella di testo immutabile dopo l'esecuzione. Nella sezione Gradio Events, abbiamo definito l'api_key Submit Event, che chiama la funzione set_apikey. Impostiamo la chiave API come variabile di ambiente utilizzando la libreria del sistema operativo.

Facendo clic sul pulsante Cambia chiave API viene restituita la variabile enable_box, che abilita nuovamente la mutabilità della casella di testo.


Creiamo la catena di Langchain

Questo è il passo più importante. Questo passaggio comporta l'estrazione di testi e la creazione di incorporamenti e la loro memorizzazione in archivi vettoriali. Grazie a Langchain, che fornisce wrapper per più servizi semplificando le cose. Quindi, definiamo la funzione.

def process_file(self,file):

        loader = PyPDFLoader(file.name)
        documents = loader.load()  
        pattern = r"/([^/]+)$"
        match = re.search(pattern, file.name)
        file_name = match.group(1)
        return documents, file_name
    
    def build_chain(self, file):
        documents, file_name = self.process_file(file)
        #Load embeddings model
        embeddings = OpenAIEmbeddings(openai_api_key=self.OPENAI_API_KEY) 
        pdfsearch = Chroma.from_documents(documents, embeddings, collection_name= file_name,)

        chain = ConversationalRetrievalChain.from_llm(ChatOpenAI(temperature=0.0, openai_api_key=self.OPENAI_API_KEY), retriever=pdfsearch.as_retriever(search_kwargs={"k": 1}),return_source_documents=True,)
        return chain

  1. Creato un controllo se la chiave API è impostata o meno. Ciò genererà un errore sul front-end se la chiave non è impostata.

  2. Funzione Carica il file PDF usando PyPDFLoader

  3. Funzionalità di incorporamento definita con OpenAIEmbeddings.

  4. Creato un archivio vettoriale dall'elenco di testi dal PDF

  5. Definita una catena con chatOpenAI (per impostazione predefinita ChatOpenAI usa gpt-3.5-turbo) e un base retriever (usa una ricerca per similarità).



Genera le risposte

Una volta creata la catena, chiameremo la catena e invieremo le nostre query. Invia una cronologia della chat insieme alle query per mantenere il contesto delle conversazioni e trasmettere le risposte all'interfaccia della chat. Definiamo la funzione.

def generate_response(history, query, btn):  
        if not file:
            raise gr.Error(message='Upload a PDF')
           
        chain = app(file)

        result = chain({"question": query, 'chat_history':app.chat_history},return_only_outputs=True)
        app.chat_history += [(query, result["answer"])]
        app.N = list(result['source_documents'][0])[1][1]['page']

        for char in result['answer']:
           history[-1][-1] += char
           yield history,''

  • Genera un errore se non è stato caricato alcun PDF.

  • Chiama la funzione process_file solo una volta.

  • Invia query e cronologia chat alla catena

  • Recupera il numero di pagina della risposta più pertinente.

  • Rendi le risposte al front-end.



Renderizza l'immagine di un file PDF

Il passaggio finale consiste nel rendere l'immagine del file PDF con la risposta più pertinente. Possiamo usare le librerie PyMuPdf e PIL per renderizzare le immagini del documento.

def render_file(file):
    global N# Open the PDF document using fitz
    doc = fitz.open(file.name)# Get the specific page to render
    page = doc[N]# Render the page as a PNG image with a resolution of 300 DPI
    pix = page.get_pixmap(matrix=fitz.Matrix(300/72, 300/72))# Create an Image object from the rendered pixel data
    image = Image.frombytes('RGB', [pix.width, pix.height], pix.samples)# Return the rendered imagereturn image


  • Apri il file con Fitz di PyMuPdf.

  • Ottieni la pagina pertinente.

  • Ottieni la mappa dei pixel per la pagina.

  • Crea l'immagine dalla classe Image di PIL.

Questo è tutto ciò che dobbiamo fare per un'app Web funzionale per chattare con qualsiasi PDF.




Mettiamo tutto insieme

from typing import Any
import gradio as gr
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.vectorstores import Chroma

from langchain.chains import ConversationalRetrievalChain
from langchain.chat_models import ChatOpenAI

from langchain.document_loaders import PyPDFLoader

import fitz
from PIL import Image

import chromadb
import re
import uuid 

enable_box = gr.Textbox.update(value=None,placeholder= 'Upload your OpenAI API key',interactive=True)
disable_box = gr.Textbox.update(value = 'OpenAI API key is Set',interactive=False)

def set_apikey(api_key):

        app.OPENAI_API_KEY = api_key
        
        return disable_box
    
def enable_api_box():
        return enable_box


def add_text(history, text):
    if not text:
         raise gr.Error('enter text')
    history = history + [(text,'')] 
    return history

class my_app:
    def __init__(self, OPENAI_API_KEY= None ) -> None:
        self.OPENAI_API_KEY = OPENAI_API_KEY
        self.chain = None
        self.chat_history = []
        self.N = 0
        self.count = 0

    def __call__(self, file) -> Any:
        if self.count==0:
            print('This is here')
            self.build_chain(file)
            self.count+=1

        return self.chain
    
    def chroma_client(self):
        #create a chroma client
        client = chromadb.Client()
        #create a collecyion
        collection = client.get_or_create_collection(name="my-collection")

        return client
    
    def process_file(self,file):

        loader = PyPDFLoader(file.name)
        documents = loader.load()  
        pattern = r"/([^/]+)$"
        match = re.search(pattern, file.name)
        file_name = match.group(1)
        return documents, file_name
    
    def build_chain(self, file):
        documents, file_name = self.process_file(file)
        #Load embeddings model
        embeddings = OpenAIEmbeddings(openai_api_key=self.OPENAI_API_KEY) 
        pdfsearch = Chroma.from_documents(documents, embeddings, collection_name= file_name,)

        chain = ConversationalRetrievalChain.from_llm(ChatOpenAI(temperature=0.0, openai_api_key=self.OPENAI_API_KEY), 
                                                  retriever=pdfsearch.as_retriever(search_kwargs={"k": 1}),
                                                  return_source_documents=True,)
        return chain
    

def get_response(history, query, file):
        
        
        if not file:
            raise gr.Error(message='Upload a PDF')
           
        chain = app(file)

        result = chain({"question": query, 'chat_history':app.chat_history},return_only_outputs=True)
        app.chat_history += [(query, result["answer"])]
        app.N = list(result['source_documents'][0])[1][1]['page']

        for char in result['answer']:
           history[-1][-1] += char
           yield history,''

def render_file(file):
 
        doc = fitz.open(file.name)
        page = doc[app.N]
        #Render the page as a PNG image with a resolution of 300 DPI
        pix = page.get_pixmap(matrix=fitz.Matrix(300/72, 300/72))
        image = Image.frombytes('RGB', [pix.width, pix.height], pix.samples)
        return image

def render_first(file):
        doc = fitz.open(file.name)
        page = doc[0]
        #Render the page as a PNG image with a resolution of 300 DPI
        pix = page.get_pixmap(matrix=fitz.Matrix(300/72, 300/72))
        image = Image.frombytes('RGB', [pix.width, pix.height], pix.samples)
        return image,[]

app = my_app()
with gr.Blocks() as demo:
    state = gr.State(uuid.uuid4().hex)
    with gr.Column():
        with gr.Row():
            with gr.Column(scale=0.8):
                api_key = gr.Textbox(placeholder='Enter OpenAI API key', show_label=False, interactive=True).style(container=False)
            with gr.Column(scale=0.2):
                change_api_key = gr.Button('Change Key')
        with gr.Row():           
            chatbot = gr.Chatbot(value=[], elem_id='chatbot').style(height=650)
            show_img = gr.Image(label='Upload PDF', tool='select' ).style(height=680)
    with gr.Row():
        with gr.Column(scale=0.60):
            txt = gr.Textbox(
                        show_label=False,
                        placeholder="Enter text and press enter",
                    ).style(container=False)
        with gr.Column(scale=0.20):
            submit_btn = gr.Button('submit')
        with gr.Column(scale=0.20):
            btn = gr.UploadButton("📁 upload a PDF", file_types=[".pdf"]).style()
        
  
    api_key.submit(fn=set_apikey, inputs=[api_key], outputs=[api_key,])
    change_api_key.click(fn= enable_api_box,outputs=[api_key])
    btn.upload(fn=render_first, inputs=[btn], outputs=[show_img,chatbot],)
    
    submit_btn.click(fn=add_text, inputs=[chatbot,txt], outputs=[chatbot, ], queue=False).success(fn=get_response,inputs = [chatbot, txt, btn],
                                    outputs = [chatbot,txt]).success(fn=render_file,inputs = [btn], outputs=[show_img])

    
demo.queue()
demo.launch() 

Ora che abbiamo configurato tutto, lanciamo la nostra applicazione.

È possibile avviare l'applicazione in modalità debug con il seguente comando


gradio app.py

Altrimenti, puoi anche semplicemente eseguire l'applicazione con il comando Python.

Di seguito è riportato il risultato finale.



PCR (5).gif
PCR (4).gif
PCR.gif
PCR.gif
PCR.gif
PCR.gif
PCR (5).gif
3.gif
Vediamo se riesci a cliccarmi ! Nascondo una Sorpresa... (2).png

Ciao 

🤗 Articoli consigliati dalla nostra
Intelligenza Artificiale in base ai tuoi interessi

Correlazione Alta

Correlazione Media

Correlazione Bassa

Iscriviti

VUOI DIVENTARE UN MEMBRO DI INTELLIGENZA ARTIFICIALE ITALIA GRATUITAMENTE E TRARNE I SEGUENTI BENEFICI?

Corsi Gratis

più di 150 lezioni online

Dataset Gratis

più di 150o dataset

Ebook Gratis

più di 10 libri da leggere

Editor Gratis

un editor python online

Progetti Gratis

più di 25 progetti python

App Gratis

4 servizi web con I.A.

Unisciti Ora a oltre
1.000.000
di lettori e appassionanti d'I.A.

Tutto ciò che riguarda l'intelligenza Artificiale, in unico posto, in italiano e gratis.

MEGLIO DI COSI' NON SI PUO' FARE

Dopo l'iscrizione riceverai diversi Regali

VUOI SCRIVERE ARTICOLI INSIEME A NOI.

Grazie

bottom of page