Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| import os | |
| import requests | |
| import json | |
| # Simple RAG system for HuggingFace Spaces deployment | |
| class SimpleRAGChatbot: | |
| def __init__(self): | |
| # Restaurant policies data | |
| self.data_dict = { | |
| "refund_policy": """ | |
| Our refund policy is customer-friendly and straightforward: | |
| - Full refunds are available within 2 hours of ordering if the food hasn't been prepared | |
| - If you're unsatisfied with your meal, we offer a full refund or replacement | |
| - For delivered orders, refunds are processed within 3-5 business days | |
| - No questions asked policy - customer satisfaction is our priority | |
| - Special dietary restriction mix-ups receive immediate full refunds plus a $20 credit | |
| """, | |
| "privacy_policy": """ | |
| We take your privacy seriously at our restaurant: | |
| - We only collect necessary information: name, phone, email, and payment details | |
| - Your data is never sold or shared with third parties | |
| - We use your information only for order processing and customer service | |
| - You can request data deletion at any time by emailing [email protected] | |
| - We use encrypted payment processing and secure servers | |
| - Marketing emails are opt-in only and you can unsubscribe anytime | |
| """, | |
| "baby_policy": """ | |
| We absolutely welcome families with babies! | |
| - High chairs are available upon request (we have 12 high chairs) | |
| - Baby changing stations are available in both restrooms | |
| - We provide complimentary baby food heating service | |
| - Quiet family seating area is available in the back section | |
| - Baby bottles and sippy cups can be cleaned by our staff | |
| - We have a kids menu with healthy options for toddlers | |
| - No age restrictions - babies are welcome at all times | |
| """, | |
| "weekend_hours": """ | |
| Our weekend hours are designed for your convenience: | |
| - Friday: 11:00 AM - 11:00 PM (extended hours) | |
| - Saturday: 10:00 AM - 12:00 AM (brunch starts at 10 AM) | |
| - Sunday: 10:00 AM - 10:00 PM (brunch until 3 PM) | |
| - Weekend reservations are highly recommended | |
| - Happy hour on weekends: 3:00 PM - 6:00 PM | |
| - Late night menu available until 1 hour before closing | |
| - Takeout and delivery available during all operating hours | |
| """, | |
| "allergen_policy": """ | |
| We take food allergies very seriously: | |
| - Please inform staff of any allergies when ordering | |
| - We have detailed allergen information for all menu items | |
| - Separate prep areas for gluten-free orders | |
| - Nut-free options are clearly marked on the menu | |
| - We can accommodate most dietary restrictions with advance notice | |
| - Our staff is trained in allergen awareness and cross-contamination prevention | |
| - Emergency protocols in place for severe allergic reactions | |
| """, | |
| "reservation_policy": """ | |
| Making reservations is easy and recommended: | |
| - Reservations can be made online, by phone, or in person | |
| - We accept reservations up to 30 days in advance | |
| - Party size limit: 12 people (larger groups need special arrangements) | |
| - 15-minute grace period for late arrivals | |
| - Cancellations must be made at least 2 hours in advance | |
| - Weekend reservations during peak hours (6-8 PM) have a 90-minute time limit | |
| - Walk-ins are welcome but may have longer wait times | |
| """, | |
| "menu_highlights": """ | |
| Our signature dishes and popular items: | |
| - Wood-fired pizza made with organic ingredients | |
| - Fresh pasta made daily in-house | |
| - Sustainable seafood sourced locally | |
| - Vegan and vegetarian options available | |
| - Gluten-free pasta and pizza bases | |
| - Seasonal specials featuring local produce | |
| - Craft cocktails and local beer selection | |
| - Homemade desserts including our famous tiramisu | |
| """, | |
| "contact_delivery": """ | |
| Contact and delivery information: | |
| - Phone: (555) 123-4567 | |
| - Email: [email protected] | |
| - Address: 123 Main Street, Food City, FC 12345 | |
| - Delivery radius: 5 miles | |
| - Delivery fee: $3.99 (free over $30) | |
| - Delivery time: 30-45 minutes | |
| - We use DoorDash, UberEats, and our own delivery service | |
| - Online ordering available at our website | |
| """ | |
| } | |
| # Create keyword mappings for simple search | |
| self.keyword_mappings = { | |
| "refund": ["refund_policy"], | |
| "money": ["refund_policy"], | |
| "return": ["refund_policy"], | |
| "privacy": ["privacy_policy"], | |
| "data": ["privacy_policy"], | |
| "information": ["privacy_policy"], | |
| "baby": ["baby_policy"], | |
| "child": ["baby_policy"], | |
| "kid": ["baby_policy"], | |
| "family": ["baby_policy"], | |
| "weekend": ["weekend_hours"], | |
| "saturday": ["weekend_hours"], | |
| "sunday": ["weekend_hours"], | |
| "friday": ["weekend_hours"], | |
| "hours": ["weekend_hours"], | |
| "open": ["weekend_hours"], | |
| "time": ["weekend_hours"], | |
| "allergy": ["allergen_policy"], | |
| "allergic": ["allergen_policy"], | |
| "gluten": ["allergen_policy"], | |
| "nut": ["allergen_policy"], | |
| "reservation": ["reservation_policy"], | |
| "book": ["reservation_policy"], | |
| "table": ["reservation_policy"], | |
| "menu": ["menu_highlights"], | |
| "food": ["menu_highlights"], | |
| "dish": ["menu_highlights"], | |
| "pizza": ["menu_highlights"], | |
| "pasta": ["menu_highlights"], | |
| "contact": ["contact_delivery"], | |
| "phone": ["contact_delivery"], | |
| "address": ["contact_delivery"], | |
| "delivery": ["contact_delivery"], | |
| "order": ["contact_delivery"] | |
| } | |
| def search_documents(self, query): | |
| """Simple keyword-based search""" | |
| query_lower = query.lower() | |
| relevant_docs = set() | |
| # Check for keyword matches | |
| for keyword, doc_ids in self.keyword_mappings.items(): | |
| if keyword in query_lower: | |
| relevant_docs.update(doc_ids) | |
| # If no keyword matches, return most general documents | |
| if not relevant_docs: | |
| relevant_docs = {"menu_highlights", "contact_delivery", "weekend_hours"} | |
| # Return the matching documents | |
| results = [] | |
| for doc_id in relevant_docs: | |
| results.append({ | |
| 'id': doc_id, | |
| 'title': doc_id.replace('_', ' ').title(), | |
| 'content': self.data_dict[doc_id] | |
| }) | |
| return results | |
| def call_together_ai(self, prompt, context): | |
| """Call Together.ai API with context""" | |
| # Try multiple ways to get the API key | |
| api_key = ( | |
| os.getenv("TOGETHER_API_KEY") or | |
| os.getenv("TOGETHER_API_KEY_SECRET") or | |
| os.getenv("HF_TOKEN") or # Sometimes HF uses this | |
| None | |
| ) | |
| # If no API key, provide a smart fallback response | |
| if not api_key: | |
| return self.create_smart_fallback_response(prompt, context) | |
| url = "https://api.together.xyz/v1/chat/completions" | |
| headers = { | |
| "Authorization": f"Bearer {api_key}", | |
| "Content-Type": "application/json" | |
| } | |
| system_prompt = f"""You are a friendly and knowledgeable restaurant customer service assistant. | |
| Use the following context to answer questions about our restaurant policies, services, and offerings. | |
| Context: | |
| {context} | |
| Instructions: | |
| - Answer based on the provided context when possible | |
| - Be warm, friendly, and helpful | |
| - If the information isn't in the context, politely say so and offer to help in other ways | |
| - Keep responses conversational and informative | |
| - Use emojis appropriately to make responses more engaging | |
| """ | |
| data = { | |
| "model": "meta-llama/Llama-3.2-3B-Instruct-Turbo", | |
| "messages": [ | |
| {"role": "system", "content": system_prompt}, | |
| {"role": "user", "content": prompt} | |
| ], | |
| "max_tokens": 400, | |
| "temperature": 0.7 | |
| } | |
| try: | |
| response = requests.post(url, headers=headers, json=data) | |
| if response.status_code == 200: | |
| result = response.json() | |
| return result["choices"][0]["message"]["content"] | |
| else: | |
| print(f"API Error: {response.status_code} - {response.text}") | |
| return self.create_smart_fallback_response(prompt, context) | |
| except Exception as e: | |
| print(f"API Exception: {str(e)}") | |
| return self.create_smart_fallback_response(prompt, context) | |
| def create_smart_fallback_response(self, prompt, context): | |
| """Create a smart response without AI API""" | |
| prompt_lower = prompt.lower() | |
| # Extract key information from context | |
| context_lines = [line.strip() for line in context.split('\n') if line.strip() and not line.strip().startswith('Information about')] | |
| # Create a personalized response based on the question type | |
| if any(word in prompt_lower for word in ['menu', 'food', 'dish', 'eat', 'pizza', 'pasta']): | |
| response = "π **Our Menu Highlights:**\n\n" | |
| for line in context_lines: | |
| if line.startswith('- '): | |
| response += line + "\n" | |
| response += "\n⨠All our dishes are prepared fresh daily with high-quality ingredients!" | |
| elif any(word in prompt_lower for word in ['baby', 'child', 'kid', 'family']): | |
| response = "πΆ **Family-Friendly Features:**\n\n" | |
| for line in context_lines: | |
| if line.startswith('- '): | |
| response += line + "\n" | |
| response += "\nπ We love welcoming families and have everything you need for a comfortable dining experience!" | |
| elif any(word in prompt_lower for word in ['refund', 'money', 'return', 'policy']): | |
| response = "π° **Our Refund Policy:**\n\n" | |
| for line in context_lines: | |
| if line.startswith('- '): | |
| response += line + "\n" | |
| response += "\nπ Customer satisfaction is our top priority!" | |
| elif any(word in prompt_lower for word in ['hour', 'open', 'weekend', 'time']): | |
| response = "π **Restaurant Hours:**\n\n" | |
| for line in context_lines: | |
| if line.startswith('- '): | |
| response += line + "\n" | |
| response += "\nπ We recommend calling ahead for weekend reservations!" | |
| elif any(word in prompt_lower for word in ['allergy', 'allergic', 'gluten', 'vegan']): | |
| response = "π₯ **Dietary Accommodations:**\n\n" | |
| for line in context_lines: | |
| if line.startswith('- '): | |
| response += line + "\n" | |
| response += "\nβ οΈ Please always inform our staff about any allergies when ordering!" | |
| elif any(word in prompt_lower for word in ['contact', 'phone', 'address', 'delivery']): | |
| response = "π **Contact & Delivery Info:**\n\n" | |
| for line in context_lines: | |
| if line.startswith('- '): | |
| response += line + "\n" | |
| response += "\nπ We're here to serve you however you prefer!" | |
| else: | |
| # General response | |
| response = "π€ **Here's what I found for you:**\n\n" | |
| for line in context_lines[:5]: # Show first 5 relevant lines | |
| if line.startswith('- '): | |
| response += line + "\n" | |
| response += "\n㪠Feel free to ask me more specific questions about our restaurant!" | |
| return response | |
| def answer_question(self, question): | |
| """Answer a question using simple RAG""" | |
| if not question.strip(): | |
| return "π Hi there! I'm here to help you with questions about our restaurant. What would you like to know?" | |
| # Search for relevant documents | |
| search_results = self.search_documents(question) | |
| # Prepare context from search results | |
| context = "" | |
| for result in search_results: | |
| context += f"Information about {result['title']}:\n" | |
| context += f"{result['content']}\n\n" | |
| if not context: | |
| return "π€ I don't have specific information about that in my knowledge base. Could you try asking about our policies, hours, reservations, or menu? I'm here to help!" | |
| # Generate answer using LLM (or fallback to context) | |
| answer = self.call_together_ai(question, context) | |
| return answer | |
| # Initialize the RAG chatbot | |
| rag_chatbot = SimpleRAGChatbot() | |
| def chatbot_interface(message, history): | |
| """Interface function for Gradio""" | |
| return rag_chatbot.answer_question(message) | |
| # Create the Gradio interface | |
| demo = gr.ChatInterface( | |
| fn=chatbot_interface, | |
| title="π Restaurant Assistant - RAG Powered", | |
| description=""" | |
| **Welcome to our restaurant's AI assistant!** | |
| I'm powered by RAG (Retrieval-Augmented Generation) technology, which means I can provide | |
| accurate, up-to-date information about our restaurant by searching through our knowledge base. | |
| πͺ **Ask me about:** | |
| - π½οΈ Menu highlights and special dishes | |
| - π Restaurant policies (refund, privacy, allergens) | |
| - πΆ Family-friendly amenities and baby policies | |
| - π Weekend hours and reservations | |
| - π Contact information and delivery options | |
| **How it works:** I search through our restaurant's knowledge base to find the most relevant | |
| information for your questions, then provide helpful, accurate answers! | |
| *Try asking me anything about our restaurant!* | |
| """, | |
| examples=[ | |
| "What are your most popular dishes?", | |
| "Can I bring my baby to the restaurant?", | |
| "What's your refund policy?", | |
| "Are you open on weekends?", | |
| "Do you handle food allergies?", | |
| "How do I make a reservation?", | |
| "What's your contact information?", | |
| "Do you offer delivery?", | |
| "What's your privacy policy?", | |
| "Do you have vegan options?" | |
| ], | |
| theme=gr.themes.Soft(), | |
| css=""" | |
| .gradio-container { | |
| background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| } | |
| .contain { | |
| max-width: 1200px; | |
| margin: 0 auto; | |
| } | |
| .message.user { | |
| background: linear-gradient(135deg, #667eea, #764ba2); | |
| color: white; | |
| border-radius: 18px; | |
| padding: 12px 16px; | |
| margin: 8px; | |
| } | |
| .message.bot { | |
| background: linear-gradient(135deg, #f093fb, #f5576c); | |
| color: white; | |
| border-radius: 18px; | |
| padding: 12px 16px; | |
| margin: 8px; | |
| } | |
| .chat-interface { | |
| border-radius: 15px; | |
| overflow: hidden; | |
| box-shadow: 0 10px 30px rgba(0,0,0,0.1); | |
| } | |
| """ | |
| ) | |
| # Launch the interface | |
| if __name__ == "__main__": | |
| demo.launch( | |
| share=True, | |
| show_error=True, | |
| server_name="0.0.0.0", | |
| server_port=7860 | |
| ) | |