Spaces:
Sleeping
Sleeping
Upload folder using huggingface_hub
Browse files- .here +0 -0
- Helper.md +43 -0
- README.md +92 -12
- conda_env_requirements.txt +179 -0
- configs/app_config.yml +52 -0
- data/docs/FIRST AID IN COMMON EMERGENCY CONDITIONS.pdf +0 -0
- data/docs_2/FIRST AID IN COMMON EMERGENCY CONDITIONS.pdf +0 -0
- data/vectordb/processed/chroma/8008bb97-d12e-40c0-870f-b02d5699f748/data_level0.bin +3 -0
- data/vectordb/processed/chroma/8008bb97-d12e-40c0-870f-b02d5699f748/header.bin +3 -0
- data/vectordb/processed/chroma/8008bb97-d12e-40c0-870f-b02d5699f748/length.bin +3 -0
- data/vectordb/processed/chroma/8008bb97-d12e-40c0-870f-b02d5699f748/link_lists.bin +0 -0
- data/vectordb/processed/chroma/chroma.sqlite3 +0 -0
- images/AI_RT.png +0 -0
- images/RAGGPT UI.png +0 -0
- images/RAGGPT_schema.png +0 -0
- images/openai_.png +0 -0
- requirements.txt +12 -0
- src/.gradio/certificate.pem +31 -0
- src/README.md +6 -0
- src/configs/app_config.yml +52 -0
- src/raggpt.py +87 -0
- src/serve.py +76 -0
- src/terminal_q_and_a.py +48 -0
- src/upload_data_manually.py +41 -0
- src/utils/.env +1 -0
- src/utils/__pycache__/chatbot.cpython-312.pyc +0 -0
- src/utils/__pycache__/load_config.cpython-312.pyc +0 -0
- src/utils/__pycache__/prepare_vectordb.cpython-312.pyc +0 -0
- src/utils/__pycache__/summarizer.cpython-312.pyc +0 -0
- src/utils/__pycache__/ui_settings.cpython-312.pyc +0 -0
- src/utils/__pycache__/upload_file.cpython-312.pyc +0 -0
- src/utils/__pycache__/utilities.cpython-312.pyc +0 -0
- src/utils/chatbot.py +78 -0
- src/utils/load_config.py +153 -0
- src/utils/prepare_vectordb.py +86 -0
- src/utils/summarizer.py +118 -0
- src/utils/ui_settings.py +37 -0
- src/utils/upload_file.py +52 -0
- src/utils/utilities.py +15 -0
.here
ADDED
|
File without changes
|
Helper.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Helper for controling ports. Example is for port 8000.
|
| 2 |
+
|
| 3 |
+
### On Windows:
|
| 4 |
+
|
| 5 |
+
Open Command Prompt as an administrator.
|
| 6 |
+
|
| 7 |
+
Run the following command to find out which process is using port 8000:
|
| 8 |
+
```
|
| 9 |
+
netstat -ano | findstr :8000
|
| 10 |
+
```
|
| 11 |
+
|
| 12 |
+
Look for the line that has 0.0.0.0:8000 or [::]:8000 and note the PID (Process Identifier) at the end of that line.
|
| 13 |
+
|
| 14 |
+
To find out which application the PID corresponds to, run:
|
| 15 |
+
```
|
| 16 |
+
tasklist /fi "pid eq <PID>"
|
| 17 |
+
```
|
| 18 |
+
Replace <PID> with the actual PID number.
|
| 19 |
+
|
| 20 |
+
Once you know which application is using the port, you can decide if you want to close it. If you do, you can either close the application normally or use the following command to forcefully terminate the process:
|
| 21 |
+
```
|
| 22 |
+
taskkill /PID <PID> /F
|
| 23 |
+
```
|
| 24 |
+
Again, replace <PID> with the actual PID number.
|
| 25 |
+
|
| 26 |
+
|
| 27 |
+
### On macOS and Linux:
|
| 28 |
+
|
| 29 |
+
|
| 30 |
+
Open Terminal.
|
| 31 |
+
|
| 32 |
+
Run the following command to find out which process is using port 8000:
|
| 33 |
+
```
|
| 34 |
+
sudo lsof -i :8000
|
| 35 |
+
```
|
| 36 |
+
|
| 37 |
+
Look for the PID in the output, which is usually in the second column.
|
| 38 |
+
|
| 39 |
+
To stop the process, you can use the kill command:
|
| 40 |
+
```
|
| 41 |
+
sudo kill -9 <PID>
|
| 42 |
+
```
|
| 43 |
+
Replace <PID> with the actual PID number.
|
README.md
CHANGED
|
@@ -1,12 +1,92 @@
|
|
| 1 |
-
---
|
| 2 |
-
title:
|
| 3 |
-
|
| 4 |
-
|
| 5 |
-
|
| 6 |
-
|
| 7 |
-
|
| 8 |
-
|
| 9 |
-
|
| 10 |
-
|
| 11 |
-
|
| 12 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: First_Aid_Assistant
|
| 3 |
+
app_file: src/raggpt.py
|
| 4 |
+
sdk: gradio
|
| 5 |
+
sdk_version: 5.12.0
|
| 6 |
+
---
|
| 7 |
+
# RAG-GPT: Retrieval Augmented generation (RAG) chatbot using OpenAI GPT Model, Langchain, ChromaDB, and Gradio
|
| 8 |
+
|
| 9 |
+
**RAG-GPT** supports both PDFs and Docs.
|
| 10 |
+
|
| 11 |
+
**The chatbot offers versatile usage through three different methods:**
|
| 12 |
+
1. **Offline Documents**: Engage with documents that you've pre-processed and vectorized. These documents can be seamlessly integrated into your chat sessions.
|
| 13 |
+
2. **Real-time Uploads:** Easily upload documents during your chat sessions, allowing the chatbot to process and respond to the content on-the-fly.
|
| 14 |
+
3. **Summarization Requests:** Request the chatbot to provide a comprehensive summary of an entire PDF or document in a single interaction, streamlining information retrieval.
|
| 15 |
+
|
| 16 |
+
To employ any of these methods, simply configure the appropriate settings in the "RAG with" dropdown menu within the chatbot interface. Tailor your interactions with documents to suit your preferences and needs efficiently.
|
| 17 |
+
|
| 18 |
+
* The project provides guidance on configuring various settings, such as adjusting the GPT model's temperature for optimal performance.
|
| 19 |
+
* The user interface is crafted with gradio, ensuring an intuitive and user-friendly experience.
|
| 20 |
+
* The model incorporates memory, retaining user Q&As for an enhanced and personalized user experience.
|
| 21 |
+
* For each response, you can access the retrieved content along with the option to view the corresponding PDF.
|
| 22 |
+
|
| 23 |
+
## RAG-GPT User Interface
|
| 24 |
+
<div align="center">
|
| 25 |
+
<img src="images/RAGGPT UI.png" alt="RAG-GPT UI">
|
| 26 |
+
</div>
|
| 27 |
+
|
| 28 |
+
## Project Schema
|
| 29 |
+
<div align="center">
|
| 30 |
+
<img src="images/RAGGPT_schema.png" alt="Schema">
|
| 31 |
+
</div>
|
| 32 |
+
|
| 33 |
+
* NOTE: This project is currently set up as a **demo**. As such, the document management is simplified and not suitable for production environments.
|
| 34 |
+
|
| 35 |
+
## Document Storage
|
| 36 |
+
Documents are stored in two separate folders within the `data` directory:
|
| 37 |
+
- `data/docs_2`: For files that you want to **upload**.
|
| 38 |
+
- `data/docs`: For files that should be **processed in advance**.
|
| 39 |
+
|
| 40 |
+
## Server Setup
|
| 41 |
+
The `serve.py` module leverages these folders to create an **HTTPS server** that hosts the PDF files, making them accessible for user viewing.
|
| 42 |
+
|
| 43 |
+
## Database Creation
|
| 44 |
+
Vector databases (vectorDBs) are generated within the `data` folder, facilitating the project's functionality.
|
| 45 |
+
|
| 46 |
+
## Important Considerations
|
| 47 |
+
- The current file management system is intended for **demonstration purposes only**.
|
| 48 |
+
- It is **strongly recommended** to design a more robust and secure document handling process for any production deployment.
|
| 49 |
+
- Ensure that you place your files in the correct directories (`data/docs_2` and `data/docs`) for the project to function as intended.
|
| 50 |
+
|
| 51 |
+
## Running the Project
|
| 52 |
+
|
| 53 |
+
To get the project up and running, you'll need to set up your environment and install the necessary dependencies. You can do this in two ways:
|
| 54 |
+
|
| 55 |
+
### Option 1: Using the Parent Directory Instructions
|
| 56 |
+
|
| 57 |
+
Follow the instruction on the [parent directory](https://github.com/Farzad-R/LLM-playground/tree/master) to create an environment and install required libraries.
|
| 58 |
+
|
| 59 |
+
### Option 2: Installing Dependencies Individually
|
| 60 |
+
If you prefer to install the dependencies individually, run the following command:
|
| 61 |
+
|
| 62 |
+
```
|
| 63 |
+
pip install gradio==4.13.0 langchain==0.0.354 openai==0.28.0 chromadb==0.4.22 pypdf==3.17.4 pandas==2.1.4
|
| 64 |
+
```
|
| 65 |
+
|
| 66 |
+
1. **Configuration and Execution**
|
| 67 |
+
* Open cfg.py and fill in your GPT API credentials.
|
| 68 |
+
|
| 69 |
+
2. **Activate Your Environment.**
|
| 70 |
+
3. **Ensure you are in the RAG-GPT directory**
|
| 71 |
+
4. **Run the Application:**
|
| 72 |
+
|
| 73 |
+
In Terminal 1:
|
| 74 |
+
```
|
| 75 |
+
python src\serve.py
|
| 76 |
+
```
|
| 77 |
+
|
| 78 |
+
In Terminal 2:
|
| 79 |
+
```
|
| 80 |
+
python src\raggpt_app.py
|
| 81 |
+
```
|
| 82 |
+
5. Chat with your documents.
|
| 83 |
+
|
| 84 |
+
**YouTube video: **[Link](https://www.youtube.com/watch?v=1FERFfut4Uw&t=3s)
|
| 85 |
+
|
| 86 |
+
**Slides:** [Link](https://github.com/Farzad-R/LLM-Zero-to-Hundred/blob/master/presentation/presentation.pdf)
|
| 87 |
+
|
| 88 |
+
Extra read:
|
| 89 |
+
- [GPT model](https://platform.openai.com/docs/models/overview)
|
| 90 |
+
- [Gradio](https://www.gradio.app/guides/quickstart)
|
| 91 |
+
- [Langchain](https://python.langchain.com/docs/get_started/quickstart)
|
| 92 |
+
- [ChromaDB](https://www.trychroma.com/)
|
conda_env_requirements.txt
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# This file may be used to create an environment using:
|
| 2 |
+
# $ conda create --name <env> --file <this file>
|
| 3 |
+
# platform: win-64
|
| 4 |
+
aiofiles=23.2.1=pypi_0
|
| 5 |
+
aiohttp=3.9.1=pypi_0
|
| 6 |
+
aiosignal=1.3.1=pypi_0
|
| 7 |
+
altair=5.2.0=pypi_0
|
| 8 |
+
annotated-types=0.6.0=pypi_0
|
| 9 |
+
anyio=3.7.1=pypi_0
|
| 10 |
+
asgiref=3.7.2=pypi_0
|
| 11 |
+
asyncer=0.0.2=pypi_0
|
| 12 |
+
attrs=23.2.0=pypi_0
|
| 13 |
+
backoff=2.2.1=pypi_0
|
| 14 |
+
bcrypt=4.1.2=pypi_0
|
| 15 |
+
beautifulsoup4=4.12.2=pypi_0
|
| 16 |
+
bidict=0.22.1=pypi_0
|
| 17 |
+
bs4=0.0.1=pypi_0
|
| 18 |
+
build=1.0.3=pypi_0
|
| 19 |
+
bzip2=1.0.8=he774522_0
|
| 20 |
+
ca-certificates=2023.12.12=haa95532_0
|
| 21 |
+
cachetools=5.3.2=pypi_0
|
| 22 |
+
certifi=2023.11.17=pypi_0
|
| 23 |
+
cffi=1.16.0=pypi_0
|
| 24 |
+
charset-normalizer=3.3.2=pypi_0
|
| 25 |
+
chroma-hnswlib=0.7.3=pypi_0
|
| 26 |
+
chromadb=0.4.22=pypi_0
|
| 27 |
+
click=8.1.7=pypi_0
|
| 28 |
+
colorama=0.4.6=pypi_0
|
| 29 |
+
coloredlogs=15.0.1=pypi_0
|
| 30 |
+
contourpy=1.2.0=pypi_0
|
| 31 |
+
curl-cffi=0.5.10=pypi_0
|
| 32 |
+
cycler=0.12.1=pypi_0
|
| 33 |
+
dataclasses-json=0.5.14=pypi_0
|
| 34 |
+
deprecated=1.2.14=pypi_0
|
| 35 |
+
duckduckgo-search=4.1.1=pypi_0
|
| 36 |
+
fastapi=0.100.1=pypi_0
|
| 37 |
+
fastapi-socketio=0.0.10=pypi_0
|
| 38 |
+
ffmpy=0.3.1=pypi_0
|
| 39 |
+
filelock=3.13.1=pypi_0
|
| 40 |
+
filetype=1.2.0=pypi_0
|
| 41 |
+
flatbuffers=23.5.26=pypi_0
|
| 42 |
+
fonttools=4.47.0=pypi_0
|
| 43 |
+
frozenlist=1.4.1=pypi_0
|
| 44 |
+
fsspec=2023.12.2=pypi_0
|
| 45 |
+
google-auth=2.26.1=pypi_0
|
| 46 |
+
googleapis-common-protos=1.62.0=pypi_0
|
| 47 |
+
gradio=4.13.0=pypi_0
|
| 48 |
+
gradio-client=0.8.0=pypi_0
|
| 49 |
+
greenlet=3.0.3=pypi_0
|
| 50 |
+
grpcio=1.60.0=pypi_0
|
| 51 |
+
h11=0.14.0=pypi_0
|
| 52 |
+
httpcore=0.17.3=pypi_0
|
| 53 |
+
httptools=0.6.1=pypi_0
|
| 54 |
+
httpx=0.24.1=pypi_0
|
| 55 |
+
huggingface-hub=0.20.2=pypi_0
|
| 56 |
+
humanfriendly=10.0=pypi_0
|
| 57 |
+
idna=3.6=pypi_0
|
| 58 |
+
importlib-metadata=6.11.0=pypi_0
|
| 59 |
+
importlib-resources=6.1.1=pypi_0
|
| 60 |
+
jinja2=3.1.2=pypi_0
|
| 61 |
+
jsonpatch=1.33=pypi_0
|
| 62 |
+
jsonpointer=2.4=pypi_0
|
| 63 |
+
jsonschema=4.20.0=pypi_0
|
| 64 |
+
jsonschema-specifications=2023.12.1=pypi_0
|
| 65 |
+
kiwisolver=1.4.5=pypi_0
|
| 66 |
+
kubernetes=28.1.0=pypi_0
|
| 67 |
+
langchain=0.0.354=pypi_0
|
| 68 |
+
langchain-community=0.0.8=pypi_0
|
| 69 |
+
langchain-core=0.1.6=pypi_0
|
| 70 |
+
langsmith=0.0.77=pypi_0
|
| 71 |
+
lazify=0.4.0=pypi_0
|
| 72 |
+
libffi=3.4.4=hd77b12b_0
|
| 73 |
+
lxml=5.0.0=pypi_0
|
| 74 |
+
markdown-it-py=3.0.0=pypi_0
|
| 75 |
+
markupsafe=2.1.3=pypi_0
|
| 76 |
+
marshmallow=3.20.1=pypi_0
|
| 77 |
+
matplotlib=3.8.2=pypi_0
|
| 78 |
+
mdurl=0.1.2=pypi_0
|
| 79 |
+
mmh3=4.0.1=pypi_0
|
| 80 |
+
monotonic=1.6=pypi_0
|
| 81 |
+
mpmath=1.3.0=pypi_0
|
| 82 |
+
multidict=6.0.4=pypi_0
|
| 83 |
+
mypy-extensions=1.0.0=pypi_0
|
| 84 |
+
nest-asyncio=1.5.8=pypi_0
|
| 85 |
+
numpy=1.26.3=pypi_0
|
| 86 |
+
oauthlib=3.2.2=pypi_0
|
| 87 |
+
onnxruntime=1.16.3=pypi_0
|
| 88 |
+
openai=0.28.0=pypi_0
|
| 89 |
+
openssl=3.0.12=h2bbff1b_0
|
| 90 |
+
opentelemetry-api=1.22.0=pypi_0
|
| 91 |
+
opentelemetry-exporter-otlp=1.22.0=pypi_0
|
| 92 |
+
opentelemetry-exporter-otlp-proto-common=1.22.0=pypi_0
|
| 93 |
+
opentelemetry-exporter-otlp-proto-grpc=1.22.0=pypi_0
|
| 94 |
+
opentelemetry-exporter-otlp-proto-http=1.22.0=pypi_0
|
| 95 |
+
opentelemetry-instrumentation=0.43b0=pypi_0
|
| 96 |
+
opentelemetry-instrumentation-asgi=0.43b0=pypi_0
|
| 97 |
+
opentelemetry-instrumentation-fastapi=0.43b0=pypi_0
|
| 98 |
+
opentelemetry-proto=1.22.0=pypi_0
|
| 99 |
+
opentelemetry-sdk=1.22.0=pypi_0
|
| 100 |
+
opentelemetry-semantic-conventions=0.43b0=pypi_0
|
| 101 |
+
opentelemetry-util-http=0.43b0=pypi_0
|
| 102 |
+
orjson=3.9.10=pypi_0
|
| 103 |
+
overrides=7.4.0=pypi_0
|
| 104 |
+
packaging=23.2=pypi_0
|
| 105 |
+
pandas=2.1.4=pypi_0
|
| 106 |
+
pillow=10.2.0=pypi_0
|
| 107 |
+
pip=23.3.1=py311haa95532_0
|
| 108 |
+
posthog=3.1.0=pypi_0
|
| 109 |
+
protobuf=4.25.1=pypi_0
|
| 110 |
+
pulsar-client=3.4.0=pypi_0
|
| 111 |
+
pyasn1=0.5.1=pypi_0
|
| 112 |
+
pyasn1-modules=0.3.0=pypi_0
|
| 113 |
+
pycparser=2.21=pypi_0
|
| 114 |
+
pydantic=2.5.1=pypi_0
|
| 115 |
+
pydantic-core=2.14.3=pypi_0
|
| 116 |
+
pydub=0.25.1=pypi_0
|
| 117 |
+
pygments=2.17.2=pypi_0
|
| 118 |
+
pyjwt=2.8.0=pypi_0
|
| 119 |
+
pyparsing=3.1.1=pypi_0
|
| 120 |
+
pypdf=3.17.4=pypi_0
|
| 121 |
+
pypika=0.48.9=pypi_0
|
| 122 |
+
pyproject-hooks=1.0.0=pypi_0
|
| 123 |
+
pyprojroot=0.3.0=pypi_0
|
| 124 |
+
pyreadline3=3.4.1=pypi_0
|
| 125 |
+
python=3.11.5=he1021f5_0
|
| 126 |
+
python-dateutil=2.8.2=pypi_0
|
| 127 |
+
python-dotenv=1.0.0=pypi_0
|
| 128 |
+
python-engineio=4.8.1=pypi_0
|
| 129 |
+
python-graphql-client=0.4.3=pypi_0
|
| 130 |
+
python-multipart=0.0.6=pypi_0
|
| 131 |
+
python-socketio=5.10.0=pypi_0
|
| 132 |
+
pytz=2023.3.post1=pypi_0
|
| 133 |
+
pyyaml=6.0.1=pypi_0
|
| 134 |
+
referencing=0.32.0=pypi_0
|
| 135 |
+
regex=2023.12.25=pypi_0
|
| 136 |
+
requests=2.31.0=pypi_0
|
| 137 |
+
requests-oauthlib=1.3.1=pypi_0
|
| 138 |
+
rich=13.7.0=pypi_0
|
| 139 |
+
rpds-py=0.16.2=pypi_0
|
| 140 |
+
rsa=4.9=pypi_0
|
| 141 |
+
semantic-version=2.10.0=pypi_0
|
| 142 |
+
setuptools=68.2.2=py311haa95532_0
|
| 143 |
+
shellingham=1.5.4=pypi_0
|
| 144 |
+
simple-websocket=1.0.0=pypi_0
|
| 145 |
+
six=1.16.0=pypi_0
|
| 146 |
+
sniffio=1.3.0=pypi_0
|
| 147 |
+
soupsieve=2.5=pypi_0
|
| 148 |
+
sqlalchemy=2.0.25=pypi_0
|
| 149 |
+
sqlite=3.41.2=h2bbff1b_0
|
| 150 |
+
starlette=0.27.0=pypi_0
|
| 151 |
+
sympy=1.12=pypi_0
|
| 152 |
+
syncer=2.0.3=pypi_0
|
| 153 |
+
tenacity=8.2.3=pypi_0
|
| 154 |
+
tiktoken=0.5.2=pypi_0
|
| 155 |
+
tk=8.6.12=h2bbff1b_0
|
| 156 |
+
tokenizers=0.15.0=pypi_0
|
| 157 |
+
tomli=2.0.1=pypi_0
|
| 158 |
+
tomlkit=0.12.0=pypi_0
|
| 159 |
+
toolz=0.12.0=pypi_0
|
| 160 |
+
tqdm=4.66.1=pypi_0
|
| 161 |
+
typer=0.9.0=pypi_0
|
| 162 |
+
typing-extensions=4.9.0=pypi_0
|
| 163 |
+
typing-inspect=0.9.0=pypi_0
|
| 164 |
+
tzdata=2023.4=pypi_0
|
| 165 |
+
uptrace=1.22.0=pypi_0
|
| 166 |
+
urllib3=1.26.18=pypi_0
|
| 167 |
+
uvicorn=0.23.2=pypi_0
|
| 168 |
+
vc=14.2=h21ff451_1
|
| 169 |
+
vs2015_runtime=14.27.29016=h5e58377_2
|
| 170 |
+
watchfiles=0.20.0=pypi_0
|
| 171 |
+
websocket-client=1.7.0=pypi_0
|
| 172 |
+
websockets=11.0.3=pypi_0
|
| 173 |
+
wheel=0.41.2=py311haa95532_0
|
| 174 |
+
wrapt=1.16.0=pypi_0
|
| 175 |
+
wsproto=1.2.0=pypi_0
|
| 176 |
+
xz=5.4.5=h8cc25b3_0
|
| 177 |
+
yarl=1.9.4=pypi_0
|
| 178 |
+
zipp=3.17.0=pypi_0
|
| 179 |
+
zlib=1.2.13=h8cc25b3_0
|
configs/app_config.yml
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
directories:
|
| 2 |
+
data_directory: data/docs
|
| 3 |
+
data_directory_2: data/docs_2
|
| 4 |
+
persist_directory: data/vectordb/processed/chroma/
|
| 5 |
+
custom_persist_directory: data/vectordb/uploaded/chroma/
|
| 6 |
+
|
| 7 |
+
embedding_model_config:
|
| 8 |
+
engine: "text-embedding-ada-002"
|
| 9 |
+
|
| 10 |
+
llm_config:
|
| 11 |
+
llm_system_role: "You are a chatbot. You'll receive a prompt that includes a chat history, retrieved content from the vectorDB based on the user's question, and the source.\
|
| 12 |
+
Your task is to respond to the user's new question using the information from the vectorDB without relying on your own knowledge.\
|
| 13 |
+
you will receive a prompt with the the following format:
|
| 14 |
+
|
| 15 |
+
# Chat history:\n
|
| 16 |
+
[user query, response]\n\n
|
| 17 |
+
|
| 18 |
+
# Retrieved content number:\n
|
| 19 |
+
Content\n\n
|
| 20 |
+
Source\n\n
|
| 21 |
+
|
| 22 |
+
# User question:\n
|
| 23 |
+
New question
|
| 24 |
+
"
|
| 25 |
+
engine: "gpt-3.5-turbo"
|
| 26 |
+
temperature: 0.0
|
| 27 |
+
max_token: 4096
|
| 28 |
+
|
| 29 |
+
summarizer_config:
|
| 30 |
+
max_final_token: 3000
|
| 31 |
+
character_overlap: 100
|
| 32 |
+
token_threshold: 0
|
| 33 |
+
summarizer_llm_system_role: "You are an expert text summarizer. You will receive a text and your task is to summarize and keep all the key information.\
|
| 34 |
+
Kepp the maximum length of summary within {} number of tokens."
|
| 35 |
+
final_summarizer_llm_system_role: "You are an expert text summarizer. You will receive a text and your task is to give a comprehensive summary and keep all the key information."
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
splitter_config:
|
| 39 |
+
chunk_size: 1500
|
| 40 |
+
chunk_overlap: 500
|
| 41 |
+
|
| 42 |
+
retrieval_config:
|
| 43 |
+
k: 3
|
| 44 |
+
|
| 45 |
+
serve:
|
| 46 |
+
port: 8000
|
| 47 |
+
|
| 48 |
+
memory:
|
| 49 |
+
number_of_q_a_pairs: 2
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
|
data/docs/FIRST AID IN COMMON EMERGENCY CONDITIONS.pdf
ADDED
|
Binary file (348 kB). View file
|
|
|
data/docs_2/FIRST AID IN COMMON EMERGENCY CONDITIONS.pdf
ADDED
|
Binary file (348 kB). View file
|
|
|
data/vectordb/processed/chroma/8008bb97-d12e-40c0-870f-b02d5699f748/data_level0.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:f18abd8c514282db82706e52b0a33ed659cd534e925a6f149deb7af9ce34bd8e
|
| 3 |
+
size 6284000
|
data/vectordb/processed/chroma/8008bb97-d12e-40c0-870f-b02d5699f748/header.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:effaa959ce2b30070fdafc2fe82096fc46e4ee7561b75920dd3ce43d09679b21
|
| 3 |
+
size 100
|
data/vectordb/processed/chroma/8008bb97-d12e-40c0-870f-b02d5699f748/length.bin
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:72b7b120a031fe290fdb383f7bfe6e676c0ff5de0191a136a9ff5548b85c4f8f
|
| 3 |
+
size 4000
|
data/vectordb/processed/chroma/8008bb97-d12e-40c0-870f-b02d5699f748/link_lists.bin
ADDED
|
File without changes
|
data/vectordb/processed/chroma/chroma.sqlite3
ADDED
|
Binary file (598 kB). View file
|
|
|
images/AI_RT.png
ADDED
|
images/RAGGPT UI.png
ADDED
|
images/RAGGPT_schema.png
ADDED
|
images/openai_.png
ADDED
|
requirements.txt
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
gradio
|
| 2 |
+
huggingface_hub
|
| 3 |
+
openai
|
| 4 |
+
langchain
|
| 5 |
+
langchain_community
|
| 6 |
+
langchain_chroma
|
| 7 |
+
langchain_openai
|
| 8 |
+
chromadb
|
| 9 |
+
tiktoken
|
| 10 |
+
pydantic
|
| 11 |
+
numpy
|
| 12 |
+
|
src/.gradio/certificate.pem
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
-----BEGIN CERTIFICATE-----
|
| 2 |
+
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
|
| 3 |
+
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
|
| 4 |
+
cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
|
| 5 |
+
WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
|
| 6 |
+
ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
|
| 7 |
+
MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
|
| 8 |
+
h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
|
| 9 |
+
0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
|
| 10 |
+
A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
|
| 11 |
+
T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
|
| 12 |
+
B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
|
| 13 |
+
B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
|
| 14 |
+
KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
|
| 15 |
+
OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
|
| 16 |
+
jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
|
| 17 |
+
qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
|
| 18 |
+
rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
|
| 19 |
+
HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
|
| 20 |
+
hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
|
| 21 |
+
ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
|
| 22 |
+
3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
|
| 23 |
+
NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
|
| 24 |
+
ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
|
| 25 |
+
TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
|
| 26 |
+
jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
|
| 27 |
+
oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
|
| 28 |
+
4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
|
| 29 |
+
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
|
| 30 |
+
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
|
| 31 |
+
-----END CERTIFICATE-----
|
src/README.md
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: First_Aid_Tutor
|
| 3 |
+
app_file: raggpt_app.py
|
| 4 |
+
sdk: gradio
|
| 5 |
+
sdk_version: 5.12.0
|
| 6 |
+
---
|
src/configs/app_config.yml
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
directories:
|
| 2 |
+
data_directory: data/docs
|
| 3 |
+
data_directory_2: data/docs_2
|
| 4 |
+
persist_directory: data/vectordb/processed/chroma/
|
| 5 |
+
custom_persist_directory: data/vectordb/uploaded/chroma/
|
| 6 |
+
|
| 7 |
+
embedding_model_config:
|
| 8 |
+
engine: "text-embedding-ada-002"
|
| 9 |
+
|
| 10 |
+
llm_config:
|
| 11 |
+
llm_system_role: "You are a chatbot. You'll receive a prompt that includes a chat history, retrieved content from the vectorDB based on the user's question, and the source.\
|
| 12 |
+
Your task is to respond to the user's new question using the information from the vectorDB without relying on your own knowledge.\
|
| 13 |
+
you will receive a prompt with the the following format:
|
| 14 |
+
|
| 15 |
+
# Chat history:\n
|
| 16 |
+
[user query, response]\n\n
|
| 17 |
+
|
| 18 |
+
# Retrieved content number:\n
|
| 19 |
+
Content\n\n
|
| 20 |
+
Source\n\n
|
| 21 |
+
|
| 22 |
+
# User question:\n
|
| 23 |
+
New question
|
| 24 |
+
"
|
| 25 |
+
engine: "gpt-35-turbo"
|
| 26 |
+
temperature: 0.0
|
| 27 |
+
max_token: 4096
|
| 28 |
+
|
| 29 |
+
summarizer_config:
|
| 30 |
+
max_final_token: 3000
|
| 31 |
+
character_overlap: 100
|
| 32 |
+
token_threshold: 0
|
| 33 |
+
summarizer_llm_system_role: "You are an expert text summarizer. You will receive a text and your task is to summarize and keep all the key information.\
|
| 34 |
+
Kepp the maximum length of summary within {} number of tokens."
|
| 35 |
+
final_summarizer_llm_system_role: "You are an expert text summarizer. You will receive a text and your task is to give a comprehensive summary and keep all the key information."
|
| 36 |
+
|
| 37 |
+
|
| 38 |
+
splitter_config:
|
| 39 |
+
chunk_size: 1500
|
| 40 |
+
chunk_overlap: 500
|
| 41 |
+
|
| 42 |
+
retrieval_config:
|
| 43 |
+
k: 3
|
| 44 |
+
|
| 45 |
+
serve:
|
| 46 |
+
port: 8000
|
| 47 |
+
|
| 48 |
+
memory:
|
| 49 |
+
number_of_q_a_pairs: 2
|
| 50 |
+
|
| 51 |
+
|
| 52 |
+
|
src/raggpt.py
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
from utils.chatbot import ChatBot
|
| 3 |
+
|
| 4 |
+
|
| 5 |
+
# Define CSS styles for a clean and modern UI
|
| 6 |
+
custom_css = """
|
| 7 |
+
body {
|
| 8 |
+
background: linear-gradient(to right, #004aad, #00a2ff);
|
| 9 |
+
color: white;
|
| 10 |
+
font-family: 'Poppins', sans-serif;
|
| 11 |
+
}
|
| 12 |
+
|
| 13 |
+
h1 {
|
| 14 |
+
text-align: center;
|
| 15 |
+
font-size: 36px;
|
| 16 |
+
font-weight: bold;
|
| 17 |
+
color: white;
|
| 18 |
+
text-shadow: 2px 2px 10px rgba(255, 255, 255, 0.5);
|
| 19 |
+
margin-bottom: 20px;
|
| 20 |
+
}
|
| 21 |
+
|
| 22 |
+
#chatbot {
|
| 23 |
+
background: #dfe9ff;
|
| 24 |
+
border-radius: 15px;
|
| 25 |
+
padding: 15px;
|
| 26 |
+
color: #003366;
|
| 27 |
+
font-size: 16px;
|
| 28 |
+
min-height: 500px;
|
| 29 |
+
border: 2px solid #003366;
|
| 30 |
+
box-shadow: 0 0 10px rgba(0, 162, 255, 0.6);
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
input {
|
| 34 |
+
border-radius: 8px;
|
| 35 |
+
padding: 10px;
|
| 36 |
+
font-size: 16px;
|
| 37 |
+
border: 2px solid #007bff;
|
| 38 |
+
background-color: #eef6ff;
|
| 39 |
+
color: #003366;
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
button {
|
| 43 |
+
background-color: #003366;
|
| 44 |
+
color: white;
|
| 45 |
+
border-radius: 8px;
|
| 46 |
+
padding: 12px 18px;
|
| 47 |
+
border: none;
|
| 48 |
+
cursor: pointer;
|
| 49 |
+
font-weight: bold;
|
| 50 |
+
transition: 0.3s ease-in-out;
|
| 51 |
+
box-shadow: 0px 4px 8px rgba(255, 255, 255, 0.2);
|
| 52 |
+
}
|
| 53 |
+
|
| 54 |
+
button:hover {
|
| 55 |
+
background-color: #00a2ff;
|
| 56 |
+
box-shadow: 0px 4px 12px rgba(255, 255, 255, 0.4);
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
.gradio-container {
|
| 60 |
+
max-width: 900px;
|
| 61 |
+
margin: auto;
|
| 62 |
+
padding: 20px;
|
| 63 |
+
text-align: center;
|
| 64 |
+
}
|
| 65 |
+
"""
|
| 66 |
+
|
| 67 |
+
# Define the chatbot UI with only input and response
|
| 68 |
+
with gr.Blocks(css=custom_css) as demo:
|
| 69 |
+
gr.Markdown("<h1>🚑 First Aid Tutor</h1>")
|
| 70 |
+
|
| 71 |
+
chatbot = gr.Chatbot([], elem_id="chatbot", bubble_full_width=False, height=500, type="messages")
|
| 72 |
+
|
| 73 |
+
user_input = gr.Textbox(
|
| 74 |
+
label="💬 Ask a First Aid Question:",
|
| 75 |
+
placeholder="Type your question here...",
|
| 76 |
+
)
|
| 77 |
+
|
| 78 |
+
submit_button = gr.Button("🚀 Get First Aid Advice")
|
| 79 |
+
|
| 80 |
+
submit_button.click(
|
| 81 |
+
fn=ChatBot.respond,
|
| 82 |
+
inputs=[chatbot, user_input], # Only chatbot & input
|
| 83 |
+
outputs=[user_input, chatbot],
|
| 84 |
+
)
|
| 85 |
+
|
| 86 |
+
if __name__ == "__main__":
|
| 87 |
+
demo.launch(share=True)
|
src/serve.py
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import http.server
|
| 2 |
+
import socketserver
|
| 3 |
+
import yaml
|
| 4 |
+
import os
|
| 5 |
+
from pyprojroot import here
|
| 6 |
+
|
| 7 |
+
with open(here("configs/app_config.yml")) as cfg:
|
| 8 |
+
app_config = yaml.load(cfg, Loader=yaml.FullLoader)
|
| 9 |
+
|
| 10 |
+
PORT = app_config["serve"]["port"]
|
| 11 |
+
DIRECTORY1 = app_config["directories"]["data_directory"]
|
| 12 |
+
DIRECTORY2 = app_config["directories"]["data_directory_2"]
|
| 13 |
+
|
| 14 |
+
|
| 15 |
+
class SingleDirectoryHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
|
| 16 |
+
"""
|
| 17 |
+
Custom HTTP request handler that serves files from a single directory.
|
| 18 |
+
|
| 19 |
+
This class extends the SimpleHTTPRequestHandler and sets the serving directory to DIRECTORY1.
|
| 20 |
+
"""
|
| 21 |
+
|
| 22 |
+
def __init__(self, *args, **kwargs):
|
| 23 |
+
"""
|
| 24 |
+
Initialize the SingleDirectoryHTTPRequestHandler.
|
| 25 |
+
|
| 26 |
+
Parameters:
|
| 27 |
+
args: Additional positional arguments for the base class.
|
| 28 |
+
kwargs: Additional keyword arguments for the base class.
|
| 29 |
+
"""
|
| 30 |
+
super().__init__(*args, directory=DIRECTORY1, **kwargs)
|
| 31 |
+
|
| 32 |
+
|
| 33 |
+
class MultiDirectoryHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
|
| 34 |
+
"""
|
| 35 |
+
Custom HTTP request handler that serves files from multiple directories.
|
| 36 |
+
|
| 37 |
+
This class extends the SimpleHTTPRequestHandler and allows serving files from DIRECTORY1 and DIRECTORY2
|
| 38 |
+
based on the first directory component in the requested path.
|
| 39 |
+
"""
|
| 40 |
+
|
| 41 |
+
def translate_path(self, path):
|
| 42 |
+
"""
|
| 43 |
+
Translate the requested path to the actual file path.
|
| 44 |
+
|
| 45 |
+
Parameters:
|
| 46 |
+
path (str): The requested path.
|
| 47 |
+
|
| 48 |
+
Returns:
|
| 49 |
+
str: The translated file path.
|
| 50 |
+
"""
|
| 51 |
+
# Split the path to get the first directory component
|
| 52 |
+
parts = path.split('/', 2)
|
| 53 |
+
if len(parts) > 1:
|
| 54 |
+
first_directory = parts[1]
|
| 55 |
+
# Check if the first directory matches any of your target directories
|
| 56 |
+
if first_directory == os.path.basename(DIRECTORY1):
|
| 57 |
+
path = os.path.join(DIRECTORY1, *parts[2:])
|
| 58 |
+
|
| 59 |
+
elif first_directory == os.path.basename(DIRECTORY2):
|
| 60 |
+
path = os.path.join(DIRECTORY2, *parts[2:])
|
| 61 |
+
else:
|
| 62 |
+
# If the first part of the path is not a directory, check both directories for the file
|
| 63 |
+
file_path1 = os.path.join(DIRECTORY1, first_directory)
|
| 64 |
+
file_path2 = os.path.join(DIRECTORY2, first_directory)
|
| 65 |
+
if os.path.isfile(file_path1):
|
| 66 |
+
return file_path1
|
| 67 |
+
elif os.path.isfile(file_path2):
|
| 68 |
+
return file_path2
|
| 69 |
+
# If there's no match, use the default directory
|
| 70 |
+
return super().translate_path(path)
|
| 71 |
+
|
| 72 |
+
|
| 73 |
+
if __name__ == "__main__":
|
| 74 |
+
with socketserver.TCPServer(("", PORT), MultiDirectoryHTTPRequestHandler) as httpd:
|
| 75 |
+
print(f"Serving at port {PORT}")
|
| 76 |
+
httpd.serve_forever()
|
src/terminal_q_and_a.py
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
This module is not part of the main RAG-GPT pipeline and it is only for showing how we can perform RAG using openai and vectordb in the terminal.
|
| 3 |
+
|
| 4 |
+
To execute the code, after preparing the python environment and the vector database, in the terminal execute:
|
| 5 |
+
|
| 6 |
+
python src\terminal_q_and_a.py
|
| 7 |
+
"""
|
| 8 |
+
|
| 9 |
+
import openai
|
| 10 |
+
import yaml
|
| 11 |
+
from langchain_community.embeddings import OpenAIEmbeddings
|
| 12 |
+
from langchain_community.vectorstores import Chroma
|
| 13 |
+
import os
|
| 14 |
+
from typing import List, Tuple
|
| 15 |
+
from utils.load_config import LoadConfig
|
| 16 |
+
|
| 17 |
+
# For loading openai credentials
|
| 18 |
+
APPCFG = LoadConfig()
|
| 19 |
+
|
| 20 |
+
client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY"))
|
| 21 |
+
|
| 22 |
+
with open("configs/app_config.yml") as cfg:
|
| 23 |
+
app_config = yaml.load(cfg, Loader=yaml.FullLoader)
|
| 24 |
+
|
| 25 |
+
# Load the embedding function
|
| 26 |
+
embedding = OpenAIEmbeddings()
|
| 27 |
+
# Load the vector database
|
| 28 |
+
vectordb = Chroma(persist_directory=APPCFG.persist_directory,
|
| 29 |
+
embedding_function=embedding)
|
| 30 |
+
|
| 31 |
+
print("Number of vectors in vectordb:", vectordb._collection.count())
|
| 32 |
+
|
| 33 |
+
# Prepare the RAG with openai in terminal
|
| 34 |
+
while True:
|
| 35 |
+
question = input("\n\nEnter your question or press 'q' to exit: ")
|
| 36 |
+
if question.lower() =='q':
|
| 37 |
+
break
|
| 38 |
+
question = "# user new question:\n" + question
|
| 39 |
+
docs = vectordb.similarity_search(question, k=APPCFG.k)
|
| 40 |
+
retrieved_docs_page_content: List[Tuple] = [
|
| 41 |
+
str(x.page_content)+"\n\n" for x in docs]
|
| 42 |
+
retrieved_docs_str = "# Retrieved content:\n\n" + str(retrieved_docs_page_content)
|
| 43 |
+
prompt = retrieved_docs_str + "\n\n" + question
|
| 44 |
+
response = client.chat.completions.create(
|
| 45 |
+
model="gpt-3.5-turbo",
|
| 46 |
+
messages=[{"role": "user", "content": prompt}]
|
| 47 |
+
)
|
| 48 |
+
print(response.choices[0].message.content)
|
src/upload_data_manually.py
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import os
|
| 2 |
+
from utils.prepare_vectordb import PrepareVectorDB
|
| 3 |
+
from utils.load_config import LoadConfig
|
| 4 |
+
|
| 5 |
+
CONFIG = LoadConfig()
|
| 6 |
+
|
| 7 |
+
def upload_data_manually() -> None:
|
| 8 |
+
"""
|
| 9 |
+
Uploads data manually to the VectorDB.
|
| 10 |
+
|
| 11 |
+
This function initializes a PrepareVectorDB instance with configuration parameters
|
| 12 |
+
such as data_directory, persist_directory, embedding_model_engine, chunk_size,
|
| 13 |
+
and chunk_overlap. It then checks if the VectorDB already exists in the specified
|
| 14 |
+
persist_directory. If not, it calls the prepare_and_save_vectordb method to
|
| 15 |
+
create and save the VectorDB. If the VectorDB already exists, a message is printed
|
| 16 |
+
indicating its presence.
|
| 17 |
+
|
| 18 |
+
Returns:
|
| 19 |
+
None
|
| 20 |
+
"""
|
| 21 |
+
prepare_vectordb_instance = PrepareVectorDB(
|
| 22 |
+
data_directory=CONFIG.data_directory,
|
| 23 |
+
persist_directory=CONFIG.persist_directory,
|
| 24 |
+
embedding_model_engine=CONFIG.embedding_model_engine,
|
| 25 |
+
chunk_size=CONFIG.chunk_size,
|
| 26 |
+
chunk_overlap=CONFIG.chunk_overlap,
|
| 27 |
+
)
|
| 28 |
+
|
| 29 |
+
# ✅ Corrected condition to check if directory is empty
|
| 30 |
+
if not os.path.exists(CONFIG.persist_directory) or not os.listdir(CONFIG.persist_directory):
|
| 31 |
+
print("🔄 Creating new ChromaDB Vector Database...")
|
| 32 |
+
prepare_vectordb_instance.prepare_and_save_vectordb()
|
| 33 |
+
print("✅ VectorDB successfully created and saved!")
|
| 34 |
+
else:
|
| 35 |
+
print(f"⚠️ VectorDB already exists in {CONFIG.persist_directory}, skipping creation.")
|
| 36 |
+
|
| 37 |
+
return None
|
| 38 |
+
|
| 39 |
+
|
| 40 |
+
if __name__ == "__main__":
|
| 41 |
+
upload_data_manually()
|
src/utils/.env
ADDED
|
@@ -0,0 +1 @@
|
|
|
|
|
|
|
| 1 |
+
OPENAI_API_KEY=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
|
src/utils/__pycache__/chatbot.cpython-312.pyc
ADDED
|
Binary file (3.73 kB). View file
|
|
|
src/utils/__pycache__/load_config.cpython-312.pyc
ADDED
|
Binary file (7.49 kB). View file
|
|
|
src/utils/__pycache__/prepare_vectordb.cpython-312.pyc
ADDED
|
Binary file (4.49 kB). View file
|
|
|
src/utils/__pycache__/summarizer.cpython-312.pyc
ADDED
|
Binary file (4.99 kB). View file
|
|
|
src/utils/__pycache__/ui_settings.cpython-312.pyc
ADDED
|
Binary file (1.69 kB). View file
|
|
|
src/utils/__pycache__/upload_file.cpython-312.pyc
ADDED
|
Binary file (2.97 kB). View file
|
|
|
src/utils/__pycache__/utilities.cpython-312.pyc
ADDED
|
Binary file (868 Bytes). View file
|
|
|
src/utils/chatbot.py
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
import os
|
| 3 |
+
import openai
|
| 4 |
+
import re
|
| 5 |
+
import html
|
| 6 |
+
from typing import List, Tuple
|
| 7 |
+
from langchain_chroma import Chroma # ✅ Updated import
|
| 8 |
+
from utils.load_config import LoadConfig
|
| 9 |
+
|
| 10 |
+
# Load configuration
|
| 11 |
+
APPCFG = LoadConfig()
|
| 12 |
+
|
| 13 |
+
# OpenAI Client
|
| 14 |
+
client = openai.OpenAI()
|
| 15 |
+
|
| 16 |
+
class ChatBot:
|
| 17 |
+
"""
|
| 18 |
+
Chatbot class that only retrieves answers from a pre-uploaded document stored in ChromaDB.
|
| 19 |
+
"""
|
| 20 |
+
|
| 21 |
+
@staticmethod
|
| 22 |
+
def respond(chatbot: List, message: str) -> Tuple:
|
| 23 |
+
"""
|
| 24 |
+
Retrieve an answer strictly from the pre-uploaded document.
|
| 25 |
+
If no relevant information is found, return a "no answer found" message.
|
| 26 |
+
"""
|
| 27 |
+
# Ensure the pre-processed document database exists
|
| 28 |
+
if not os.path.exists(APPCFG.persist_directory):
|
| 29 |
+
chatbot.append({"role": "assistant", "content": "⚠️ No document database found. Please ensure the First Aid PDF is preloaded."})
|
| 30 |
+
return "", chatbot
|
| 31 |
+
|
| 32 |
+
# Load ChromaDB with stored document embeddings
|
| 33 |
+
vectordb = Chroma(persist_directory=APPCFG.persist_directory, embedding_function=APPCFG.embedding_model)
|
| 34 |
+
docs = vectordb.similarity_search(message, k=APPCFG.k)
|
| 35 |
+
|
| 36 |
+
if not docs:
|
| 37 |
+
chatbot.append({"role": "assistant", "content": "⚠️ No relevant answer found in the document."})
|
| 38 |
+
return "", chatbot
|
| 39 |
+
|
| 40 |
+
# Extract retrieved content
|
| 41 |
+
retrieved_content = ChatBot.clean_references(docs)
|
| 42 |
+
chat_history = f"Chat history:\n {str(chatbot[-APPCFG.number_of_q_a_pairs:])}\n\n"
|
| 43 |
+
prompt = f"{chat_history}{retrieved_content}# User question:\n{message}"
|
| 44 |
+
|
| 45 |
+
# Generate response using OpenAI GPT
|
| 46 |
+
response = client.chat.completions.create(
|
| 47 |
+
model=APPCFG.llm_engine,
|
| 48 |
+
messages=[
|
| 49 |
+
{"role": "system", "content": "Answer only using the First Aid document. If unsure, say 'I don't know'."},
|
| 50 |
+
{"role": "user", "content": prompt}
|
| 51 |
+
]
|
| 52 |
+
)
|
| 53 |
+
|
| 54 |
+
chatbot.append({"role": "user", "content": message}) # ✅ User input
|
| 55 |
+
chatbot.append({"role": "assistant", "content": response.choices[0].message.content}) # ✅ AI response
|
| 56 |
+
|
| 57 |
+
return "", chatbot
|
| 58 |
+
|
| 59 |
+
@staticmethod
|
| 60 |
+
def clean_references(documents: List) -> str:
|
| 61 |
+
"""
|
| 62 |
+
Extract and format relevant content from retrieved documents.
|
| 63 |
+
"""
|
| 64 |
+
cleaned_content = []
|
| 65 |
+
for doc in documents:
|
| 66 |
+
# ✅ Ensure correct extraction of content and metadata
|
| 67 |
+
content = doc.page_content
|
| 68 |
+
metadata = doc.metadata
|
| 69 |
+
|
| 70 |
+
# ✅ Handle missing metadata safely
|
| 71 |
+
source = metadata.get('source', 'Unknown source')
|
| 72 |
+
page_number = metadata.get('page', 'Unknown page')
|
| 73 |
+
|
| 74 |
+
cleaned_content.append(
|
| 75 |
+
f"📄 Page {page_number}: {content}\n📌 Source: {source}\n"
|
| 76 |
+
)
|
| 77 |
+
|
| 78 |
+
return "\n".join(cleaned_content)
|
src/utils/load_config.py
ADDED
|
@@ -0,0 +1,153 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
import openai
|
| 3 |
+
import os
|
| 4 |
+
from dotenv import load_dotenv
|
| 5 |
+
import yaml
|
| 6 |
+
from langchain_openai import OpenAIEmbeddings
|
| 7 |
+
from pyprojroot import here
|
| 8 |
+
import shutil
|
| 9 |
+
|
| 10 |
+
load_dotenv()
|
| 11 |
+
|
| 12 |
+
|
| 13 |
+
class LoadConfig:
|
| 14 |
+
"""
|
| 15 |
+
A class for loading configuration settings and managing directories.
|
| 16 |
+
|
| 17 |
+
This class loads various configuration settings from the 'app_config.yml' file,
|
| 18 |
+
including language model (LLM) configurations, retrieval configurations, summarizer
|
| 19 |
+
configurations, and memory configurations. It also sets up OpenAI API credentials
|
| 20 |
+
and performs directory-related operations such as creating and removing directories.
|
| 21 |
+
|
| 22 |
+
...
|
| 23 |
+
|
| 24 |
+
Attributes:
|
| 25 |
+
llm_engine : str
|
| 26 |
+
The language model engine specified in the configuration.
|
| 27 |
+
llm_system_role : str
|
| 28 |
+
The role of the language model system specified in the configuration.
|
| 29 |
+
persist_directory : str
|
| 30 |
+
The path to the persist directory where data is stored.
|
| 31 |
+
custom_persist_directory : str
|
| 32 |
+
The path to the custom persist directory.
|
| 33 |
+
embedding_model : OpenAIEmbeddings
|
| 34 |
+
An instance of the OpenAIEmbeddings class for language model embeddings.
|
| 35 |
+
data_directory : str
|
| 36 |
+
The path to the data directory.
|
| 37 |
+
k : int
|
| 38 |
+
The value of 'k' specified in the retrieval configuration.
|
| 39 |
+
embedding_model_engine : str
|
| 40 |
+
The engine specified in the embedding model configuration.
|
| 41 |
+
chunk_size : int
|
| 42 |
+
The chunk size specified in the splitter configuration.
|
| 43 |
+
chunk_overlap : int
|
| 44 |
+
The chunk overlap specified in the splitter configuration.
|
| 45 |
+
max_final_token : int
|
| 46 |
+
The maximum number of final tokens specified in the summarizer configuration.
|
| 47 |
+
token_threshold : float
|
| 48 |
+
The token threshold specified in the summarizer configuration.
|
| 49 |
+
summarizer_llm_system_role : str
|
| 50 |
+
The role of the summarizer language model system specified in the configuration.
|
| 51 |
+
temperature : float
|
| 52 |
+
The temperature specified in the LLM configuration.
|
| 53 |
+
number_of_q_a_pairs : int
|
| 54 |
+
The number of question-answer pairs specified in the memory configuration.
|
| 55 |
+
|
| 56 |
+
Methods:
|
| 57 |
+
load_openai_cfg():
|
| 58 |
+
Load OpenAI configuration settings.
|
| 59 |
+
create_directory(directory_path):
|
| 60 |
+
Create a directory if it does not exist.
|
| 61 |
+
remove_directory(directory_path):
|
| 62 |
+
Removes the specified directory.
|
| 63 |
+
"""
|
| 64 |
+
|
| 65 |
+
def __init__(self) -> None:
|
| 66 |
+
with open(here("configs/app_config.yml")) as cfg:
|
| 67 |
+
app_config = yaml.load(cfg, Loader=yaml.FullLoader)
|
| 68 |
+
|
| 69 |
+
# LLM configs
|
| 70 |
+
self.llm_engine = app_config["llm_config"]["engine"]
|
| 71 |
+
self.llm_system_role = app_config["llm_config"]["llm_system_role"]
|
| 72 |
+
self.persist_directory = str(here(
|
| 73 |
+
app_config["directories"]["persist_directory"])) # needs to be strin for summation in chromadb backend: self._settings.require("persist_directory") + "/chroma.sqlite3"
|
| 74 |
+
self.custom_persist_directory = str(here(
|
| 75 |
+
app_config["directories"]["custom_persist_directory"]))
|
| 76 |
+
self.embedding_model = OpenAIEmbeddings(openai_api_key=os.getenv("OPENAI_API_KEY"))
|
| 77 |
+
|
| 78 |
+
|
| 79 |
+
# Retrieval configs
|
| 80 |
+
self.data_directory = app_config["directories"]["data_directory"]
|
| 81 |
+
self.k = app_config["retrieval_config"]["k"]
|
| 82 |
+
self.embedding_model_engine = app_config["embedding_model_config"]["engine"]
|
| 83 |
+
self.chunk_size = app_config["splitter_config"]["chunk_size"]
|
| 84 |
+
self.chunk_overlap = app_config["splitter_config"]["chunk_overlap"]
|
| 85 |
+
|
| 86 |
+
# Summarizer config
|
| 87 |
+
self.max_final_token = app_config["summarizer_config"]["max_final_token"]
|
| 88 |
+
self.token_threshold = app_config["summarizer_config"]["token_threshold"]
|
| 89 |
+
self.summarizer_llm_system_role = app_config["summarizer_config"]["summarizer_llm_system_role"]
|
| 90 |
+
self.character_overlap = app_config["summarizer_config"]["character_overlap"]
|
| 91 |
+
self.final_summarizer_llm_system_role = app_config[
|
| 92 |
+
"summarizer_config"]["final_summarizer_llm_system_role"]
|
| 93 |
+
self.temperature = app_config["llm_config"]["temperature"]
|
| 94 |
+
|
| 95 |
+
# Memory
|
| 96 |
+
self.number_of_q_a_pairs = app_config["memory"]["number_of_q_a_pairs"]
|
| 97 |
+
|
| 98 |
+
# Load OpenAI credentials
|
| 99 |
+
self.load_openai_cfg()
|
| 100 |
+
|
| 101 |
+
# clean up the upload doc vectordb if it exists
|
| 102 |
+
self.create_directory(self.persist_directory)
|
| 103 |
+
self.remove_directory(self.custom_persist_directory)
|
| 104 |
+
|
| 105 |
+
def load_openai_cfg(self):
|
| 106 |
+
"""
|
| 107 |
+
Load OpenAI configuration settings.
|
| 108 |
+
|
| 109 |
+
This function sets the OpenAI API configuration settings, including the API type, base URL,
|
| 110 |
+
version, and API key. It is intended to be called at the beginning of the script or application
|
| 111 |
+
to configure OpenAI settings.
|
| 112 |
+
|
| 113 |
+
Note:
|
| 114 |
+
Replace "Your API TYPE," "Your API BASE," "Your API VERSION," and "Your API KEY" with your actual
|
| 115 |
+
OpenAI API credentials.
|
| 116 |
+
"""
|
| 117 |
+
openai.api_type = os.getenv("OPENAI_API_TYPE")
|
| 118 |
+
openai.api_base = os.getenv("OPENAI_API_BASE")
|
| 119 |
+
openai.api_version = os.getenv("OPENAI_API_VERSION")
|
| 120 |
+
openai.api_key = os.getenv("OPENAI_API_KEY")
|
| 121 |
+
|
| 122 |
+
def create_directory(self, directory_path: str):
|
| 123 |
+
"""
|
| 124 |
+
Create a directory if it does not exist.
|
| 125 |
+
|
| 126 |
+
Parameters:
|
| 127 |
+
directory_path (str): The path of the directory to be created.
|
| 128 |
+
"""
|
| 129 |
+
if not os.path.exists(directory_path):
|
| 130 |
+
os.makedirs(directory_path)
|
| 131 |
+
|
| 132 |
+
def remove_directory(self, directory_path: str):
|
| 133 |
+
"""
|
| 134 |
+
Removes the specified directory.
|
| 135 |
+
|
| 136 |
+
Parameters:
|
| 137 |
+
directory_path (str): The path of the directory to be removed.
|
| 138 |
+
|
| 139 |
+
Raises:
|
| 140 |
+
OSError: If an error occurs during the directory removal process.
|
| 141 |
+
|
| 142 |
+
Returns:
|
| 143 |
+
None
|
| 144 |
+
"""
|
| 145 |
+
if os.path.exists(directory_path):
|
| 146 |
+
try:
|
| 147 |
+
shutil.rmtree(directory_path)
|
| 148 |
+
print(
|
| 149 |
+
f"The directory '{directory_path}' has been successfully removed.")
|
| 150 |
+
except OSError as e:
|
| 151 |
+
print(f"Error: {e}")
|
| 152 |
+
else:
|
| 153 |
+
print(f"The directory '{directory_path}' does not exist.")
|
src/utils/prepare_vectordb.py
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from langchain_community.vectorstores import Chroma
|
| 2 |
+
from langchain_community.document_loaders import PyPDFLoader
|
| 3 |
+
from langchain.text_splitter import RecursiveCharacterTextSplitter
|
| 4 |
+
import os
|
| 5 |
+
from typing import List
|
| 6 |
+
from langchain_openai import OpenAIEmbeddings # ✅ Fixed import
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class PrepareVectorDB:
|
| 10 |
+
"""
|
| 11 |
+
A class for preparing and saving a VectorDB using OpenAI embeddings.
|
| 12 |
+
"""
|
| 13 |
+
|
| 14 |
+
def __init__(
|
| 15 |
+
self,
|
| 16 |
+
data_directory: str,
|
| 17 |
+
persist_directory: str,
|
| 18 |
+
embedding_model_engine: str,
|
| 19 |
+
chunk_size: int,
|
| 20 |
+
chunk_overlap: int
|
| 21 |
+
) -> None:
|
| 22 |
+
"""
|
| 23 |
+
Initialize the PrepareVectorDB instance.
|
| 24 |
+
"""
|
| 25 |
+
self.embedding_model_engine = embedding_model_engine
|
| 26 |
+
self.text_splitter = RecursiveCharacterTextSplitter(
|
| 27 |
+
chunk_size=chunk_size,
|
| 28 |
+
chunk_overlap=chunk_overlap,
|
| 29 |
+
separators=["\n\n", "\n", " ", ""]
|
| 30 |
+
)
|
| 31 |
+
self.data_directory = data_directory
|
| 32 |
+
self.persist_directory = persist_directory
|
| 33 |
+
self.embedding = OpenAIEmbeddings()
|
| 34 |
+
|
| 35 |
+
def __load_all_documents(self) -> List:
|
| 36 |
+
"""
|
| 37 |
+
Load all documents from the specified directory or directories.
|
| 38 |
+
"""
|
| 39 |
+
doc_counter = 0
|
| 40 |
+
docs = []
|
| 41 |
+
|
| 42 |
+
if isinstance(self.data_directory, list):
|
| 43 |
+
print("Loading the uploaded documents...")
|
| 44 |
+
for doc_dir in self.data_directory:
|
| 45 |
+
docs.extend(PyPDFLoader(doc_dir).load())
|
| 46 |
+
doc_counter += 1
|
| 47 |
+
else:
|
| 48 |
+
print("Loading documents manually...")
|
| 49 |
+
if not os.path.exists(self.data_directory):
|
| 50 |
+
os.makedirs(self.data_directory) # ✅ Ensure the directory exists
|
| 51 |
+
print(f"Created missing directory: {self.data_directory}")
|
| 52 |
+
|
| 53 |
+
document_list = os.listdir(self.data_directory) # ✅ Fixed undefined variable
|
| 54 |
+
|
| 55 |
+
for doc_name in document_list:
|
| 56 |
+
docs.extend(PyPDFLoader(os.path.join(self.data_directory, doc_name)).load())
|
| 57 |
+
doc_counter += 1
|
| 58 |
+
|
| 59 |
+
print("Number of loaded documents:", doc_counter)
|
| 60 |
+
print("Number of pages:", len(docs), "\n\n")
|
| 61 |
+
return docs
|
| 62 |
+
|
| 63 |
+
def __chunk_documents(self, docs: List) -> List:
|
| 64 |
+
"""
|
| 65 |
+
Chunk the loaded documents using the specified text splitter.
|
| 66 |
+
"""
|
| 67 |
+
print("Chunking documents...")
|
| 68 |
+
chunked_documents = self.text_splitter.split_documents(docs)
|
| 69 |
+
print("Number of chunks:", len(chunked_documents), "\n\n")
|
| 70 |
+
return chunked_documents
|
| 71 |
+
|
| 72 |
+
def prepare_and_save_vectordb(self):
|
| 73 |
+
"""
|
| 74 |
+
Load, chunk, and create a VectorDB with OpenAI embeddings, and save it.
|
| 75 |
+
"""
|
| 76 |
+
docs = self.__load_all_documents()
|
| 77 |
+
chunked_documents = self.__chunk_documents(docs)
|
| 78 |
+
print("Preparing vectordb...")
|
| 79 |
+
vectordb = Chroma.from_documents(
|
| 80 |
+
documents=chunked_documents,
|
| 81 |
+
embedding=self.embedding,
|
| 82 |
+
persist_directory=self.persist_directory
|
| 83 |
+
)
|
| 84 |
+
print("VectorDB is created and saved.")
|
| 85 |
+
print("Number of vectors in vectordb:", vectordb._collection.count(), "\n\n")
|
| 86 |
+
return vectordb
|
src/utils/summarizer.py
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
|
| 2 |
+
from langchain_community.document_loaders import PyPDFLoader
|
| 3 |
+
from utils.utilities import count_num_tokens
|
| 4 |
+
import openai
|
| 5 |
+
|
| 6 |
+
|
| 7 |
+
class Summarizer:
|
| 8 |
+
"""
|
| 9 |
+
A class for summarizing PDF documents using OpenAI's ChatGPT engine.
|
| 10 |
+
|
| 11 |
+
Attributes:
|
| 12 |
+
None
|
| 13 |
+
|
| 14 |
+
Methods:
|
| 15 |
+
summarize_the_pdf:
|
| 16 |
+
Summarizes the content of a PDF file using OpenAI's ChatGPT engine.
|
| 17 |
+
|
| 18 |
+
get_llm_response:
|
| 19 |
+
Retrieves the response from the ChatGPT engine for a given prompt.
|
| 20 |
+
|
| 21 |
+
Note: Ensure that you have the required dependencies installed and configured, including the OpenAI API key.
|
| 22 |
+
"""
|
| 23 |
+
@staticmethod
|
| 24 |
+
def summarize_the_pdf(
|
| 25 |
+
file_dir: str,
|
| 26 |
+
max_final_token: int,
|
| 27 |
+
token_threshold: int,
|
| 28 |
+
gpt_model: str,
|
| 29 |
+
temperature: float,
|
| 30 |
+
summarizer_llm_system_role: str,
|
| 31 |
+
final_summarizer_llm_system_role: str,
|
| 32 |
+
character_overlap: int
|
| 33 |
+
):
|
| 34 |
+
"""
|
| 35 |
+
Summarizes the content of a PDF file using OpenAI's ChatGPT engine.
|
| 36 |
+
|
| 37 |
+
Args:
|
| 38 |
+
file_dir (str): The path to the PDF file.
|
| 39 |
+
max_final_token (int): The maximum number of tokens in the final summary.
|
| 40 |
+
token_threshold (int): The threshold for token count reduction.
|
| 41 |
+
gpt_model (str): The ChatGPT engine model name.
|
| 42 |
+
temperature (float): The temperature parameter for ChatGPT response generation.
|
| 43 |
+
summarizer_llm_system_role (str): The system role for the summarizer.
|
| 44 |
+
|
| 45 |
+
Returns:
|
| 46 |
+
str: The final summarized content.
|
| 47 |
+
"""
|
| 48 |
+
docs = []
|
| 49 |
+
docs.extend(PyPDFLoader(file_dir).load())
|
| 50 |
+
print(f"Document length: {len(docs)}")
|
| 51 |
+
max_summarizer_output_token = int(
|
| 52 |
+
max_final_token/len(docs)) - token_threshold
|
| 53 |
+
full_summary = ""
|
| 54 |
+
counter = 1
|
| 55 |
+
print("Generating the summary..")
|
| 56 |
+
# if the document has more than one pages
|
| 57 |
+
if len(docs) > 1:
|
| 58 |
+
for i in range(len(docs)):
|
| 59 |
+
# NOTE: This part can be optimized by considering a better technique for creating the prompt. (e.g: lanchain "chunksize" and "chunkoverlap" arguments.)
|
| 60 |
+
|
| 61 |
+
if i == 0: # For the first page
|
| 62 |
+
prompt = docs[i].page_content + \
|
| 63 |
+
docs[i+1].page_content[:character_overlap]
|
| 64 |
+
# For pages except the fist and the last one.
|
| 65 |
+
elif i < len(docs)-1:
|
| 66 |
+
prompt = docs[i-1].page_content[-character_overlap:] + \
|
| 67 |
+
docs[i].page_content + \
|
| 68 |
+
docs[i+1].page_content[:character_overlap]
|
| 69 |
+
else: # For the last page
|
| 70 |
+
prompt = docs[i-1].page_content[-character_overlap:] + \
|
| 71 |
+
docs[i].page_content
|
| 72 |
+
summarizer_llm_system_role = summarizer_llm_system_role.format(
|
| 73 |
+
max_summarizer_output_token)
|
| 74 |
+
full_summary += Summarizer.get_llm_response(
|
| 75 |
+
gpt_model,
|
| 76 |
+
temperature,
|
| 77 |
+
summarizer_llm_system_role,
|
| 78 |
+
prompt=prompt
|
| 79 |
+
)
|
| 80 |
+
else: # if the document has only one page
|
| 81 |
+
full_summary = docs[0].page_content
|
| 82 |
+
|
| 83 |
+
print(f"Page {counter} was summarized. ", end="")
|
| 84 |
+
counter += 1
|
| 85 |
+
print("\nFull summary token length:", count_num_tokens(
|
| 86 |
+
full_summary, model=gpt_model))
|
| 87 |
+
final_summary = Summarizer.get_llm_response(
|
| 88 |
+
gpt_model,
|
| 89 |
+
temperature,
|
| 90 |
+
final_summarizer_llm_system_role,
|
| 91 |
+
prompt=full_summary
|
| 92 |
+
)
|
| 93 |
+
return final_summary
|
| 94 |
+
|
| 95 |
+
@staticmethod
|
| 96 |
+
def get_llm_response(gpt_model: str, temperature: float, llm_system_role: str, prompt: str):
|
| 97 |
+
"""
|
| 98 |
+
Retrieves the response from the ChatGPT engine for a given prompt.
|
| 99 |
+
|
| 100 |
+
Args:
|
| 101 |
+
gpt_model (str): The ChatGPT engine model name.
|
| 102 |
+
temperature (float): The temperature parameter for ChatGPT response generation.
|
| 103 |
+
summarizer_llm_system_role (str): The system role for the summarizer.
|
| 104 |
+
max_summarizer_output_token (int): The maximum number of tokens for the summarizer output.
|
| 105 |
+
prompt (str): The input prompt for the ChatGPT engine.
|
| 106 |
+
|
| 107 |
+
Returns:
|
| 108 |
+
str: The response content from the ChatGPT engine.
|
| 109 |
+
"""
|
| 110 |
+
response = openai.ChatCompletion.create(
|
| 111 |
+
engine=gpt_model,
|
| 112 |
+
messages=[
|
| 113 |
+
{"role": "system", "content": llm_system_role},
|
| 114 |
+
{"role": "user", "content": prompt}
|
| 115 |
+
],
|
| 116 |
+
temperature=temperature,
|
| 117 |
+
)
|
| 118 |
+
return response.choices[0].message.content
|
src/utils/ui_settings.py
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
class UISettings:
|
| 5 |
+
"""
|
| 6 |
+
Utility class for managing UI settings.
|
| 7 |
+
|
| 8 |
+
This class provides static methods for toggling UI components, such as a sidebar.
|
| 9 |
+
"""
|
| 10 |
+
@staticmethod
|
| 11 |
+
def toggle_sidebar(state):
|
| 12 |
+
"""
|
| 13 |
+
Toggle the visibility state of a UI component.
|
| 14 |
+
|
| 15 |
+
Parameters:
|
| 16 |
+
state: The current state of the UI component.
|
| 17 |
+
|
| 18 |
+
Returns:
|
| 19 |
+
Tuple: A tuple containing the updated UI component state and the new state.
|
| 20 |
+
"""
|
| 21 |
+
state = not state
|
| 22 |
+
return gr.update(visible=state), state
|
| 23 |
+
|
| 24 |
+
@staticmethod
|
| 25 |
+
def feedback(data: gr.LikeData):
|
| 26 |
+
"""
|
| 27 |
+
Process user feedback on the generated response.
|
| 28 |
+
|
| 29 |
+
Parameters:
|
| 30 |
+
data (gr.LikeData): Gradio LikeData object containing user feedback.
|
| 31 |
+
"""
|
| 32 |
+
if data.liked:
|
| 33 |
+
print("You upvoted this response: " + data.value)
|
| 34 |
+
else:
|
| 35 |
+
print("You downvoted this response: " + data.value)
|
| 36 |
+
|
| 37 |
+
|
src/utils/upload_file.py
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from utils.prepare_vectordb import PrepareVectorDB
|
| 2 |
+
from typing import List, Tuple
|
| 3 |
+
from utils.load_config import LoadConfig
|
| 4 |
+
from utils.summarizer import Summarizer
|
| 5 |
+
|
| 6 |
+
APPCFG = LoadConfig()
|
| 7 |
+
|
| 8 |
+
|
| 9 |
+
class UploadFile:
|
| 10 |
+
"""
|
| 11 |
+
Utility class for handling file uploads and processing.
|
| 12 |
+
|
| 13 |
+
This class provides static methods for checking directories and processing uploaded files
|
| 14 |
+
to prepare a VectorDB.
|
| 15 |
+
"""
|
| 16 |
+
|
| 17 |
+
@staticmethod
|
| 18 |
+
def process_uploaded_files(files_dir: List, chatbot: List, rag_with_dropdown: str) -> Tuple:
|
| 19 |
+
"""
|
| 20 |
+
Process uploaded files to prepare a VectorDB.
|
| 21 |
+
|
| 22 |
+
Parameters:
|
| 23 |
+
files_dir (List): List of paths to the uploaded files.
|
| 24 |
+
chatbot: An instance of the chatbot for communication.
|
| 25 |
+
|
| 26 |
+
Returns:
|
| 27 |
+
Tuple: A tuple containing an empty string and the updated chatbot instance.
|
| 28 |
+
"""
|
| 29 |
+
if rag_with_dropdown == "Upload doc: Process for RAG":
|
| 30 |
+
prepare_vectordb_instance = PrepareVectorDB(data_directory=files_dir,
|
| 31 |
+
persist_directory=APPCFG.custom_persist_directory,
|
| 32 |
+
embedding_model_engine=APPCFG.embedding_model_engine,
|
| 33 |
+
chunk_size=APPCFG.chunk_size,
|
| 34 |
+
chunk_overlap=APPCFG.chunk_overlap)
|
| 35 |
+
prepare_vectordb_instance.prepare_and_save_vectordb()
|
| 36 |
+
chatbot.append(
|
| 37 |
+
(" ", "Uploaded files are ready. Please ask your question"))
|
| 38 |
+
elif rag_with_dropdown == "Upload doc: Give Full summary":
|
| 39 |
+
final_summary = Summarizer.summarize_the_pdf(file_dir=files_dir[0],
|
| 40 |
+
max_final_token=APPCFG.max_final_token,
|
| 41 |
+
token_threshold=APPCFG.token_threshold,
|
| 42 |
+
gpt_model=APPCFG.llm_engine,
|
| 43 |
+
temperature=APPCFG.temperature,
|
| 44 |
+
summarizer_llm_system_role=APPCFG.summarizer_llm_system_role,
|
| 45 |
+
final_summarizer_llm_system_role=APPCFG.final_summarizer_llm_system_role,
|
| 46 |
+
character_overlap=APPCFG.character_overlap)
|
| 47 |
+
chatbot.append(
|
| 48 |
+
(" ", final_summary))
|
| 49 |
+
else:
|
| 50 |
+
chatbot.append(
|
| 51 |
+
(" ", "If you would like to upload a PDF, please select your desired action in 'rag_with' dropdown."))
|
| 52 |
+
return "", chatbot
|
src/utils/utilities.py
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import tiktoken
|
| 2 |
+
|
| 3 |
+
|
| 4 |
+
def count_num_tokens(text: str, model: str) -> int:
|
| 5 |
+
"""
|
| 6 |
+
Returns the number of tokens in the given text.
|
| 7 |
+
Args:
|
| 8 |
+
text (str): The text to count tokens in.
|
| 9 |
+
model (str, optional): The name of the GPT model to use. Defaults to the model specified in the app config.
|
| 10 |
+
|
| 11 |
+
Returns:
|
| 12 |
+
int: The number of tokens in the text.
|
| 13 |
+
"""
|
| 14 |
+
encoding = tiktoken.encoding_for_model(model)
|
| 15 |
+
return len(encoding.encode(text))
|