| Server IP : 54.37.205.81 / Your IP : 216.73.216.76 Web Server : nginx/1.22.1 System : Linux vps-249481fa 6.1.0-50-cloud-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.176-1 (2026-07-02) x86_64 User : debian ( 1000) PHP Version : 8.2.32 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : OFF | Sudo : ON | Pkexec : OFF Directory : /var/www/app.copyrightchain.it/_tmp_patch/server/ai-gateway/ |
Upload File : |
import os, json, time, secrets
from datetime import datetime, timezone
from flask import Flask, request, jsonify, make_response
from flask_cors import CORS
import requests
APP = Flask(__name__)
CORS(APP)
ADMIN_TOKEN = os.environ.get("CCP_AI_ADMIN_TOKEN", "")
OPENAI_API_KEY = os.environ.get("OPENAI_API_KEY", "")
GEMINI_API_KEY = os.environ.get("GEMINI_API_KEY", "")
TOWER_PASSWORD = os.environ.get("CCP_TOWER_PASSWORD", "")
SESSION_SECRET = os.environ.get("CCP_SESSION_SECRET", "")
DATA_DIR = os.environ.get("CCP_AI_DATA_DIR", "/opt/ccp-ai-gateway/data")
USERS_FILE = os.path.join(DATA_DIR, "users.json")
USAGE_LOG = os.path.join(DATA_DIR, "ai_usage.jsonl")
DEFAULT_COST_PER_REQUEST_EUR_OPENAI = float(os.environ.get("CCP_COST_OPENAI_EUR_PER_REQ", "0.00") or "0.00")
DEFAULT_COST_PER_REQUEST_EUR_GEMINI = float(os.environ.get("CCP_COST_GEMINI_EUR_PER_REQ", "0.04") or "0.04")
os.makedirs(DATA_DIR, exist_ok=True)
def _now_iso():
return datetime.now(timezone.utc).isoformat()
def _json_load(path, default):
try:
with open(path, "r", encoding="utf-8") as f:
return json.load(f)
except Exception:
return default
def _json_save(path, obj):
tmp = path + ".tmp"
with open(tmp, "w", encoding="utf-8") as f:
json.dump(obj, f, ensure_ascii=False, indent=2)
os.replace(tmp, path)
def _append_jsonl(path, obj):
with open(path, "a", encoding="utf-8") as f:
f.write(json.dumps(obj, ensure_ascii=False) + "\n")
def require_admin_token(req):
if not ADMIN_TOKEN:
return True
return req.headers.get("X-CCP-Token", "") == ADMIN_TOKEN
def _sign(payload: dict) -> str:
if not SESSION_SECRET:
return ""
raw = json.dumps(payload, separators=(",", ":"), sort_keys=True)
salt = secrets.token_urlsafe(12)
import hashlib
h = hashlib.sha256()
h.update(SESSION_SECRET.encode("utf-8"))
h.update(salt.encode("utf-8"))
h.update(raw.encode("utf-8"))
digest = h.hexdigest()
return f"{salt}.{digest}.{raw}"
def _verify(token: str):
try:
salt, digest, raw = token.split(".", 2)
import hashlib
h = hashlib.sha256()
h.update(SESSION_SECRET.encode("utf-8"))
h.update(salt.encode("utf-8"))
h.update(raw.encode("utf-8"))
if h.hexdigest() != digest:
return None
payload = json.loads(raw)
exp = payload.get("exp")
if exp and time.time() > float(exp):
return None
return payload
except Exception:
return None
def tower_session():
tok = request.cookies.get("ccp_tower", "")
if not tok or not SESSION_SECRET:
return None
payload = _verify(tok)
if not payload:
return None
if payload.get("role") != "tower_admin":
return None
return payload
def require_tower():
if not TOWER_PASSWORD or not SESSION_SECRET:
return False
return tower_session() is not None
def ensure_users_file():
if not os.path.exists(USERS_FILE):
_json_save(USERS_FILE, {"users": []})
def find_user(uid: str):
ensure_users_file()
data = _json_load(USERS_FILE, {"users": []})
for u in data.get("users", []):
if str(u.get("id")) == str(uid):
return u, data
return None, data
def upsert_user(user: dict):
ensure_users_file()
data = _json_load(USERS_FILE, {"users": []})
users = data.get("users", [])
uid = str(user.get("id"))
for i, u in enumerate(users):
if str(u.get("id")) == uid:
users[i] = {**u, **user}
break
else:
users.append(user)
data["users"] = users
_json_save(USERS_FILE, data)
return user
def log_ai_usage(event: dict):
try:
_append_jsonl(USAGE_LOG, event)
except Exception:
pass
def summarize_usage(days: int = 30):
cutoff = time.time() - days * 86400
totals = {
"days": days,
"total_requests": 0,
"openai_requests": 0,
"gemini_requests": 0,
"estimated_cost_eur": 0.0,
"by_user": {}
}
try:
if not os.path.exists(USAGE_LOG):
return totals
with open(USAGE_LOG, "r", encoding="utf-8") as f:
for line in f:
line = line.strip()
if not line:
continue
try:
ev = json.loads(line)
except Exception:
continue
ts = ev.get("ts_epoch", 0)
if ts and ts < cutoff:
continue
totals["total_requests"] += 1
provider = ev.get("provider")
cost = float(ev.get("estimated_cost_eur", 0.0) or 0.0)
totals["estimated_cost_eur"] += cost
if provider == "openai":
totals["openai_requests"] += 1
elif provider == "gemini":
totals["gemini_requests"] += 1
uid = str(ev.get("user_id") or "unknown")
totals["by_user"].setdefault(uid, {"requests": 0, "estimated_cost_eur": 0.0})
totals["by_user"][uid]["requests"] += 1
totals["by_user"][uid]["estimated_cost_eur"] += cost
return totals
except Exception:
return totals
@APP.get("/health")
def health():
return jsonify({
"ok": True,
"has_openai_key": bool(os.environ.get("OPENAI_API_KEY", "")),
"has_gemini_key": bool(os.environ.get("GEMINI_API_KEY", "")),
"tower_configured": bool(TOWER_PASSWORD and SESSION_SECRET)
})
@APP.post("/tower/login")
def tower_login():
if not TOWER_PASSWORD or not SESSION_SECRET:
return jsonify({"error": "tower_not_configured"}), 500
data = request.get_json(silent=True) or {}
pwd = str(data.get("password", ""))
if not pwd or pwd != TOWER_PASSWORD:
return jsonify({"error": "unauthorized"}), 401
payload = {"role": "tower_admin", "iat": time.time(), "exp": time.time() + 24 * 3600}
tok = _sign(payload)
resp = make_response(jsonify({"ok": True}))
resp.set_cookie("ccp_tower", tok, httponly=True, secure=True, samesite="Lax", max_age=24 * 3600, path="/")
return resp
@APP.post("/tower/logout")
def tower_logout():
resp = make_response(jsonify({"ok": True}))
resp.set_cookie("ccp_tower", "", httponly=True, secure=True, samesite="Lax", max_age=0, path="/")
return resp
def _tower_guard():
if not require_tower():
return jsonify({"error": "unauthorized"}), 401
return None
@APP.get("/tower/ai/stats")
def tower_ai_stats():
g = _tower_guard()
if g: return g
days = int(request.args.get("days", "30") or "30")
days = max(1, min(days, 365))
return jsonify(summarize_usage(days))
@APP.get("/tower/users")
def tower_users_list():
g = _tower_guard()
if g: return g
ensure_users_file()
data = _json_load(USERS_FILE, {"users": []})
return jsonify(data)
@APP.post("/tower/users/upsert")
def tower_users_upsert():
g = _tower_guard()
if g: return g
data = request.get_json(silent=True) or {}
uid = data.get("id")
if not uid:
return jsonify({"error": "missing_id"}), 400
user = {
"id": str(uid),
"email": data.get("email", ""),
"name": data.get("name", ""),
"wallet": data.get("wallet", ""),
"plan": data.get("plan", "free"),
"ai_limit_monthly": int(data.get("ai_limit_monthly", 0) or 0),
"updated_at": _now_iso(),
}
upsert_user(user)
return jsonify({"ok": True, "user": user})
@APP.post("/tower/users/send_abo")
def tower_send_abo():
g = _tower_guard()
if g: return g
data = request.get_json(silent=True) or {}
uid = data.get("user_id")
amount = data.get("amount")
if not uid or amount is None:
return jsonify({"error": "missing_params"}), 400
user, _ = find_user(str(uid))
if not user or not user.get("wallet"):
return jsonify({"error": "wallet_not_found"}), 400
return jsonify({"ok": True, "queued": True, "user_id": str(uid), "wallet": user.get("wallet"), "amount": amount})
@APP.post("/text")
def ai_text():
if not require_admin_token(request):
return jsonify({"error": "unauthorized"}), 401
payload = request.get_json(silent=True) or {}
prompt = str(payload.get("prompt", "")).strip()
provider = str(payload.get("provider", "openai")).lower()
user_id = str(payload.get("user_id", "tower_admin"))
if not prompt:
return jsonify({"error": "missing_prompt"}), 400
started = time.time()
if provider == "gemini":
res = _call_gemini(prompt)
est_cost = DEFAULT_COST_PER_REQUEST_EUR_GEMINI
provider_name = "gemini"
else:
res = _call_openai(prompt)
est_cost = DEFAULT_COST_PER_REQUEST_EUR_OPENAI
provider_name = "openai"
log_ai_usage({
"ts_iso": _now_iso(),
"ts_epoch": time.time(),
"user_id": user_id,
"provider": provider_name,
"estimated_cost_eur": est_cost,
"latency_ms": int((time.time() - started) * 1000),
"ok": bool(res.get("ok")),
"status": res.get("status"),
"model": res.get("model"),
})
if not res.get("ok"):
return jsonify({"error": res.get("error"), "status": res.get("status"), "details": res.get("details")}), int(res.get("status") or 500)
return jsonify({"ok": True, "text": res.get("text", ""), "model": res.get("model")})
def _call_openai(prompt: str):
key = os.environ.get("OPENAI_API_KEY", "")
model = os.environ.get("OPENAI_TEXT_MODEL", "gpt-4.1-mini")
if not key:
return {"ok": False, "error": "missing_openai_key", "status": 400, "model": model}
url = "https://api.openai.com/v1/responses"
body = {"model": model, "input": prompt}
try:
r = requests.post(url, headers={"Authorization": f"Bearer {key}", "Content-Type": "application/json"}, json=body, timeout=120)
if r.status_code >= 400:
return {"ok": False, "error": "openai_error", "status": r.status_code, "details": r.text, "model": model}
j = r.json()
text = ""
try:
for item in j.get("output", []):
for c in item.get("content", []):
if c.get("type") == "output_text":
text += c.get("text", "")
except Exception:
text = j.get("output_text", "") or ""
return {"ok": True, "text": text.strip(), "status": 200, "model": model}
except Exception as e:
return {"ok": False, "error": "openai_exception", "status": 500, "details": str(e), "model": model}
def _call_gemini(prompt: str):
key = os.environ.get("GEMINI_API_KEY", "")
if not key:
return {"ok": False, "error": "missing_gemini_key", "status": 400, "model": "gemini"}
return {"ok": False, "error": "gemini_not_implemented", "status": 501, "details": "Gemini call will be added in next bundle.", "model": "gemini"}
if __name__ == "__main__":
APP.run(host="127.0.0.1", port=5060)