from fastapi import FastAPI, HTTPException from pydantic import BaseModel, Field from automation import ShopeeBot from typing import Optional import logging import os import sys import urllib.request import uuid import threading from collections import defaultdict from facebook_bot import FacebookBot # Quản lý hàng đợi (Lock) cho từng thiết bị device_locks = defaultdict(threading.Lock) # Cấu hình logging: ghi log ra cả màn hình (console) và file (shopee_bot.log) logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s', handlers=[ logging.FileHandler("shopee_bot.log", encoding="utf-8"), logging.StreamHandler(sys.stdout) ] ) app = FastAPI(title="n8n Shopee Bridge API") class CommissionRequest(BaseModel): link: str # Cho phép truyền IP linh hoạt từ n8n. device_ip: Optional[str] = Field(default=None, description="IP:Port của điện thoại, ví dụ 192.168.1.100:5555 (WiFi) hoặc 10.8.0.5:5555 (VPN)") from typing import Optional, Any class FacebookCommentRequest(BaseModel): device_ip: Optional[str] = Field(default=None, description="IP:Port của điện thoại (Cấu hình trên n8n)") group_id: Any content: str image_url: Optional[str] = None @app.post("/get_commission") def get_commission_endpoint(req: CommissionRequest): if not req.link: raise HTTPException(status_code=400, detail="Thiếu link sản phẩm") try: # Lấy IP theo độ ưu tiên raw_ip = req.device_ip or os.environ.get("DEVICE_IP") or "" lock_key = raw_ip if raw_ip else "default_device" # Dùng Lock để xếp hàng: Nếu điện thoại đang bận, request sau phải chờ with device_locks[lock_key]: logging.info(f"Đã khóa thiết bị {lock_key} để chạy tác vụ Shopee.") bot = ShopeeBot(device_ip=raw_ip) result = bot.get_commission_rate(req.link) # Nếu đã có status thì gộp thẳng các thuộc tính của result vào JSON trả về if isinstance(result, dict) and "status" in result: return result return { "status": "success", "commission": result } except Exception as e: logging.error(f"Lỗi API: {str(e)}") raise HTTPException(status_code=500, detail=str(e)) @app.post("/post_facebook_comment") def post_facebook_comment(req: FacebookCommentRequest): try: raw_ip = req.device_ip or os.environ.get("DEVICE_IP") or "" lock_key = raw_ip if raw_ip else "default_device" with device_locks[lock_key]: logging.info(f"Đã khóa thiết bị {lock_key} để chạy tác vụ Facebook.") bot = FacebookBot(device_ip=raw_ip) local_image_path = None if req.image_url: # Tải ảnh về máy chủ Python tạm thời local_image_path = f"temp_fb_{uuid.uuid4().hex}.jpg" urllib.request.urlretrieve(str(req.image_url), local_image_path) logging.info(f"Đã tải ảnh tạm thời: {local_image_path}") result = bot.post_comment(str(req.group_id), str(req.content), local_image_path) # Dọn dẹp ảnh tạm sau khi xong if local_image_path and os.path.exists(local_image_path): os.remove(local_image_path) logging.info(f"Đã xóa ảnh tạm: {local_image_path}") if isinstance(result, dict) and "status" in result: if result["status"] == "error": raise HTTPException(status_code=500, detail=result.get("message")) return result return {"status": "success", "message": "Hoàn tất"} except Exception as e: logging.error(f"Lỗi API Facebook: {str(e)}") raise HTTPException(status_code=500, detail=str(e)) if __name__ == "__main__": import uvicorn # Chạy server API ở cổng 8000 uvicorn.run(app, host="0.0.0.0", port=8000)