instanum-api / app.py
Bruhletme's picture
Upload app.py with huggingface_hub
4bbb678 verified
Raw
History Blame Contribute Delete
5.53 kB
import os, sqlite3, threading
from fastapi import FastAPI, Query
from fastapi.responses import JSONResponse
from fastapi.middleware.cors import CORSMiddleware
from huggingface_hub import hf_hub_download
import uvicorn
app = FastAPI(title="InstaNum API v3")
app.add_middleware(CORSMiddleware, allow_origins=["*"], allow_methods=["GET"])
DB1_PATH = "instadb.db"
DB2_PATH = "Instagram.db"
db1_ready = threading.Event()
db1_error = None
def download_db():
global db1_error
try:
print("Downloading instadb.db from HF Dataset...")
hf_hub_download(
repo_id="Bruhletme/instanum",
filename="instadb.db",
repo_type="dataset",
local_dir="."
)
print("DB1 ready!")
db1_ready.set()
except Exception as e:
db1_error = str(e)
print(f"DB1 download failed: {e}")
db1_ready.set()
threading.Thread(target=download_db, daemon=True).start()
def get_columns(db_path):
try:
conn = sqlite3.connect(db_path)
cur = conn.cursor()
cur.execute("PRAGMA table_info(users)")
cols = [r[1] for r in cur.fetchall()]
conn.close()
return cols
except:
return []
def query_db(db_path, field, val, limit):
if not os.path.exists(db_path):
return []
try:
cols = get_columns(db_path)
col = field
if field == "instagram_id":
if "instagram_id" in cols:
col = "instagram_id"
elif "username" in cols:
col = "username"
val = val.lstrip("@")
else:
return []
if col not in cols:
return []
conn = sqlite3.connect(db_path)
conn.row_factory = sqlite3.Row
cur = conn.cursor()
if col == "phone":
cur.execute(
f"SELECT * FROM users WHERE {col} = ? OR {col} = ? LIMIT ?",
(val, f"'{val}'", limit)
)
elif col == "username":
clean = val.lstrip("@")
cur.execute(
f"SELECT * FROM users WHERE {col} = ? OR {col} = ? LIMIT ?",
(clean, "@" + clean, limit)
)
else:
cur.execute(f"SELECT * FROM users WHERE {col} = ? LIMIT ?", (val, limit))
rows = [dict(r) for r in cur.fetchall()]
conn.close()
return rows
except Exception as e:
print(f"Query error on {db_path}: {e}")
return []
def normalize_row(row):
"""Normalize row to match insta.js expectations"""
# Get username from instagram_id or username column
username = row.get("instagram_id") or row.get("username") or ""
# Build full name
fname = row.get("fname") or row.get("name") or ""
lname = row.get("lname") or ""
name = f"{fname} {lname}".strip() or None
# Strip quotes from phone
phone = row.get("phone") or ""
phone = phone.replace("'", "").strip() or None
return {
"id": row.get("id"),
"username": username,
"name": name,
"email": row.get("email") or None,
"phone": phone,
"address": row.get("address") or None,
}
def merge_results(r1, r2, limit):
seen = set()
merged = []
for row in r1 + r2:
key = (row.get("username", ""), row.get("phone", ""), row.get("email", ""))
if key not in seen:
seen.add(key)
merged.append(row)
if len(merged) >= limit:
break
return merged
@app.get("/")
def root():
db1_ok = db1_ready.is_set() and not db1_error
db2_ok = os.path.exists(DB2_PATH)
return {
"status": "ready",
"db1_17M": "ready" if db1_ok else ("error: " + str(db1_error) if db1_error else "loading"),
"db2_4.9M": "ready" if db2_ok else "not found",
"endpoints": {
"/api?username=": "search by instagram username",
"/api?phone=": "search by phone",
"/api?email=": "search by email",
"/api?name=": "search by name",
}
}
@app.get("/status")
def status():
return {
"db1_ready": db1_ready.is_set(),
"db1_error": db1_error,
"db1_exists": os.path.exists(DB1_PATH),
"db1_columns": get_columns(DB1_PATH),
"db2_exists": os.path.exists(DB2_PATH),
"db2_columns": get_columns(DB2_PATH),
}
@app.get("/api")
def search(
username: str = Query(None),
phone: str = Query(None),
email: str = Query(None),
name: str = Query(None),
limit: int = Query(10, ge=1, le=50)
):
fields = {
"instagram_id": "@" + username.lstrip("@") if username else None,
"phone": phone,
"email": email,
"fname": name,
}
col, val = next(((k, v) for k, v in fields.items() if v), (None, None))
if not col:
return {"success": False, "error": "no_query", "hint": "Use ?username= ?phone= ?email= ?name="}
val = val.strip()
r1 = query_db(DB1_PATH, col, val, limit) if db1_ready.is_set() and not db1_error else []
r2 = query_db(DB2_PATH, col, val, limit)
raw = merge_results(r1, r2, limit)
# Normalize for insta.js compatibility
results = [normalize_row(r) for r in raw]
return {
"success": True,
"count": len(results),
"sources": {"db1_17M": len(r1), "db2_4.9M": len(r2)},
"results": results
}
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=7860)
# 1774199147