fguryel commited on
Commit
bde494c
·
1 Parent(s): 8fc10eb
Files changed (5) hide show
  1. app.py +17 -0
  2. app_backup.py +0 -621
  3. app_hf.py +0 -0
  4. chroma_db/chroma.sqlite3 +1 -1
  5. run.py +0 -0
app.py CHANGED
@@ -488,4 +488,21 @@ def main():
488
 
489
 
490
  if __name__ == "__main__":
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
491
  main()
 
488
 
489
 
490
  if __name__ == "__main__":
491
+ # Check if running with streamlit vs directly with python
492
+ import sys
493
+
494
+ # Check if this is being run directly with python (not via streamlit)
495
+ # When run with streamlit, sys.argv[0] typically contains 'streamlit' or the script is run in a different context
496
+ if len(sys.argv) == 1 and 'streamlit' not in sys.modules:
497
+ print("⚠️ This is a Streamlit application!")
498
+ print("🚀 Please run it with: streamlit run app.py")
499
+ print()
500
+ print("📝 Instructions:")
501
+ print("1. Make sure you have streamlit installed: pip install streamlit")
502
+ print("2. Run the app: streamlit run app.py")
503
+ print("3. Enter your OpenAI API key in the sidebar")
504
+ print("4. Start asking questions about Scikit-learn!")
505
+ sys.exit(0)
506
+
507
+ # If we get here, we're likely running via streamlit
508
  main()
app_backup.py DELETED
@@ -1,621 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- Scikit-learn Documentation Q&A Bot
4
-
5
- A Retrieval-Augmented Generation (RAG) chatbot built with Streamlit
6
- that answers questions about Scikit-learn documentation using ChromaDB
7
- for retrieval and OpenAI for generation.
8
-
9
- Author: AI Assistant
10
- Date: September 2025
11
- """
12
-
13
- import os
14
- import sys
15
- import json
16
- import logging
17
- from typing import List, Dict, Any, Optional, Tuple
18
- import streamlit as st
19
- import chromadb
20
- from chromadb.config import Settings
21
- from sentence_transformers import SentenceTransformer
22
- from openai import OpenAI
23
-
24
-
25
- # Configure logging
26
- logging.basicConfig(level=logging.INFO)
27
- logger = logging.getLogger(__name__)
28
-
29
-
30
- class RAGChatbot:
31
- """
32
- A Retrieval-Augmented Generation chatbot for Scikit-learn documentation.
33
-
34
- This class handles the complete RAG pipeline: retrieval from ChromaDB,
35
- augmentation with context, and generation using OpenAI's API.
36
- """
37
-
38
- def __init__(
39
- self,
40
- db_path: str = './chroma_db',
41
- collection_name: str = 'sklearn_docs',
42
- embedding_model_name: str = 'all-MiniLM-L6-v2'
43
- ):
44
- """
45
- Initialize the RAG chatbot.
46
-
47
- Args:
48
- db_path (str): Path to ChromaDB database
49
- collection_name (str): Name of the ChromaDB collection
50
- embedding_model_name (str): Name of the embedding model
51
- """
52
- self.db_path = db_path
53
- self.collection_name = collection_name
54
- self.embedding_model_name = embedding_model_name
55
-
56
- # Initialize components
57
- self.chroma_client = None
58
- self.collection = None
59
- self.embedding_model = None
60
- self.openai_client = None
61
-
62
- # Initialize the retrieval system
63
- self._initialize_retrieval_system()
64
-
65
- def _initialize_retrieval_system(self) -> None:
66
- """
67
- Initialize ChromaDB client and embedding model for retrieval.
68
- """
69
- try:
70
- # Check if we're in Hugging Face Spaces environment
71
- if os.path.exists('chroma.sqlite3'):
72
- # We're likely in HF Spaces - use current directory
73
- self.db_path = '.'
74
-
75
- # Initialize ChromaDB client
76
- self.chroma_client = chromadb.PersistentClient(
77
- path=self.db_path,
78
- settings=Settings(anonymized_telemetry=False)
79
- )
80
-
81
- # Get or create collection
82
- try:
83
- self.collection = self.chroma_client.get_collection(
84
- name=self.collection_name
85
- )
86
- except Exception:
87
- # If collection doesn't exist, try to recreate it from chunks
88
- if os.path.exists('chunks.json'):
89
- st.warning("Database collection not found. Rebuilding from chunks...")
90
- self._rebuild_collection_from_chunks()
91
- else:
92
- raise Exception("Neither database collection nor chunks.json found. Please build the database first.")
93
-
94
- # Load embedding model (same as used for building the database)
95
- self.embedding_model = SentenceTransformer(self.embedding_model_name)
96
-
97
- logger.info("RAG retrieval system initialized successfully")
98
-
99
- except Exception as e:
100
- logger.error(f"Failed to initialize retrieval system: {e}")
101
- # In Streamlit, show user-friendly error
102
- if 'streamlit' in sys.modules:
103
- st.error(f"❌ Database initialization failed: {e}")
104
- st.info("💡 This might be the first run. The database needs to be built from the scraped content.")
105
- raise
106
-
107
- def _rebuild_collection_from_chunks(self) -> None:
108
- """
109
- Rebuild the ChromaDB collection from chunks.json file.
110
- This is useful for Hugging Face Spaces deployment.
111
- """
112
- try:
113
- st.info("🔄 Rebuilding database collection from chunks...")
114
-
115
- # Load chunks
116
- with open('chunks.json', 'r', encoding='utf-8') as f:
117
- chunks = json.load(f)
118
-
119
- # Create collection
120
- try:
121
- self.chroma_client.delete_collection(name=self.collection_name)
122
- except:
123
- pass # Collection might not exist
124
-
125
- self.collection = self.chroma_client.create_collection(
126
- name=self.collection_name,
127
- metadata={"description": "Scikit-learn documentation embeddings"}
128
- )
129
-
130
- # Load embedding model if not loaded
131
- if not hasattr(self, 'embedding_model') or self.embedding_model is None:
132
- self.embedding_model = SentenceTransformer(self.embedding_model_name)
133
-
134
- # Process chunks in batches
135
- batch_size = 100
136
- progress_bar = st.progress(0)
137
- status_text = st.empty()
138
-
139
- for i in range(0, len(chunks), batch_size):
140
- batch_chunks = chunks[i:i + batch_size]
141
-
142
- # Prepare data
143
- texts = [chunk['page_content'] for chunk in batch_chunks]
144
- metadatas = []
145
-
146
- for chunk in batch_chunks:
147
- metadata = {
148
- 'url': chunk['metadata']['url'],
149
- 'chunk_index': str(chunk['metadata']['chunk_index']),
150
- 'source': chunk['metadata'].get('source', 'scikit-learn-docs'),
151
- 'content_length': str(len(chunk['page_content']))
152
- }
153
- metadatas.append(metadata)
154
-
155
- # Create embeddings
156
- embeddings = self.embedding_model.encode(texts).tolist()
157
-
158
- # Generate IDs
159
- ids = [f"chunk_{i+j}" for j in range(len(batch_chunks))]
160
-
161
- # Add to collection
162
- self.collection.add(
163
- ids=ids,
164
- documents=texts,
165
- metadatas=metadatas,
166
- embeddings=embeddings
167
- )
168
-
169
- # Update progress
170
- progress = (i + batch_size) / len(chunks)
171
- progress_bar.progress(min(progress, 1.0))
172
- status_text.text(f"Processing chunks: {min(i + batch_size, len(chunks))}/{len(chunks)}")
173
-
174
- progress_bar.empty()
175
- status_text.empty()
176
- st.success(f"✅ Successfully rebuilt collection with {len(chunks)} chunks!")
177
-
178
- except Exception as e:
179
- st.error(f"❌ Failed to rebuild collection: {e}")
180
- raise
181
-
182
- def set_openai_client(self, api_key: str) -> bool:
183
- """
184
- Initialize OpenAI client with API key.
185
-
186
- Args:
187
- api_key (str): OpenAI API key
188
-
189
- Returns:
190
- bool: True if successful, False otherwise
191
- """
192
- try:
193
- self.openai_client = OpenAI(api_key=api_key)
194
-
195
- # Test the API key with a simple request
196
- self.openai_client.models.list()
197
-
198
- logger.info("OpenAI client initialized successfully")
199
- return True
200
-
201
- except Exception as e:
202
- logger.error(f"Failed to initialize OpenAI client: {e}")
203
- st.error(f"Invalid API key or OpenAI connection error: {e}")
204
- return False
205
-
206
- def retrieve_relevant_chunks(
207
- self,
208
- query: str,
209
- n_results: int = 3,
210
- min_relevance_score: float = 0.1
211
- ) -> List[Dict[str, Any]]:
212
- """
213
- Retrieve relevant text chunks from the vector database.
214
-
215
- Args:
216
- query (str): User question/query
217
- n_results (int): Number of chunks to retrieve
218
- min_relevance_score (float): Minimum relevance score threshold
219
-
220
- Returns:
221
- List[Dict[str, Any]]: Retrieved chunks with content and metadata
222
- """
223
- try:
224
- # Query the collection
225
- results = self.collection.query(
226
- query_texts=[query],
227
- n_results=n_results
228
- )
229
-
230
- retrieved_chunks = []
231
-
232
- # Process results
233
- if results['documents'] and results['documents'][0]:
234
- for i in range(len(results['documents'][0])):
235
- chunk_data = {
236
- 'content': results['documents'][0][i],
237
- 'metadata': results['metadatas'][0][i],
238
- 'distance': results['distances'][0][i] if 'distances' in results else None
239
- }
240
-
241
- # Filter by relevance score if available
242
- if chunk_data['distance'] is None or chunk_data['distance'] >= min_relevance_score:
243
- retrieved_chunks.append(chunk_data)
244
-
245
- logger.info(f"Retrieved {len(retrieved_chunks)} relevant chunks for query: {query[:50]}...")
246
- return retrieved_chunks
247
-
248
- except Exception as e:
249
- logger.error(f"Error retrieving chunks: {e}")
250
- st.error(f"Error during retrieval: {e}")
251
- return []
252
-
253
- def create_rag_prompt(
254
- self,
255
- user_question: str,
256
- retrieved_chunks: List[Dict[str, Any]]
257
- ) -> str:
258
- """
259
- Create an augmented prompt for OpenAI with retrieved context.
260
-
261
- Args:
262
- user_question (str): Original user question
263
- retrieved_chunks (List[Dict[str, Any]]): Retrieved relevant chunks
264
-
265
- Returns:
266
- str: Augmented prompt for OpenAI
267
- """
268
- # Build context from retrieved chunks
269
- context_parts = []
270
-
271
- for i, chunk in enumerate(retrieved_chunks, 1):
272
- url = chunk['metadata'].get('url', 'Unknown source')
273
- content = chunk['content'].strip()
274
-
275
- context_part = f"--- Context {i} (Source: {url}) ---\n{content}\n"
276
- context_parts.append(context_part)
277
-
278
- context = "\n".join(context_parts)
279
-
280
- # Create the RAG prompt
281
- rag_prompt = f"""You are an expert AI assistant specializing in Scikit-learn, a popular Python machine learning library. Your task is to answer questions about Scikit-learn based ONLY on the provided context from the official documentation.
282
-
283
- CONTEXT:
284
- {context}
285
-
286
- USER QUESTION:
287
- {user_question}
288
-
289
- INSTRUCTIONS:
290
- 1. Answer the question using ONLY the information provided in the context above
291
- 2. Be accurate, helpful, and specific
292
- 3. If the context doesn't contain enough information to fully answer the question, say so clearly
293
- 4. Include relevant code examples if they appear in the context
294
- 5. Mention specific function names, class names, or parameter names when relevant
295
- 6. Structure your answer clearly with appropriate formatting
296
-
297
- ANSWER:"""
298
-
299
- return rag_prompt
300
-
301
- def generate_answer(
302
- self,
303
- prompt: str,
304
- model: str = "gpt-3.5-turbo",
305
- max_tokens: int = 1000,
306
- temperature: float = 0.1
307
- ) -> Optional[str]:
308
- """
309
- Generate answer using OpenAI API.
310
-
311
- Args:
312
- prompt (str): Augmented prompt with context
313
- model (str): OpenAI model to use
314
- max_tokens (int): Maximum tokens in response
315
- temperature (float): Temperature for generation
316
-
317
- Returns:
318
- Optional[str]: Generated answer or None if failed
319
- """
320
- try:
321
- response = self.openai_client.chat.completions.create(
322
- model=model,
323
- messages=[
324
- {
325
- "role": "system",
326
- "content": "You are a helpful AI assistant specializing in Scikit-learn documentation. Provide accurate, helpful answers based only on the provided context."
327
- },
328
- {
329
- "role": "user",
330
- "content": prompt
331
- }
332
- ],
333
- max_tokens=max_tokens,
334
- temperature=temperature,
335
- top_p=0.9
336
- )
337
-
338
- answer = response.choices[0].message.content.strip()
339
- logger.info(f"Generated answer of length: {len(answer)}")
340
- return answer
341
-
342
- except Exception as e:
343
- logger.error(f"Error generating answer: {e}")
344
- st.error(f"Error generating answer: {e}")
345
- return None
346
-
347
- def get_answer(
348
- self,
349
- user_question: str,
350
- n_chunks: int = 3,
351
- model: str = "gpt-3.5-turbo"
352
- ) -> Tuple[Optional[str], List[str]]:
353
- """
354
- Complete RAG pipeline: retrieve, augment, generate.
355
-
356
- Args:
357
- user_question (str): User's question
358
- n_chunks (int): Number of chunks to retrieve
359
- model (str): OpenAI model to use
360
-
361
- Returns:
362
- Tuple[Optional[str], List[str]]: Generated answer and source URLs
363
- """
364
- if not self.openai_client:
365
- st.error("OpenAI client not initialized. Please provide a valid API key.")
366
- return None, []
367
-
368
- # Step 1: Retrieve relevant chunks
369
- with st.spinner("🔍 Searching relevant documentation..."):
370
- retrieved_chunks = self.retrieve_relevant_chunks(user_question, n_chunks)
371
-
372
- if not retrieved_chunks:
373
- return "I couldn't find relevant information in the Scikit-learn documentation to answer your question. Please try rephrasing your question or ask about a different topic.", []
374
-
375
- # Step 2: Create augmented prompt
376
- with st.spinner("📝 Preparing context..."):
377
- rag_prompt = self.create_rag_prompt(user_question, retrieved_chunks)
378
-
379
- # Step 3: Generate answer
380
- with st.spinner("🤖 Generating answer..."):
381
- answer = self.generate_answer(rag_prompt, model)
382
-
383
- # Extract source URLs
384
- source_urls = [chunk['metadata'].get('url', 'Unknown') for chunk in retrieved_chunks]
385
- source_urls = list(dict.fromkeys(source_urls)) # Remove duplicates while preserving order
386
-
387
- return answer, source_urls
388
-
389
-
390
- def initialize_session_state():
391
- """Initialize Streamlit session state variables."""
392
- if 'chatbot' not in st.session_state:
393
- try:
394
- # Show initialization message
395
- init_placeholder = st.empty()
396
- init_placeholder.info("🔄 Initializing RAG system...")
397
-
398
- st.session_state.chatbot = RAGChatbot()
399
- init_placeholder.empty()
400
-
401
- except Exception as e:
402
- st.error(f"❌ Failed to initialize chatbot: {e}")
403
-
404
- # Provide helpful instructions
405
- st.markdown("""
406
- ### 🔧 Troubleshooting
407
-
408
- This error typically occurs when:
409
- 1. **First deployment**: The database hasn't been built yet
410
- 2. **Missing files**: Required data files are not available
411
-
412
- ### 📋 Required Files
413
- Make sure these files are present:
414
- - `chunks.json` (processed text chunks)
415
- - `chroma.sqlite3` (database file) OR `chroma_db/` directory
416
-
417
- ### 🚀 Quick Fix for Hugging Face Spaces
418
- If you're running this on Hugging Face Spaces, make sure you've uploaded:
419
- 1. All Python files (`app.py`, `build_vector_db.py`, etc.)
420
- 2. Data files (`chunks.json`, `scraped_content.json`)
421
- 3. Database files (`chroma.sqlite3` or the `chroma_db/` folder)
422
- """)
423
- st.stop()
424
-
425
- if 'openai_initialized' not in st.session_state:
426
- st.session_state.openai_initialized = False
427
-
428
- if 'chat_history' not in st.session_state:
429
- st.session_state.chat_history = []
430
-
431
-
432
- def main():
433
- """Main Streamlit application."""
434
-
435
- # Page configuration
436
- st.set_page_config(
437
- page_title="Scikit-learn Q&A Bot",
438
- page_icon="🤖",
439
- layout="wide",
440
- initial_sidebar_state="expanded"
441
- )
442
-
443
- # Initialize session state
444
- initialize_session_state()
445
-
446
- # Main title and description
447
- st.title("🤖 Scikit-learn Documentation Q&A Bot")
448
-
449
- # Show database status
450
- try:
451
- collection_count = st.session_state.chatbot.collection.count()
452
- st.success(f"✅ Database ready with {collection_count:,} documentation chunks")
453
- except:
454
- st.warning("⚠️ Database status unknown")
455
-
456
- st.markdown("""
457
- Welcome to the **Scikit-learn Documentation Q&A Bot**! This intelligent assistant can answer your questions about Scikit-learn using the official documentation.
458
-
459
- **How it works:**
460
- 1. 🔍 **Retrieval**: Searches through 1,249+ documentation chunks
461
- 2. 📝 **Augmentation**: Provides relevant context to the AI
462
- 3. 🤖 **Generation**: Uses OpenAI to generate accurate answers
463
-
464
- **👈 To get started**: Enter your OpenAI API key in the sidebar!
465
- """)
466
-
467
- # Sidebar for API key and settings
468
- with st.sidebar:
469
- st.header("⚙️ Configuration")
470
-
471
- # OpenAI API Key input
472
- api_key = st.text_input(
473
- "🔑 OpenAI API Key",
474
- type="password",
475
- placeholder="sk-...",
476
- help="Enter your OpenAI API key to enable the chatbot"
477
- )
478
-
479
- if api_key and not st.session_state.openai_initialized:
480
- if st.session_state.chatbot.set_openai_client(api_key):
481
- st.session_state.openai_initialized = True
482
- st.success("✅ API key validated!")
483
- st.rerun()
484
-
485
- # Model selection
486
- model = st.selectbox(
487
- "🧠 AI Model",
488
- ["gpt-3.5-turbo", "gpt-4", "gpt-4-turbo-preview"],
489
- index=0,
490
- help="Choose the OpenAI model for generating answers"
491
- )
492
-
493
- # Number of context chunks
494
- n_chunks = st.slider(
495
- "📄 Context Chunks",
496
- min_value=1,
497
- max_value=5,
498
- value=3,
499
- help="Number of relevant documentation chunks to use for context"
500
- )
501
-
502
- st.markdown("---")
503
-
504
- # Database info
505
- st.header("📊 Database Info")
506
- try:
507
- collection_count = st.session_state.chatbot.collection.count()
508
- st.metric("Total Documents", f"{collection_count:,}")
509
- st.metric("Embedding Model", "all-MiniLM-L6-v2")
510
- st.metric("Vector Dimensions", "384")
511
- except:
512
- st.error("Could not load database info")
513
-
514
- st.markdown("---")
515
-
516
- # Clear chat history
517
- if st.button("🗑️ Clear Chat History"):
518
- st.session_state.chat_history = []
519
- st.rerun()
520
-
521
- # Main chat interface
522
- col1, col2 = st.columns([2, 1])
523
-
524
- with col1:
525
- st.header("💬 Ask Your Question")
526
-
527
- # Question input
528
- default_question = st.session_state.get('selected_question', '')
529
- user_question = st.text_input(
530
- "Enter your question about Scikit-learn:",
531
- value=default_question,
532
- placeholder="e.g., How do I perform cross-validation in scikit-learn?",
533
- key="question_input"
534
- )
535
-
536
- # Clear selected question after using it
537
- if 'selected_question' in st.session_state:
538
- del st.session_state['selected_question']
539
-
540
- # Submit button
541
- submit_button = st.button("🚀 Get Answer", type="primary")
542
-
543
- # Process question
544
- if submit_button and user_question:
545
- if not st.session_state.openai_initialized:
546
- st.error("⚠️ Please enter a valid OpenAI API key in the sidebar first.")
547
- else:
548
- # Get answer using RAG
549
- answer, sources = st.session_state.chatbot.get_answer(
550
- user_question, n_chunks, model
551
- )
552
-
553
- if answer:
554
- # Add to chat history
555
- st.session_state.chat_history.append({
556
- 'question': user_question,
557
- 'answer': answer,
558
- 'sources': sources
559
- })
560
-
561
- # Clear input
562
- st.rerun()
563
-
564
- # Display chat history
565
- if st.session_state.chat_history:
566
- st.header("📝 Chat History")
567
-
568
- for i, chat in enumerate(reversed(st.session_state.chat_history)):
569
- with st.expander(f"Q: {chat['question'][:60]}...", expanded=(i == 0)):
570
- st.markdown(f"**Question:** {chat['question']}")
571
- st.markdown(f"**Answer:**\n{chat['answer']}")
572
-
573
- if chat['sources']:
574
- st.markdown("**Sources:**")
575
- for j, source in enumerate(chat['sources'], 1):
576
- source_name = source.split('/')[-1] if '/' in source else source
577
- st.markdown(f"{j}. [{source_name}]({source})")
578
-
579
- with col2:
580
- st.header("💡 Example Questions")
581
-
582
- example_questions = [
583
- "How do I perform cross-validation in scikit-learn?",
584
- "What is the difference between Ridge and Lasso regression?",
585
- "How do I use GridSearchCV for parameter tuning?",
586
- "What clustering algorithms are available in scikit-learn?",
587
- "How do I preprocess data using StandardScaler?",
588
- "What is the difference between classification and regression?",
589
- "How do I handle missing values in my dataset?",
590
- "What is feature selection and how do I use it?",
591
- "How do I visualize decision trees?",
592
- "What is ensemble learning in scikit-learn?"
593
- ]
594
-
595
- for question in example_questions:
596
- if st.button(question, key=f"example_{hash(question)}"):
597
- # Use a different approach to set the question
598
- st.session_state['selected_question'] = question
599
- st.rerun()
600
-
601
- st.markdown("---")
602
-
603
- st.header("ℹ️ Tips")
604
- st.markdown("""
605
- **For best results:**
606
- - Be specific in your questions
607
- - Ask about scikit-learn functionality
608
- - Include context when possible
609
- - Check the sources for verification
610
-
611
- **The bot can help with:**
612
- - API usage and parameters
613
- - Algorithm explanations
614
- - Code examples
615
- - Best practices
616
- - Troubleshooting
617
- """)
618
-
619
-
620
- if __name__ == "__main__":
621
- main()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app_hf.py DELETED
File without changes
chroma_db/chroma.sqlite3 CHANGED
@@ -1,3 +1,3 @@
1
  version https://git-lfs.github.com/spec/v1
2
- oid sha256:9b2ea1d7cd9a55d50c44e113c9160a4c759fdbe3f2912d3770d89fda8b8cd1fb
3
  size 13279232
 
1
  version https://git-lfs.github.com/spec/v1
2
+ oid sha256:58b93c87e29c6b2a74e2b9bf0d13b8a76878037325a1fb5cfbb1886bc2068e68
3
  size 13279232
run.py DELETED
File without changes