Spaces:
Build error
Build error
| #!/usr/bin/env python3 | |
| """ | |
| Textilindo AI Assistant - Hugging Face Spaces (Gradio Version) | |
| """ | |
| import gradio as gr | |
| import os | |
| import json | |
| import requests | |
| from difflib import SequenceMatcher | |
| import logging | |
| # Setup logging | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| def load_system_prompt(default_text): | |
| """Load system prompt from configs/system_prompt.md if available""" | |
| try: | |
| base_dir = os.path.dirname(__file__) | |
| prompt_path = os.path.join(base_dir, "configs", "system_prompt.md") | |
| if os.path.exists(prompt_path): | |
| with open(prompt_path, 'r', encoding='utf-8') as f: | |
| return f.read().strip() | |
| except Exception as e: | |
| logger.warning(f"Could not load system prompt: {e}") | |
| return default_text | |
| class TextilindoAI: | |
| def __init__(self): | |
| self.dataset = [] | |
| self.system_prompt = load_system_prompt( | |
| "You are a helpful AI assistant for Textilindo, a textile company. " | |
| "Provide accurate and helpful information about Textilindo's products, services, and business information." | |
| ) | |
| self.load_all_datasets() | |
| logger.info(f"Total examples loaded: {len(self.dataset)}") | |
| def load_all_datasets(self): | |
| """Load all JSONL datasets from the data directory""" | |
| base_dir = os.path.dirname(__file__) | |
| data_dir = os.path.join(base_dir, "data") | |
| if not os.path.exists(data_dir): | |
| logger.warning(f"Data directory not found: {data_dir}") | |
| return | |
| logger.info(f"Found data directory: {data_dir}") | |
| # Load all JSONL files | |
| for filename in os.listdir(data_dir): | |
| if filename.endswith('.jsonl'): | |
| filepath = os.path.join(data_dir, filename) | |
| file_examples = 0 | |
| try: | |
| with open(filepath, 'r', encoding='utf-8') as f: | |
| for line in f: | |
| line = line.strip() | |
| if line: | |
| try: | |
| data = json.loads(line) | |
| data['source'] = filename # Add source tracking | |
| self.dataset.append(data) | |
| file_examples += 1 | |
| except json.JSONDecodeError as e: | |
| logger.warning(f"Invalid JSON in {filename}: {e}") | |
| continue | |
| logger.info(f"Loaded {filename}: {file_examples} examples") | |
| except Exception as e: | |
| logger.error(f"Error loading {filename}: {e}") | |
| def find_most_similar(self, query, top_k=3): | |
| """Find most similar examples using sequence matching""" | |
| similarities = [] | |
| for example in self.dataset: | |
| # Try different field names that might exist in the dataset | |
| question = example.get('question', example.get('instruction', '')).lower() | |
| similarity = SequenceMatcher(None, query.lower(), question).ratio() | |
| similarities.append((similarity, example)) | |
| # Sort by similarity and return top_k | |
| similarities.sort(key=lambda x: x[0], reverse=True) | |
| return [example for _, example in similarities[:top_k]] | |
| def chat(self, message, temperature=0.7, max_tokens=300): | |
| """Generate AI response using RAG""" | |
| try: | |
| # Find similar examples | |
| similar_examples = self.find_most_similar(message, top_k=3) | |
| # Build context from similar examples | |
| context = "" | |
| for example in similar_examples: | |
| # Try different field names that might exist in the dataset | |
| question = example.get('question', example.get('instruction', '')) | |
| answer = example.get('answer', example.get('output', '')) | |
| context += f"Q: {question}\nA: {answer}\n\n" | |
| # Create prompt | |
| prompt = f"""System: {self.system_prompt} | |
| Context from Textilindo knowledge base: | |
| {context} | |
| User Question: {message} | |
| Please provide a helpful response based on the context above. If the context doesn't contain relevant information, provide a general helpful response about Textilindo.""" | |
| # For now, return a simple response based on context | |
| if similar_examples: | |
| # Return the most similar answer | |
| best_answer = similar_examples[0].get('answer', similar_examples[0].get('output', '')) | |
| if best_answer: | |
| return f"Based on our knowledge base: {best_answer}" | |
| else: | |
| return "I found some relevant information but couldn't extract a proper answer. Please try rephrasing your question." | |
| else: | |
| return "I'm sorry, I don't have specific information about that. Please contact Textilindo directly for more details." | |
| except Exception as e: | |
| logger.error(f"Error in chat: {e}") | |
| return f"Error: {str(e)}" | |
| # Initialize AI assistant (will be created when needed) | |
| ai = None | |
| def get_ai_assistant(): | |
| """Get or create the AI assistant instance""" | |
| global ai | |
| if ai is None: | |
| try: | |
| logger.info("Initializing Textilindo AI Assistant...") | |
| ai = TextilindoAI() | |
| logger.info("AI Assistant initialized successfully") | |
| except Exception as e: | |
| logger.error(f"Failed to initialize AI Assistant: {e}") | |
| # Create a minimal fallback | |
| ai = type('FallbackAI', (), { | |
| 'dataset': [], | |
| 'chat': lambda self, message, **kwargs: f"AI Assistant is not available. Error: {str(e)}" | |
| })() | |
| return ai | |
| def chat_function(message, temperature=0.7, max_tokens=300): | |
| """Chat function for Gradio interface""" | |
| try: | |
| if not message: | |
| return "Please enter a message." | |
| # Get AI assistant (initializes if needed) | |
| ai_assistant = get_ai_assistant() | |
| # Get AI response | |
| response = ai_assistant.chat(message, temperature=temperature, max_tokens=max_tokens) | |
| return response | |
| except Exception as e: | |
| logger.error(f"Error in chat function: {str(e)}") | |
| return f"Error: {str(e)}" | |
| # Create Gradio interface | |
| def create_interface(): | |
| """Create the Gradio interface""" | |
| with gr.Blocks(title="Textilindo AI Assistant") as interface: | |
| gr.Markdown("# 🤖 Textilindo AI Assistant") | |
| gr.Markdown("AI-powered customer service for Textilindo") | |
| with gr.Row(): | |
| with gr.Column(): | |
| message_input = gr.Textbox( | |
| label="Your Message", | |
| placeholder="Ask me anything about Textilindo...", | |
| lines=3 | |
| ) | |
| with gr.Row(): | |
| temperature = gr.Slider( | |
| minimum=0.1, | |
| maximum=2.0, | |
| value=0.7, | |
| step=0.1, | |
| label="Temperature" | |
| ) | |
| max_tokens = gr.Slider( | |
| minimum=50, | |
| maximum=1000, | |
| value=300, | |
| step=50, | |
| label="Max Tokens" | |
| ) | |
| submit_btn = gr.Button("Send Message", variant="primary") | |
| with gr.Column(): | |
| response_output = gr.Textbox( | |
| label="AI Response", | |
| lines=10, | |
| interactive=False | |
| ) | |
| # Event handlers | |
| submit_btn.click( | |
| fn=chat_function, | |
| inputs=[message_input, temperature, max_tokens], | |
| outputs=response_output | |
| ) | |
| # Allow Enter key to submit | |
| message_input.submit( | |
| fn=chat_function, | |
| inputs=[message_input, temperature, max_tokens], | |
| outputs=response_output | |
| ) | |
| # Add examples | |
| gr.Examples( | |
| examples=[ | |
| "Dimana lokasi Textilindo?", | |
| "Apa saja produk yang dijual di Textilindo?", | |
| "Jam berapa Textilindo buka?", | |
| "Bagaimana cara menghubungi Textilindo?" | |
| ], | |
| inputs=message_input | |
| ) | |
| # Add footer with stats | |
| try: | |
| ai_assistant = get_ai_assistant() | |
| dataset_size = len(ai_assistant.dataset) if hasattr(ai_assistant, 'dataset') else 0 | |
| gr.Markdown(f"**Dataset loaded:** {dataset_size} examples") | |
| except: | |
| gr.Markdown("**Dataset:** Loading...") | |
| return interface | |
| if __name__ == '__main__': | |
| try: | |
| logger.info("Starting Textilindo AI Assistant...") | |
| # Try to initialize AI assistant early to catch any issues | |
| try: | |
| ai_assistant = get_ai_assistant() | |
| logger.info(f"Dataset loaded: {len(ai_assistant.dataset)} examples") | |
| except Exception as e: | |
| logger.warning(f"AI Assistant initialization failed: {e}") | |
| logger.info("Continuing with fallback mode...") | |
| # Create and launch the interface | |
| logger.info("Creating Gradio interface...") | |
| interface = create_interface() | |
| logger.info("Gradio interface created successfully") | |
| # Get server configuration from environment variables | |
| server_name = os.environ.get("GRADIO_SERVER_NAME", "0.0.0.0") | |
| server_port = int(os.environ.get("GRADIO_SERVER_PORT", "7860")) | |
| logger.info(f"Launching Gradio interface on {server_name}:{server_port}") | |
| # Launch with basic configuration for Hugging Face Spaces | |
| interface.launch( | |
| server_name=server_name, | |
| server_port=server_port, | |
| share=False, # Hugging Face Spaces handles tunneling automatically | |
| show_error=True, | |
| quiet=False, | |
| inbrowser=False, | |
| prevent_thread_lock=False # Essential for keeping the process alive | |
| ) | |
| logger.info("Gradio interface launched successfully") | |
| # Keep the application running | |
| try: | |
| import time | |
| while True: | |
| time.sleep(1) | |
| except KeyboardInterrupt: | |
| logger.info("Application stopped by user") | |
| except Exception as e: | |
| logger.error(f"Failed to start application: {e}") | |
| # Create a simple fallback interface | |
| try: | |
| with gr.Blocks() as fallback: | |
| gr.Markdown("# Textilindo AI Assistant") | |
| gr.Markdown("Application is starting... Please wait.") | |
| gr.Markdown(f"Error: {str(e)}") | |
| # Get server configuration from environment variables | |
| server_name = os.environ.get("GRADIO_SERVER_NAME", "0.0.0.0") | |
| server_port = int(os.environ.get("GRADIO_SERVER_PORT", "7860")) | |
| fallback.launch( | |
| server_name=server_name, | |
| server_port=server_port, | |
| share=False, | |
| inbrowser=False, | |
| prevent_thread_lock=False # Essential for keeping the process alive | |
| ) | |
| # Keep the fallback running | |
| import time | |
| while True: | |
| time.sleep(1) | |
| except Exception as fallback_error: | |
| logger.error(f"Fallback interface also failed: {fallback_error}") | |
| # If everything fails, just keep the process alive | |
| import time | |
| while True: | |
| time.sleep(1) | |