Spaces:
Running
Running
17
Browse files
app.py
CHANGED
|
@@ -1,7 +1,7 @@
|
|
| 1 |
# app.py
|
| 2 |
# PapuaTranslate β Flask + SQLAlchemy (Supabase/SQLite) + mT5-LoRA (lazy)
|
| 3 |
import os, re, logging, threading
|
| 4 |
-
from datetime import datetime, timezone
|
| 5 |
from functools import wraps
|
| 6 |
from flask import Flask, render_template, request, redirect, url_for, session, jsonify, flash
|
| 7 |
from werkzeug.middleware.proxy_fix import ProxyFix
|
|
@@ -11,22 +11,24 @@ logging.basicConfig(level=logging.INFO, format="%(asctime)s | %(levelname)s | %(
|
|
| 11 |
log = logging.getLogger("papua-app")
|
| 12 |
|
| 13 |
# ===== Flask =====
|
| 14 |
-
# Template ada di 'frontend/'
|
| 15 |
app = Flask(__name__, template_folder="frontend", static_folder="static")
|
| 16 |
|
| 17 |
-
#
|
| 18 |
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1)
|
| 19 |
|
| 20 |
-
# Session config: aman untuk iframe
|
| 21 |
app.config.update(
|
| 22 |
SECRET_KEY=os.getenv("SECRET_KEY", "dev-secret-change-me"),
|
| 23 |
SESSION_COOKIE_NAME="hfspace_session",
|
| 24 |
-
SESSION_COOKIE_SAMESITE="None", # penting
|
| 25 |
SESSION_COOKIE_SECURE=True, # wajib True kalau SAMESITE=None
|
| 26 |
SESSION_COOKIE_HTTPONLY=True,
|
| 27 |
SESSION_COOKIE_PATH="/",
|
| 28 |
PREFERRED_URL_SCHEME="https",
|
| 29 |
)
|
|
|
|
|
|
|
| 30 |
|
| 31 |
# ===== DB: SQLAlchemy (Supabase Postgres / SQLite fallback) =====
|
| 32 |
from sqlalchemy import create_engine, Column, Integer, Text, DateTime, ForeignKey, func
|
|
@@ -37,7 +39,7 @@ if not DATABASE_URL:
|
|
| 37 |
DATABASE_URL = "sqlite:////tmp/app.db"
|
| 38 |
log.warning("[DB] DATABASE_URL tidak diset; pakai SQLite /tmp/app.db")
|
| 39 |
else:
|
| 40 |
-
# normalisasi
|
| 41 |
if DATABASE_URL.startswith("postgres://"):
|
| 42 |
DATABASE_URL = DATABASE_URL.replace("postgres://", "postgresql+psycopg2://", 1)
|
| 43 |
elif DATABASE_URL.startswith("postgresql://"):
|
|
@@ -103,7 +105,7 @@ def prenorm(text: str) -> str:
|
|
| 103 |
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
|
| 104 |
from peft import PeftModel
|
| 105 |
|
| 106 |
-
# Mulai dengan model kecil
|
| 107 |
BASE_MODEL_ID = os.getenv("BASE_MODEL_ID", "google/mt5-small")
|
| 108 |
ADAPTER_ID = os.getenv("ADAPTER_ID", "")
|
| 109 |
DEVICE = "cuda" if os.getenv("DEVICE", "cpu") == "cuda" else "cpu"
|
|
@@ -153,9 +155,10 @@ def _err(e):
|
|
| 153 |
log.exception("Unhandled error")
|
| 154 |
return "Internal Server Error", 500
|
| 155 |
|
| 156 |
-
# ===== Debug endpoints
|
| 157 |
@app.get("/debug/session/set")
|
| 158 |
def dbg_set():
|
|
|
|
| 159 |
session["uid"] = "test-user"
|
| 160 |
session["email"] = "[email protected]"
|
| 161 |
return {"ok": True, "set": True}
|
|
@@ -184,7 +187,11 @@ def login_post():
|
|
| 184 |
u = s.query(User).filter_by(email=email).first()
|
| 185 |
if not u or not verify_password(u, pwd):
|
| 186 |
flash("Email atau password salah", "error"); return redirect(url_for("login_get"))
|
|
|
|
|
|
|
|
|
|
| 187 |
session["uid"], session["email"] = u.id, u.email
|
|
|
|
| 188 |
return redirect(url_for("index"))
|
| 189 |
|
| 190 |
@app.get("/register")
|
|
@@ -202,6 +209,7 @@ def register_post():
|
|
| 202 |
flash("Email sudah terdaftar", "error"); return redirect(url_for("register_get"))
|
| 203 |
u = User(email=email); set_password(u, pwd)
|
| 204 |
s.add(u); s.commit()
|
|
|
|
| 205 |
session["uid"], session["email"] = u.id, u.email
|
| 206 |
return redirect(url_for("index"))
|
| 207 |
|
|
@@ -247,4 +255,5 @@ def api_translate():
|
|
| 247 |
return jsonify({"error": "server error"}), 500
|
| 248 |
|
| 249 |
if __name__ == "__main__":
|
|
|
|
| 250 |
app.run(host="0.0.0.0", port=int(os.getenv("PORT", "7860")), debug=False)
|
|
|
|
| 1 |
# app.py
|
| 2 |
# PapuaTranslate β Flask + SQLAlchemy (Supabase/SQLite) + mT5-LoRA (lazy)
|
| 3 |
import os, re, logging, threading
|
| 4 |
+
from datetime import datetime, timezone, timedelta
|
| 5 |
from functools import wraps
|
| 6 |
from flask import Flask, render_template, request, redirect, url_for, session, jsonify, flash
|
| 7 |
from werkzeug.middleware.proxy_fix import ProxyFix
|
|
|
|
| 11 |
log = logging.getLogger("papua-app")
|
| 12 |
|
| 13 |
# ===== Flask =====
|
| 14 |
+
# Template HTML kamu ada di 'frontend/'
|
| 15 |
app = Flask(__name__, template_folder="frontend", static_folder="static")
|
| 16 |
|
| 17 |
+
# Trust reverse proxy di Hugging Face -> Flask tahu proto HTTPS & host asli (perlu untuk cookie/redirect)
|
| 18 |
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1)
|
| 19 |
|
| 20 |
+
# Session config: aman untuk iframe/third-party, dan bekerja baik saat dibuka di tab langsung hf.space
|
| 21 |
app.config.update(
|
| 22 |
SECRET_KEY=os.getenv("SECRET_KEY", "dev-secret-change-me"),
|
| 23 |
SESSION_COOKIE_NAME="hfspace_session",
|
| 24 |
+
SESSION_COOKIE_SAMESITE="None", # penting untuk iframe / third-party
|
| 25 |
SESSION_COOKIE_SECURE=True, # wajib True kalau SAMESITE=None
|
| 26 |
SESSION_COOKIE_HTTPONLY=True,
|
| 27 |
SESSION_COOKIE_PATH="/",
|
| 28 |
PREFERRED_URL_SCHEME="https",
|
| 29 |
)
|
| 30 |
+
# Lama hidup session (untuk session.permanent=True)
|
| 31 |
+
app.permanent_session_lifetime = timedelta(hours=8)
|
| 32 |
|
| 33 |
# ===== DB: SQLAlchemy (Supabase Postgres / SQLite fallback) =====
|
| 34 |
from sqlalchemy import create_engine, Column, Integer, Text, DateTime, ForeignKey, func
|
|
|
|
| 39 |
DATABASE_URL = "sqlite:////tmp/app.db"
|
| 40 |
log.warning("[DB] DATABASE_URL tidak diset; pakai SQLite /tmp/app.db")
|
| 41 |
else:
|
| 42 |
+
# normalisasi ke psycopg2 driver
|
| 43 |
if DATABASE_URL.startswith("postgres://"):
|
| 44 |
DATABASE_URL = DATABASE_URL.replace("postgres://", "postgresql+psycopg2://", 1)
|
| 45 |
elif DATABASE_URL.startswith("postgresql://"):
|
|
|
|
| 105 |
from transformers import AutoTokenizer, AutoModelForSeq2SeqLM
|
| 106 |
from peft import PeftModel
|
| 107 |
|
| 108 |
+
# Mulai dengan model kecil untuk uji UI; setelah lancar, ganti ke model kamu
|
| 109 |
BASE_MODEL_ID = os.getenv("BASE_MODEL_ID", "google/mt5-small")
|
| 110 |
ADAPTER_ID = os.getenv("ADAPTER_ID", "")
|
| 111 |
DEVICE = "cuda" if os.getenv("DEVICE", "cpu") == "cuda" else "cpu"
|
|
|
|
| 155 |
log.exception("Unhandled error")
|
| 156 |
return "Internal Server Error", 500
|
| 157 |
|
| 158 |
+
# ===== Debug endpoints (cek cookie session) =====
|
| 159 |
@app.get("/debug/session/set")
|
| 160 |
def dbg_set():
|
| 161 |
+
session.permanent = True
|
| 162 |
session["uid"] = "test-user"
|
| 163 |
session["email"] = "[email protected]"
|
| 164 |
return {"ok": True, "set": True}
|
|
|
|
| 187 |
u = s.query(User).filter_by(email=email).first()
|
| 188 |
if not u or not verify_password(u, pwd):
|
| 189 |
flash("Email atau password salah", "error"); return redirect(url_for("login_get"))
|
| 190 |
+
|
| 191 |
+
# penting: buat session 'permanent' supaya cookie ditulis dengan benar
|
| 192 |
+
session.permanent = True
|
| 193 |
session["uid"], session["email"] = u.id, u.email
|
| 194 |
+
|
| 195 |
return redirect(url_for("index"))
|
| 196 |
|
| 197 |
@app.get("/register")
|
|
|
|
| 209 |
flash("Email sudah terdaftar", "error"); return redirect(url_for("register_get"))
|
| 210 |
u = User(email=email); set_password(u, pwd)
|
| 211 |
s.add(u); s.commit()
|
| 212 |
+
session.permanent = True
|
| 213 |
session["uid"], session["email"] = u.id, u.email
|
| 214 |
return redirect(url_for("index"))
|
| 215 |
|
|
|
|
| 255 |
return jsonify({"error": "server error"}), 500
|
| 256 |
|
| 257 |
if __name__ == "__main__":
|
| 258 |
+
# Jalankan lokal: python app.py, atau di HF pakai gunicorn
|
| 259 |
app.run(host="0.0.0.0", port=int(os.getenv("PORT", "7860")), debug=False)
|