Spaces:
Sleeping
Sleeping
Upload folder using huggingface_hub
Browse files- .gitignore +14 -0
- 2024-08-06T15:30:18.239414.json +1 -0
- Dockerfile +63 -0
- EmbedUpsert.py +121 -0
- OpenAIChat.py +525 -0
- README.Docker.md +22 -0
- README.md +2 -8
- __pycache__/OpenAIUpsert.cpython-312.pyc +0 -0
- __pycache__/utils.cpython-311.pyc +0 -0
- __pycache__/utils.cpython-312.pyc +0 -0
- compose.yaml +52 -0
- requirements.txt +193 -0
- utils.py +23 -0
.gitignore
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
.env
|
| 2 |
+
.openai
|
| 3 |
+
.dockerignore
|
| 4 |
+
chat_history.pkl
|
| 5 |
+
embeddings.json
|
| 6 |
+
new_uploads/*
|
| 7 |
+
prev_uploads/*
|
| 8 |
+
|
| 9 |
+
|
| 10 |
+
# Work in Progress
|
| 11 |
+
app.py
|
| 12 |
+
index.html
|
| 13 |
+
index.js
|
| 14 |
+
index.css
|
2024-08-06T15:30:18.239414.json
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
[{"timestamp": "2024-08-06T15:30:18.239414"}, {"role": "user", "content": "Tell me about a lease"}, {"role": "assistant", "content": "A lease is a legal agreement between a landlord (or lessor) and a tenant (or lessee) that outlines the terms and conditions under which a property is rented. It typically includes details such as the duration of the lease (term), the amount of rent to be paid, any security deposits required, maintenance responsibilities, and other provisions related to the use of the property. Leases can vary in length, with some being short-term (e.g., month-to-month) and others lasting several years. A lease provides both parties with rights and obligations regarding the property being rented for the specified period."}, {"full_prompt": [{"role": "system", "content": "You are a helpful assistant."}, {"role": "user", "content": "Context:\nTERM\n\na) The term of the Lease shall be for sixteen (16) years, commencing on the first day of May, 1998, and ending on the last day of April, 2014.\n\nPOSSESSION\n\na) Lessee shall be entitled to possession on or about May 1, 1998 or upon completion of Tenant Improvement work.\n\nb) In the event the Lessor shall permit the Lessee to occupy the Premises prior to the commencement date of the term of this Lease, such occupancy shall be subject to all the provisions of this Lease. Early possession shall not advance the termination date of this Lease, and Lessor shall not be responsible for equipment installed by the Lessee.\n\nRENT\n\na) This Lease is the type commonly referred to as a \u201cgross lease\u201d. Lessee shall pay\nQUIET ENJOYMENT\n\nLessor warrants that Lessee, upon discharge of all of Lessee\u2019s obligations hereunder, shall and may be peaceably and quietly hold and enjoy the premises for the term of the Lease.\n\nLSEKENN.DOC 7\n\n26. GROUND LEASE The Lessee acknowledges that the Lessor has entered into a Ground Lease for the property described in Exhibit A, and has constructed an office building on said property. All rights of Lessor are subject to that Ground Lease, and in the event of any dispute between the terms of this Lease and that of the Ground Lease, the Ground Lease shall control.\n\nDATED this__/ S* day of RornQ , 1998,\n\nLESSOR:\n\nHIGHLINE PROFESSIONAL BUILDING ASSOCIATES LIMITED PARTNERSHIP 10900 N.E. Fourth, Suite 1550\n\nBellevue, WA 98004\n\nBy: Lf (A vl I) hid!\n\nGeneral Pa\n\nLESSEE: Surgery Associates Michael Kennelly, M.D.\n\n16122 Eighth Street SW Suite D-1 Seattle, WA 98166\n\nLESSEE\n\nLESSEE:\n\nSurgery Associates\n\nWilliam L. White, M.D.\n\n16122 Eighth Street SW Suite D-1 Seattle, WA 98166\nWu-Hsun Yang and Geoffrey Bender\n\nFirst Amendment to Lease\n\nHighline Professional Building\n\nThe parties to this First Amendment to Lease dated the December ___, 2023 are Highline Professional Building Associates, Limited Partnership (\u201cLandlord\u201d) and Wu-Hsun Yang and Geoffrey Bender (\u201cTenant\u201d).\t\n\nWHEREAS, Landlord and Tenant have a binding Lease Agreement dated June 10, 2021, together the lease in and to the premises described in Exhibit A Legal Description of the Property more commonly known as Highline Professional Building, 16122 8th, Avenue SW, Suite D3, City of Burien, County of King, State of Washington.\n\nThe parties do hereby mutually agree to modify certain particulars of the Lease Agreement as follow:\n\n1.\tSection 4 Term\n\nSection 4 shall be modified as follows:\n\n\u201cThe term of the Lease shall be extended ten (10) years commencing August 1, 2024 and ending July 31, 2034.\u201d\n\n2.\tSection 5 Rent.\n\n\tMonthly rent for the extended term of the Lease shall be as follows:\nSouth Seattle Nephrology Associates, LLC.\n\nFirst Amendment to Lease\n\nHighline Professional Building\n\nThe parties to this First Amendment to Lease dated the December ___, 2023 are Highline Professional Building Associates, Limited Partnership (\u201cLandlord\u201d) and South Seattle Nephrology Associates, LLC. a Washington Limited Liability Company (\u201cTenant\u201d).\t\n\nWHEREAS, Landlord and Tenant have a binding Lease Agreement dated October 1, 2018, together the lease in and to the premises described in Exhibit A Legal Description of the Property more commonly known as Highline Professional Building, 16122 8th, Avenue SW, Suite E-2, City of Burien, County of King, State of Washington.\n\nThe parties do hereby mutually agree to modify certain particulars of the Lease Agreement as follow:\n\n1.\tSection 4 Term\n\nSection 4 shall be modified as follows:\n\n\u201cThe term of the Lease shall be extended three (3) years commencing January 1, 2024 and ending December 31, 2026.\u201d\n\n2.\tSection 5 Rent.\nSteven McClean MD, PC\n\nFirst Amendment to Lease\n\nHighline Professional Building\n\nThe parties to this First Amendment to Lease dated the September 15, 2022, are Highline Professional Building Associates, Limited Partnership (\u201cLandlord\u201d) and Steven P. McClean MD, PC. an individual (\u201cTenant\u201d).\t\n\nWHEREAS, Landlord and Tenant have a binding Lease Agreement dated July 5, 2012, together the lease in and to the premises described in Exhibit A Legal Description of the Property more commonly known as Highline Professional Building, 16122 8th, Avenue SW, Suite E-3, City of Burien, County of King, State of Washington.\n\nThe parties do hereby mutually agree to modify certain particulars of the Lease Agreement as follow:\n\n1.\tSection 4 Term\n\nSection 4 shall be modified as follows:\n\n\u201cThe term of the Lease shall be extended five (5) years commencing October 1, 2022 and ending September 30, 2027.\u201d\n\n2.\tSection 5 Rent.\n\n\tMonthly rent for the extended term of the Lease shall be as follows:\n\n\nQuestion: Tell me about a lease\nAnswer:"}]}]
|
Dockerfile
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# syntax=docker/dockerfile:1
|
| 2 |
+
|
| 3 |
+
# Comments are provided throughout this file to help you get started.
|
| 4 |
+
# If you need more help, visit the Dockerfile reference guide at
|
| 5 |
+
# https://docs.docker.com/go/dockerfile-reference/
|
| 6 |
+
|
| 7 |
+
# Want to help us make this template better? Share your feedback here: https://forms.gle/ybq9Krt8jtBL3iCk7
|
| 8 |
+
|
| 9 |
+
ARG PYTHON_VERSION=3.12.4
|
| 10 |
+
FROM python:${PYTHON_VERSION}-slim as base
|
| 11 |
+
|
| 12 |
+
# Prevents Python from writing pyc files.
|
| 13 |
+
ENV PYTHONDONTWRITEBYTECODE=1
|
| 14 |
+
|
| 15 |
+
# Keeps Python from buffering stdout and stderr to avoid situations where
|
| 16 |
+
# the application crashes without emitting any logs due to buffering.
|
| 17 |
+
ENV PYTHONUNBUFFERED=1
|
| 18 |
+
|
| 19 |
+
WORKDIR /app
|
| 20 |
+
|
| 21 |
+
# Create a non-privileged user that the app will run under.
|
| 22 |
+
# See https://docs.docker.com/go/dockerfile-user-best-practices/
|
| 23 |
+
ARG UID=10001
|
| 24 |
+
RUN adduser \
|
| 25 |
+
--disabled-password \
|
| 26 |
+
--gecos "" \
|
| 27 |
+
--home "/nonexistent" \
|
| 28 |
+
--shell "/sbin/nologin" \
|
| 29 |
+
--no-create-home \
|
| 30 |
+
--uid "${UID}" \
|
| 31 |
+
appuser
|
| 32 |
+
|
| 33 |
+
# Install system dependencies.
|
| 34 |
+
RUN apt-get update && apt-get install -y \
|
| 35 |
+
build-essential \
|
| 36 |
+
meson \
|
| 37 |
+
ninja-build \
|
| 38 |
+
pkg-config \
|
| 39 |
+
libpoppler-cpp-dev \
|
| 40 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 41 |
+
|
| 42 |
+
# Download dependencies as a separate step to take advantage of Docker's caching.
|
| 43 |
+
# Leverage a cache mount to /root/.cache/pip to speed up subsequent builds.
|
| 44 |
+
# Leverage a bind mount to requirements.txt to avoid having to copy them into
|
| 45 |
+
# into this layer.
|
| 46 |
+
RUN --mount=type=cache,target=/root/.cache/pip \
|
| 47 |
+
--mount=type=bind,source=requirements.txt,target=requirements.txt \
|
| 48 |
+
python -m pip install -r requirements.txt
|
| 49 |
+
|
| 50 |
+
# Switch to the non-privileged user to run the application.
|
| 51 |
+
USER appuser
|
| 52 |
+
|
| 53 |
+
# Copy the source code into the container.
|
| 54 |
+
COPY . .
|
| 55 |
+
|
| 56 |
+
# Expose the port that the application listens on.
|
| 57 |
+
EXPOSE 7860
|
| 58 |
+
|
| 59 |
+
# Ensure Gradio listens on all network interfaces
|
| 60 |
+
ENV GRADIO_SERVER_NAME="0.0.0.0"
|
| 61 |
+
|
| 62 |
+
# Run the application.
|
| 63 |
+
CMD ["python", "OpenAIChat.py"]
|
EmbedUpsert.py
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import json
|
| 3 |
+
import dotenv
|
| 4 |
+
from openai import OpenAI
|
| 5 |
+
from langchain.text_splitter import CharacterTextSplitter
|
| 6 |
+
from langchain_community.document_loaders import DirectoryLoader
|
| 7 |
+
from utils import DOC_CHUNK_SIZE, DOC_CHUNK_OVERLAP, DOC_DIRECTORY, EMBEDDING_FILE
|
| 8 |
+
|
| 9 |
+
'''
|
| 10 |
+
This file handles the loading and embedding of documents.
|
| 11 |
+
Saves the embeddings to a json file specified by EMBEDDING_FILE.
|
| 12 |
+
Uses OpenAI's text-embedding-3-small model for embeddings.
|
| 13 |
+
|
| 14 |
+
Supported formats: pdf
|
| 15 |
+
|
| 16 |
+
Format of saved json file:
|
| 17 |
+
List of dictionaries with keys:
|
| 18 |
+
'doc_id': {filename}_{chunk number}
|
| 19 |
+
'embeddings': List of embeddings for the chunk, one embedding for each character in chunk
|
| 20 |
+
|
| 21 |
+
Specifications:
|
| 22 |
+
OpenAI embeds with a dimension of 1536 per character
|
| 23 |
+
'''
|
| 24 |
+
|
| 25 |
+
# Load environment variables
|
| 26 |
+
dotenv.load_dotenv()
|
| 27 |
+
|
| 28 |
+
def load_documents():
|
| 29 |
+
'''
|
| 30 |
+
Load documents from a specified directory into a list
|
| 31 |
+
|
| 32 |
+
Returns:
|
| 33 |
+
documents: List of documents loaded from the directory, split by chunks
|
| 34 |
+
'''
|
| 35 |
+
# Create document loaders
|
| 36 |
+
pdf_loader = DirectoryLoader(DOC_DIRECTORY, glob='*.pdf')
|
| 37 |
+
docx_loader = DirectoryLoader(DOC_DIRECTORY, glob='*.docx')
|
| 38 |
+
txt_loader = DirectoryLoader(DOC_DIRECTORY, glob='*.txt')
|
| 39 |
+
loaders = [pdf_loader]
|
| 40 |
+
|
| 41 |
+
# Load documents
|
| 42 |
+
print("Loading documents...")
|
| 43 |
+
documents = []
|
| 44 |
+
for loader in loaders:
|
| 45 |
+
try:
|
| 46 |
+
documents.extend(loader.load())
|
| 47 |
+
except Exception as e:
|
| 48 |
+
print(f"Error loading documents: {e}")
|
| 49 |
+
|
| 50 |
+
if (len(documents) == 0):
|
| 51 |
+
print("No documents loaded.")
|
| 52 |
+
return []
|
| 53 |
+
|
| 54 |
+
# Split documents into chunks
|
| 55 |
+
text_splitter = CharacterTextSplitter(chunk_size=DOC_CHUNK_SIZE, chunk_overlap=DOC_CHUNK_OVERLAP)
|
| 56 |
+
documents = text_splitter.split_documents(documents)
|
| 57 |
+
|
| 58 |
+
# Iterate to edit metadata to include chunk number
|
| 59 |
+
# format = {filename}_{chunk number}
|
| 60 |
+
chunk_num = 1
|
| 61 |
+
prev_doc_id = documents[0].metadata['source']
|
| 62 |
+
for chunk in documents:
|
| 63 |
+
print(chunk.metadata)
|
| 64 |
+
if chunk.metadata['source'] != prev_doc_id:
|
| 65 |
+
chunk_num = 1
|
| 66 |
+
prev_doc_id = chunk.metadata['source']
|
| 67 |
+
chunk.metadata['source'] = f"{prev_doc_id}_{chunk_num}"
|
| 68 |
+
chunk_num += 1
|
| 69 |
+
|
| 70 |
+
return documents
|
| 71 |
+
|
| 72 |
+
def embed_documents(documents):
|
| 73 |
+
'''
|
| 74 |
+
Embed documents using OpenAIEmbeddings
|
| 75 |
+
|
| 76 |
+
Args:
|
| 77 |
+
documents: List of documents to embed
|
| 78 |
+
|
| 79 |
+
Returns:
|
| 80 |
+
List of JSON objects {doc_id, embeddings, metadata}
|
| 81 |
+
'''
|
| 82 |
+
# Use OpenAI to embed documents
|
| 83 |
+
client = OpenAI(
|
| 84 |
+
api_key=os.getenv("OPENAI_API_KEY")
|
| 85 |
+
)
|
| 86 |
+
embeddings = []
|
| 87 |
+
print("Embedding documents...")
|
| 88 |
+
|
| 89 |
+
# Embed each chunk
|
| 90 |
+
for chunk in documents:
|
| 91 |
+
chunk_embeddings = client.embeddings.create(
|
| 92 |
+
model="text-embedding-3-small",
|
| 93 |
+
input=chunk.page_content
|
| 94 |
+
)
|
| 95 |
+
# Extract embeddings from response
|
| 96 |
+
chunk_embedding = [record.embedding for record in chunk_embeddings.data]
|
| 97 |
+
embeddings.append({
|
| 98 |
+
'doc_id': chunk.metadata['source'],
|
| 99 |
+
'embeddings': chunk_embedding[0],
|
| 100 |
+
'metadata': {'source': chunk.metadata['source'], 'text': chunk.page_content}
|
| 101 |
+
})
|
| 102 |
+
return embeddings
|
| 103 |
+
|
| 104 |
+
def save_embeddings(embeddings, filename):
|
| 105 |
+
'''
|
| 106 |
+
Save generated embedding to a json file
|
| 107 |
+
|
| 108 |
+
Args:
|
| 109 |
+
embeddings: List of embeddings to save
|
| 110 |
+
filename: Name of the file to save the embeddings
|
| 111 |
+
'''
|
| 112 |
+
print("Saving embedding...")
|
| 113 |
+
with open(filename, 'w') as file:
|
| 114 |
+
json.dump(embeddings, file)
|
| 115 |
+
|
| 116 |
+
### Main code
|
| 117 |
+
documents = load_documents()
|
| 118 |
+
if (len(documents) == 0):
|
| 119 |
+
exit()
|
| 120 |
+
embeddings = embed_documents(documents)
|
| 121 |
+
save_embeddings(embeddings, EMBEDDING_FILE)
|
OpenAIChat.py
ADDED
|
@@ -0,0 +1,525 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
import gradio
|
| 3 |
+
import shutil
|
| 4 |
+
import json
|
| 5 |
+
import dotenv
|
| 6 |
+
import pickle
|
| 7 |
+
import itertools
|
| 8 |
+
from collections import Counter
|
| 9 |
+
from datetime import datetime
|
| 10 |
+
from huggingface_hub import HfApi, HfFolder
|
| 11 |
+
from openai import OpenAI as OpenAIClient
|
| 12 |
+
from pinecone import ServerlessSpec
|
| 13 |
+
from pinecone.grpc import PineconeGRPC as Pinecone
|
| 14 |
+
from transformers import BertTokenizerFast
|
| 15 |
+
from langchain.text_splitter import CharacterTextSplitter
|
| 16 |
+
from langchain_community.document_loaders import DirectoryLoader
|
| 17 |
+
|
| 18 |
+
'''
|
| 19 |
+
This file contains the code for user prompting of the language model.
|
| 20 |
+
The language model used is gpt 3.5 turbo and uses documents stored in Pinecone.
|
| 21 |
+
'''
|
| 22 |
+
|
| 23 |
+
# Load environment variables
|
| 24 |
+
dotenv.load_dotenv()
|
| 25 |
+
assert os.getenv("OPENAI_API_KEY") is not None, "Please set the OPENAI_API_KEY environment variable."
|
| 26 |
+
assert os.getenv("PINECONE_API_KEY") is not None, "Please set the PINECONE_API_KEY environment variable."
|
| 27 |
+
assert os.getenv("HUGGINGFACE_API_KEY") is not None, "Please set the HUGGINGFACE_API_KEY environment variable."
|
| 28 |
+
|
| 29 |
+
HfFolder.save_token(os.getenv("HUGGINGFACE_API_KEY"))
|
| 30 |
+
|
| 31 |
+
CHAT_HISTORY_FILE = "chat_history.pkl"
|
| 32 |
+
NEW_UPLOAD_DIRECTORY = "new_uploads/"
|
| 33 |
+
PREV_UPLOAD_DIRECTORY = "prev_uploads/"
|
| 34 |
+
DOC_CHUNK_SIZE = 1000
|
| 35 |
+
DOC_CHUNK_OVERLAP = 40
|
| 36 |
+
EMBEDDING_FILE = 'embeddings.json'
|
| 37 |
+
INDEX_NAME = "hybrid"
|
| 38 |
+
BATCH_SIZE = 100
|
| 39 |
+
INTERACTIONS_DATASET = "ryanRocks/FalconOpenAIInteractions"
|
| 40 |
+
FILES_DATASET = "ryanRocks/FalconOpenAIFiles"
|
| 41 |
+
|
| 42 |
+
# Ensure uploads directory exists
|
| 43 |
+
os.makedirs(NEW_UPLOAD_DIRECTORY, exist_ok=True)
|
| 44 |
+
os.makedirs(PREV_UPLOAD_DIRECTORY, exist_ok=True)
|
| 45 |
+
|
| 46 |
+
chat_history = []
|
| 47 |
+
chatbot_history = []
|
| 48 |
+
|
| 49 |
+
# Initialize Pinecone database
|
| 50 |
+
try:
|
| 51 |
+
pc = Pinecone(
|
| 52 |
+
api_key=os.getenv("PINECONE_API_KEY"),
|
| 53 |
+
pool_threads=30,
|
| 54 |
+
spec=ServerlessSpec(
|
| 55 |
+
cloud="aws",
|
| 56 |
+
region="us-east-1",
|
| 57 |
+
),
|
| 58 |
+
)
|
| 59 |
+
print("Connected to Pinecone")
|
| 60 |
+
except Exception as e:
|
| 61 |
+
print(f"Error initializing Pinecone: {e}")
|
| 62 |
+
exit()
|
| 63 |
+
|
| 64 |
+
# Initialize index if it does not exist
|
| 65 |
+
existing_indexes = [index.name for index in pc.list_indexes().indexes]
|
| 66 |
+
if INDEX_NAME not in existing_indexes:
|
| 67 |
+
pc.create_index(
|
| 68 |
+
name=INDEX_NAME,
|
| 69 |
+
dimension=1536,
|
| 70 |
+
metric="dotproduct",
|
| 71 |
+
spec=ServerlessSpec(
|
| 72 |
+
cloud="aws",
|
| 73 |
+
region="us-east-1",
|
| 74 |
+
),
|
| 75 |
+
)
|
| 76 |
+
print(f"Created index {INDEX_NAME}")
|
| 77 |
+
else:
|
| 78 |
+
print(f"Index {INDEX_NAME} already exists")
|
| 79 |
+
|
| 80 |
+
|
| 81 |
+
def initialize_chat_history():
|
| 82 |
+
'''
|
| 83 |
+
Initialize the chat history using the chat history pickle file.
|
| 84 |
+
'''
|
| 85 |
+
global chatbot_history
|
| 86 |
+
loaded_chat_history = []
|
| 87 |
+
if (os.path.exists(CHAT_HISTORY_FILE)):
|
| 88 |
+
with open(CHAT_HISTORY_FILE, "rb") as f:
|
| 89 |
+
loaded_chat_history = pickle.load(f)
|
| 90 |
+
else:
|
| 91 |
+
loaded_chat_history = []
|
| 92 |
+
|
| 93 |
+
for i in range(0, len(loaded_chat_history), 2):
|
| 94 |
+
chatbot_history.append((
|
| 95 |
+
loaded_chat_history[i]['content'],
|
| 96 |
+
loaded_chat_history[i+1]['content']
|
| 97 |
+
))
|
| 98 |
+
|
| 99 |
+
async def upload_file(files):
|
| 100 |
+
'''
|
| 101 |
+
Upload files to Pinecone
|
| 102 |
+
|
| 103 |
+
Args:
|
| 104 |
+
files: List of file paths to process
|
| 105 |
+
'''
|
| 106 |
+
# Copy files to uploads directory for easier processing
|
| 107 |
+
for file in files:
|
| 108 |
+
file_path = os.path.join(NEW_UPLOAD_DIRECTORY, file.name.split('/')[-1])
|
| 109 |
+
shutil.move(file.name, file_path)
|
| 110 |
+
|
| 111 |
+
# Load documents
|
| 112 |
+
documents = read_documents()
|
| 113 |
+
dense_embeddings = dense_embed(documents)
|
| 114 |
+
sparse_embeddings = sparse_embed(documents)
|
| 115 |
+
|
| 116 |
+
#save_embeddings(dense_embeddings, EMBEDDING_FILE)
|
| 117 |
+
|
| 118 |
+
# Upsert embeddings into Pinecone
|
| 119 |
+
await upsert(dense_embeddings, sparse_embeddings)
|
| 120 |
+
|
| 121 |
+
# Move newly uploaded files to previous uploads directory
|
| 122 |
+
move_files()
|
| 123 |
+
|
| 124 |
+
return get_uploaded_files()
|
| 125 |
+
|
| 126 |
+
def read_documents():
|
| 127 |
+
'''
|
| 128 |
+
Load documents from a specified directory into a list
|
| 129 |
+
|
| 130 |
+
Args:
|
| 131 |
+
file_paths: List of file paths to load documents from
|
| 132 |
+
Returns:
|
| 133 |
+
documents: List of documents loaded from the directory, split by chunks
|
| 134 |
+
'''
|
| 135 |
+
# Load documents
|
| 136 |
+
print("Loading documents...")
|
| 137 |
+
documents = []
|
| 138 |
+
|
| 139 |
+
# Declare loaders for different file types
|
| 140 |
+
pdf_loader = DirectoryLoader(NEW_UPLOAD_DIRECTORY, glob="*.pdf")
|
| 141 |
+
docx_loader = DirectoryLoader(NEW_UPLOAD_DIRECTORY, glob="*.docx")
|
| 142 |
+
txt_loader = DirectoryLoader(NEW_UPLOAD_DIRECTORY, glob="*.txt")
|
| 143 |
+
|
| 144 |
+
for loader in [pdf_loader, docx_loader, txt_loader]:
|
| 145 |
+
# Load document
|
| 146 |
+
try:
|
| 147 |
+
# Error loading documents: Expected directory, got file: '/private/var/folders/sc/_5mj781j5315nzv10s8kvs1w0000gn/T/gradio/33a9766ee3f05c368d3c7fe56f6f2356e88a4348/YuYouChen Resume.pdf'
|
| 148 |
+
documents.extend(loader.load())
|
| 149 |
+
except Exception as e:
|
| 150 |
+
print(f"Error loading documents: {e}")
|
| 151 |
+
|
| 152 |
+
if (len(documents) == 0):
|
| 153 |
+
print("No documents loaded.")
|
| 154 |
+
return []
|
| 155 |
+
|
| 156 |
+
# Split documents into chunks
|
| 157 |
+
text_splitter = CharacterTextSplitter(chunk_size=DOC_CHUNK_SIZE, chunk_overlap=DOC_CHUNK_OVERLAP)
|
| 158 |
+
documents = text_splitter.split_documents(documents)
|
| 159 |
+
|
| 160 |
+
# Iterate to edit metadata to include chunk number
|
| 161 |
+
# format = {filename}_{chunk number}
|
| 162 |
+
chunk_num = 1
|
| 163 |
+
prev_doc_id = documents[0].metadata['source']
|
| 164 |
+
for chunk in documents:
|
| 165 |
+
if chunk.metadata['source'] != prev_doc_id:
|
| 166 |
+
chunk_num = 1
|
| 167 |
+
prev_doc_id = chunk.metadata['source']
|
| 168 |
+
chunk.metadata['source'] = f"{prev_doc_id}_{chunk_num}"
|
| 169 |
+
chunk_num += 1
|
| 170 |
+
|
| 171 |
+
print("Documents loaded")
|
| 172 |
+
return documents
|
| 173 |
+
|
| 174 |
+
def dense_embed(documents):
|
| 175 |
+
'''
|
| 176 |
+
Embed documents using OpenAIEmbeddings
|
| 177 |
+
|
| 178 |
+
Args:
|
| 179 |
+
documents: List of documents to embed
|
| 180 |
+
|
| 181 |
+
Returns:
|
| 182 |
+
List of JSON objects {doc_id, embeddings, metadata}
|
| 183 |
+
'''
|
| 184 |
+
print("Generating dense embeddings...")
|
| 185 |
+
# Use OpenAI to embed documents
|
| 186 |
+
client = OpenAIClient(
|
| 187 |
+
api_key=os.getenv("OPENAI_API_KEY")
|
| 188 |
+
)
|
| 189 |
+
embeddings = []
|
| 190 |
+
|
| 191 |
+
# Embed each chunk
|
| 192 |
+
for chunk in documents:
|
| 193 |
+
chunk_embeddings = client.embeddings.create(
|
| 194 |
+
model="text-embedding-3-small",
|
| 195 |
+
input=chunk.page_content
|
| 196 |
+
)
|
| 197 |
+
# Extract embeddings from response
|
| 198 |
+
chunk_embedding = [record.embedding for record in chunk_embeddings.data]
|
| 199 |
+
embeddings.append({
|
| 200 |
+
'doc_id': chunk.metadata['source'].split('/')[-1],
|
| 201 |
+
'embeddings': chunk_embedding[0],
|
| 202 |
+
'metadata': {'source': chunk.metadata['source'], 'text': chunk.page_content}
|
| 203 |
+
})
|
| 204 |
+
|
| 205 |
+
print("Complete")
|
| 206 |
+
return embeddings
|
| 207 |
+
|
| 208 |
+
def sparse_embed(documents):
|
| 209 |
+
'''
|
| 210 |
+
Generate sparse embeddings for a list of documents
|
| 211 |
+
|
| 212 |
+
Args:
|
| 213 |
+
documents: List of documents to generate sparse embeddings for
|
| 214 |
+
|
| 215 |
+
Returns:
|
| 216 |
+
List of sparse embeddings in dictionary format
|
| 217 |
+
'''
|
| 218 |
+
print("Generating sparse embeddings...")
|
| 219 |
+
tokenizer = BertTokenizerFast.from_pretrained('bert-base-uncased')
|
| 220 |
+
sparse_embeds = []
|
| 221 |
+
|
| 222 |
+
for chunk in documents:
|
| 223 |
+
# Create batch of input_ids
|
| 224 |
+
inputs = tokenizer(
|
| 225 |
+
chunk.page_content,
|
| 226 |
+
padding=True,
|
| 227 |
+
truncation=True,
|
| 228 |
+
max_length=512,
|
| 229 |
+
add_special_tokens=False,
|
| 230 |
+
)['input_ids']
|
| 231 |
+
|
| 232 |
+
# Create sparse dictionaries
|
| 233 |
+
sparse_embed = build_dict(inputs)
|
| 234 |
+
sparse_embeds.append(sparse_embed)
|
| 235 |
+
|
| 236 |
+
print("Complete")
|
| 237 |
+
return sparse_embeds
|
| 238 |
+
|
| 239 |
+
def build_dict(input_batch):
|
| 240 |
+
'''
|
| 241 |
+
Build a dictionary for sparse embeddings
|
| 242 |
+
|
| 243 |
+
Args:
|
| 244 |
+
input_batch: List of embeddings to convert to a dictionary
|
| 245 |
+
|
| 246 |
+
Returns:
|
| 247 |
+
List of sparse embeddings in dictionary format
|
| 248 |
+
'''
|
| 249 |
+
sparse_emb = []
|
| 250 |
+
|
| 251 |
+
# Iterate through input batch
|
| 252 |
+
indices = []
|
| 253 |
+
values = []
|
| 254 |
+
|
| 255 |
+
# Convert the input_batch list to a dictionary of key to frequency values
|
| 256 |
+
freqs = dict(Counter(input_batch))
|
| 257 |
+
for idx in freqs:
|
| 258 |
+
indices.append(idx)
|
| 259 |
+
values.append(float(freqs[idx]))
|
| 260 |
+
sparse_emb.append({'indices': indices, 'values': values})
|
| 261 |
+
|
| 262 |
+
return sparse_emb
|
| 263 |
+
|
| 264 |
+
def save_embeddings(embeddings, filename):
|
| 265 |
+
'''
|
| 266 |
+
Save generated embedding to a json file
|
| 267 |
+
|
| 268 |
+
Args:
|
| 269 |
+
embeddings: List of embeddings to save
|
| 270 |
+
filename: Name of the file to save the embeddings
|
| 271 |
+
'''
|
| 272 |
+
print("Saving embedding...")
|
| 273 |
+
with open(filename, 'w') as file:
|
| 274 |
+
json.dump(embeddings, file)
|
| 275 |
+
print("Complete")
|
| 276 |
+
|
| 277 |
+
def chunks(iterable):
|
| 278 |
+
'''
|
| 279 |
+
Breaks vector list into chunks of BATCH_SIZE for parallel upserts
|
| 280 |
+
|
| 281 |
+
Args:
|
| 282 |
+
iterable: List of vectors to chunk
|
| 283 |
+
'''
|
| 284 |
+
print("Chunking")
|
| 285 |
+
it = iter(iterable)
|
| 286 |
+
chunk = tuple(itertools.islice(it, BATCH_SIZE))
|
| 287 |
+
while chunk:
|
| 288 |
+
yield chunk
|
| 289 |
+
chunk = tuple(itertools.islice(it, BATCH_SIZE))
|
| 290 |
+
print("Complete")
|
| 291 |
+
|
| 292 |
+
def vectorize(dense_embeddings, sparse_embeddings):
|
| 293 |
+
'''
|
| 294 |
+
Vectorize embeddings with document ids to prepare for insertion into Pinecone
|
| 295 |
+
|
| 296 |
+
Args:
|
| 297 |
+
embeddings: List of embeddings to vectorize
|
| 298 |
+
|
| 299 |
+
Returns:
|
| 300 |
+
List of vectors with tuples (chunk ids, embeddings)
|
| 301 |
+
'''
|
| 302 |
+
print("Vectorizing...")
|
| 303 |
+
vectors = []
|
| 304 |
+
for dense, sparse in zip(dense_embeddings, sparse_embeddings):
|
| 305 |
+
vectors.append({
|
| 306 |
+
'id': dense['doc_id'],
|
| 307 |
+
'values': dense['embeddings'],
|
| 308 |
+
'sparse_values': sparse[0],
|
| 309 |
+
'metadata': dense['metadata'],
|
| 310 |
+
})
|
| 311 |
+
print("Vectorized")
|
| 312 |
+
return vectors
|
| 313 |
+
|
| 314 |
+
async def upsert(dense_embeddings, sparse_embeddings):
|
| 315 |
+
'''
|
| 316 |
+
Upsert embeddings into pinecone
|
| 317 |
+
'''
|
| 318 |
+
index = pc.Index(INDEX_NAME)
|
| 319 |
+
vectors = vectorize(dense_embeddings, sparse_embeddings)
|
| 320 |
+
|
| 321 |
+
# Insert vectors into database in chunks
|
| 322 |
+
print("Upserting embeddings...")
|
| 323 |
+
vector_chunks = chunks(vectors)
|
| 324 |
+
for chunk in vector_chunks:
|
| 325 |
+
index.upsert(chunk)
|
| 326 |
+
|
| 327 |
+
print("Complete")
|
| 328 |
+
|
| 329 |
+
def move_files():
|
| 330 |
+
'''
|
| 331 |
+
Move uploaded files to the previous uploads directory
|
| 332 |
+
'''
|
| 333 |
+
print("Moving files...")
|
| 334 |
+
api = HfApi()
|
| 335 |
+
for file in os.listdir(NEW_UPLOAD_DIRECTORY):
|
| 336 |
+
file_path = os.path.join(NEW_UPLOAD_DIRECTORY, file)
|
| 337 |
+
if (os.path.isfile(file_path)):
|
| 338 |
+
# Upload file to HuggingFace Datasets
|
| 339 |
+
api.upload_file(
|
| 340 |
+
path_or_fileobj = file_path,
|
| 341 |
+
path_in_repo = file,
|
| 342 |
+
repo_id = "ryanRocks/FalconOpenAIFiles",
|
| 343 |
+
repo_type = "dataset",
|
| 344 |
+
)
|
| 345 |
+
# Move file to previous uploads directory
|
| 346 |
+
new_file_path = os.path.join(PREV_UPLOAD_DIRECTORY, file)
|
| 347 |
+
shutil.move(file_path, new_file_path)
|
| 348 |
+
|
| 349 |
+
def hybrid_scale(dense, sparse, alpha):
|
| 350 |
+
print("Hybrid scaling...")
|
| 351 |
+
# Check alpha value in range 0 to 1
|
| 352 |
+
if alpha < 0 or alpha > 1:
|
| 353 |
+
raise ValueError("Alpha must be between 0 and 1")
|
| 354 |
+
|
| 355 |
+
# Scale dense and sparse vectors to create hybrid search vectors
|
| 356 |
+
hdense = [v * alpha for v in dense]
|
| 357 |
+
hsparse = {
|
| 358 |
+
'indices': sparse['indices'],
|
| 359 |
+
'values': [v * (1 - alpha) for v in sparse['values']],
|
| 360 |
+
}
|
| 361 |
+
print("Complete")
|
| 362 |
+
return hdense, hsparse
|
| 363 |
+
|
| 364 |
+
def hybrid_query(question, top_k, alpha):
|
| 365 |
+
try:
|
| 366 |
+
print("Hybrid querying...")
|
| 367 |
+
|
| 368 |
+
# Convert the question into a dense vector
|
| 369 |
+
print("Converting question to dense vector...")
|
| 370 |
+
client = OpenAIClient(
|
| 371 |
+
api_key=os.getenv("OPENAI_API_KEY")
|
| 372 |
+
)
|
| 373 |
+
query_embedding = client.embeddings.create(
|
| 374 |
+
model="text-embedding-3-small",
|
| 375 |
+
input=question,
|
| 376 |
+
)
|
| 377 |
+
dense_vec = [record.embedding for record in query_embedding.data][0]
|
| 378 |
+
print("Complete")
|
| 379 |
+
|
| 380 |
+
# Convert the question into a sparse vector
|
| 381 |
+
print("Converting question to sparse vector...")
|
| 382 |
+
tokenizer = BertTokenizerFast.from_pretrained('bert-base-uncased')
|
| 383 |
+
inputs = tokenizer(
|
| 384 |
+
question,
|
| 385 |
+
padding=True,
|
| 386 |
+
truncation=True,
|
| 387 |
+
max_length=512,
|
| 388 |
+
add_special_tokens=False,
|
| 389 |
+
)['input_ids']
|
| 390 |
+
sparse_vec = build_dict(inputs)[0]
|
| 391 |
+
print("Complete")
|
| 392 |
+
|
| 393 |
+
# Scale alpha with hybrid_scale
|
| 394 |
+
dense_vec, sparse_vec = hybrid_scale(
|
| 395 |
+
dense_vec, sparse_vec, alpha
|
| 396 |
+
)
|
| 397 |
+
|
| 398 |
+
# Query pinecone with the query parameters
|
| 399 |
+
print("Querying Pinecone...")
|
| 400 |
+
index = pc.Index(INDEX_NAME)
|
| 401 |
+
result = index.query(
|
| 402 |
+
vector=dense_vec,
|
| 403 |
+
sparse_vector=sparse_vec,
|
| 404 |
+
top_k=top_k,
|
| 405 |
+
include_values=True,
|
| 406 |
+
include_metadata=True,
|
| 407 |
+
)
|
| 408 |
+
print("Complete")
|
| 409 |
+
|
| 410 |
+
# Return search results as json
|
| 411 |
+
return result
|
| 412 |
+
except Exception as e:
|
| 413 |
+
print(f"Error querying Pinecone: {e}")
|
| 414 |
+
|
| 415 |
+
def prompt(question, history):
|
| 416 |
+
'''
|
| 417 |
+
Prompt the language model with user input
|
| 418 |
+
|
| 419 |
+
Args:
|
| 420 |
+
question: User string input to prompt the language model
|
| 421 |
+
Returns:
|
| 422 |
+
Language model response to the user
|
| 423 |
+
'''
|
| 424 |
+
|
| 425 |
+
global chatbot_history
|
| 426 |
+
global chat_history
|
| 427 |
+
|
| 428 |
+
# Handle clearing history
|
| 429 |
+
if len(history) == 0:
|
| 430 |
+
chatbot_history = []
|
| 431 |
+
chat_history = []
|
| 432 |
+
with open(CHAT_HISTORY_FILE, "wb") as f:
|
| 433 |
+
pickle.dump(chat_history, f)
|
| 434 |
+
|
| 435 |
+
# Check for API key
|
| 436 |
+
if (os.getenv("OPENAI_API_KEY") is None):
|
| 437 |
+
return "Please set the OPENAI_API_KEY environment variable."
|
| 438 |
+
|
| 439 |
+
# Query database and prompt the language model with results
|
| 440 |
+
try:
|
| 441 |
+
# Query database for context
|
| 442 |
+
results = hybrid_query(question, top_k=5, alpha=0.4)
|
| 443 |
+
context = ""
|
| 444 |
+
for match in results['matches']:
|
| 445 |
+
context += match['metadata']['text'] + "\n"
|
| 446 |
+
|
| 447 |
+
client = OpenAIClient()
|
| 448 |
+
|
| 449 |
+
# Prepare prompt with chat history
|
| 450 |
+
prompt = f"Context:\n{context}\n\nQuestion: {question}\nAnswer:"
|
| 451 |
+
messages = [{"role": "system", "content": "You are a helpful assistant."}]
|
| 452 |
+
messages.extend(chat_history)
|
| 453 |
+
messages.append({"role": "user", "content": prompt})
|
| 454 |
+
|
| 455 |
+
time = datetime.now().isoformat()
|
| 456 |
+
print("Prompting language model...")
|
| 457 |
+
response = client.chat.completions.create(
|
| 458 |
+
messages=messages,
|
| 459 |
+
model="gpt-3.5-turbo",
|
| 460 |
+
)
|
| 461 |
+
|
| 462 |
+
# Extract answer from response
|
| 463 |
+
answer = response.choices[0].message.content.strip()
|
| 464 |
+
|
| 465 |
+
interaction = [
|
| 466 |
+
{"timestamp": time},
|
| 467 |
+
{"role": "user", "content": question},
|
| 468 |
+
{"role": "assistant", "content": answer},
|
| 469 |
+
{"full_prompt": messages},
|
| 470 |
+
]
|
| 471 |
+
|
| 472 |
+
with open(f"{time}.json", "w") as f:
|
| 473 |
+
json.dump(interaction, f)
|
| 474 |
+
|
| 475 |
+
# Upload interaction to HuggingFace Datasets
|
| 476 |
+
api = HfApi()
|
| 477 |
+
api.upload_file(
|
| 478 |
+
path_or_fileobj = f"{time}.json",
|
| 479 |
+
path_in_repo = f"{time}.json",
|
| 480 |
+
repo_id = INTERACTIONS_DATASET,
|
| 481 |
+
repo_type = "dataset",
|
| 482 |
+
)
|
| 483 |
+
|
| 484 |
+
# Save chat history
|
| 485 |
+
chat_history.extend([
|
| 486 |
+
{"role": "user", "content": question},
|
| 487 |
+
{"role": "assistant", "content": answer},
|
| 488 |
+
])
|
| 489 |
+
|
| 490 |
+
with open(CHAT_HISTORY_FILE, "wb") as f:
|
| 491 |
+
pickle.dump(chat_history, f)
|
| 492 |
+
|
| 493 |
+
return answer
|
| 494 |
+
|
| 495 |
+
# Handle exceptions
|
| 496 |
+
except Exception as e:
|
| 497 |
+
return "Error: " + str(e)
|
| 498 |
+
|
| 499 |
+
def get_uploaded_files():
|
| 500 |
+
'''
|
| 501 |
+
Get uploaded files in prev_uploads directory
|
| 502 |
+
'''
|
| 503 |
+
uploaded_files = []
|
| 504 |
+
|
| 505 |
+
for file in os.listdir(PREV_UPLOAD_DIRECTORY):
|
| 506 |
+
file_path = os.path.join(PREV_UPLOAD_DIRECTORY, file)
|
| 507 |
+
if (os.path.isfile(file_path)):
|
| 508 |
+
uploaded_files.append(file_path)
|
| 509 |
+
return uploaded_files
|
| 510 |
+
|
| 511 |
+
# Create a Gradio interface
|
| 512 |
+
with gradio.Blocks() as demo:
|
| 513 |
+
# Load chat history
|
| 514 |
+
initialize_chat_history()
|
| 515 |
+
|
| 516 |
+
# Create chatbot interface
|
| 517 |
+
chatbot = gradio.Chatbot(value=chat_history, placeholder="What would you like to know?")
|
| 518 |
+
gradio.ChatInterface(fn=prompt, chatbot=chatbot)
|
| 519 |
+
|
| 520 |
+
# Create file upload interface
|
| 521 |
+
file_output = gradio.File(value=get_uploaded_files())
|
| 522 |
+
upload_button = gradio.UploadButton("Click to upload a file", file_types=["pdf, docx, txt"], file_count="multiple")
|
| 523 |
+
upload_button.upload(upload_file, upload_button, file_output)
|
| 524 |
+
|
| 525 |
+
demo.launch()
|
README.Docker.md
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
### Building and running your application
|
| 2 |
+
|
| 3 |
+
When you're ready, start your application by running:
|
| 4 |
+
`docker compose up --build`.
|
| 5 |
+
|
| 6 |
+
Your application will be available at http://localhost:8000.
|
| 7 |
+
|
| 8 |
+
### Deploying your application to the cloud
|
| 9 |
+
|
| 10 |
+
First, build your image, e.g.: `docker build -t myapp .`.
|
| 11 |
+
If your cloud uses a different CPU architecture than your development
|
| 12 |
+
machine (e.g., you are on a Mac M1 and your cloud provider is amd64),
|
| 13 |
+
you'll want to build the image for that platform, e.g.:
|
| 14 |
+
`docker build --platform=linux/amd64 -t myapp .`.
|
| 15 |
+
|
| 16 |
+
Then, push it to your registry, e.g. `docker push myregistry.com/myapp`.
|
| 17 |
+
|
| 18 |
+
Consult Docker's [getting started](https://docs.docker.com/go/get-started-sharing/)
|
| 19 |
+
docs for more detail on building and pushing.
|
| 20 |
+
|
| 21 |
+
### References
|
| 22 |
+
* [Docker's Python guide](https://docs.docker.com/language/python/)
|
README.md
CHANGED
|
@@ -1,12 +1,6 @@
|
|
| 1 |
---
|
| 2 |
title: FalconOpenAI
|
| 3 |
-
|
| 4 |
-
colorFrom: red
|
| 5 |
-
colorTo: blue
|
| 6 |
sdk: gradio
|
| 7 |
-
sdk_version: 4.
|
| 8 |
-
app_file: app.py
|
| 9 |
-
pinned: false
|
| 10 |
---
|
| 11 |
-
|
| 12 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
|
| 1 |
---
|
| 2 |
title: FalconOpenAI
|
| 3 |
+
app_file: OpenAIChat.py
|
|
|
|
|
|
|
| 4 |
sdk: gradio
|
| 5 |
+
sdk_version: 4.38.1
|
|
|
|
|
|
|
| 6 |
---
|
|
|
|
|
|
__pycache__/OpenAIUpsert.cpython-312.pyc
ADDED
|
Binary file (3.1 kB). View file
|
|
|
__pycache__/utils.cpython-311.pyc
ADDED
|
Binary file (1.08 kB). View file
|
|
|
__pycache__/utils.cpython-312.pyc
ADDED
|
Binary file (946 Bytes). View file
|
|
|
compose.yaml
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Comments are provided throughout this file to help you get started.
|
| 2 |
+
# If you need more help, visit the Docker Compose reference guide at
|
| 3 |
+
# https://docs.docker.com/go/compose-spec-reference/
|
| 4 |
+
|
| 5 |
+
# Here the instructions define your application as a service called "server".
|
| 6 |
+
# This service is built from the Dockerfile in the current directory.
|
| 7 |
+
# You can add other services your application may depend on here, such as a
|
| 8 |
+
# database or a cache. For examples, see the Awesome Compose repository:
|
| 9 |
+
# https://github.com/docker/awesome-compose
|
| 10 |
+
services:
|
| 11 |
+
server:
|
| 12 |
+
build:
|
| 13 |
+
context: .
|
| 14 |
+
ports:
|
| 15 |
+
- 7860:7860
|
| 16 |
+
env_file:
|
| 17 |
+
- .env
|
| 18 |
+
image: ryanyyc/project-falcon:openai
|
| 19 |
+
|
| 20 |
+
# The commented out section below is an example of how to define a PostgreSQL
|
| 21 |
+
# database that your application can use. `depends_on` tells Docker Compose to
|
| 22 |
+
# start the database before your application. The `db-data` volume persists the
|
| 23 |
+
# database data between container restarts. The `db-password` secret is used
|
| 24 |
+
# to set the database password. You must create `db/password.txt` and add
|
| 25 |
+
# a password of your choosing to it before running `docker compose up`.
|
| 26 |
+
# depends_on:
|
| 27 |
+
# db:
|
| 28 |
+
# condition: service_healthy
|
| 29 |
+
# db:
|
| 30 |
+
# image: postgres
|
| 31 |
+
# restart: always
|
| 32 |
+
# user: postgres
|
| 33 |
+
# secrets:
|
| 34 |
+
# - db-password
|
| 35 |
+
# volumes:
|
| 36 |
+
# - db-data:/var/lib/postgresql/data
|
| 37 |
+
# environment:
|
| 38 |
+
# - POSTGRES_DB=example
|
| 39 |
+
# - POSTGRES_PASSWORD_FILE=/run/secrets/db-password
|
| 40 |
+
# expose:
|
| 41 |
+
# - 5432
|
| 42 |
+
# healthcheck:
|
| 43 |
+
# test: [ "CMD", "pg_isready" ]
|
| 44 |
+
# interval: 10s
|
| 45 |
+
# timeout: 5s
|
| 46 |
+
# retries: 5
|
| 47 |
+
# volumes:
|
| 48 |
+
# db-data:
|
| 49 |
+
# secrets:
|
| 50 |
+
# db-password:
|
| 51 |
+
# file: db/password.txt
|
| 52 |
+
|
requirements.txt
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
aiofiles==23.2.1
|
| 2 |
+
aiohttp==3.9.5
|
| 3 |
+
aiosignal==1.3.1
|
| 4 |
+
altair==5.3.0
|
| 5 |
+
annotated-types==0.7.0
|
| 6 |
+
antlr4-python3-runtime==4.9.3
|
| 7 |
+
anyio==4.4.0
|
| 8 |
+
attrs==23.2.0
|
| 9 |
+
backoff==2.2.1
|
| 10 |
+
beautifulsoup4==4.12.3
|
| 11 |
+
blinker==1.8.2
|
| 12 |
+
cachetools==5.4.0
|
| 13 |
+
certifi==2024.7.4
|
| 14 |
+
cffi==1.16.0
|
| 15 |
+
chardet==5.2.0
|
| 16 |
+
charset-normalizer==3.3.2
|
| 17 |
+
click==8.1.7
|
| 18 |
+
coloredlogs==15.0.1
|
| 19 |
+
contourpy==1.2.1
|
| 20 |
+
cryptography==43.0.0
|
| 21 |
+
cycler==0.12.1
|
| 22 |
+
dataclasses-json==0.6.7
|
| 23 |
+
datasets==2.20.0
|
| 24 |
+
deepdiff==7.0.1
|
| 25 |
+
Deprecated==1.2.14
|
| 26 |
+
dill==0.3.8
|
| 27 |
+
distro==1.9.0
|
| 28 |
+
dnspython==2.6.1
|
| 29 |
+
effdet==0.4.1
|
| 30 |
+
email_validator==2.2.0
|
| 31 |
+
emoji==2.12.1
|
| 32 |
+
et-xmlfile==1.1.0
|
| 33 |
+
fastapi==0.111.0
|
| 34 |
+
fastapi-cli==0.0.4
|
| 35 |
+
ffmpy==0.3.2
|
| 36 |
+
filelock==3.15.4
|
| 37 |
+
filetype==1.2.0
|
| 38 |
+
Flask==3.0.3
|
| 39 |
+
flatbuffers==24.3.25
|
| 40 |
+
fonttools==4.53.1
|
| 41 |
+
frozenlist==1.4.1
|
| 42 |
+
fsspec==2024.5.0
|
| 43 |
+
google-api-core==2.19.1
|
| 44 |
+
google-auth==2.32.0
|
| 45 |
+
google-cloud-vision==3.7.3
|
| 46 |
+
googleapis-common-protos==1.63.2
|
| 47 |
+
gradio==4.38.1
|
| 48 |
+
gradio_client==1.1.0
|
| 49 |
+
grpc-gateway-protoc-gen-openapiv2==0.1.0
|
| 50 |
+
grpcio==1.65.1
|
| 51 |
+
h11==0.14.0
|
| 52 |
+
httpcore==1.0.5
|
| 53 |
+
httptools==0.6.1
|
| 54 |
+
httpx==0.27.0
|
| 55 |
+
huggingface-hub==0.23.4
|
| 56 |
+
humanfriendly==10.0
|
| 57 |
+
idna==3.7
|
| 58 |
+
importlib_resources==6.4.0
|
| 59 |
+
iopath==0.1.10
|
| 60 |
+
itsdangerous==2.2.0
|
| 61 |
+
Jinja2==3.1.4
|
| 62 |
+
joblib==1.4.2
|
| 63 |
+
jsonpatch==1.33
|
| 64 |
+
jsonpath-python==1.0.6
|
| 65 |
+
jsonpointer==3.0.0
|
| 66 |
+
jsonschema==4.23.0
|
| 67 |
+
jsonschema-specifications==2023.12.1
|
| 68 |
+
kiwisolver==1.4.5
|
| 69 |
+
langchain==0.2.7
|
| 70 |
+
langchain-community==0.2.7
|
| 71 |
+
langchain-core==0.2.17
|
| 72 |
+
langchain-openai==0.1.16
|
| 73 |
+
langchain-pinecone==0.1.1
|
| 74 |
+
langchain-text-splitters==0.2.2
|
| 75 |
+
langdetect==1.0.9
|
| 76 |
+
langsmith==0.1.85
|
| 77 |
+
layoutparser==0.3.4
|
| 78 |
+
libmagic==1.0
|
| 79 |
+
lxml==5.2.2
|
| 80 |
+
lz4==4.3.3
|
| 81 |
+
Markdown==3.6
|
| 82 |
+
markdown-it-py==3.0.0
|
| 83 |
+
MarkupSafe==2.1.5
|
| 84 |
+
marshmallow==3.21.3
|
| 85 |
+
matplotlib==3.9.1
|
| 86 |
+
mdurl==0.1.2
|
| 87 |
+
mpmath==1.3.0
|
| 88 |
+
multidict==6.0.5
|
| 89 |
+
multiprocess==0.70.16
|
| 90 |
+
mypy-extensions==1.0.0
|
| 91 |
+
nest-asyncio==1.6.0
|
| 92 |
+
networkx==3.3
|
| 93 |
+
nltk==3.8.1
|
| 94 |
+
numpy==1.26.4
|
| 95 |
+
olefile==0.47
|
| 96 |
+
omegaconf==2.3.0
|
| 97 |
+
onnx==1.16.1
|
| 98 |
+
onnxruntime==1.18.1
|
| 99 |
+
openai==1.35.13
|
| 100 |
+
opencv-python==4.10.0.84
|
| 101 |
+
openpyxl==3.1.5
|
| 102 |
+
ordered-set==4.1.0
|
| 103 |
+
orjson==3.10.6
|
| 104 |
+
packaging==24.1
|
| 105 |
+
pandas==2.2.2
|
| 106 |
+
pdf2image==1.17.0
|
| 107 |
+
pdfminer.six==20231228
|
| 108 |
+
pdfplumber==0.11.2
|
| 109 |
+
pikepdf==9.0.0
|
| 110 |
+
pillow==10.4.0
|
| 111 |
+
pillow_heif==0.17.0
|
| 112 |
+
pinecone==4.0.0
|
| 113 |
+
pinecone-client==3.2.2
|
| 114 |
+
portalocker==2.10.1
|
| 115 |
+
proto-plus==1.24.0
|
| 116 |
+
protobuf==3.20.3
|
| 117 |
+
psutil==6.0.0
|
| 118 |
+
pyarrow==17.0.0
|
| 119 |
+
pyarrow-hotfix==0.6
|
| 120 |
+
pyasn1==0.6.0
|
| 121 |
+
pyasn1_modules==0.4.0
|
| 122 |
+
pycocotools==2.0.8
|
| 123 |
+
pycparser==2.22
|
| 124 |
+
pydantic==2.8.2
|
| 125 |
+
pydantic_core==2.20.1
|
| 126 |
+
pydub==0.25.1
|
| 127 |
+
Pygments==2.18.0
|
| 128 |
+
pypandoc==1.13
|
| 129 |
+
pyparsing==3.1.2
|
| 130 |
+
pypdf==4.3.1
|
| 131 |
+
pypdfium2==4.30.0
|
| 132 |
+
pytesseract==0.3.10
|
| 133 |
+
python-dateutil==2.9.0.post0
|
| 134 |
+
python-docx==1.1.2
|
| 135 |
+
python-dotenv==1.0.1
|
| 136 |
+
python-iso639==2024.4.27
|
| 137 |
+
python-magic==0.4.27
|
| 138 |
+
python-multipart==0.0.9
|
| 139 |
+
python-oxmsg==0.0.1
|
| 140 |
+
python-pptx==0.6.23
|
| 141 |
+
pytz==2024.1
|
| 142 |
+
PyYAML==6.0.1
|
| 143 |
+
rapidfuzz==3.9.4
|
| 144 |
+
referencing==0.35.1
|
| 145 |
+
regex==2024.5.15
|
| 146 |
+
requests==2.32.3
|
| 147 |
+
requests-toolbelt==1.0.0
|
| 148 |
+
rich==13.7.1
|
| 149 |
+
rpds-py==0.19.0
|
| 150 |
+
rsa==4.9
|
| 151 |
+
ruff==0.5.1
|
| 152 |
+
safetensors==0.4.3
|
| 153 |
+
scipy==1.14.0
|
| 154 |
+
semantic-version==2.10.0
|
| 155 |
+
shellingham==1.5.4
|
| 156 |
+
six==1.16.0
|
| 157 |
+
sniffio==1.3.1
|
| 158 |
+
soupsieve==2.5
|
| 159 |
+
SQLAlchemy==2.0.31
|
| 160 |
+
starlette==0.37.2
|
| 161 |
+
sympy==1.13.1
|
| 162 |
+
tabulate==0.9.0
|
| 163 |
+
tenacity==8.5.0
|
| 164 |
+
tesseract==0.1.3
|
| 165 |
+
tiktoken==0.7.0
|
| 166 |
+
timm==1.0.7
|
| 167 |
+
tokenizers==0.19.1
|
| 168 |
+
tomlkit==0.12.0
|
| 169 |
+
toolz==0.12.1
|
| 170 |
+
torch==2.3.1
|
| 171 |
+
torchvision==0.18.1
|
| 172 |
+
tqdm==4.66.4
|
| 173 |
+
transformers==4.42.4
|
| 174 |
+
typer==0.12.3
|
| 175 |
+
typing-inspect==0.9.0
|
| 176 |
+
typing_extensions==4.12.2
|
| 177 |
+
tzdata==2024.1
|
| 178 |
+
ujson==5.10.0
|
| 179 |
+
unstructured==0.15.0
|
| 180 |
+
unstructured-client==0.24.1
|
| 181 |
+
unstructured-inference==0.7.36
|
| 182 |
+
unstructured.pytesseract==0.3.12
|
| 183 |
+
urllib3==2.2.2
|
| 184 |
+
uvicorn==0.30.1
|
| 185 |
+
uvloop==0.19.0
|
| 186 |
+
watchfiles==0.22.0
|
| 187 |
+
websockets==11.0.3
|
| 188 |
+
Werkzeug==3.0.3
|
| 189 |
+
wrapt==1.16.0
|
| 190 |
+
xlrd==2.0.1
|
| 191 |
+
XlsxWriter==3.2.0
|
| 192 |
+
xxhash==3.4.1
|
| 193 |
+
yarl==1.9.4
|
utils.py
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import json
|
| 2 |
+
|
| 3 |
+
def load_embeddings(filename):
|
| 4 |
+
'''
|
| 5 |
+
Load embeddings from specified json file
|
| 6 |
+
|
| 7 |
+
Args:
|
| 8 |
+
filename: Name of the json file to load embeddings from
|
| 9 |
+
|
| 10 |
+
Returns:
|
| 11 |
+
List of embeddings loaded from the file
|
| 12 |
+
'''
|
| 13 |
+
print("Loading embeddings...")
|
| 14 |
+
with open(filename, 'r') as file:
|
| 15 |
+
embeddings = json.load(file)
|
| 16 |
+
return embeddings
|
| 17 |
+
|
| 18 |
+
DOC_CHUNK_SIZE = 1000
|
| 19 |
+
DOC_CHUNK_OVERLAP = 40
|
| 20 |
+
DOC_DIRECTORY = './'
|
| 21 |
+
EMBEDDING_FILE = 'embeddings.json'
|
| 22 |
+
BATCH_SIZE = 100
|
| 23 |
+
INDEX_NAME = "project-falcon"
|