webzepetoku's picture
Update UnityProject/app.py
ef96d38 verified
Raw
History Blame Contribute Delete
4.56 kB
import os
import shutil
import subprocess
import json
import time
import requests
from fastapi import FastAPI, BackgroundTasks, HTTPException, Request
from fastapi.middleware.cors import CORSMiddleware
from pydantic import BaseModel
from playwright.sync_api import sync_playwright
app = FastAPI()
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
# --- KONFIGURASI ---
UNITY_PATH = "/opt/unity/Editor/Unity"
PROJECT_PATH = "/app/UnityProject"
TEMP_DIR = "/tmp/zepeto_work"
os.makedirs(TEMP_DIR, exist_ok=True)
# --- MODEL DATA (Sesuai dengan kiriman Cloudflare + Cloudinary) ---
class ConversionRequest(BaseModel):
file_url: str # URL dari Cloudinary
filename: str # Nama file (contoh: baju_keren.fbx)
zepeto_id: str
zepeto_password: str
# --- FUNGSI: LOGIN & UPLOAD KE ZEPETO STUDIO ---
def upload_to_zepeto(file_path, z_id, z_pw):
print(f"πŸ” [Zepeto] Mencoba login untuk: {z_id}")
try:
with sync_playwright() as p:
browser = p.chromium.launch(headless=True, args=['--no-sandbox'])
context = browser.new_context(user_agent="Mozilla/5.0...")
page = context.new_page()
# Login Process
page.goto("https://account.zepeto.me/signin?sm=1")
page.fill('input[name="userId"]', z_id)
page.fill('input[type="password"]', z_pw)
page.click('button[type="submit"]')
# Tunggu Token/Cookie
page.wait_for_url(lambda u: "signin" not in u, timeout=15000)
cookies = context.cookies()
jwt_token = next((c['value'] for c in cookies if c['name'] == 'token'), None)
browser.close()
if not jwt_token:
return False, "Gagal mendapatkan JWT Token"
# API Upload Zepeto Studio
print("πŸš€ [Zepeto] Mengirim file ke Studio API...")
upload_url = "https://cf-api-studio.zepeto.me/api/items"
headers = {"Authorization": f"Bearer {jwt_token}"}
with open(file_path, "rb") as f:
files = {"file": (os.path.basename(file_path), f, "application/octet-stream")}
res = requests.post(upload_url, headers=headers, files=files)
if res.status_code in [200, 201]:
return True, "Sukses Upload"
else:
return False, f"API Error: {res.text}"
except Exception as e:
return False, str(e)
# --- FUNGSI UTAMA: DOWNLOAD -> UNITY -> UPLOAD ---
def process_pipeline(req: ConversionRequest):
local_fbx = os.path.join(PROJECT_PATH, "Assets", req.filename)
output_filename = req.filename.replace(".fbx", ".zepeto")
local_zepeto = os.path.join(PROJECT_PATH, "output", output_filename)
try:
# 1. DOWNLOAD DARI CLOUDINARY
print(f"πŸ“₯ [Cloudinary] Downloading: {req.filename}")
r = requests.get(req.file_url, stream=True)
with open(local_fbx, 'wb') as f:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
# 2. JALANKAN UNITY (Konversi & Optimasi Poligon)
print("βš™οΈ [Unity] Memulai konversi & optimasi...")
# Perhatikan: Method C# harus menangani decimation/polygon reduction
cmd = [
UNITY_PATH, "-batchmode", "-nographics",
"-projectPath", PROJECT_PATH,
"-executeMethod", "TestBuilder.ManualConvert",
"-inputFile", req.filename,
"-quit", "-logFile", "-"
]
result = subprocess.run(cmd, capture_output=True, text=True)
if not os.path.exists(local_zepeto):
print(f"❌ [Unity] Gagal. Log: {result.stdout}")
return
# 3. UPLOAD KE ZEPETO STUDIO
success, msg = upload_to_zepeto(local_zepeto, req.z_id, req.z_pw)
if success:
print(f"βœ… [FINAL] {req.filename} Berhasil dikirim ke Zepeto!")
else:
print(f"❌ [FINAL] Gagal upload ke Zepeto Studio: {msg}")
except Exception as e:
print(f"❌ [CRITICAL] Pipeline Error: {e}")
finally:
# Cleanup
if os.path.exists(local_fbx): os.remove(local_fbx)
@app.post("/convert")
async def api_convert(req: ConversionRequest, background_tasks: BackgroundTasks):
background_tasks.add_task(process_pipeline, req)
return {"status": "success", "message": "Proses konversi dan upload Zepeto dimulai di background"}