UKURIKIYEYEZU commited on
Commit
05b59ed
·
verified ·
1 Parent(s): 68f4004

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +251 -75
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
- # Set folder path
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
- # Folder containing the PDFs
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 intelligent chatbot designed to assist users in a conversational and human-like manner. Your goal is to provide accurate, helpful, and engaging responses based on the provided context: {context}. Follow these guidelines:
276
-
277
- 1. **Contextual Interaction**
278
- - Begin with a warm and empathetic welcome message
279
- - Extract precise details from provided context: {context}
280
- - Respond directly to user's question: {question}
281
- - Remember the user's name is {first_name} and address them by name occasionally not always
282
-
283
- 2. **Communication Guidelines**
284
- - Maintain warm, conversational tone
285
- - Use occasional emojis for engagement
286
- - Provide clear, concise information
287
-
288
- 3. **Response Strategies**
289
- - Greet users naturally and ask about their wellbeing (e.g., "Hello {first_name}! 😊 How are you feeling today?", "Welcome, {first_name}! 😊 You're in a safe and caring space. What's on your mind today?")
290
- - Always start with a check-in about the user's wellbeing or current situation
291
- - Deliver only relevant information
292
- - Avoid generating content beyond context
293
- - Handle missing information transparently
294
-
295
- 4. **No Extra Content**
296
- - If no information matches user's request:
 
 
 
 
 
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
- 5. **Extracting Relevant Links**
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, {first_name}: [URL]"
306
 
307
- 6. **Real-Time Awareness**
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
- **Welcome Message:** {welcome_message}
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, api_key: str):
329
- self.client = OpenAI(
330
- base_url="https://openrouter.ai/api/v1",
331
- api_key=api
332
- )
333
- self.headers = {
334
- "HTTP-Referer": "http://localhost:3000",
335
- "X-Title": "Local Development"
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
- if chunk.choices[0].delta.content is not None:
351
- yield chunk.choices[0].delta.content
 
352
  except Exception as e:
353
- yield f"Error: {str(e)}"
354
-
355
-
356
-
357
 
358
  class UserSession:
359
  def __init__(self):
360
  self.current_user = None
361
- self.is_first_message = True
362
 
363
  def set_user(self, user_info):
364
  self.current_user = user_info
365
- self.is_first_message = True
366
 
367
  def get_user(self):
368
  return self.current_user
369
 
370
- def mark_message_sent(self):
371
- self.is_first_message = False
 
 
 
 
 
 
 
 
 
372
 
373
- def is_first(self):
374
- return self.is_first_message
375
 
376
- # Initialize session and LLM
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)