Download app.py from vsmdvic/idea: direct link, hf CLI and curl.
- Browser
- Download file 14.3 kB
-
https://huggingface.co/spaces/vsmdvic/idea/resolve/main/app.py
- Command line
-
hf download hf://spaces/vsmdvic/idea/app.py
-
curl -L -o app.py https://huggingface.co/spaces/vsmdvic/idea/resolve/main/app.py
14.3 kB
| from flask import Flask, send_from_directory, request, jsonify, Response | |
| import requests, time, threading, json, os | |
| import cloudinary | |
| import cloudinary.uploader | |
| import cloudinary.api | |
| app = Flask(__name__, static_folder='static') | |
| # ββ Cloudinary config βββββββββββββββββββββββββββββββββββββββββ | |
| cloudinary.config( | |
| cloud_name = "db6wrclc7", | |
| api_key = "371945239656253", | |
| api_secret = "ZgN-B2lyAz6zk2MI2N5b_1dc1r8", | |
| secure = True | |
| ) | |
| # ββ Firebase ββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| FIREBASE_API_KEY = "AIzaSyB9--Onx3-_YjD-YzblhZjaWSVVqTQJ1lU" | |
| FIRESTORE_BASE = "https://firestore.googleapis.com/v1/projects/vservers1/databases/(default)/documents" | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # CLOUDINARY ROUTES | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def drive_upload(): | |
| try: | |
| elev_vpass = request.form.get("elevId", "unknown") | |
| materie = request.form.get("materieId", "general") | |
| f = request.files.get("file") | |
| if not f: | |
| return jsonify({"error": "no file"}), 400 | |
| file_bytes = f.read() | |
| file_name = f.filename or "fisier" | |
| print(f"[UPLOAD] {elev_vpass}/{materie}/{file_name} ({len(file_bytes)} bytes)") | |
| # Folder: SGE/RV-0022/Matematica | |
| folder = f"SGE/{elev_vpass}/{materie}" | |
| # Upload ca raw β public_id = numele complet cu extensie | |
| import io | |
| result = cloudinary.uploader.upload( | |
| io.BytesIO(file_bytes), | |
| folder = folder, | |
| public_id = file_name, # pastram extensia | |
| resource_type = "raw", | |
| use_filename = True, | |
| unique_filename = False, | |
| overwrite = False, | |
| context = f"uploaded_at={int(time.time())}|original_name={file_name}", | |
| ) | |
| print(f"[UPLOAD] OK β {result['public_id']}") | |
| _fs_log("upload", {"elevVpass": elev_vpass, "materie": materie, | |
| "fisier": file_name, "fileId": result["public_id"]}) | |
| return jsonify({ | |
| "fileId": result["public_id"], | |
| "name": file_name, | |
| "size": result.get("bytes", 0), | |
| "url": result.get("secure_url", ""), | |
| }) | |
| except Exception as e: | |
| import traceback; traceback.print_exc() | |
| return jsonify({"error": str(e)}), 500 | |
| def drive_list(): | |
| try: | |
| elev_vpass = request.args.get("elevId", "") | |
| materie = request.args.get("materieId", "") | |
| folder = f"SGE/{elev_vpass}/{materie}" | |
| result = cloudinary.api.resources( | |
| type = "upload", | |
| resource_type = "raw", | |
| prefix = folder + "/", | |
| max_results = 100, | |
| ) | |
| files = [] | |
| for r in result.get("resources", []): | |
| pid = r["public_id"] | |
| # Incearca sa extraga numele original din context | |
| ctx = r.get("context", {}).get("custom", {}) | |
| name = ctx.get("original_name", "") | |
| if not name: | |
| # fallback: ultimul segment din public_id | |
| name = pid.split("/")[-1] | |
| files.append({ | |
| "id": pid, | |
| "name": name, | |
| "size": r.get("bytes", 0), | |
| "mimeType": r.get("resource_type", "raw"), | |
| "createdTime": r.get("created_at", ""), | |
| "url": r.get("secure_url", ""), | |
| }) | |
| return jsonify({"files": files}) | |
| except cloudinary.exceptions.NotFound: | |
| return jsonify({"files": []}) | |
| except Exception as e: | |
| print(f"[LIST ERROR] {e}") | |
| return jsonify({"files": [], "error": str(e)}) | |
| def drive_download(file_id): | |
| try: | |
| # Cloudinary: genereaza URL de download direct | |
| url = cloudinary.utils.cloudinary_url( | |
| file_id, | |
| resource_type = "raw", | |
| type = "upload", | |
| )[0] | |
| # Redirect catre URL-ul Cloudinary | |
| from flask import redirect | |
| return redirect(url) | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 500 | |
| def drive_delete(file_id): | |
| try: | |
| cloudinary.uploader.destroy(file_id, resource_type="raw") | |
| return jsonify({"ok": True}) | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 500 | |
| def drive_test(): | |
| try: | |
| result = cloudinary.api.ping() | |
| return jsonify({"ok": True, "cloudinary": result}) | |
| except Exception as e: | |
| return jsonify({"ok": False, "error": str(e)}), 500 | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # FIRESTORE HELPERS | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _to_fields(data): | |
| fields = {} | |
| for k, v in data.items(): | |
| if v is None: fields[k] = {"nullValue": None} | |
| elif isinstance(v, bool): fields[k] = {"booleanValue": v} | |
| elif isinstance(v, int): fields[k] = {"integerValue": str(v)} | |
| else: fields[k] = {"stringValue": str(v)} | |
| return fields | |
| def _fs_add(col, data): | |
| r = requests.post(f"{FIRESTORE_BASE}/{col}?key={FIREBASE_API_KEY}", | |
| json={"fields": _to_fields(data)}, timeout=15) | |
| return r.status_code == 200 | |
| def _fs_log(tip, extra={}): | |
| try: | |
| payload = {"tip": tip, "ts": int(time.time()), **extra} | |
| _fs_add("loguri", payload) | |
| except: pass | |
| # ββ Log endpoint ββββββββββββββββββββββββββββββββββββββββββββββ | |
| def api_log(): | |
| try: | |
| data = request.get_json(silent=True) or {} | |
| _fs_log(data.get("tip","event"), {k:v for k,v in data.items() if k!="tip"}) | |
| return jsonify({"ok": True}) | |
| except Exception as e: | |
| return jsonify({"error": str(e)}), 500 | |
| # ββ Logs endpoint βββββββββββββββββββββββββββββββββββββββββββββ | |
| def api_logs(): | |
| try: | |
| r = requests.get(f"{FIRESTORE_BASE}/loguri?key={FIREBASE_API_KEY}&pageSize=200", timeout=15) | |
| docs = r.json().get("documents", []) | |
| logs = [] | |
| for d in docs: | |
| f = d.get("fields", {}) | |
| entry = {} | |
| for k, v in f.items(): | |
| entry[k] = v.get("stringValue") or v.get("integerValue") or v.get("booleanValue") or "" | |
| entry["_id"] = d["name"].split("/")[-1] | |
| logs.append(entry) | |
| logs.sort(key=lambda x: int(x.get("ts",0)), reverse=True) | |
| return jsonify({"logs": logs[:150]}) | |
| except Exception as e: | |
| return jsonify({"error": str(e), "logs": []}), 500 | |
| # ββ Ping / Online βββββββββββββββββββββββββββββββββββββββββββββ | |
| _online = {} | |
| def api_ping(): | |
| data = request.get_json(silent=True) or {} | |
| key = f"{data.get('vpass','?')}_{data.get('role','?')}" | |
| _online[key] = {"ts": time.time(), "vpass": data.get("vpass","?"), | |
| "role": data.get("role","?"), "name": data.get("name","")} | |
| now = time.time() | |
| expired = [k for k,v in _online.items() if now - v["ts"] > 120] | |
| for k in expired: del _online[k] | |
| return jsonify({"ok": True}) | |
| def api_online(): | |
| now = time.time() | |
| active = {k:v for k,v in _online.items() if now - v["ts"] <= 120} | |
| return jsonify({ | |
| "total": len(active), | |
| "elevi": [v for v in active.values() if v["role"]=="elev"], | |
| "profesori": [v for v in active.values() if v["role"]=="profesor"], | |
| }) | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # CLEANUP β sterge fisierele mai vechi de 7 zile din Cloudinary | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def cleanup_old_files(): | |
| while True: | |
| try: | |
| time.sleep(3600) | |
| print("[CLEANUP] Verific fisiere vechi...") | |
| limit_ts = int(time.time()) - 7 * 24 * 3600 | |
| result = cloudinary.api.resources( | |
| type="upload", resource_type="raw", | |
| prefix="SGE/", max_results=500, | |
| ) | |
| deleted = 0 | |
| for r in result.get("resources", []): | |
| created = r.get("created_at","") | |
| if created: | |
| try: | |
| from datetime import datetime, timezone | |
| dt = datetime.fromisoformat(created.replace("Z","+00:00")) | |
| if int(dt.timestamp()) < limit_ts: | |
| cloudinary.uploader.destroy(r["public_id"], resource_type="raw") | |
| deleted += 1 | |
| print(f"[CLEANUP] Sters: {r['public_id']}") | |
| _fs_log("cleanup_delete", {"fisier": r["public_id"]}) | |
| except: pass | |
| print(f"[CLEANUP] Gata: {deleted} sterse.") | |
| except Exception as ex: | |
| print(f"[CLEANUP] Eroare: {ex}") | |
| time.sleep(300) | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| # AUTO SEED | |
| # ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| ELEVI = [ | |
| {"pozitie":1,"nume":"Andronic Aniela","vpassId":"AA-0001"}, | |
| {"pozitie":2,"nume":"Badan Alexandra","vpassId":"BA-0002"}, | |
| {"pozitie":3,"nume":"Bunescu Lavinia","vpassId":"BL-0003"}, | |
| {"pozitie":4,"nume":"Bunescu Lorena","vpassId":"BL-0004"}, | |
| {"pozitie":5,"nume":"Burdujan Damian","vpassId":"BD-0005"}, | |
| {"pozitie":6,"nume":"Ceban Madalina","vpassId":"CM-0006"}, | |
| {"pozitie":7,"nume":"Ceban Valeria","vpassId":"CV-0007"}, | |
| {"pozitie":8,"nume":"Cebanu Nichita","vpassId":"CN-0008"}, | |
| {"pozitie":9,"nume":"Chele Ilinca","vpassId":"CI-0009"}, | |
| {"pozitie":10,"nume":"Chihai Mirela","vpassId":"CM-0010"}, | |
| {"pozitie":11,"nume":"Cojocari Ciprian","vpassId":"CC-0011"}, | |
| {"pozitie":12,"nume":"Creciun Leonard","vpassId":"CL-0012"}, | |
| {"pozitie":13,"nume":"Lozovan Sanda","vpassId":"LS-0013"}, | |
| {"pozitie":14,"nume":"Lungu Sergiu","vpassId":"LS-0014"}, | |
| {"pozitie":15,"nume":"Mahnea Adelina","vpassId":"MA-0015"}, | |
| {"pozitie":16,"nume":"Morcan Ina","vpassId":"MI-0016"}, | |
| {"pozitie":17,"nume":"Morcan Ion","vpassId":"MI-0017"}, | |
| {"pozitie":18,"nume":"Popa Cristina","vpassId":"PC-0018"}, | |
| {"pozitie":19,"nume":"Pricob Adelina","vpassId":"PA-0019"}, | |
| {"pozitie":20,"nume":"Prinos Catalina","vpassId":"PC-0020"}, | |
| {"pozitie":21,"nume":"Radu Daniela","vpassId":"RD-0021"}, | |
| {"pozitie":22,"nume":"Rosca Victor","vpassId":"RV-0022"}, | |
| {"pozitie":23,"nume":"Rotari Cristian","vpassId":"RC-0023"}, | |
| {"pozitie":24,"nume":"Rotaru Camelia","vpassId":"RC-0024"}, | |
| {"pozitie":25,"nume":"Sambris Stanislav","vpassId":"SS-0025"}, | |
| {"pozitie":26,"nume":"Sirbu Delia","vpassId":"SD-0026"}, | |
| {"pozitie":27,"nume":"Soltoian Elena","vpassId":"SE-0027"}, | |
| {"pozitie":28,"nume":"Tabuncic Chiril","vpassId":"TC-0028"}, | |
| {"pozitie":29,"nume":"Turcan Gabriel","vpassId":"TG-0029"}, | |
| {"pozitie":30,"nume":"Turcan Mihai","vpassId":"TM-0030"}, | |
| {"pozitie":31,"nume":"Turcanu Ilie","vpassId":"TI-0031"}, | |
| {"pozitie":32,"nume":"Virlan Daniela","vpassId":"VD-0032"}, | |
| ] | |
| def auto_seed(): | |
| time.sleep(4) | |
| try: | |
| r = requests.get(f"{FIRESTORE_BASE}/elevi?key={FIREBASE_API_KEY}&pageSize=1", timeout=15) | |
| if r.json().get("documents"): | |
| print("[SGE] DB populat β seed omis."); return | |
| print("[SGE] Seed automat...") | |
| ok = 0 | |
| for e in ELEVI: | |
| if _fs_add("elevi", {"nume":e["nume"],"vpassId":e["vpassId"], | |
| "pozitie":e["pozitie"],"pin":None,"confirmed":False}): | |
| ok += 1 | |
| time.sleep(0.12) | |
| print(f"[SGE] Seed gata: {ok}/{len(ELEVI)}") | |
| except Exception as ex: | |
| print(f"[SGE] Seed eroare: {ex}") | |
| threading.Thread(target=auto_seed, daemon=True).start() | |
| threading.Thread(target=cleanup_old_files, daemon=True).start() | |
| # ββ Serve static ββββββββββββββββββββββββββββββββββββββββββββββ | |
| def index(): return send_from_directory("static", "index.html") | |
| def not_found(e): return send_from_directory("static", "503.html"), 404 | |
| def serve_files(filename): | |
| try: return send_from_directory("static", filename) | |
| except: return send_from_directory("static", "503.html"), 404 | |
| if __name__ == "__main__": | |
| app.run(host="0.0.0.0", port=7860, debug=False) | |