Files

1 line
8.2 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{"repo": "alayadb-ai/alayalite", "files": {"examples/rag/ui.py": {"87a79a2411e172e5c2c56feef64d14fff25fe389": {"t": 1785768171.08095, "n": 7781, "h": "6fd2dbc2f7aa3753", "c": "# SPDX-FileCopyrightText: 2025 AlayaDB.AI\n#\n# SPDX-License-Identifier: AGPL-3.0-only\n\n\"\"\"\nThis module provides the Streamlit user interface for a Retrieval-Augmented Generation (RAG) Q&A application.\nIt handles file uploads, knowledge base management, and the chat interface.\n\"\"\"\n\nimport json\nimport os\nfrom datetime import datetime\nfrom typing import Callable, Generator, Tuple\n\nimport streamlit as st\nimport torch\nfrom db import insert_text, query_text, reset_db\nfrom docx import Document\nfrom llm import ask_llm\nfrom pypdf import PdfReader\n\ntorch.classes.__path__ = [os.path.join(torch.__path__[0], torch.classes.__file__)]\nUSE_STREAM = True\nst.set_page_config(page_title=\"My RAG\", page_icon=\"🤖\", layout=\"wide\", initial_sidebar_state=\"expanded\")\n\n# Init session\nif \"user\" not in st.session_state:\n st.session_state.update({\"user\": None, \"chat_history\": [], \"current_db\": \"default\"})\n\n\ndef read_file(uploaded_file):\n content = \"\"\n\n file_type = uploaded_file.type\n\n if uploaded_file.name.endswith(\".md\"):\n file_type = \"text/markdown\"\n\n try:\n if file_type in [\"text/plain\", \"text/x-markdown\", \"text/markdown\"]:\n content = uploaded_file.read().decode(\"utf-8\")\n elif file_type == \"application/pdf\":\n pdf_reader = PdfReader(uploaded_file)\n content = \"\\n\".join([page.extract_text() for page in pdf_reader.pages])\n elif file_type == \"application/vnd.openxmlformats-officedocument.wordprocessingml.document\":\n doc = Document(uploaded_file)\n content = \"\\n\".join([para.text for para in doc.paragraphs])\n else:\n raise ValueError(f\"Unsupported file types: {uploaded_file.type} for file {uploaded_file.name}\")\n except Exception as e:\n raise RuntimeError(f\"Fail to read files: {uploaded_file.name}. Type: {uploaded_file.type}.\") from e\n return content\n\n\ndef enhanced_file_processor(file):\n content = read_file(file)\n content = content.replace(\"\\n\", \" \")\n content = \" \".join(content.split())\n return content\n\n\ndef context_aware_query(\n collection_name: str,\n query: str,\n history: list,\n *,\n llm_url: str,\n llm_api_key: str,\n llm_model: str,\n embed_model_path: str,\n is_stream: bool = True,\n) -> Tuple[str | Callable[[], Generator[str, None, None]], str]:\n context = \"\\n\".join([f\"Q: {q}\\nA: {a}\" for q, a, d in history[-3:]])\n enhanced_query = f\"{context}\\n\\nNew question:{query}\"\n\n retrieved_docs = query_text(\n collection_name=collection_name,\n query=enhanced_query,\n embed_model_path=embed_model_path,\n )\n return ask_llm(\n llm_url, llm_api_key, llm_model, query=query, retrieved_docs=retrieved_docs, is_stream=is_stream\n ), retrieved_docs\n\n\ndef main_interface():\n with st.sidebar:\n with st.expander(\"🛠️ Service Setting\", expanded=True):\n llm_url = st.text_input(\"LLM Base URL\", value=\"https://api.lkeap.cloud.tencent.com/v1/chat\")\n llm_api_key = st.text_input(\"LLM API Key\", value=\"Your API Key\")\n llm_model = st.text_input(\"LLM Model\", value=\"deepseek-v3\")\n embed_model_path = st.text_input(\"Embedding Model\", value=\"BAAI/bge-small-zh-v1.5\")\n\n with st.expander(\"📚 Knowledge Base Management\", expanded=True):\n with st.form(\"upload_form\"):\n collection_name = \"rag_collection\"\n uploaded_file = st.file_uploader(\n \"Upload documents\", type=[\"txt\", \"pdf\", \"docx\", \"md\"], accept_multiple_files=True\n )\n if st.form_submit_button(\"🚀 Start processing\"):\n reset_db()\n if uploaded_file:\n success = True\n for file in uploaded_file:\n with st.spinner(f\"Process {file.name}...\"):\n content = enhanced_file_processor(file)\n success = insert_text(\n collection_name=collection_name,\n docs=content,\n embed_model_path=embed_model_path,\n chunksize=256,\n overlap=25,\n )\n if not success:\n break\n if success:\n st.success(\"Document processing completed\")\n else:\n st.error(\"Document processing failed!\")\n else:\n st.error(\"No document uploaded yet!\")\n\n with st.expander(\"🗃️ Dialogue management\", expanded=True):\n if st.button(\"🔄 Clear all records\", use_container_width=True):\n st.session_state.chat_history = []\n st.rerun()\n\n timestamp = datetime.now().strftime(\"%Y%m%d\")\n if st.download_button(\n \"💾 Export all records\",\n data=json.dumps(st.session_state.chat_history),\n file_name=f\"chat_{timestamp}.json\",\n mime=\"application/json\",\n use_container_width=True,\n ):\n st.toast(\"Exported!\")\n\n with st.container():\n st.header(\"💬 RAG QA\")\n\n # Real-time dialog display container\n chat_container = st.container(height=600, border=False)\n # Render the existing history first\n with chat_container:\n for _, (q, a, d) in enumerate(st.session_state.chat_history):\n with st.chat_message(\"user\", avatar=\"👤\"):\n st.markdown(f\"{q}\")\n with st.chat_message(\"assistant\", avatar=\"🤖\"):\n st.markdown(a)\n if d:\n with st.popover(\"References\"):\n st.markdown(d)\n\n # Input processing\n if prompt := st.chat_input(\"Please enter your question...\"):\n # Display user input\n with chat_container:\n with st.chat_message(\"user\", avatar=\"👤\"):\n st.markdown(f\"{prompt}\")\n\n # Add a placeholder response\n with st.chat_message(\"assistant\", avatar=\"🤖\"):\n answer_placeholder = st.empty()\n answer_placeholder.markdown(\"▌\")\n\n # Execute the query (keep the original logic)\n try:\n resp_or_stream, retrieved_docs = context_aware_query(\n collection_name=collection_name,\n query=prompt,\n history=st.session_state.chat_history,\n llm_url=llm_url,\n llm_api_key=llm_api_key,\n llm_model=llm_model,\n embed_model_path=embed_model_path,\n is_stream=USE_STREAM,\n )\n\n # Update the answer\n full_resp = \"\"\n if USE_STREAM:\n for chunk in resp_or_stream():\n full_resp += chunk\n answer_placeholder.markdown(full_resp)\n else:\n full_resp = resp_or_stream\n answer_placeholder.markdown(full_resp)\n\n # Update session history\n st.session_state.chat_history.append((prompt, full_resp, retrieved_docs))\n # pylint: disable=broad-exception-caught\n except Exception as e:\n answer_placeholder.error(f\"Handling failures: {str(e)}\")\n st.session_state.chat_history.append((prompt, f\"⚠️ Error: {str(e)}\", \"\"))\n\n st.rerun()\n\n\ndef main():\n main_interface()\n\n\nif __name__ == \"__main__\":\n main()\n"}}}}