# app.py import os import time import gradio as gr import importlib.util import markdown from huggingface_hub import hf_hub_download # ---------------------------------------------------------------------- # Helper to read secrets from the HF Space environment # ---------------------------------------------------------------------- def _secret(key: str, fallback: str = None) -> str: val = os.getenv(key) if val is not None: return val if fallback is not None: return fallback raise RuntimeError(f"Secret '{key}' not found. Please add it to your Space secrets.") # ---------------------------------------------------------------------- # 1. Configuration & Constants # ---------------------------------------------------------------------- # The private repo containing the vector DB and the logic script REPO_ID = _secret("REPO_ID") # Files to download from the repo FILES_TO_DOWNLOAD = ["index.faiss", "index.pkl", "agent_logic.py"] # A local directory to store all downloaded assets LOCAL_DOWNLOAD_DIR = "downloaded_assets" EMBEDDING_MODEL_NAME = "google/embeddinggemma-300m" # ---------------------------------------------------------------------- # 2. Bootstrap Phase: Download assets and initialize the engine # (This code runs only once when the Space starts up) # ---------------------------------------------------------------------- print("--- [UI App] Starting bootstrap process ---") os.makedirs(LOCAL_DOWNLOAD_DIR, exist_ok=True) hf_token = _secret("HF_TOKEN") # A read-access token is required for private repos for filename in FILES_TO_DOWNLOAD: print(f"--- [UI App] Downloading '{filename}'... ---") try: hf_hub_download( repo_id=REPO_ID, filename=filename, repo_type="dataset", local_dir=LOCAL_DOWNLOAD_DIR, token=hf_token, ) except Exception as e: raise RuntimeError(f"Failed to download '{filename}'. Check repo/file names and HF_TOKEN. Error: {e}") # Dynamically import the RAG_Engine class from the downloaded script logic_script_path = os.path.join(LOCAL_DOWNLOAD_DIR, "agent_logic.py") spec = importlib.util.spec_from_file_location("agent_logic", logic_script_path) agent_logic_module = importlib.util.module_from_spec(spec) spec.loader.exec_module(agent_logic_module) print("--- [UI App] Agent logic module imported successfully. ---") # Instantiate the engine. This single line triggers all the complex setup # defined in the private_logic.py file. engine = agent_logic_module.RAG_Engine( local_download_dir=LOCAL_DOWNLOAD_DIR, embedding_model_name=EMBEDDING_MODEL_NAME ) print("--- [UI App] Bootstrap complete. Gradio UI is starting. ---") # ---------------------------------------------------------------------- # 3. Core Gradio Chat Logic (Now a simple wrapper) # ---------------------------------------------------------------------- def respond(message: str, history: list[dict[str, str]]): """ This function is called by Gradio for each user message. It passes the inputs to the RAG engine and streams the output. """ final_response = engine.get_response(message, history) # Stream the response back to the UI for a "typing" effect response = "" for char in final_response: response += char time.sleep(0.01) yield response # ---------------------------------------------------------------------- # 4. Custom CSS for better styling # ---------------------------------------------------------------------- custom_css = """ /* Main container styling */ .contain { background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); min-height: 100vh; padding: 20px; } /* Header styling */ .header { text-align: center; margin-bottom: 30px; } .header h1 { color: #2c3e50; font-weight: 700; margin-bottom: 10px; font-size: 2.5rem; } .header p { color: #7f8c8d; font-size: 1.2rem; } /* Chat container styling */ .gr-chat-message { padding: 16px 20px; border-radius: 18px; margin: 10px 0; line-height: 1.5; } .gr-chat-message-user { background: linear-gradient(135deg, #3498db 0%, #2980b9 100%); color: white; margin-left: 20%; } .gr-chat-message-bot { background: linear-gradient(135deg, #ecf0f1 0%, #ffffff 100%); color: #2c3e50; margin-right: 20%; border: 1px solid #e0e0e0; } /* Chat input styling */ .gr-text-input textarea { border-radius: 12px; padding: 15px; font-size: 16px; border: 2px solid #bdc3c7; } .gr-text-input textarea:focus { border-color: #3498db; box-shadow: 0 0 0 3px rgba(52, 152, 219, 0.2); } /* Button styling */ .gr-button { background: linear-gradient(135deg, #2ecc71 0%, #27ae60 100%); color: white; border: none; border-radius: 12px; padding: 12px 24px; font-weight: 600; transition: all 0.3s ease; } .gr-button:hover { transform: translateY(-2px); box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); } /* Example styling */ .gr-examples { border-radius: 12px; background: white; padding: 15px; box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); } .gr-examples button { background: #f8f9fa; border: 1px solid #e9ecef; border-radius: 8px; padding: 10px 15px; margin: 5px; transition: all 0.2s ease; } .gr-examples button:hover { background: #e9ecef; transform: translateY(-1px); } /* Formula styling */ .formula { background-color: #f8f9fa; border-left: 4px solid #3498db; padding: 15px; margin: 15px 0; border-radius: 0 8px 8px 0; overflow-x: auto; } .formula p { margin: 0; font-family: monospace; color: #2c3e50; } /* Responsive adjustments */ @media (max-width: 768px) { .gr-chat-message-user, .gr-chat-message-bot { margin-left: 10%; margin-right: 10%; } .header h1 { font-size: 2rem; } } """ # ---------------------------------------------------------------------- # 5. UI Layout and Launch # ---------------------------------------------------------------------- with gr.Blocks(css=custom_css, theme=gr.themes.Soft()) as demo: # Header section with gr.Row(): with gr.Column(scale=1): gr.HTML("""

🤖 PRECISE RAG Agent

Silakan bertanya tentang PRECISE dan sistem promosinya

""") # Chat interface chatbot = gr.ChatInterface( respond, type="messages", examples=[ ["Apa rumus untuk menghitung PVR?"], ["Apa tujuan pengadaan PRECISE?"], ["Jelaskan tentang promo 'beli 4 gratis 2'"], ], cache_examples=False, ) # Additional information section with gr.Accordion("📊 Informasi Formula PVR", open=False): gr.Markdown(""" **PVR untuk promo "beli 4 gratis 2" dihitung dengan rumus:** ```math \\text{PVR} = \\frac{\\text{added\\_value}}{\\text{purchase\\_value}} = \\frac{\\text{target\\_value} \\times \\text{avg\\_price\\_AVP}} {\\text{target\\_value} \\times \\text{avg\\_price\\_AVP} + \\text{condition\\_value} \\times \\text{avg\\_price\\_REP}} ``` Keterangan: - **added_value**: Nilai tambah dari promo - **purchase_value**: Nilai pembelian keseluruhan - **target_value**: Jumlah produk target dalam promo - **avg_price_AVP**: Harga rata-rata produk AVP - **condition_value**: Jumlah produk kondisi dalam promo - **avg_price_REP**: Harga rata-rata produk REP """) if __name__ == "__main__": allowed_user = _secret("CHAT_USER") allowed_pass = _secret("CHAT_PASS") demo.launch( auth=(allowed_user, allowed_pass), server_name="0.0.0.0", ssr_mode=False, server_port=7860 )