| | """ |
| | Gradio app for Norwegian RAG chatbot. |
| | Provides a web interface for interacting with the chatbot. |
| | """ |
| |
|
| | import os |
| | import gradio as gr |
| | import tempfile |
| | from typing import List, Dict, Any, Tuple, Optional |
| |
|
| | from ..api.huggingface_api import HuggingFaceAPI |
| | from ..document_processing.processor import DocumentProcessor |
| | from ..rag.retriever import Retriever |
| | from ..rag.generator import Generator |
| |
|
| | class ChatbotApp: |
| | """ |
| | Gradio app for Norwegian RAG chatbot. |
| | """ |
| | |
| | def __init__( |
| | self, |
| | api_client: Optional[HuggingFaceAPI] = None, |
| | document_processor: Optional[DocumentProcessor] = None, |
| | retriever: Optional[Retriever] = None, |
| | generator: Optional[Generator] = None, |
| | title: str = "Norwegian RAG Chatbot", |
| | description: str = "En chatbot basert på Retrieval-Augmented Generation (RAG) for norsk språk." |
| | ): |
| | """ |
| | Initialize the chatbot app. |
| | |
| | Args: |
| | api_client: HuggingFaceAPI client |
| | document_processor: Document processor |
| | retriever: Retriever for finding relevant chunks |
| | generator: Generator for creating responses |
| | title: App title |
| | description: App description |
| | """ |
| | |
| | self.api_client = api_client or HuggingFaceAPI() |
| | self.document_processor = document_processor or DocumentProcessor(api_client=self.api_client) |
| | self.retriever = retriever or Retriever(api_client=self.api_client) |
| | self.generator = generator or Generator(api_client=self.api_client) |
| | |
| | |
| | self.title = title |
| | self.description = description |
| | |
| | |
| | self.app = self._build_interface() |
| | |
| | def _build_interface(self) -> gr.Blocks: |
| | """ |
| | Build the Gradio interface. |
| | |
| | Returns: |
| | Gradio Blocks interface |
| | """ |
| | with gr.Blocks(title=self.title) as app: |
| | gr.Markdown(f"# {self.title}") |
| | gr.Markdown(self.description) |
| | |
| | with gr.Tabs(): |
| | |
| | with gr.Tab("Chat"): |
| | chatbot = gr.Chatbot(height=500) |
| | |
| | with gr.Row(): |
| | msg = gr.Textbox( |
| | placeholder="Skriv din melding her...", |
| | show_label=False, |
| | scale=9 |
| | ) |
| | submit_btn = gr.Button("Send", scale=1) |
| | |
| | with gr.Accordion("Avanserte innstillinger", open=False): |
| | temperature = gr.Slider( |
| | minimum=0.1, |
| | maximum=1.0, |
| | value=0.7, |
| | step=0.1, |
| | label="Temperatur" |
| | ) |
| | |
| | clear_btn = gr.Button("Tøm chat") |
| | |
| | |
| | submit_btn.click( |
| | fn=self._respond, |
| | inputs=[msg, chatbot, temperature], |
| | outputs=[msg, chatbot] |
| | ) |
| | |
| | msg.submit( |
| | fn=self._respond, |
| | inputs=[msg, chatbot, temperature], |
| | outputs=[msg, chatbot] |
| | ) |
| | |
| | clear_btn.click( |
| | fn=lambda: None, |
| | inputs=None, |
| | outputs=chatbot, |
| | queue=False |
| | ) |
| | |
| | |
| | with gr.Tab("Last opp dokumenter"): |
| | with gr.Row(): |
| | with gr.Column(scale=2): |
| | file_output = gr.File(label="Opplastede dokumenter") |
| | upload_button = gr.UploadButton( |
| | "Klikk for å laste opp dokument", |
| | file_types=["pdf", "txt", "html"], |
| | file_count="multiple" |
| | ) |
| | |
| | with gr.Column(scale=3): |
| | documents_list = gr.Dataframe( |
| | headers=["Dokument ID", "Filnavn", "Dato", "Chunks"], |
| | label="Dokumentliste", |
| | interactive=False |
| | ) |
| | |
| | process_status = gr.Textbox(label="Status", interactive=False) |
| | refresh_btn = gr.Button("Oppdater dokumentliste") |
| | |
| | |
| | upload_button.upload( |
| | fn=self._process_uploaded_files, |
| | inputs=[upload_button], |
| | outputs=[process_status, documents_list] |
| | ) |
| | |
| | refresh_btn.click( |
| | fn=self._get_documents_list, |
| | inputs=None, |
| | outputs=[documents_list] |
| | ) |
| | |
| | |
| | with gr.Tab("Integrer"): |
| | gr.Markdown("## Integrer chatboten på din nettside") |
| | |
| | with gr.Row(): |
| | with gr.Column(): |
| | gr.Markdown("### iFrame-kode") |
| | iframe_code = gr.Code( |
| | label="iFrame", |
| | language="html", |
| | value='<iframe src="https://huggingface.co/spaces/username/norwegian-rag-chatbot" width="100%" height="500px"></iframe>' |
| | ) |
| | |
| | with gr.Column(): |
| | gr.Markdown("### JavaScript Widget") |
| | js_code = gr.Code( |
| | label="JavaScript", |
| | language="html", |
| | value='<script src="https://huggingface.co/spaces/username/norwegian-rag-chatbot/widget.js"></script>' |
| | ) |
| | |
| | gr.Markdown("### Forhåndsvisning") |
| | gr.Markdown("*Forhåndsvisning vil være tilgjengelig etter at chatboten er distribuert til Hugging Face Spaces.*") |
| | |
| | gr.Markdown("---") |
| | gr.Markdown("Bygget med [Hugging Face](https://huggingface.co/) og [Gradio](https://gradio.app/)") |
| | |
| | return app |
| | |
| | def _respond( |
| | self, |
| | message: str, |
| | chat_history: List[Tuple[str, str]], |
| | temperature: float |
| | ) -> Tuple[str, List[Tuple[str, str]]]: |
| | """ |
| | Generate a response to the user message. |
| | |
| | Args: |
| | message: User message |
| | chat_history: Chat history |
| | temperature: Temperature for text generation |
| | |
| | Returns: |
| | Empty message and updated chat history |
| | """ |
| | if not message: |
| | return "", chat_history |
| | |
| | |
| | chat_history.append((message, None)) |
| | |
| | try: |
| | |
| | retrieved_chunks = self.retriever.retrieve(message) |
| | |
| | |
| | response = self.generator.generate( |
| | query=message, |
| | retrieved_chunks=retrieved_chunks, |
| | temperature=temperature |
| | ) |
| | |
| | |
| | chat_history[-1] = (message, response) |
| | except Exception as e: |
| | |
| | error_message = f"Beklager, det oppstod en feil: {str(e)}" |
| | chat_history[-1] = (message, error_message) |
| | |
| | return "", chat_history |
| | |
| | def _process_uploaded_files( |
| | self, |
| | files: List[tempfile._TemporaryFileWrapper] |
| | ) -> Tuple[str, List[List[str]]]: |
| | """ |
| | Process uploaded files. |
| | |
| | Args: |
| | files: List of uploaded files |
| | |
| | Returns: |
| | Status message and updated documents list |
| | """ |
| | if not files: |
| | return "Ingen filer lastet opp.", self._get_documents_list() |
| | |
| | processed_files = [] |
| | |
| | for file in files: |
| | try: |
| | |
| | document_id = self.document_processor.process_document(file.name) |
| | processed_files.append(os.path.basename(file.name)) |
| | except Exception as e: |
| | return f"Feil ved behandling av {os.path.basename(file.name)}: {str(e)}", self._get_documents_list() |
| | |
| | if len(processed_files) == 1: |
| | status = f"Fil behandlet: {processed_files[0]}" |
| | else: |
| | status = f"{len(processed_files)} filer behandlet: {', '.join(processed_files)}" |
| | |
| | return status, self._get_documents_list() |
| | |
| | def _get_documents_list(self) -> List[List[str]]: |
| | """ |
| | Get list of processed documents. |
| | |
| | Returns: |
| | List of document information |
| | """ |
| | documents = self.document_processor.get_all_documents() |
| | |
| | |
| | documents_list = [] |
| | for doc_id, metadata in documents.items(): |
| | filename = metadata.get("filename", "N/A") |
| | processed_date = metadata.get("processed_date", "N/A") |
| | chunk_count = metadata.get("chunk_count", 0) |
| | |
| | documents_list.append([doc_id, filename, processed_date, chunk_count]) |
| | |
| | return documents_list |
| | |
| | def launch(self, **kwargs): |
| | """ |
| | Launch the Gradio app. |
| | |
| | Args: |
| | **kwargs: Additional arguments for gr.launch() |
| | """ |
| | self.app.launch(**kwargs) |
| |
|
| |
|
| | def create_app(): |
| | """ |
| | Create and configure the chatbot app. |
| | |
| | Returns: |
| | Configured ChatbotApp instance |
| | """ |
| | |
| | api_client = HuggingFaceAPI() |
| | |
| | |
| | document_processor = DocumentProcessor(api_client=api_client) |
| | retriever = Retriever(api_client=api_client) |
| | generator = Generator(api_client=api_client) |
| | |
| | |
| | app = ChatbotApp( |
| | api_client=api_client, |
| | document_processor=document_processor, |
| | retriever=retriever, |
| | generator=generator |
| | ) |
| | |
| | return app |
| |
|