File size: 7,951 Bytes
e87b1c3
 
0ff301d
e87b1c3
4e4df74
e87b1c3
57ec1a6
e87b1c3
4e4df74
de611b5
e87b1c3
859ac01
e87b1c3
 
 
 
 
de611b5
 
e87b1c3
de611b5
57ec1a6
e87b1c3
57ec1a6
e87b1c3
57ec1a6
e87b1c3
 
0ff301d
e87b1c3
 
57ec1a6
e87b1c3
 
 
57ec1a6
e87b1c3
 
 
 
 
 
 
21bc7cc
e87b1c3
 
 
57ec1a6
e87b1c3
 
 
 
 
 
57ec1a6
 
e87b1c3
 
 
d94ed24
e87b1c3
4e4df74
e87b1c3
57ec1a6
e87b1c3
57ec1a6
 
 
 
 
 
4e8dab9
57ec1a6
 
e87b1c3
57ec1a6
e87b1c3
57ec1a6
40b4466
de611b5
57ec1a6
de611b5
57ec1a6
 
 
 
 
 
 
4e4df74
57ec1a6
 
 
 
 
6aabd52
57ec1a6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6aabd52
57ec1a6
 
 
 
 
4e4df74
57ec1a6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6aabd52
57ec1a6
 
 
6aabd52
57ec1a6
6aabd52
 
57ec1a6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6aabd52
4e4df74
859ac01
 
de611b5
e87b1c3
 
2b88a3b
57ec1a6
de611b5
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
# 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("""
            <div class="header">
                <h1>🤖 PRECISE RAG Agent</h1>
                <p>Silakan bertanya tentang PRECISE dan sistem promosinya</p>
            </div>
            """)
    
    # 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
    )