Изграждане на чатбот „втори мозък“ с Google Таблици, векторно търсене на Python и NextJS
Искали ли сте някога да създадете чатбот, който да заеме вашето място на интервю? Или може би AI агент, който може да се представя за вашата баба и знае всичко, което тя прави. Благодарение на векторното търсене вашите социопатични тенденции вече могат да бъдат реализирани 😎 Днес ще направим чатбот с GPT4 на OpenAI, FastAPI на Python, Google Sheets и NextJS. Начинаещи добре дошли!
Можете да изпробвате готовата версия тук, за да видите дали това е това, което търсите.
Ще изградим бекенда в част 1 и фронтенда в част 2.
Съдържание
- „Създаване на база данни“
- Получаване на вграждания от OpenAI
- „Изграждане на FastAPI сървър“
Стъпка 1: Създаване на „Векторна база данни“
Знам, че знам, използването на електронна таблица като база данни е най-голямото престъпление, познато на човечеството. Но това е урок, подходящ за начинаещи, а аз съм мързелив. Ако искате по-стабилно решение, опитайте PineconeDB, Milvus, QDrant или Weaviate (уведомете ме в коментарите, ако съм забравил нещо).
Отидете в Google Таблици и направете електронна таблица с една колона „текст“. След това се развихрете и пишете каквото искате. Опитайте се да запазите фактите кратки, тъй като ще извличаме няколко от тях наведнъж и включете неща, които не се променят често. Някои идеи са
- Любими неща
- Места и имена
- Умения и хобита
- Вашето резюме
- Как бихте отговорили на често задавани въпроси
Просто помислете какво бихте попитали истински човек при първия разговор с него.
След като сте готови, изтеглете файла като .csv
Стъпка 2: Вземете вграждания от OpenAI
Искаме да направим текстовете на „базата данни“ достъпни за запитване от естествен език. За да направим това, ще присвоим вектор за вграждане на всеки текст, който получаваме от text-embedding-ada-002 на OpenAI „крайна точка на API“.
На високо ниво ще изпращаме нашите текстове към API и ще получаваме обратно вектор, който ще съхраняваме във формат JSON както с текст, така и с вграждане.
В същата директория като вашия csv файл създайте файл на python или бележник на Jupyter (аз ще използвам Jupyter).
Ето пълния код, който ще обясня по-долу
import openai import pandas as pd #set API Key openai.api_key="YOUR_API_KEY" #load data into pandas and check df = pd.read_csv("aboutme.csv") df = pd.DataFrame(df["text"]) df.head() # Function to get embeddings for a batch of texts def get_embedding_batch(texts, model="text-embedding-ada-002"): embeddings = [] for text in texts: text = text.replace("\n", " ") embedding = openai.Embedding.create(input=[text], model=model)['data'][0]['embedding'] embeddings.append(embedding) return embeddings #get embeddings and add it to the dataframe embeddings = get_embedding_batch(df["text"]) df["embeddings"] = embeddings df.head() #save the dataframe as a json file df.to_json("aboutme3.json")
Първо импортирайте библиотеките openai и pandas dataframe.
import openai import pandas as pd
Задайте вашия OpenAI API ключ, който можете да получите тук
openai.api_key="YOUR_API_KEY"
Заредете csv файла в рамка с данни на pandas и проверете съдържанието му
df = pd.read_csv("aboutme.csv") df = pd.DataFrame(df["text"]) df.head()
В Юпитер трябва да получите нещо подобно
След това създаваме функция, която преминава през всеки текст и създава вграждане, връщайки списък
# Function to get embeddings for a batch of texts def get_embedding_batch(texts, model="text-embedding-ada-002"): embeddings = [] for text in texts: text = text.replace("\n", " ") embedding = openai.Embedding.create(input=[text], model=model)['data'][0]['embedding'] embeddings.append(embedding) return embeddings embeddings = get_embedding_batch(df["text"])
Добавете този списък към рамката с данни като „вграждания“ или каквото искате
df["embeddings"] = embeddings df.head()
Експортиране в JSON
df.to_json("aboutme3.json")
Стъпка 3: Създайте FastAPI
Сега искаме да създадем бекенд услуга, която приема входящите потребителски съобщения и връща най-добрите k най-подходящи текстове
Препоръчвам ви първо да създадете виртуална среда с conda или инструмент по ваш избор, за да съхранявате python пакети.
Използвайки conda, стартирайте в терминала
conda create --name your_env_name conda activate your_env_name
След това инсталирайте тези пакети
pip install fastapi pandas numpy scikit-learn openai uvicorn
Създайте файл server.py в същата директория като вашия json файл със следния код
from fastapi import FastAPI, HTTPException from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse import pandas as pd import numpy as np from sklearn.metrics.pairwise import cosine_similarity import openai import os app = FastAPI() app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], ) directory_path = './' # Initialize an empty list to store the loaded DataFrames dataframes = [] # Iterate over the files in the directory for filename in os.listdir(directory_path): if filename.endswith('.json'): # Consider only JSON files file_path = os.path.join(directory_path, filename) # Load the JSON file into a DataFrame df = pd.read_json(file_path, orient='records') # Append the DataFrame to the list dataframes.append(df) # Concatenate all DataFrames into a single DataFrame df = pd.concat(dataframes, ignore_index=True) #home page that redirects to the api @app.get("/") def home(): return "/get_similar_texts for similar texts" #print(type(df['embeddings'][0])) #debugging, to check if the embeddings are lists @app.post('/get_similar_texts') async def get_similar_texts(text:str, k: int = 10): try: openai.api_key = "YOUR_API_KEY" response = openai.Embedding.create(input=text,model="text-embedding-ada-002") vector = response['data'][0]['embedding'] except Exception as e: raise HTTPException(status_code=500, detail="openai error: "+str(e)) try: # Normalize the input vector vector = np.array(vector).reshape(1, -1) vector /= np.linalg.norm(vector) # Compute cosine similarity between input vector and all embeddings in the DataFrame embeddings = np.array(df['embeddings'].tolist()) similarities = cosine_similarity(vector, embeddings) # Get the indices of the top K similar texts top_indices = np.argsort(similarities[0])[::-1][:k] # Get the top K similar texts and their corresponding cosine similarities results = [] for index in top_indices: try: text = df.loc[index, 'text'] except: text = df.loc[0, 'text'] similarity = similarities[0][index] results.append({'text': text, 'similarity': similarity}) return JSONResponse(content=results) except Exception as e: raise HTTPException(status_code=500, detail=str(e)) #run server dev: uvicorn server:app --host 0.0.0.0 --port 8000 --reload #run server production: uvicorn server:app --host 0.0.0.0 --port 8000 #$ kill $(pgrep -P $uvicorn_pid) shutdown #go to /docs for api documentation
Първо импортирайте инсталираните от вас пакети
from fastapi import FastAPI, HTTPException from fastapi.middleware.cors import CORSMiddleware from fastapi.responses import JSONResponse import pandas as pd import numpy as np from sklearn.metrics.pairwise import cosine_similarity import openai import os
Създайте приложението FastAPI и задайте междинен софтуер.
app = FastAPI() app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], )
По принцип ние разрешаваме заявки от всички източници, всички методи и всички заглавки, от всеки. Правим това основно, за да предотвратим досадните „CORS грешки“ и други протоколи за сигурност. Кой се нуждае от сигурност за вашите най-дълбоки тайни амирит?
След това заредете всички json файлове в директорията в рамка с данни. Този код работи и с един json
# Initialize an empty list to store the loaded DataFrames dataframes = [] # Iterate over the files in the directory for filename in os.listdir(directory_path): if filename.endswith('.json'): # Consider only JSON files file_path = os.path.join(directory_path, filename) # Load the JSON file into a DataFrame df = pd.read_json(file_path, orient='records') # Append the DataFrame to the list dataframes.append(df) # Concatenate all DataFrames into a single DataFrame df = pd.concat(dataframes, ignore_index=True)
Само за да тествам дали API може да получава заявки, направих проста начална страница, която казва на потребителя да отиде до крайната точка get_similar_texts.
#home page that redirects to the api @app.get("/") def home(): return "/get_similar_texts for similar texts"
Декораторът app.get(“/”) създава маршрут на get метод в /
След това правим маршрут за публикация в /get_similar_texts, който приема низ и няколко най-добри текстове за връщане. Опитваме се да извикаме Openai embeddings API с текста като вход, извеждайки грешка, ако нещо не работи.
@app.post('/get_similar_texts') async def get_similar_texts(text:str, k: int = 10): try: openai.api_key = "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" response = openai.Embedding.create(input=text,model="text-embedding-ada-002") vector = response['data'][0]['embedding'] except Exception as e: raise HTTPException(status_code=500, detail="openai error: "+str(e))
По същия маршрут правим някои numpy магии върху този вектор и го сравняваме с всеки друг вектор във вашия JSON файл. Той ги класира въз основа на косинусово сходство, стойност от 0 до 1, и връща първите k най-високи резултата като JSON
try: # Normalize the input vector vector = np.array(vector).reshape(1, -1) vector /= np.linalg.norm(vector) # Compute cosine similarity between input vector and all embeddings in the DataFrame embeddings = np.array(df['embeddings'].tolist()) similarities = cosine_similarity(vector, embeddings) # Get the indices of the top K similar texts top_indices = np.argsort(similarities[0])[::-1][:k] # Get the top K similar texts and their corresponding cosine similarities results = [] for index in top_indices: try: text = df.loc[index, 'text'] except: text = df.loc[0, 'text'] similarity = similarities[0][index] results.append({'text': text, 'similarity': similarity}) return JSONResponse(content=results)
Ние също улавяме всякакви грешки
except Exception as e: raise HTTPException(status_code=500, detail=str(e))
Сега за забавната част: в терминала стартирайте вашия сървър с командата. Той изпълнява извиканото приложение FastAPI във файла с име server.py, с вашата локална машина като хост, на порт 8000. Презареждането слуша за всички промени във вашия сървърен файл и автоматично преустройва, така че премахнете това, когато внедрявате в производствена среда.
uvicorn server:app --host 0.0.0.0 --port 8000 --reload
Уверете се, че uvicorn е инсталиран и вашата правилна среда е активна
Трябва да видите нещо подобно
Отворете браузъра си и отворете http://localhost:8000/
Трябва да видиш
За да го тествате, отидете на http://localhost:8000/docs. FastAPI автоматично генерира красива справка за API за вас.
Отворете метода post и опитайте да изпълните заявка
Ако всичко върви добре, трябва да получите 200 отговора като
И вашият API е готов за работа, поздравления! Просто направете заявки за публикуване на http://localhost:8000/get_similar_text с инструмента по ваш избор. Ако по някаква причина нещо не работи, вижте съобщенията за грешка или ми изпратете съобщение на [email protected].
Тази статия вече е твърде дълга, така че следващия път ще направим интерфейса в NextJS. Благодаря за четенето и очаквайте част 2!