Spaces:
Sleeping
Sleeping
| """Gradio web application for Francis Botcon.""" | |
| import gradio as gr | |
| from typing import List, Tuple | |
| import sys | |
| from pathlib import Path | |
| # Add project root to path | |
| sys.path.insert(0, str(Path(__file__).parent.parent)) | |
| from src.model import FrancisModel | |
| from src.rag_system import RAGSystem | |
| from src.logger import LoggerSetup | |
| from src.config_loader import config | |
| logger = LoggerSetup.setup("INFO", "./logs/app.log") | |
| class FrancisBotconApp: | |
| """Gradio application for Francis Botcon chatbot.""" | |
| def __init__(self): | |
| """Initialize the application.""" | |
| logger.info("Initializing Francis Botcon Application...") | |
| try: | |
| # Check if LoRA adapter exists | |
| adapter_path = None | |
| if Path("./models/francis_botcon_lora").exists(): | |
| adapter_path = "./models/francis_botcon_lora" | |
| logger.info("✓ LoRA adapter found, will use fine-tuned model") | |
| # Initialize model | |
| logger.info("Loading language model...") | |
| self.model = FrancisModel(adapter_path=adapter_path) | |
| logger.info("✓ Model loaded") | |
| # Initialize RAG system | |
| logger.info("Initializing RAG system...") | |
| self.rag_system = RAGSystem() | |
| logger.info("✓ RAG system initialized") | |
| self.conversation_history: List[Tuple[str, str]] = [] | |
| except Exception as e: | |
| logger.error(f"Failed to initialize application: {str(e)}") | |
| raise | |
| def respond(self, message: str, history: List) -> Tuple[str, List]: | |
| """Generate a response to a user message. | |
| Args: | |
| message: User's input message | |
| history: Conversation history | |
| Returns: | |
| Tuple of (response, updated_history) | |
| """ | |
| if not message.strip(): | |
| return "", history | |
| logger.info(f"User: {message[:100]}...") | |
| try: | |
| # Retrieve context using RAG | |
| context_docs = self.rag_system.retrieve_context(message, top_k=5) | |
| # Build prompt with context | |
| prompt = self.rag_system.build_prompt(message, context_docs) | |
| # Generate response | |
| response = self.model.generate( | |
| prompt, | |
| max_length=512, | |
| temperature=0.7, | |
| top_p=0.9 | |
| ) | |
| logger.info(f"Generated response ({len(response)} chars)") | |
| # Format response with citations | |
| formatted_response = self._format_response(response, context_docs) | |
| return formatted_response | |
| except Exception as e: | |
| logger.error(f"Error generating response: {str(e)}") | |
| return f"I apologize, but I encountered an error: {str(e)}", history | |
| def _format_response(self, response: str, context_docs: List) -> str: | |
| """Format response with citations. | |
| Args: | |
| response: Generated response text | |
| context_docs: Retrieved context documents | |
| Returns: | |
| Formatted response with citations | |
| """ | |
| formatted = f"{response}\n\n" | |
| if context_docs: | |
| formatted += "---\n**Sources from My Works:**\n" | |
| for i, doc in enumerate(context_docs[:3], 1): # Show top 3 sources | |
| metadata = doc["metadata"] | |
| title = metadata.get("title", "Unknown Work") | |
| source = metadata.get("source", "") | |
| similarity = doc["similarity"] | |
| formatted += f"\n{i}. *{title}*" | |
| if source: | |
| formatted += f" ({source})" | |
| formatted += f" - Relevance: {similarity:.1%}" | |
| return formatted | |
| def create_interface(self) -> gr.Interface: | |
| """Create Gradio interface. | |
| Returns: | |
| Gradio Interface | |
| """ | |
| with gr.Blocks(title="Francis Botcon", theme=gr.themes.Soft()) as interface: | |
| gr.Markdown("# Francis Botcon") | |
| gr.Markdown( | |
| "A conversational AI that emulates the philosophical style of Francis Bacon (1561-1626). " | |
| "Ask questions and receive responses in his distinctive voice, with citations from his works." | |
| ) | |
| chatbot = gr.Chatbot( | |
| label="Conversation with Francis Bacon", | |
| height=500 | |
| ) | |
| with gr.Row(): | |
| message_input = gr.Textbox( | |
| label="Your Question", | |
| placeholder="Ask Francis Bacon anything...", | |
| lines=2 | |
| ) | |
| submit_button = gr.Button("Send", variant="primary") | |
| with gr.Accordion("Settings", open=False): | |
| with gr.Row(): | |
| temperature = gr.Slider( | |
| label="Temperature", | |
| minimum=0.1, | |
| maximum=1.0, | |
| value=0.7, | |
| step=0.1 | |
| ) | |
| top_p = gr.Slider( | |
| label="Top P", | |
| minimum=0.0, | |
| maximum=1.0, | |
| value=0.9, | |
| step=0.1 | |
| ) | |
| def chat(message, chat_history): | |
| """Chat function.""" | |
| response = self.respond(message, chat_history) | |
| chat_history.append((message, response)) | |
| return "", chat_history | |
| # Connect events | |
| submit_button.click( | |
| chat, | |
| inputs=[message_input, chatbot], | |
| outputs=[message_input, chatbot] | |
| ) | |
| message_input.submit( | |
| chat, | |
| inputs=[message_input, chatbot], | |
| outputs=[message_input, chatbot] | |
| ) | |
| gr.Markdown(""" | |
| --- | |
| **About Francis Botcon:** | |
| - Based on Llama 3.2:3b fine-tuned on Francis Bacon's works | |
| - Uses Retrieval-Augmented Generation (RAG) for contextual responses | |
| - Citations refer to passages from Bacon's authentic works | |
| **Note:** This is an AI model trained to emulate Bacon's style. | |
| For academic purposes, always verify citations with original sources. | |
| """) | |
| return interface | |
| def launch(self, share: bool = False, server_name: str = "0.0.0.0", server_port: int = 7860): | |
| """Launch the Gradio app. | |
| Args: | |
| share: Whether to create a shareable link | |
| server_name: Server address | |
| server_port: Server port | |
| """ | |
| logger.info(f"Launching Francis Botcon on {server_name}:{server_port}") | |
| interface = self.create_interface() | |
| interface.launch( | |
| share=share, | |
| server_name=server_name, | |
| server_port=server_port, | |
| ) | |
| def main(): | |
| """Main entry point.""" | |
| try: | |
| app = FrancisBotconApp() | |
| app.launch( | |
| share=config.get("app.share", False), | |
| server_port=config.get("app.port", 7860) | |
| ) | |
| except Exception as e: | |
| logger.error(f"Application failed: {str(e)}", exc_info=True) | |
| sys.exit(1) | |
| if __name__ == "__main__": | |
| main() | |