DrSyedFaizan commited on
Commit
f8bf7df
·
verified ·
1 Parent(s): d772f1c

Upload folder using huggingface_hub

Browse files
Files changed (39) hide show
  1. .here +0 -0
  2. Helper.md +43 -0
  3. README.md +92 -12
  4. conda_env_requirements.txt +179 -0
  5. configs/app_config.yml +52 -0
  6. data/docs/FIRST AID IN COMMON EMERGENCY CONDITIONS.pdf +0 -0
  7. data/docs_2/FIRST AID IN COMMON EMERGENCY CONDITIONS.pdf +0 -0
  8. data/vectordb/processed/chroma/8008bb97-d12e-40c0-870f-b02d5699f748/data_level0.bin +3 -0
  9. data/vectordb/processed/chroma/8008bb97-d12e-40c0-870f-b02d5699f748/header.bin +3 -0
  10. data/vectordb/processed/chroma/8008bb97-d12e-40c0-870f-b02d5699f748/length.bin +3 -0
  11. data/vectordb/processed/chroma/8008bb97-d12e-40c0-870f-b02d5699f748/link_lists.bin +0 -0
  12. data/vectordb/processed/chroma/chroma.sqlite3 +0 -0
  13. images/AI_RT.png +0 -0
  14. images/RAGGPT UI.png +0 -0
  15. images/RAGGPT_schema.png +0 -0
  16. images/openai_.png +0 -0
  17. requirements.txt +12 -0
  18. src/.gradio/certificate.pem +31 -0
  19. src/README.md +6 -0
  20. src/configs/app_config.yml +52 -0
  21. src/raggpt.py +87 -0
  22. src/serve.py +76 -0
  23. src/terminal_q_and_a.py +48 -0
  24. src/upload_data_manually.py +41 -0
  25. src/utils/.env +1 -0
  26. src/utils/__pycache__/chatbot.cpython-312.pyc +0 -0
  27. src/utils/__pycache__/load_config.cpython-312.pyc +0 -0
  28. src/utils/__pycache__/prepare_vectordb.cpython-312.pyc +0 -0
  29. src/utils/__pycache__/summarizer.cpython-312.pyc +0 -0
  30. src/utils/__pycache__/ui_settings.cpython-312.pyc +0 -0
  31. src/utils/__pycache__/upload_file.cpython-312.pyc +0 -0
  32. src/utils/__pycache__/utilities.cpython-312.pyc +0 -0
  33. src/utils/chatbot.py +78 -0
  34. src/utils/load_config.py +153 -0
  35. src/utils/prepare_vectordb.py +86 -0
  36. src/utils/summarizer.py +118 -0
  37. src/utils/ui_settings.py +37 -0
  38. src/utils/upload_file.py +52 -0
  39. 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: First Aid Assistant
3
- emoji: 🐠
4
- colorFrom: pink
5
- colorTo: indigo
6
- sdk: gradio
7
- sdk_version: 5.12.0
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: 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))