Julien Simon commited on
Commit
ab96bbb
Β·
0 Parent(s):

Initial version

Browse files
Files changed (5) hide show
  1. .gitattributes +36 -0
  2. README.md +95 -0
  3. app.py +136 -0
  4. demo.py +280 -0
  5. requirements.txt +11 -0
.gitattributes ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tar filter=lfs diff=lfs merge=lfs -text
29
+ *.tflite filter=lfs diff=lfs merge=lfs -text
30
+ *.tgz filter=lfs diff=lfs merge=lfs -text
31
+ *.wasm filter=lfs diff=lfs merge=lfs -text
32
+ *.xz filter=lfs diff=lfs merge=lfs -text
33
+ *.zip filter=lfs diff=lfs merge=lfs -text
34
+ *.zst filter=lfs diff=lfs merge=lfs -text
35
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ *.pdf filter=lfs diff=lfs merge=lfs -text
README.md ADDED
@@ -0,0 +1,95 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Conductor RAG
3
+ emoji: πŸš€
4
+ colorFrom: pink
5
+ colorTo: green
6
+ sdk: gradio
7
+ sdk_version: "5.23.1"
8
+ app_file: app.py
9
+ pinned: false
10
+ ---
11
+
12
+ # Conductor RAG - Document Question-Answering System
13
+ πŸš€ A Retrieval-Augmented Generation (RAG) powered chat interface for document Q&A using Arcee Conductor
14
+
15
+ ## Overview
16
+ This application provides an interactive chat interface that allows users to ask questions about their documents. It combines the power of Large Language Models with document retrieval to provide accurate, source-backed answers.
17
+
18
+ ## Features
19
+ - **RAG-Powered Responses**: Leverages document context to provide accurate, factual answers
20
+ - **Flexible Query Modes**: Switch between RAG and vanilla LLM responses
21
+ - **Source Citations**: Automatically includes relevant document sources and page numbers
22
+ - **Interactive Interface**: Clean, user-friendly Gradio-based chat interface
23
+ - **Context Visibility**: View the retrieved document chunks used to generate responses
24
+
25
+ ## Technical Details
26
+ - Built with Langchain and Gradio
27
+ - Uses Arcee Conductor API for LLM capabilities
28
+ - Document embedding via BAAI/bge-small-en-v1.5
29
+ - ChromaDB for vector storage
30
+ - Supports PDF document processing
31
+
32
+ ## Included Papers
33
+ The following research papers are included in the `pdf` directory:
34
+
35
+ - [arXiv:2306.13649v3](https://arxiv.org/abs/2306.13649)
36
+ - [arXiv:2309.16609v1](https://arxiv.org/abs/2309.16609)
37
+ - [arXiv:2312.06795v1](https://arxiv.org/abs/2312.06795)
38
+ - [arXiv:2403.19522v1](https://arxiv.org/abs/2403.19522)
39
+ - [arXiv:2405.04434v5](https://arxiv.org/abs/2405.04434)
40
+ - [arXiv:2406.11617v1](https://arxiv.org/abs/2406.11617)
41
+ - [arXiv:2410.21228v1](https://arxiv.org/abs/2410.21228)
42
+ - [arXiv:2411.05059v2](https://arxiv.org/abs/2411.05059)
43
+ - [arXiv:2501.09223v1](https://arxiv.org/abs/2501.09223)
44
+ - [arXiv:2501.12948v1](https://arxiv.org/abs/2501.12948)
45
+ - [arXiv:2503.04872v1](https://arxiv.org/abs/2503.04872)
46
+
47
+ ## Deployment
48
+ This application is hosted as a Hugging Face Space. Configuration details can be found in the [spaces config reference](https://huggingface.co/docs/hub/spaces-config-reference).
49
+
50
+ ## Creating Your Own Hugging Face Space Using CLI
51
+
52
+ You can easily deploy this application as your own Hugging Face Space using the Hugging Face CLI. Follow these steps:
53
+
54
+ 1. **Install the Hugging Face CLI**:
55
+ ```bash
56
+ pip install huggingface_hub
57
+ ```
58
+
59
+ 2. **Login to Hugging Face**:
60
+ ```bash
61
+ huggingface-cli login
62
+ ```
63
+ You'll be prompted to enter your Hugging Face token, which you can find in your account settings.
64
+
65
+ 3. **Clone this Repository**:
66
+ ```bash
67
+ git clone https://github.com/username/conductor-rag.git
68
+ cd conductor-rag
69
+ ```
70
+
71
+ 4. **Create a New Space**:
72
+ ```bash
73
+ huggingface-cli repo create conductor-rag-your-name --type space --space-sdk gradio
74
+ ```
75
+
76
+ 5. **Add Your Environment Variables**:
77
+ The application uses the following environment variables, which you need to set in the Space settings:
78
+ - `OPENAI_API_KEY`: Your Arcee Conductor API key
79
+
80
+ 7. **Push Your Code to the Space**:
81
+ ```bash
82
+ git remote add space https://huggingface.co/spaces/your-username/conductor-rag
83
+ git push space main
84
+ ```
85
+
86
+ 8. **Add Your PDF Documents**:
87
+ You can either add PDFs directly to the repository before pushing, or upload them later through git.
88
+
89
+ 9. **Monitor Deployment**:
90
+ Visit `https://huggingface.co/spaces/your-username/conductor-rag-your-name` to see your Space being built and deployed.
91
+
92
+ Your Space will automatically build and deploy the application. Once complete, you can access it via the provided URL and share it with others.
93
+
94
+ ---
95
+ Built with πŸ’– using Arcee Conductor
app.py ADDED
@@ -0,0 +1,136 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import gradio as gr
2
+ from demo import create_llm, create_embeddings, load_or_create_vectorstore, create_qa_chain
3
+
4
+ def initialize_chain():
5
+ """Initialize the RAG chain and return it."""
6
+ llm = create_llm()
7
+ embeddings = create_embeddings()
8
+ vectorstore = load_or_create_vectorstore(embeddings)
9
+ return create_qa_chain(llm, vectorstore)
10
+
11
+ def chat_response(message, history, query_type):
12
+ """Process chat messages and return responses using either RAG or vanilla LLM.
13
+
14
+ Args:
15
+ message (str): The user's input message
16
+ history (list): List of previous message-response pairs
17
+ query_type (str): Either "RAG" or "Vanilla LLM"
18
+
19
+ Returns:
20
+ str: The formatted response text including sources for RAG queries
21
+ """
22
+ # Convert Gradio history to list of tuples
23
+ chat_history = [(msg, resp) for msg, resp in history] if history else []
24
+
25
+ if query_type == "RAG":
26
+ result = qa_chain.invoke({
27
+ "question": message,
28
+ "chat_history": chat_history
29
+ })
30
+ response_text = result["answer"]
31
+
32
+ # Add source citations if available
33
+ if result.get("source_documents"):
34
+ sources = []
35
+ seen_sources = set()
36
+
37
+ # Deduplicate sources while preserving order
38
+ for doc in result["source_documents"]:
39
+ source = doc.metadata.get('source', 'Unknown')
40
+ page = doc.metadata.get('page', 'unknown')
41
+ source_key = f"{source}:{page}"
42
+
43
+ if source_key not in seen_sources:
44
+ sources.append(f"- {source}, page {page}")
45
+ seen_sources.add(source_key)
46
+
47
+ if sources:
48
+ response_text += "\n\nSources:\n" + "\n".join(sources)
49
+ else:
50
+ # Use vanilla LLM for direct responses
51
+ result = llm.invoke(message)
52
+ response_text = result.content
53
+
54
+ return response_text
55
+
56
+ # Initialize components globally
57
+ llm = create_llm()
58
+ qa_chain = initialize_chain()
59
+
60
+ # Create the Gradio interface
61
+ with gr.Blocks() as demo:
62
+ # UI Setup
63
+ gr.Markdown("# RAG-Powered Document Chat with Arcee Conductor")
64
+ gr.Markdown("Ask questions about your documents. The system will provide answers based on the content of your PDFs.")
65
+
66
+ rag_enabled = gr.Checkbox(
67
+ value=True,
68
+ label="Enable RAG",
69
+ info="Toggle between RAG-powered document search or vanilla LLM responses"
70
+ )
71
+
72
+ chatbot = gr.Chatbot()
73
+ context_box = gr.Textbox(
74
+ label="Retrieved Context",
75
+ interactive=False,
76
+ visible=True,
77
+ lines=5
78
+ )
79
+
80
+ # Input controls
81
+ with gr.Row():
82
+ msg = gr.Textbox(label="Query", scale=8)
83
+ with gr.Column(scale=1):
84
+ submit = gr.Button("Submit")
85
+ clear = gr.Button("Clear")
86
+
87
+ def respond(message, chat_history, is_rag_enabled):
88
+ """Handle user messages and generate responses.
89
+
90
+ Args:
91
+ message (str): User input message
92
+ chat_history (list): Previous conversation history
93
+ is_rag_enabled (bool): Whether to use RAG or vanilla LLM
94
+
95
+ Returns:
96
+ tuple: (cleared message, updated history, context, RAG state)
97
+ """
98
+ if not message:
99
+ return "", chat_history, "", is_rag_enabled
100
+
101
+ query_type = "RAG" if is_rag_enabled else "Vanilla LLM"
102
+ bot_message = chat_response(message, chat_history, query_type)
103
+
104
+ # Create new history to avoid modifying the original
105
+ new_history = list(chat_history)
106
+ new_history.append((message, bot_message))
107
+
108
+ # Get relevant context for RAG queries
109
+ context = ""
110
+ if is_rag_enabled and qa_chain.retriever:
111
+ docs = qa_chain.retriever.get_relevant_documents(message)
112
+ context = "\n\n".join(doc.page_content for doc in docs)
113
+
114
+ return "", new_history, context, is_rag_enabled
115
+
116
+ def update_context_visibility(is_rag_enabled):
117
+ """Update context box visibility based on RAG toggle."""
118
+ return gr.update(visible=is_rag_enabled, value="" if not is_rag_enabled else None)
119
+
120
+ # Wire up event handlers
121
+ msg.submit(respond, [msg, chatbot, rag_enabled], [msg, chatbot, context_box, rag_enabled])
122
+ submit.click(respond, [msg, chatbot, rag_enabled], [msg, chatbot, context_box, rag_enabled])
123
+ clear.click(lambda: [[], "", True], None, [chatbot, context_box, rag_enabled], queue=False)
124
+ rag_enabled.change(update_context_visibility, rag_enabled, context_box)
125
+
126
+ # Add example queries
127
+ gr.Examples(
128
+ examples=[
129
+ "Tell me about Arcee Fusion.",
130
+ "How does deepseek-R1 differ from deepseek-v3?"
131
+ ],
132
+ inputs=msg
133
+ )
134
+
135
+ if __name__ == "__main__":
136
+ demo.launch(share=False)
demo.py ADDED
@@ -0,0 +1,280 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ import glob
3
+ # Set tokenizers parallelism before importing other libraries
4
+ os.environ["TOKENIZERS_PARALLELISM"] = "false"
5
+
6
+ from langchain_openai import ChatOpenAI
7
+ from langchain_core.prompts import ChatPromptTemplate
8
+ from langchain_community.document_loaders import DirectoryLoader, PyPDFLoader
9
+ from langchain.text_splitter import RecursiveCharacterTextSplitter
10
+ from langchain_chroma import Chroma
11
+ from langchain.chains import ConversationalRetrievalChain
12
+ from langchain_huggingface import HuggingFaceEmbeddings
13
+ from concurrent.futures import ThreadPoolExecutor, TimeoutError
14
+ import time
15
+
16
+ # Constants
17
+ OPENAI_API_KEY = os.getenv("OPENAI_API_KEY")
18
+ OPENAI_URL = "https://conductor.arcee.ai/v1"
19
+ OPENAI_MODEL = "auto"
20
+ CHROMA_PATH = "vectorstore"
21
+ PDF_PATH = "pdf"
22
+
23
+ def create_llm(streaming=False):
24
+ """Initialize the OpenAI language model.
25
+
26
+ Args:
27
+ streaming (bool): Whether to enable response streaming
28
+
29
+ Returns:
30
+ ChatOpenAI: Configured language model instance
31
+ """
32
+ return ChatOpenAI(
33
+ model=OPENAI_MODEL,
34
+ openai_api_key=OPENAI_API_KEY,
35
+ base_url=OPENAI_URL,
36
+ streaming=streaming
37
+ )
38
+
39
+ def create_embeddings():
40
+ """Initialize the embedding model."""
41
+ return HuggingFaceEmbeddings(
42
+ model_name="BAAI/bge-small-en-v1.5",
43
+ model_kwargs={'device': 'cpu'},
44
+ encode_kwargs={'normalize_embeddings': True}
45
+ )
46
+
47
+ def get_text_splitter():
48
+ """Create text splitter with optimal settings."""
49
+ return RecursiveCharacterTextSplitter(
50
+ chunk_size=512,
51
+ chunk_overlap=129,
52
+ length_function=len,
53
+ add_start_index=True,
54
+ )
55
+
56
+ def get_pdf_files():
57
+ """Get list of PDF files from the specified directory."""
58
+ if not os.path.exists(PDF_PATH):
59
+ os.makedirs(PDF_PATH)
60
+ return []
61
+ return list(glob.glob(os.path.join(PDF_PATH, "*.pdf")))
62
+
63
+ def filter_metadata(doc):
64
+ """Filter out unwanted sections from documents.
65
+
66
+ Args:
67
+ doc: Document object with metadata
68
+
69
+ Returns:
70
+ bool: True if document should be kept, False if filtered out
71
+ """
72
+ skip_sections = {
73
+ 'references',
74
+ 'acknowledgments',
75
+ 'appendix'
76
+ }
77
+ section = doc.metadata.get('section', '').lower()
78
+ return not any(s in section for s in skip_sections)
79
+
80
+ def process_documents(documents, text_splitter):
81
+ """Process and filter documents into chunks."""
82
+ chunks = text_splitter.split_documents(documents)
83
+ return [chunk for chunk in chunks if filter_metadata(chunk)]
84
+
85
+ def load_or_create_vectorstore(embeddings):
86
+ """Load existing vectorstore or create a new one."""
87
+ if os.path.exists(CHROMA_PATH):
88
+ return handle_existing_vectorstore(embeddings)
89
+ return create_new_vectorstore(embeddings)
90
+
91
+ def handle_existing_vectorstore(embeddings):
92
+ """Handle loading and updating existing vectorstore.
93
+
94
+ Args:
95
+ embeddings: Embedding model instance
96
+
97
+ Returns:
98
+ Chroma: Loaded and potentially updated vectorstore
99
+
100
+ Exits if no PDF files are found.
101
+ """
102
+ print("Loading existing Chroma database...")
103
+ vectorstore = Chroma(
104
+ persist_directory=CHROMA_PATH,
105
+ embedding_function=embeddings
106
+ )
107
+
108
+ current_pdfs = get_pdf_files()
109
+ if not current_pdfs:
110
+ print("No PDF files found in directory.")
111
+ exit(1)
112
+
113
+ collection = vectorstore.get()
114
+ processed_files = {
115
+ meta.get('source')
116
+ for meta in collection['metadatas']
117
+ if meta and meta.get('source')
118
+ }
119
+
120
+ new_pdfs = [pdf for pdf in current_pdfs if pdf not in processed_files]
121
+
122
+ if new_pdfs:
123
+ update_vectorstore(vectorstore, new_pdfs, processed_files)
124
+ else:
125
+ print("No new PDF files to process.")
126
+
127
+ return vectorstore
128
+
129
+ def update_vectorstore(vectorstore, new_pdfs, processed_files):
130
+ """Update existing vectorstore with new documents."""
131
+ print(f"Found {len(new_pdfs)} new PDF files to process...")
132
+ loader = DirectoryLoader(PDF_PATH, glob="**/*.pdf", loader_cls=PyPDFLoader)
133
+ documents = loader.load()
134
+ new_documents = [doc for doc in documents if doc.metadata.get('source') not in processed_files]
135
+
136
+ filtered_chunks = process_documents(new_documents, get_text_splitter())
137
+ if filtered_chunks:
138
+ print("Adding new documents to existing database...")
139
+ vectorstore.add_documents(filtered_chunks)
140
+ print("Database updated successfully!")
141
+
142
+ def create_new_vectorstore(embeddings):
143
+ """Create a new vectorstore from documents."""
144
+ print("Creating new Chroma database...")
145
+ pdf_files = get_pdf_files()
146
+ if not pdf_files:
147
+ print(f"No PDF files found in '{PDF_PATH}' directory!")
148
+ print(f"Please add your PDF files to the '{PDF_PATH}' directory and run again.")
149
+ exit(1)
150
+
151
+ print(f"Found {len(pdf_files)} PDF files to process...")
152
+ print("(This may take a while as documents need to be processed and embedded)")
153
+
154
+ os.makedirs(CHROMA_PATH, exist_ok=True)
155
+
156
+ loader = DirectoryLoader(PDF_PATH, glob="**/*.pdf", loader_cls=PyPDFLoader)
157
+ documents = loader.load()
158
+ filtered_chunks = process_documents(documents, get_text_splitter())
159
+
160
+ return Chroma.from_documents(
161
+ documents=filtered_chunks,
162
+ embedding=embeddings,
163
+ persist_directory=CHROMA_PATH
164
+ )
165
+
166
+ def create_qa_chain(llm, vectorstore):
167
+ """Create the question-answering chain."""
168
+ prompt_template = """Answer the question using your own knowledge and the provided context.
169
+
170
+ Context:
171
+ {context}
172
+
173
+ Question: {question}
174
+
175
+ Previous conversation:
176
+ {chat_history}
177
+
178
+ Answer:"""
179
+
180
+ prompt = ChatPromptTemplate.from_template(prompt_template)
181
+
182
+ return ConversationalRetrievalChain.from_llm(
183
+ llm=llm,
184
+ retriever=vectorstore.as_retriever(
185
+ search_type="similarity",
186
+ search_kwargs={'k': 3}
187
+ ),
188
+ return_source_documents=True,
189
+ combine_docs_chain_kwargs={'prompt': prompt},
190
+ chain_type="stuff",
191
+ verbose=True
192
+ )
193
+
194
+ def get_vanilla_response(llm, query):
195
+ """Get response from vanilla chain without RAG with streaming."""
196
+ streaming_llm = create_llm(streaming=True)
197
+
198
+ vanilla_prompt = ChatPromptTemplate.from_template("""
199
+ Question: {question}
200
+
201
+ Instructions:
202
+ - If you don't know the answer, say so
203
+ - Be concise and clear
204
+ - Only state what you're confident about
205
+
206
+ Answer:""")
207
+
208
+ chain = vanilla_prompt | streaming_llm
209
+
210
+ print("\n=== Vanilla Response (No RAG) ===")
211
+
212
+ try:
213
+ print("Answer: ", end="", flush=True)
214
+ for chunk in chain.stream({"question": query}):
215
+ print(chunk.content, end="", flush=True)
216
+ print() # New line after streaming completes
217
+
218
+ except Exception as e:
219
+ print(f"\nError getting vanilla response: {str(e)}")
220
+
221
+ def get_rag_response(qa_chain, query, chat_history):
222
+ """Get response from RAG-powered chain with streaming.
223
+
224
+ Args:
225
+ qa_chain: The QA chain instance
226
+ query (str): User's question
227
+ chat_history (list): Previous conversation history
228
+ """
229
+ print("\n=== RAG Response ===")
230
+
231
+ try:
232
+ result = qa_chain.invoke({
233
+ "question": query,
234
+ "chat_history": chat_history
235
+ })
236
+
237
+ # Print answer with streaming
238
+ print("\nAnswer: ", end="", flush=True)
239
+ for chunk in result["answer"]:
240
+ print(chunk, end="", flush=True)
241
+ print()
242
+
243
+ # Print unique sources
244
+ if result.get("source_documents"):
245
+ print("\nSources:")
246
+ seen_sources = set()
247
+ for doc in result["source_documents"]:
248
+ source = doc.metadata.get('source', 'Unknown')
249
+ page = doc.metadata.get('page', 'unknown')
250
+ source_key = f"{source}:{page}"
251
+
252
+ if source_key not in seen_sources:
253
+ print(f"- {source}, page {page}")
254
+ seen_sources.add(source_key)
255
+
256
+ except Exception as e:
257
+ print(f"\nError: {str(e)}")
258
+
259
+ def main():
260
+ """Main execution function."""
261
+ # Create streaming LLM for RAG
262
+ llm = create_llm(streaming=True)
263
+ embeddings = create_embeddings()
264
+ vectorstore = load_or_create_vectorstore(embeddings)
265
+ qa_chain = create_qa_chain(llm, vectorstore)
266
+
267
+ chat_history = []
268
+ query = "Tell me about Arcee Fusion?"
269
+
270
+ # Get both vanilla and RAG responses
271
+ get_vanilla_response(llm, query)
272
+ get_rag_response(qa_chain, query, chat_history)
273
+
274
+ if __name__ == "__main__":
275
+ main()
276
+
277
+
278
+
279
+
280
+
requirements.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ langchain
2
+ langchain-openai
3
+ langchain-huggingface
4
+ langchain-chroma
5
+ sentence-transformers
6
+ torch
7
+ transformers
8
+ langchain-community
9
+ chromadb
10
+ pypdf
11
+ gradio