Files
botAffilate/serverPython/main.py
T

141 lines
5.7 KiB
Python

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
image_base64: Optional[str] = None
post_index: int = Field(default=1, description="Số thứ tự bài viết (1 là bài đầu tiên)")
@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_base64:
import base64
# Bỏ phần header data:image/jpeg;base64, nếu có
b64_data = req.image_base64
if "," in b64_data:
b64_data = b64_data.split(",", 1)[1]
local_image_path = f"temp_fb_{uuid.uuid4().hex}.jpg"
with open(local_image_path, "wb") as f:
f.write(base64.b64decode(b64_data))
logging.info(f"Đã tạo ảnh từ chuỗi Base64: {local_image_path}")
elif req.image_url:
import re
url = str(req.image_url)
# Kiểm tra xem url có phải là một đường dẫn file nội bộ trên máy hay không
if os.path.exists(url):
local_image_path = url
logging.info(f"Sử dụng file ảnh nội bộ có sẵn: {local_image_path}")
else:
# Tự động chuyển link Google Drive sang link tải trực tiếp
if "drive.google.com" in url:
file_id_match = re.search(r"/d/([a-zA-Z0-9_-]+)", url)
if file_id_match:
file_id = file_id_match.group(1)
url = f"https://drive.google.com/uc?export=download&id={file_id}"
logging.info(f"Đã convert link Google Drive thành direct link: {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(url, local_image_path)
logging.info(f"Đã tải ảnh tạm thời từ internet: {local_image_path}")
result = bot.post_comment(str(req.group_id), str(req.content), local_image_path, req.post_index)
# Dọn dẹp ảnh tạm sau khi xong
if local_image_path and os.path.exists(local_image_path):
if "temp_fb_" in local_image_path:
os.remove(local_image_path)
logging.info(f"Đã dọn dẹp file tạm: {local_image_path}")
if isinstance(result, dict) and "status" in result:
# Trả về luôn JSON kết quả, n8n sẽ nhận HTTP 200 và tiếp tục vòng lặp
# Ngay cả khi status == "error", ta vẫn muốn n8n chạy tiếp nhóm khác
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)