BlackSpaces commited on
Commit
4d15d01
·
verified ·
1 Parent(s): 95efb3a

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +109 -129
app.py CHANGED
@@ -3,34 +3,35 @@ import json
3
  import requests
4
  import shutil
5
  import time
 
6
  from typing import List, Optional
7
  from fastapi import FastAPI, HTTPException, UploadFile, File, Form, Body
8
  from fastapi.middleware.cors import CORSMiddleware
9
  from fastapi.responses import FileResponse, JSONResponse
10
  from pydantic import BaseModel
 
11
  from passlib.context import CryptContext
12
  from datetime import datetime
13
 
14
  # --- KONFIGURASI ---
15
- app = FastAPI(title="BlackSpaces Brain v1.1")
16
 
17
- # JSONBIN CONFIG (USER DATABASE)
18
  JSONBIN_ID = "6962ebfe43b1c97be927b07d"
19
  JSONBIN_KEY = "$2a$10$khoKkhYEAUCG.O0xHDHiY.Ei88KlSV1l3olI2pxc86mUSsTaNpJx6"
20
  JSONBIN_URL = f"https://api.jsonbin.io/v3/b/{JSONBIN_ID}"
21
 
22
- # SECURITY
23
- pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
24
 
25
- # STORAGE (LOCAL HF - EPHEMERAL)
26
  GALLERY_DIR = "gallery_storage"
27
  if not os.path.exists(GALLERY_DIR):
28
  os.makedirs(GALLERY_DIR)
29
 
30
- # CORS (Agar Perchance bisa akses)
31
  app.add_middleware(
32
  CORSMiddleware,
33
- allow_origins=["*"], # Izinkan semua origin (Perchance)
34
  allow_credentials=True,
35
  allow_methods=["*"],
36
  allow_headers=["*"],
@@ -41,26 +42,22 @@ class UserAuth(BaseModel):
41
  username: str
42
  password: str
43
 
44
- class GalleryMeta(BaseModel):
45
- username: str
46
- prompt: str
47
- neg_prompt: str
48
- cfg: float
49
- width: int
50
- height: int
51
- model_ver: str
52
-
53
- # --- HELPER FUNCTIONS ---
54
-
55
  def get_users_db():
56
  headers = {"X-Master-Key": JSONBIN_KEY}
57
  try:
58
- response = requests.get(JSONBIN_URL + "/latest", headers=headers)
59
  if response.status_code == 200:
60
- return response.json().get("record", {}).get("users", [])
61
- return []
 
 
 
 
 
 
62
  except Exception as e:
63
- print(f"Error fetching DB: {e}")
64
  return []
65
 
66
  def update_users_db(users_list):
@@ -69,10 +66,18 @@ def update_users_db(users_list):
69
  "Content-Type": "application/json"
70
  }
71
  payload = {"users": users_list}
72
- requests.put(JSONBIN_URL, headers=headers, json=payload)
 
 
 
 
 
73
 
74
  def verify_password(plain_password, hashed_password):
75
- return pwd_context.verify(plain_password, hashed_password)
 
 
 
76
 
77
  def get_password_hash(password):
78
  return pwd_context.hash(password)
@@ -81,122 +86,97 @@ def get_password_hash(password):
81
 
82
  @app.get("/")
83
  def home():
84
- return {"status": "online", "system": "BlackSpaces Brain v1.1", "time": str(datetime.now())}
 
 
 
 
85
 
86
- # 1. AUTH SYSTEM
87
  @app.post("/auth/signup")
88
  def signup(user: UserAuth):
89
- users = get_users_db()
90
-
91
- # Cek duplikat
92
- for u in users:
93
- if u['username'].lower() == user.username.lower():
94
- raise HTTPException(status_code=400, detail="Username already taken")
95
-
96
- # Hash password & Simpan
97
- hashed_pw = get_password_hash(user.password)
98
- new_user = {
99
- "username": user.username,
100
- "password": hashed_pw, # Simpan hash, bukan plain text!
101
- "joined_at": str(datetime.now())
102
- }
103
-
104
- users.append(new_user)
105
- update_users_db(users)
106
-
107
- return {"status": "success", "message": "User registered successfully"}
 
 
 
 
 
 
 
108
 
109
  @app.post("/auth/login")
110
  def login(user: UserAuth):
111
- users = get_users_db()
112
-
113
- for u in users:
114
- if u['username'].lower() == user.username.lower():
115
- if verify_password(user.password, u['password']):
116
- return {"status": "success", "username": u['username'], "token": "dummy-token-v1"} # Simplifikasi token
117
- else:
118
- raise HTTPException(status_code=401, detail="Invalid password")
119
-
120
- raise HTTPException(status_code=404, detail="User not found")
121
-
122
- # 2. GALLERY SYSTEM
123
- @app.post("/gallery/save")
124
- async def save_to_gallery(
125
- username: str = Form(...),
126
- prompt: str = Form(...),
127
- meta: str = Form(...), # JSON string of other metadata
128
- image: UploadFile = File(...)
129
- ):
130
- # Buat folder user jika belum ada
131
- user_dir = os.path.join(GALLERY_DIR, username)
132
- if not os.path.exists(user_dir):
133
- os.makedirs(user_dir)
134
-
135
- # Generate Filename unik
136
- timestamp = int(time.time())
137
- filename_img = f"{timestamp}.jpg"
138
- filename_meta = f"{timestamp}.json"
139
-
140
- path_img = os.path.join(user_dir, filename_img)
141
- path_meta = os.path.join(user_dir, filename_meta)
142
-
143
- # Simpan Gambar
144
- with open(path_img, "wb") as buffer:
145
- shutil.copyfileobj(image.file, buffer)
146
 
147
- # Simpan Metadata
148
- metadata = {
149
- "prompt": prompt,
150
- "details": meta,
151
- "date": str(datetime.now())
152
- }
153
- with open(path_meta, "w") as f:
154
- json.dump(metadata, f)
155
 
156
- return {"status": "success", "file_id": timestamp}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
157
 
158
  @app.get("/gallery/{username}")
159
  def get_user_gallery(username: str):
160
- user_dir = os.path.join(GALLERY_DIR, username)
161
- if not os.path.exists(user_dir):
162
- return {"images": []}
163
-
164
- # List semua gambar
165
- images = []
166
- for file in os.listdir(user_dir):
167
- if file.endswith(".jpg"):
168
- img_id = file.split(".")[0]
169
- # Baca metadata
170
- meta_path = os.path.join(user_dir, f"{img_id}.json")
171
- meta_data = {}
172
- if os.path.exists(meta_path):
173
- with open(meta_path, "r") as f:
174
- meta_data = json.load(f)
175
-
176
- # Construct URL (HF Space URL logic needs to be handled in frontend, we send relative path)
177
- images.append({
178
- "id": img_id,
179
- "url": f"/gallery/view/{username}/{file}",
180
- "meta": meta_data
181
- })
182
-
183
- # Sort by terbaru
184
- images.sort(key=lambda x: x['id'], reverse=True)
185
- return {"images": images}
186
 
187
  @app.get("/gallery/view/{username}/{filename}")
188
  def view_image(username: str, filename: str):
189
- file_path = os.path.join(GALLERY_DIR, username, filename)
190
- if os.path.exists(file_path):
191
- return FileResponse(file_path)
192
- raise HTTPException(status_code=404, detail="Image not found")
193
-
194
- # 3. KEEP ALIVE (PING)
195
- @app.get("/ping")
196
- def ping():
197
- return {"status": "alive", "timestamp": time.time()}
198
-
199
- # Jalankan server
200
- if __name__ == "__main__":
201
- import uvicorn
202
- uvicorn.run(app, host="0.0.0.0", port=7860)
 
3
  import requests
4
  import shutil
5
  import time
6
+ import traceback
7
  from typing import List, Optional
8
  from fastapi import FastAPI, HTTPException, UploadFile, File, Form, Body
9
  from fastapi.middleware.cors import CORSMiddleware
10
  from fastapi.responses import FileResponse, JSONResponse
11
  from pydantic import BaseModel
12
+ # Kita ganti hashing ke yang lebih stabil untuk debugging
13
  from passlib.context import CryptContext
14
  from datetime import datetime
15
 
16
  # --- KONFIGURASI ---
17
+ app = FastAPI(title="BlackSpaces Brain v1.2 (Debug Mode)")
18
 
19
+ # JSONBIN CONFIG
20
  JSONBIN_ID = "6962ebfe43b1c97be927b07d"
21
  JSONBIN_KEY = "$2a$10$khoKkhYEAUCG.O0xHDHiY.Ei88KlSV1l3olI2pxc86mUSsTaNpJx6"
22
  JSONBIN_URL = f"https://api.jsonbin.io/v3/b/{JSONBIN_ID}"
23
 
24
+ # SECURITY (Menggunakan scheme 'sha256_crypt' yang lebih compatible daripada bcrypt di beberapa env)
25
+ pwd_context = CryptContext(schemes=["sha256_crypt"], deprecated="auto")
26
 
27
+ # STORAGE
28
  GALLERY_DIR = "gallery_storage"
29
  if not os.path.exists(GALLERY_DIR):
30
  os.makedirs(GALLERY_DIR)
31
 
 
32
  app.add_middleware(
33
  CORSMiddleware,
34
+ allow_origins=["*"],
35
  allow_credentials=True,
36
  allow_methods=["*"],
37
  allow_headers=["*"],
 
42
  username: str
43
  password: str
44
 
45
+ # --- HELPER FUNCTIONS (WITH ERROR HANDLING) ---
 
 
 
 
 
 
 
 
 
 
46
  def get_users_db():
47
  headers = {"X-Master-Key": JSONBIN_KEY}
48
  try:
49
+ response = requests.get(JSONBIN_URL + "/latest", headers=headers, timeout=10)
50
  if response.status_code == 200:
51
+ # Handle jika JSONBin mengembalikan struktur root yang berbeda
52
+ data = response.json()
53
+ if "record" in data:
54
+ return data["record"].get("users", [])
55
+ return data.get("users", [])
56
+ else:
57
+ print(f"JSONBin Error {response.status_code}: {response.text}")
58
+ return []
59
  except Exception as e:
60
+ print(f"DB Connection Error: {e}")
61
  return []
62
 
63
  def update_users_db(users_list):
 
66
  "Content-Type": "application/json"
67
  }
68
  payload = {"users": users_list}
69
+ try:
70
+ r = requests.put(JSONBIN_URL, headers=headers, json=payload, timeout=10)
71
+ if r.status_code >= 400:
72
+ print(f"Failed to save DB: {r.text}")
73
+ except Exception as e:
74
+ print(f"Save DB Exception: {e}")
75
 
76
  def verify_password(plain_password, hashed_password):
77
+ try:
78
+ return pwd_context.verify(plain_password, hashed_password)
79
+ except:
80
+ return False
81
 
82
  def get_password_hash(password):
83
  return pwd_context.hash(password)
 
86
 
87
  @app.get("/")
88
  def home():
89
+ return {"status": "online", "system": "BlackSpaces Brain v1.2", "time": str(datetime.now())}
90
+
91
+ @app.get("/ping")
92
+ def ping():
93
+ return {"status": "alive"}
94
 
 
95
  @app.post("/auth/signup")
96
  def signup(user: UserAuth):
97
+ try:
98
+ print(f"Attempting signup for {user.username}")
99
+ users = get_users_db()
100
+
101
+ # Cek duplikat
102
+ for u in users:
103
+ if u['username'].lower() == user.username.lower():
104
+ return JSONResponse(status_code=400, content={"status": "error", "detail": "Username already taken"})
105
+
106
+ # Hash password
107
+ hashed_pw = get_password_hash(user.password)
108
+
109
+ new_user = {
110
+ "username": user.username,
111
+ "password": hashed_pw,
112
+ "joined_at": str(datetime.now())
113
+ }
114
+
115
+ users.append(new_user)
116
+ update_users_db(users)
117
+
118
+ return {"status": "success", "message": "User registered successfully"}
119
+ except Exception as e:
120
+ error_msg = traceback.format_exc()
121
+ print(error_msg)
122
+ return JSONResponse(status_code=500, content={"status": "error", "detail": f"Server Error: {str(e)}"})
123
 
124
  @app.post("/auth/login")
125
  def login(user: UserAuth):
126
+ try:
127
+ users = get_users_db()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
128
 
129
+ for u in users:
130
+ if u['username'].lower() == user.username.lower():
131
+ if verify_password(user.password, u['password']):
132
+ return {"status": "success", "username": u['username'], "token": "access-granted"}
133
+ else:
134
+ return JSONResponse(status_code=401, content={"status": "error", "detail": "Wrong Password"})
 
 
135
 
136
+ return JSONResponse(status_code=404, content={"status": "error", "detail": "User not found"})
137
+ except Exception as e:
138
+ return JSONResponse(status_code=500, content={"status": "error", "detail": f"Login Error: {str(e)}"})
139
+
140
+ # Gallery endpoints tetap sama (dipersingkat untuk hemat karakter, tapi logic sama)
141
+ @app.post("/gallery/save")
142
+ async def save_to_gallery(username: str = Form(...), prompt: str = Form(...), meta: str = Form(...), image: UploadFile = File(...)):
143
+ try:
144
+ user_dir = os.path.join(GALLERY_DIR, username)
145
+ if not os.path.exists(user_dir): os.makedirs(user_dir)
146
+ timestamp = int(time.time())
147
+ path_img = os.path.join(user_dir, f"{timestamp}.jpg")
148
+ path_meta = os.path.join(user_dir, f"{timestamp}.json")
149
+
150
+ with open(path_img, "wb") as buffer: shutil.copyfileobj(image.file, buffer)
151
+ metadata = {"prompt": prompt, "details": meta, "date": str(datetime.now())}
152
+ with open(path_meta, "w") as f: json.dump(metadata, f)
153
+
154
+ return {"status": "success", "file_id": timestamp}
155
+ except Exception as e:
156
+ return JSONResponse(status_code=500, content={"status": "error", "detail": str(e)})
157
 
158
  @app.get("/gallery/{username}")
159
  def get_user_gallery(username: str):
160
+ try:
161
+ user_dir = os.path.join(GALLERY_DIR, username)
162
+ if not os.path.exists(user_dir): return {"images": []}
163
+
164
+ images = []
165
+ for file in os.listdir(user_dir):
166
+ if file.endswith(".jpg"):
167
+ img_id = file.split(".")[0]
168
+ meta_path = os.path.join(user_dir, f"{img_id}.json")
169
+ meta_data = {}
170
+ if os.path.exists(meta_path):
171
+ with open(meta_path, "r") as f: meta_data = json.load(f)
172
+ images.append({"id": img_id, "url": f"/gallery/view/{username}/{file}", "meta": meta_data})
173
+ images.sort(key=lambda x: x['id'], reverse=True)
174
+ return {"images": images}
175
+ except Exception as e:
176
+ return {"images": [], "error": str(e)}
 
 
 
 
 
 
 
 
 
177
 
178
  @app.get("/gallery/view/{username}/{filename}")
179
  def view_image(username: str, filename: str):
180
+ path = os.path.join(GALLERY_DIR, username, filename)
181
+ if os.path.exists(path): return FileResponse(path)
182
+ raise HTTPException(status_code=404, detail="Not found")