Spaces:
Sleeping
Sleeping
| import os | |
| import json | |
| import requests | |
| import shutil | |
| import time | |
| import traceback | |
| from typing import List, Optional | |
| from fastapi import FastAPI, HTTPException, UploadFile, File, Form, Body | |
| from fastapi.middleware.cors import CORSMiddleware | |
| from fastapi.responses import FileResponse, JSONResponse | |
| from pydantic import BaseModel | |
| from passlib.context import CryptContext | |
| from datetime import datetime | |
| # --- KONFIGURASI --- | |
| app = FastAPI(title="BlackSpaces Brain v1.3 (Bulletproof)") | |
| JSONBIN_ID = "6962ebfe43b1c97be927b07d" | |
| JSONBIN_KEY = "$2a$10$khoKkhYEAUCG.O0xHDHiY.Ei88KlSV1l3olI2pxc86mUSsTaNpJx6" | |
| JSONBIN_URL = f"https://api.jsonbin.io/v3/b/{JSONBIN_ID}" | |
| pwd_context = CryptContext(schemes=["sha256_crypt"], deprecated="auto") | |
| GALLERY_DIR = "gallery_storage" | |
| if not os.path.exists(GALLERY_DIR): | |
| os.makedirs(GALLERY_DIR) | |
| app.add_middleware( | |
| CORSMiddleware, | |
| allow_origins=["*"], | |
| allow_credentials=True, | |
| allow_methods=["*"], | |
| allow_headers=["*"], | |
| ) | |
| class UserAuth(BaseModel): | |
| username: str | |
| password: str | |
| # --- HELPER FUNCTIONS --- | |
| def get_users_db(): | |
| headers = {"X-Master-Key": JSONBIN_KEY} | |
| try: | |
| response = requests.get(JSONBIN_URL + "/latest", headers=headers, timeout=10) | |
| if response.status_code == 200: | |
| data = response.json() | |
| # Handle berbagai struktur JSONBin | |
| users = [] | |
| if "record" in data: | |
| users = data["record"].get("users", []) | |
| else: | |
| users = data.get("users", []) | |
| # Filter user yang rusak (tidak punya username) | |
| valid_users = [u for u in users if isinstance(u, dict) and "username" in u] | |
| return valid_users | |
| return [] | |
| except Exception as e: | |
| print(f"DB Error: {e}") | |
| return [] | |
| def update_users_db(users_list): | |
| headers = {"X-Master-Key": JSONBIN_KEY, "Content-Type": "application/json"} | |
| try: | |
| requests.put(JSONBIN_URL, headers=headers, json={"users": users_list}, timeout=10) | |
| except Exception as e: | |
| print(f"Save Error: {e}") | |
| def verify_password(plain, hashed): | |
| try: return pwd_context.verify(plain, hashed) | |
| except: return False | |
| def get_password_hash(password): | |
| return pwd_context.hash(password) | |
| # --- ENDPOINTS --- | |
| def home(): return {"status": "online", "system": "v1.3"} | |
| def ping(): return {"status": "alive"} | |
| def signup(user: UserAuth): | |
| try: | |
| users = get_users_db() | |
| # Cek duplikat dengan aman | |
| for u in users: | |
| if u.get('username', '').lower() == user.username.lower(): | |
| return JSONResponse(status_code=400, content={"status": "error", "detail": "Username taken"}) | |
| new_user = { | |
| "username": user.username, | |
| "password": get_password_hash(user.password), | |
| "joined_at": str(datetime.now()) | |
| } | |
| users.append(new_user) | |
| update_users_db(users) | |
| return {"status": "success", "message": "Registered"} | |
| except Exception as e: | |
| return JSONResponse(status_code=500, content={"status": "error", "detail": str(e)}) | |
| def login(user: UserAuth): | |
| try: | |
| users = get_users_db() | |
| for u in users: | |
| if u.get('username', '').lower() == user.username.lower(): | |
| if verify_password(user.password, u.get('password', '')): | |
| return {"status": "success", "username": u['username'], "token": "ok"} | |
| else: | |
| return JSONResponse(status_code=401, content={"status": "error", "detail": "Wrong Password"}) | |
| return JSONResponse(status_code=404, content={"status": "error", "detail": "User not found"}) | |
| except Exception as e: | |
| return JSONResponse(status_code=500, content={"status": "error", "detail": str(e)}) | |
| async def save_to_gallery(username: str = Form(...), prompt: str = Form(...), meta: str = Form(...), image: UploadFile = File(...)): | |
| try: | |
| user_dir = os.path.join(GALLERY_DIR, username) | |
| if not os.path.exists(user_dir): os.makedirs(user_dir) | |
| timestamp = int(time.time()) | |
| path_img = os.path.join(user_dir, f"{timestamp}.jpg") | |
| path_meta = os.path.join(user_dir, f"{timestamp}.json") | |
| with open(path_img, "wb") as buffer: shutil.copyfileobj(image.file, buffer) | |
| with open(path_meta, "w") as f: json.dump({"prompt": prompt, "details": meta, "date": str(datetime.now())}, f) | |
| return {"status": "success", "file_id": timestamp} | |
| except Exception as e: | |
| return JSONResponse(status_code=500, content={"status": "error", "detail": str(e)}) | |
| def get_user_gallery(username: str): | |
| try: | |
| user_dir = os.path.join(GALLERY_DIR, username) | |
| if not os.path.exists(user_dir): return {"images": []} | |
| images = [] | |
| for file in os.listdir(user_dir): | |
| if file.endswith(".jpg"): | |
| img_id = file.split(".")[0] | |
| meta_path = os.path.join(user_dir, f"{img_id}.json") | |
| meta_data = {} | |
| if os.path.exists(meta_path): | |
| with open(meta_path, "r") as f: meta_data = json.load(f) | |
| images.append({"id": img_id, "url": f"/gallery/view/{username}/{file}", "meta": meta_data}) | |
| images.sort(key=lambda x: x['id'], reverse=True) | |
| return {"images": images} | |
| except: return {"images": []} | |
| def view_image(username: str, filename: str): | |
| path = os.path.join(GALLERY_DIR, username, filename) | |
| if os.path.exists(path): return FileResponse(path) | |
| raise HTTPException(status_code=404) |