Spaces:
Runtime error
Runtime error
Update app.py
Browse files
app.py
CHANGED
@@ -9,8 +9,7 @@ embed_model = HuggingFaceEmbeddings(model_name="mixedbread-ai/mxbai-embed-large-
|
|
9 |
|
10 |
import pandas as pd
|
11 |
|
12 |
-
|
13 |
-
folder_path = "/content/drive/MyDrive/Ijwi_folder"
|
14 |
context_data = []
|
15 |
|
16 |
# List all files in the folder
|
@@ -52,9 +51,7 @@ def extract_text_from_pdf(pdf_path):
|
|
52 |
print(f"Error extracting text from {pdf_path}: {e}")
|
53 |
return ""
|
54 |
|
55 |
-
|
56 |
-
folder_path ="/content/drive/MyDrive/Ijwi_folder" # Update with your actual folder path
|
57 |
-
|
58 |
# Initialize the list to hold the extracted text chunks
|
59 |
text_chunks = []
|
60 |
|
@@ -257,9 +254,11 @@ vectorstore.get().keys()
|
|
257 |
vectorstore.add_texts(data)
|
258 |
|
259 |
|
|
|
260 |
|
261 |
|
262 |
|
|
|
263 |
|
264 |
from openai import OpenAI
|
265 |
from langchain_core.prompts import PromptTemplate
|
@@ -269,115 +268,292 @@ import gradio as gr
|
|
269 |
from typing import Iterator
|
270 |
import time
|
271 |
|
272 |
-
|
273 |
-
# Template with user personalization and improved welcome message
|
274 |
template = ("""
|
275 |
-
You are a friendly and
|
276 |
-
|
277 |
-
1. **
|
278 |
-
-
|
279 |
-
-
|
280 |
-
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
-
|
285 |
-
-
|
286 |
-
-
|
287 |
-
|
288 |
-
3. **
|
289 |
-
-
|
290 |
-
-
|
291 |
-
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
-
|
|
|
|
|
|
|
|
|
|
|
297 |
* Respond politely: "I don't have that information at the moment, {first_name}. 😊"
|
298 |
-
* Offer alternative assistance options
|
299 |
-
- Strictly avoid generating unsupported content
|
300 |
-
- Prevent information padding or speculation
|
301 |
|
302 |
-
|
303 |
- If the user asks for a link related to their request `{question}`, extract the most relevant URL from `{context}` and provide it directly.
|
304 |
- Example response:
|
305 |
-
- "Here is the link you requested,
|
306 |
|
307 |
-
|
308 |
-
- Acknowledge current context when appropriate
|
309 |
-
- Stay focused on user's immediate needs
|
310 |
-
- If this is the first message, always ask how the user is feeling and what they would like help with today
|
311 |
|
|
|
312 |
**Context:** {context}
|
313 |
**User's Question:** {question}
|
314 |
-
**
|
315 |
-
**Is First Message:** {is_first_message}
|
316 |
-
**Your Response:**
|
317 |
""")
|
318 |
|
|
|
319 |
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
|
327 |
class OpenRouterLLM:
|
328 |
-
def __init__(self,
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
|
|
|
|
|
|
339 |
def stream(self, prompt: str) -> Iterator[str]:
|
340 |
try:
|
341 |
completion = self.client.chat.completions.create(
|
342 |
-
extra_headers=self.headers,
|
343 |
model="deepseek/deepseek-r1-distill-llama-70b:free",
|
344 |
-
#model="google/gemini-2.0-flash-thinking-exp:free",
|
345 |
messages=[{"role": "user", "content": prompt}],
|
346 |
stream=True
|
347 |
)
|
348 |
-
|
349 |
for chunk in completion:
|
350 |
-
|
351 |
-
|
|
|
352 |
except Exception as e:
|
353 |
-
yield f"
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
|
358 |
class UserSession:
|
359 |
def __init__(self):
|
360 |
self.current_user = None
|
361 |
-
self.
|
362 |
|
363 |
def set_user(self, user_info):
|
364 |
self.current_user = user_info
|
365 |
-
self.
|
366 |
|
367 |
def get_user(self):
|
368 |
return self.current_user
|
369 |
|
370 |
-
def
|
371 |
-
self.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
372 |
|
373 |
-
def
|
374 |
-
return self.
|
375 |
|
376 |
-
# Initialize session
|
377 |
user_session = UserSession()
|
378 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
379 |
|
|
|
|
|
380 |
|
|
|
381 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
382 |
|
383 |
-
|
|
|
|
|
|
9 |
|
10 |
import pandas as pd
|
11 |
|
12 |
+
folder_path = "./"
|
|
|
13 |
context_data = []
|
14 |
|
15 |
# List all files in the folder
|
|
|
51 |
print(f"Error extracting text from {pdf_path}: {e}")
|
52 |
return ""
|
53 |
|
54 |
+
folder_path = "./"
|
|
|
|
|
55 |
# Initialize the list to hold the extracted text chunks
|
56 |
text_chunks = []
|
57 |
|
|
|
254 |
vectorstore.add_texts(data)
|
255 |
|
256 |
|
257 |
+
api= os.environ.get('V1')
|
258 |
|
259 |
|
260 |
|
261 |
+
|
262 |
|
263 |
from openai import OpenAI
|
264 |
from langchain_core.prompts import PromptTemplate
|
|
|
268 |
from typing import Iterator
|
269 |
import time
|
270 |
|
271 |
+
# Refined Template with Emotional Awareness
|
|
|
272 |
template = ("""
|
273 |
+
You are a friendly and empathetic chatbot designed to assist users in a conversational and human-like manner. Your goal is to provide accurate, helpful, and emotionally supportive responses based on the provided context: {context}. Follow these guidelines:
|
274 |
+
|
275 |
+
1. **Emotional Awareness**
|
276 |
+
- Acknowledge the user's emotions and respond with empathy.
|
277 |
+
- Use phrases like "I understand how you feel," "That sounds challenging," or "I'm here to support you."
|
278 |
+
- If the user expresses negative emotions, offer comfort and reassurance.
|
279 |
+
|
280 |
+
2. **Contextual Interaction**
|
281 |
+
- Begin with a warm and empathetic welcome message.
|
282 |
+
- Extract precise details from the provided context: {context}.
|
283 |
+
- Respond directly to the user's question: {question}.
|
284 |
+
- Remember the user's name is {first_name}.
|
285 |
+
|
286 |
+
3. **Communication Guidelines**
|
287 |
+
- Maintain a warm, conversational tone.
|
288 |
+
- Use occasional emojis for engagement (e.g., 😊, 🤗, ❤️).
|
289 |
+
- Provide clear, concise, and emotionally supportive information.
|
290 |
+
|
291 |
+
4. **Response Strategies**
|
292 |
+
- Greet users naturally and ask about their wellbeing (e.g., "Welcome, {first_name}! 😊 How are you feeling today?", "Hello {first_name}! 🤗 What's on your mind?").
|
293 |
+
- Always start with a check-in about the user's wellbeing or current situation.
|
294 |
+
- Deliver only relevant information.
|
295 |
+
- Avoid generating content beyond the context.
|
296 |
+
- Handle missing information transparently.
|
297 |
+
|
298 |
+
5. **No Extra Content**
|
299 |
+
- If no information matches the user's request:
|
300 |
* Respond politely: "I don't have that information at the moment, {first_name}. 😊"
|
301 |
+
* Offer alternative assistance options.
|
302 |
+
- Strictly avoid generating unsupported content.
|
303 |
+
- Prevent information padding or speculation.
|
304 |
|
305 |
+
6. **Extracting Relevant Links**
|
306 |
- If the user asks for a link related to their request `{question}`, extract the most relevant URL from `{context}` and provide it directly.
|
307 |
- Example response:
|
308 |
+
- "Here is the link you requested, [URL]"
|
309 |
|
310 |
+
7. **Real-Time Awareness**
|
311 |
+
- Acknowledge the current context when appropriate.
|
312 |
+
- Stay focused on the user's immediate needs.
|
313 |
+
- If this is the first message, always ask how the user is feeling and what they would like help with today.
|
314 |
|
315 |
+
|
316 |
**Context:** {context}
|
317 |
**User's Question:** {question}
|
318 |
+
**Your Response:**
|
|
|
|
|
319 |
""")
|
320 |
|
321 |
+
rag_prompt = PromptTemplate.from_template(template)
|
322 |
|
323 |
+
retriever = vectorstore.as_retriever()
|
|
|
|
|
|
|
|
|
|
|
324 |
|
325 |
class OpenRouterLLM:
|
326 |
+
def __init__(self, key: str):
|
327 |
+
try:
|
328 |
+
self.client = OpenAI(
|
329 |
+
base_url="https://openrouter.ai/api/v1",
|
330 |
+
api_key=key # Corrected from `key=getmod`
|
331 |
+
)
|
332 |
+
self.headers = {
|
333 |
+
"HTTP-Referer": "http://localhost:3000",
|
334 |
+
"X-Title": "Local Development"
|
335 |
+
}
|
336 |
+
except Exception as e:
|
337 |
+
print(f"Initialization error: {e}")
|
338 |
+
raise
|
339 |
+
|
340 |
def stream(self, prompt: str) -> Iterator[str]:
|
341 |
try:
|
342 |
completion = self.client.chat.completions.create(
|
|
|
343 |
model="deepseek/deepseek-r1-distill-llama-70b:free",
|
|
|
344 |
messages=[{"role": "user", "content": prompt}],
|
345 |
stream=True
|
346 |
)
|
347 |
+
|
348 |
for chunk in completion:
|
349 |
+
delta = chunk.choices[0].delta
|
350 |
+
if hasattr(delta, "content") and delta.content:
|
351 |
+
yield delta.content
|
352 |
except Exception as e:
|
353 |
+
yield f"Streaming error: {str(e)}"
|
|
|
|
|
|
|
354 |
|
355 |
class UserSession:
|
356 |
def __init__(self):
|
357 |
self.current_user = None
|
358 |
+
self.welcome_message = None
|
359 |
|
360 |
def set_user(self, user_info):
|
361 |
self.current_user = user_info
|
362 |
+
self.set_welcome_message(user_info.get("first_name", "Guest"))
|
363 |
|
364 |
def get_user(self):
|
365 |
return self.current_user
|
366 |
|
367 |
+
def set_welcome_message(self, first_name):
|
368 |
+
self.welcome_message = (
|
369 |
+
f"<div style='font-size: 18px; font-weight: bold; color: #2E86C1;'>"
|
370 |
+
f"Welcome {first_name}! 👋</div>"
|
371 |
+
f"<div style='font-size: 14px; color: #34495E;'>"
|
372 |
+
f"We appreciate you reaching out to us. You are in a safe and trusted space designed to support you. "
|
373 |
+
f"Here, you can find guidance on gender-based violence (GBV) and legal assistance.<br><br>"
|
374 |
+
f"You don’t have to go through this alone—we are here to listen, support, and help you find the right solutions. "
|
375 |
+
f"You deserve to be heard and helped, and we are committed to standing by your side."
|
376 |
+
f"</div>"
|
377 |
+
)
|
378 |
|
379 |
+
def get_welcome_message(self):
|
380 |
+
return self.welcome_message
|
381 |
|
382 |
+
# Initialize session
|
383 |
user_session = UserSession()
|
384 |
|
385 |
+
# Store user details and handle session
|
386 |
+
def collect_user_info(first_name, last_name, phone):
|
387 |
+
if not first_name or not last_name or not phone:
|
388 |
+
return "All fields are required to proceed.", gr.update(visible=False), gr.update(visible=True), []
|
389 |
+
|
390 |
+
# Validate phone number (basic validation)
|
391 |
+
if not phone.replace("+", "").replace("-", "").replace(" ", "").isdigit():
|
392 |
+
return "Please enter a valid phone number.", gr.update(visible=False), gr.update(visible=True), []
|
393 |
+
|
394 |
+
# Store user info for chat session
|
395 |
+
user_info = {
|
396 |
+
"first_name": first_name,
|
397 |
+
"last_name": last_name,
|
398 |
+
"phone": phone,
|
399 |
+
"timestamp": time.strftime("%Y-%m-%d %H:%M:%S")
|
400 |
+
}
|
401 |
+
|
402 |
+
# Set user in session
|
403 |
+
user_session.set_user(user_info)
|
404 |
+
|
405 |
+
# Generate welcome message
|
406 |
+
welcome_message = user_session.get_welcome_message()
|
407 |
+
|
408 |
+
# Add initial message to start the conversation
|
409 |
+
chat_history = add_initial_message([(None, welcome_message)])
|
410 |
+
|
411 |
+
# Return welcome message and update UI
|
412 |
+
return welcome_message, gr.update(visible=True), gr.update(visible=False), chat_history
|
413 |
+
|
414 |
+
# Add initial message to start the conversation
|
415 |
+
def add_initial_message(chatbot):
|
416 |
+
initial_message = (
|
417 |
+
"<div style='font-size: 14px; font-weight: normal; color: #16A085;'>"
|
418 |
+
f"I just want to check in and see how you are doing."
|
419 |
+
f"If you are going through something, please know you are not alone, I am here for you, no matter what.🤗"
|
420 |
+
"</div>"
|
421 |
+
)
|
422 |
+
return chatbot + [(None, initial_message)]
|
423 |
+
|
424 |
+
# Create RAG chain with user context
|
425 |
+
def create_rag_chain(retriever, template, api_key):
|
426 |
+
llm = OpenRouterLLM(api_key)
|
427 |
+
rag_prompt = PromptTemplate.from_template(template)
|
428 |
+
|
429 |
+
def stream_func(input_dict):
|
430 |
+
# Get context using the retriever's invoke method
|
431 |
+
context = retriever.invoke(input_dict["question"])
|
432 |
+
context_str = "\n".join([doc.page_content for doc in context])
|
433 |
+
|
434 |
+
# Get user info from the session
|
435 |
+
user_info = user_session.get_user() or {}
|
436 |
+
first_name = user_info.get("first_name", "User")
|
437 |
+
|
438 |
+
# Format prompt with user context
|
439 |
+
prompt = rag_prompt.format(
|
440 |
+
context=context_str,
|
441 |
+
question=input_dict["question"],
|
442 |
+
first_name=first_name
|
443 |
+
)
|
444 |
|
445 |
+
# Stream response
|
446 |
+
return llm.stream(prompt)
|
447 |
|
448 |
+
return stream_func
|
449 |
|
450 |
+
def rag_memory_stream(message, history):
|
451 |
+
# Initialize with empty response
|
452 |
+
partial_text = ""
|
453 |
+
|
454 |
+
# Get user context
|
455 |
+
user_info = user_session.get_user()
|
456 |
+
|
457 |
+
# Use the rag_chain with the question
|
458 |
+
for new_text in rag_chain({"question": message}):
|
459 |
+
partial_text += new_text
|
460 |
+
yield partial_text
|
461 |
+
|
462 |
+
# Gradio Interface Setup with improved UX
|
463 |
+
def chatbot_interface():
|
464 |
+
# Get API key (in a real application, handle this more securely)
|
465 |
+
api_key = api # This should be properly defined or imported elsewhere
|
466 |
+
|
467 |
+
# Create the RAG chain with user context
|
468 |
+
global rag_chain
|
469 |
+
rag_chain = create_rag_chain(retriever, template, api_key)
|
470 |
+
|
471 |
+
# Create theme
|
472 |
+
theme = gr.themes.Soft(
|
473 |
+
primary_hue="indigo",
|
474 |
+
secondary_hue="blue",
|
475 |
+
)
|
476 |
+
|
477 |
+
with gr.Blocks(theme=theme, css="""
|
478 |
+
.welcome-container {
|
479 |
+
text-align: center;
|
480 |
+
margin-bottom: 20px;
|
481 |
+
padding: 20px;
|
482 |
+
border-radius: 10px;
|
483 |
+
background-color: #f0f4ff;
|
484 |
+
}
|
485 |
+
.feedback-btn { margin-top: 10px; }
|
486 |
+
footer { margin-top: 30px; text-align: center; }
|
487 |
+
""") as demo:
|
488 |
+
# Welcome banner
|
489 |
+
gr.Markdown("# 🤖 Ijwi ry'Ubufasha - Your AI Assistant", elem_classes=["welcome-container"])
|
490 |
+
|
491 |
+
# User registration section
|
492 |
+
registration_container = gr.Column(visible=True)
|
493 |
+
with registration_container:
|
494 |
+
gr.Markdown("### Please provide your details to start chatting")
|
495 |
+
|
496 |
+
with gr.Row():
|
497 |
+
first_name = gr.Textbox(
|
498 |
+
label="First Name",
|
499 |
+
placeholder="Enter your first name",
|
500 |
+
scale=1
|
501 |
+
)
|
502 |
+
last_name = gr.Textbox(
|
503 |
+
label="Last Name",
|
504 |
+
placeholder="Enter your last name",
|
505 |
+
scale=1
|
506 |
+
)
|
507 |
+
|
508 |
+
phone = gr.Textbox(
|
509 |
+
label="Phone Number",
|
510 |
+
placeholder="Enter your phone number (e.g., +250...)",
|
511 |
+
)
|
512 |
+
|
513 |
+
with gr.Row():
|
514 |
+
submit_btn = gr.Button("Start Chatting", variant="primary", scale=2)
|
515 |
+
|
516 |
+
response_message = gr.Markdown(elem_id="welcome-message")
|
517 |
+
|
518 |
+
# Chatbot section (initially hidden)
|
519 |
+
chatbot_container = gr.Column(visible=False)
|
520 |
+
with chatbot_container:
|
521 |
+
chat_interface = gr.ChatInterface(
|
522 |
+
fn=rag_memory_stream,
|
523 |
+
title="🤖 Help Chatbot",
|
524 |
+
fill_height=True,
|
525 |
+
theme=theme
|
526 |
+
)
|
527 |
+
|
528 |
+
# Feedback buttons
|
529 |
+
with gr.Row():
|
530 |
+
feedback_label = gr.Markdown("### Was this conversation helpful?")
|
531 |
+
|
532 |
+
with gr.Row():
|
533 |
+
thumbs_up = gr.Button("👍 Yes, it was helpful", elem_classes=["feedback-btn"])
|
534 |
+
thumbs_down = gr.Button("👎 No, it needs improvement", elem_classes=["feedback-btn"])
|
535 |
+
|
536 |
+
# Footer with version info
|
537 |
+
gr.Markdown("Ijwi ry'Ubufasha v1.0.0 © 2025", elem_id="footer")
|
538 |
+
|
539 |
+
# Handle user registration
|
540 |
+
submit_btn.click(
|
541 |
+
collect_user_info,
|
542 |
+
inputs=[first_name, last_name, phone],
|
543 |
+
outputs=[response_message, chatbot_container, registration_container, chat_interface.chatbot]
|
544 |
+
)
|
545 |
+
|
546 |
+
# Handle feedback (placeholder functionality)
|
547 |
+
def record_feedback(feedback_type):
|
548 |
+
# Here you could log feedback to a file or database
|
549 |
+
feedback_message = f"Thank you for your feedback! We'll use it to improve our service."
|
550 |
+
return feedback_message
|
551 |
+
|
552 |
+
thumbs_up.click(lambda: record_feedback("positive"), outputs=feedback_label)
|
553 |
+
thumbs_down.click(lambda: record_feedback("negative"), outputs=feedback_label)
|
554 |
+
|
555 |
+
return demo
|
556 |
|
557 |
+
if __name__ == "__main__":
|
558 |
+
# Launch the interface
|
559 |
+
chatbot_interface().launch(share=True, inbrowser=True)
|