Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
| 3 |
# ===================================================================
|
| 4 |
from flask import Flask, render_template, request, jsonify, session
|
| 5 |
import psycopg2, redis, os, hashlib, json, time, requests
|
| 6 |
-
from
|
| 7 |
from langchain_huggingface import HuggingFaceEmbeddings
|
| 8 |
from langchain_chroma import Chroma
|
| 9 |
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
|
@@ -110,9 +110,8 @@ init_neon_db()
|
|
| 110 |
# ===================================================================
|
| 111 |
# LLM & EMBEDDING CONFIG
|
| 112 |
# ===================================================================
|
| 113 |
-
|
| 114 |
-
|
| 115 |
-
NEBIUS_API_BASE = os.getenv("NEBIUS_API_BASE")
|
| 116 |
EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL")
|
| 117 |
LLM_TEMPERATURE = float(os.getenv("LLM_TEMPERATURE"))
|
| 118 |
RETRIEVER_SEARCH_K = int(os.getenv("RETRIEVER_SEARCH_K"))
|
|
@@ -125,13 +124,13 @@ vectorstore = Chroma(
|
|
| 125 |
retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": RETRIEVER_SEARCH_K})
|
| 126 |
print(f"✅ Vectorstore siap: {EMBEDDING_MODEL}", flush=True)
|
| 127 |
|
| 128 |
-
llm =
|
| 129 |
-
model=
|
| 130 |
-
|
| 131 |
-
|
| 132 |
-
|
| 133 |
)
|
| 134 |
-
print(f"✅ LLM siap: {
|
| 135 |
|
| 136 |
# ===================================================================
|
| 137 |
# RECAPTCHA CONFIG
|
|
@@ -203,9 +202,10 @@ contextualize_q_prompt = ChatPromptTemplate.from_messages([
|
|
| 203 |
])
|
| 204 |
history_aware_retriever = create_history_aware_retriever(llm, retriever, contextualize_q_prompt)
|
| 205 |
qa_system_prompt = (
|
| 206 |
-
"Anda adalah asisten
|
| 207 |
"Gunakan semua informasi dalam data yang Anda miliki untuk menjawab dengan akurat. "
|
| 208 |
"Jangan katakan data berasal dari sumber lain. "
|
|
|
|
| 209 |
"Jika data berupa angka, sebutkan angkanya dengan akurat. "
|
| 210 |
"Jika tidak tahu jawabannya, katakan belum memiliki datanya. "
|
| 211 |
"Berikan jawaban singkat, sopan, netral, dan akurat berdasarkan pertanyaan. "
|
|
@@ -240,18 +240,14 @@ def rate_limit_before_request():
|
|
| 240 |
|
| 241 |
if status == "captcha_required":
|
| 242 |
session['captcha_required'] = True
|
| 243 |
-
# Menghentikan request lebih awal dan kirim respons captcha
|
| 244 |
return jsonify({"captcha_required": True, "reason": "Rate limit triggered"})
|
| 245 |
|
| 246 |
elif status == "rate_limited_ip":
|
| 247 |
-
# Menghentikan request lebih awal dan kirim respons rate limit
|
| 248 |
return jsonify({"error": "Maaf, Anda telah melebihi batas permintaan. Silakan tunggu beberapa saat sebelum mencoba lagi."}), 429
|
| 249 |
|
| 250 |
elif status == "rate_limited_global":
|
| 251 |
-
# Menghentikan request lebih awal dan kirim respons rate limit
|
| 252 |
return jsonify({"error": "Mohon maaf, sistem sedang menerima banyak permintaan. Silakan coba lagi nanti."}), 429
|
| 253 |
|
| 254 |
-
|
| 255 |
# ===================================================================
|
| 256 |
# FLASK ROUTES
|
| 257 |
# ===================================================================
|
|
@@ -259,11 +255,11 @@ def rate_limit_before_request():
|
|
| 259 |
def home():
|
| 260 |
return render_template('index.html')
|
| 261 |
|
| 262 |
-
@app.route('/
|
| 263 |
-
def
|
| 264 |
captcha_on_load = session.get('captcha_required', False)
|
| 265 |
return render_template(
|
| 266 |
-
'
|
| 267 |
recaptcha_site_key=RECAPTCHA_SITE_KEY,
|
| 268 |
captcha_on_load=captcha_on_load
|
| 269 |
)
|
|
@@ -293,8 +289,6 @@ def get_response():
|
|
| 293 |
redis_client.delete(f"ip_rate_limit:{user_ip}")
|
| 294 |
except Exception as e:
|
| 295 |
print(f"⚠️ Gagal reset burst limit untuk IP {user_ip}: {e}", flush=True)
|
| 296 |
-
|
| 297 |
-
# >> BLOK RATE LIMIT LAMA SUDAH DIHAPUS DARI SINI <<
|
| 298 |
|
| 299 |
# Chat history
|
| 300 |
chat_history_from_session = session.get("chat_history", [])
|
|
@@ -327,8 +321,14 @@ def get_response():
|
|
| 327 |
bot_response = "Sistem sedang sibuk, coba lagi nanti."
|
| 328 |
|
| 329 |
if not bot_response or "belum memiliki data" in bot_response.lower():
|
| 330 |
-
bot_response =
|
| 331 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 332 |
if REDIS_ENABLED:
|
| 333 |
try:
|
| 334 |
redis_client.setex(cache_key, CACHE_EXPIRATION_SECONDS, bot_response)
|
|
|
|
| 3 |
# ===================================================================
|
| 4 |
from flask import Flask, render_template, request, jsonify, session
|
| 5 |
import psycopg2, redis, os, hashlib, json, time, requests
|
| 6 |
+
from langchain_google_genai import ChatGoogleGenerativeAI
|
| 7 |
from langchain_huggingface import HuggingFaceEmbeddings
|
| 8 |
from langchain_chroma import Chroma
|
| 9 |
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder
|
|
|
|
| 110 |
# ===================================================================
|
| 111 |
# LLM & EMBEDDING CONFIG
|
| 112 |
# ===================================================================
|
| 113 |
+
GEMINI_MODEL = os.getenv("GEMINI_MODEL")
|
| 114 |
+
GOOGLE_API_KEY = os.getenv("GOOGLE_API_KEY")
|
|
|
|
| 115 |
EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL")
|
| 116 |
LLM_TEMPERATURE = float(os.getenv("LLM_TEMPERATURE"))
|
| 117 |
RETRIEVER_SEARCH_K = int(os.getenv("RETRIEVER_SEARCH_K"))
|
|
|
|
| 124 |
retriever = vectorstore.as_retriever(search_type="similarity", search_kwargs={"k": RETRIEVER_SEARCH_K})
|
| 125 |
print(f"✅ Vectorstore siap: {EMBEDDING_MODEL}", flush=True)
|
| 126 |
|
| 127 |
+
llm = ChatGoogleGenerativeAI(
|
| 128 |
+
model=GEMINI_MODEL,
|
| 129 |
+
google_api_key=GOOGLE_API_KEY,
|
| 130 |
+
temperature=LLM_TEMPERATURE,
|
| 131 |
+
convert_system_message_to_human=True
|
| 132 |
)
|
| 133 |
+
print(f"✅ LLM siap: {GEMINI_MODEL}", flush=True)
|
| 134 |
|
| 135 |
# ===================================================================
|
| 136 |
# RECAPTCHA CONFIG
|
|
|
|
| 202 |
])
|
| 203 |
history_aware_retriever = create_history_aware_retriever(llm, retriever, contextualize_q_prompt)
|
| 204 |
qa_system_prompt = (
|
| 205 |
+
"Anda adalah layanan publik digital asisten KPU Provinsi Papua Barat Daya bernama LPDA. "
|
| 206 |
"Gunakan semua informasi dalam data yang Anda miliki untuk menjawab dengan akurat. "
|
| 207 |
"Jangan katakan data berasal dari sumber lain. "
|
| 208 |
+
"Fokus Anda adalah pada seluruh data yang dikelola oleh KPU Provinsi Papua Barat Daya. "
|
| 209 |
"Jika data berupa angka, sebutkan angkanya dengan akurat. "
|
| 210 |
"Jika tidak tahu jawabannya, katakan belum memiliki datanya. "
|
| 211 |
"Berikan jawaban singkat, sopan, netral, dan akurat berdasarkan pertanyaan. "
|
|
|
|
| 240 |
|
| 241 |
if status == "captcha_required":
|
| 242 |
session['captcha_required'] = True
|
|
|
|
| 243 |
return jsonify({"captcha_required": True, "reason": "Rate limit triggered"})
|
| 244 |
|
| 245 |
elif status == "rate_limited_ip":
|
|
|
|
| 246 |
return jsonify({"error": "Maaf, Anda telah melebihi batas permintaan. Silakan tunggu beberapa saat sebelum mencoba lagi."}), 429
|
| 247 |
|
| 248 |
elif status == "rate_limited_global":
|
|
|
|
| 249 |
return jsonify({"error": "Mohon maaf, sistem sedang menerima banyak permintaan. Silakan coba lagi nanti."}), 429
|
| 250 |
|
|
|
|
| 251 |
# ===================================================================
|
| 252 |
# FLASK ROUTES
|
| 253 |
# ===================================================================
|
|
|
|
| 255 |
def home():
|
| 256 |
return render_template('index.html')
|
| 257 |
|
| 258 |
+
@app.route('/lpda')
|
| 259 |
+
def lpda():
|
| 260 |
captcha_on_load = session.get('captcha_required', False)
|
| 261 |
return render_template(
|
| 262 |
+
'lpda.html',
|
| 263 |
recaptcha_site_key=RECAPTCHA_SITE_KEY,
|
| 264 |
captcha_on_load=captcha_on_load
|
| 265 |
)
|
|
|
|
| 289 |
redis_client.delete(f"ip_rate_limit:{user_ip}")
|
| 290 |
except Exception as e:
|
| 291 |
print(f"⚠️ Gagal reset burst limit untuk IP {user_ip}: {e}", flush=True)
|
|
|
|
|
|
|
| 292 |
|
| 293 |
# Chat history
|
| 294 |
chat_history_from_session = session.get("chat_history", [])
|
|
|
|
| 321 |
bot_response = "Sistem sedang sibuk, coba lagi nanti."
|
| 322 |
|
| 323 |
if not bot_response or "belum memiliki data" in bot_response.lower():
|
| 324 |
+
bot_response = (
|
| 325 |
+
"Mohon maaf data untuk pertanyaan tersebut belum tersedia dalam sistem. "
|
| 326 |
+
"Silakan cek situs resmi KPU Papua Barat Daya untuk informasi lebih lengkap: "
|
| 327 |
+
"<a href='https://papuabaratdaya.kpu.go.id/' target='_blank' "
|
| 328 |
+
"style='color:#fafbfc !important; text-decoration: underline;'>"
|
| 329 |
+
"https://papuabaratdaya.kpu.go.id/</a>."
|
| 330 |
+
)
|
| 331 |
+
|
| 332 |
if REDIS_ENABLED:
|
| 333 |
try:
|
| 334 |
redis_client.setex(cache_key, CACHE_EXPIRATION_SECONDS, bot_response)
|