Files
2026-03-12 02:40:26 +00:00

259 lines
10 KiB
Python

import os
import requests
from flask import Flask, request, jsonify, send_from_directory
from flask_cors import CORS
import logging
from datetime import datetime
import threading
import queue
import uuid
import time
APP_ROOT = os.path.dirname(os.path.abspath(__file__))
STATIC_FOLDER = os.path.join(APP_ROOT, 'static')
app = Flask(__name__, static_folder=STATIC_FOLDER, static_url_path='/static')
CORS(app)
CHANGE_APP_BASE_URL = "http://127.0.0.1:28889"
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
logger = logging.getLogger(__name__)
def log_message(msg):
print(f"[{datetime.now().strftime('%Y-%m-%d %H:%M:%S')}] {msg}")
logger.info(msg)
class DualQueueProcessor:
def __init__(self):
self.normal_lock = threading.Lock()
self.kuzi_lock = threading.Lock()
self.normal_queue = queue.Queue()
self.kuzi_queue = queue.Queue()
self.normal_processing = 0
self.kuzi_processing = 0
self.normal_total = 0
self.kuzi_total = 0
self.stats_lock = threading.Lock()
self._start_workers()
def _start_workers(self):
normal_worker = threading.Thread(target=self._process_normal_queue, daemon=True)
normal_worker.start()
kuzi_worker = threading.Thread(target=self._process_kuzi_queue, daemon=True)
kuzi_worker.start()
log_message("Dual queue workers started: normal_queue and kuzi_queue")
def _process_normal_queue(self):
while True:
task_id, data, result_event, result_container = self.normal_queue.get()
log_message(f"[Normal Queue] Processing task {task_id}, queue_size={self.normal_queue.qsize()}")
try:
response = requests.post(
f"{CHANGE_APP_BASE_URL}/change_cloth_base64",
json=data,
timeout=600
)
result_container['status_code'] = response.status_code
result_container['json'] = response.json()
result_container['success'] = True
log_message(f"[Normal Queue] Task {task_id} completed with status {response.status_code}")
except requests.exceptions.Timeout:
result_container['success'] = False
result_container['error'] = "Request timeout"
log_message(f"[Normal Queue] Task {task_id} timeout")
except requests.exceptions.RequestException as e:
result_container['success'] = False
result_container['error'] = str(e)
log_message(f"[Normal Queue] Task {task_id} error: {str(e)}")
finally:
result_event.set()
self.normal_queue.task_done()
def _process_kuzi_queue(self):
while True:
task_id, data, result_event, result_container = self.kuzi_queue.get()
log_message(f"[Kuzi Queue] Processing task {task_id}, queue_size={self.kuzi_queue.qsize()}")
try:
response = requests.post(
f"{CHANGE_APP_BASE_URL}/change_cloth_base64",
json=data,
timeout=600
)
result_container['status_code'] = response.status_code
result_container['json'] = response.json()
result_container['success'] = True
log_message(f"[Kuzi Queue] Task {task_id} completed with status {response.status_code}")
except requests.exceptions.Timeout:
result_container['success'] = False
result_container['error'] = "Request timeout"
log_message(f"[Kuzi Queue] Task {task_id} timeout")
except requests.exceptions.RequestException as e:
result_container['success'] = False
result_container['error'] = str(e)
log_message(f"[Kuzi Queue] Task {task_id} error: {str(e)}")
finally:
result_event.set()
self.kuzi_queue.task_done()
def submit_request(self, data):
has_kuzi = data.get('kuzi_img') is not None and data.get('kuzi_img') != ''
task_id = str(uuid.uuid4())[:8]
result_event = threading.Event()
result_container = {'success': False}
if has_kuzi:
with self.stats_lock:
self.kuzi_total += 1
queue_position = self.kuzi_queue.qsize() + 1
self.kuzi_queue.put((task_id, data, result_event, result_container))
log_message(f"[Kuzi Queue] Task {task_id} submitted, position={queue_position}")
queue_name = "kuzi"
else:
with self.stats_lock:
self.normal_total += 1
queue_position = self.normal_queue.qsize() + 1
self.normal_queue.put((task_id, data, result_event, result_container))
log_message(f"[Normal Queue] Task {task_id} submitted, position={queue_position}")
queue_name = "normal"
return task_id, result_event, result_container, queue_name, queue_position
def get_stats(self):
with self.stats_lock:
return {
"normal_queue_size": self.normal_queue.qsize(),
"kuzi_queue_size": self.kuzi_queue.qsize(),
"normal_total": self.normal_total,
"kuzi_total": self.kuzi_total
}
dual_queue = DualQueueProcessor()
@app.route('/')
def index():
return send_from_directory(STATIC_FOLDER, 'index.html')
@app.route('/health', methods=['GET'])
def health():
return jsonify({"status": "ok", "service": "change_cloth_proxy"})
@app.route('/queue_stats', methods=['GET'])
def queue_stats():
stats = dual_queue.get_stats()
return jsonify({
"ret": 0,
"msg": "success",
"data": stats
})
@app.route('/change_cloth', methods=['POST'])
def change_cloth():
log_message("change_cloth called")
data = request.get_json()
if not data:
return jsonify({"ret": -1, "state": -1, "msg": "No JSON data provided"}), 400
required_fields = ["human_url", "cloth_url", "output_format"]
for field in required_fields:
if field not in data:
return jsonify({"ret": -1, "state": -1, "msg": f"Missing required field: {field}"}), 400
log_message(f"Forwarding change_cloth request: human_url={data.get('human_url')}, cloth_url={data.get('cloth_url')}")
try:
response = requests.post(
f"{CHANGE_APP_BASE_URL}/change_cloth",
json=data,
timeout=600
)
log_message(f"change_cloth response status: {response.status_code}")
return jsonify(response.json()), response.status_code
except requests.exceptions.Timeout:
log_message("change_cloth request timeout")
return jsonify({"ret": -1, "state": -1, "msg": "Request timeout"}), 504
except requests.exceptions.RequestException as e:
log_message(f"change_cloth request error: {str(e)}")
return jsonify({"ret": -1, "state": -1, "msg": f"Request failed: {str(e)}"}), 500
@app.route('/change_cloth_base64', methods=['POST'])
def change_cloth_base64():
log_message("change_cloth_base64 called")
data = request.get_json()
if not data:
return jsonify({"ret": -1, "state": -1, "msg": "No JSON data provided"}), 400
required_fields = ["human_img", "cloth_img", "output_format"]
for field in required_fields:
if field not in data:
return jsonify({"ret": -1, "state": -1, "msg": f"Missing required field: {field}"}), 400
has_kuzi = data.get('kuzi_img') is not None and data.get('kuzi_img') != ''
queue_type = "kuzi" if has_kuzi else "normal"
task_id, result_event, result_container, queue_name, queue_position = dual_queue.submit_request(data)
log_message(f"Task {task_id} queued in {queue_name} queue, position={queue_position}, waiting for result...")
if result_event.wait(timeout=610):
if result_container.get('success'):
log_message(f"Task {task_id} returned successfully")
return jsonify(result_container['json']), result_container['status_code']
else:
error_msg = result_container.get('error', 'Unknown error')
log_message(f"Task {task_id} failed: {error_msg}")
return jsonify({"ret": -1, "state": -1, "msg": error_msg}), 500
else:
log_message(f"Task {task_id} timed out waiting in queue")
return jsonify({"ret": -1, "state": -1, "msg": "Queue timeout"}), 504
@app.route('/do_change_cloth', methods=['POST'])
def do_change_cloth():
log_message("do_change_cloth called")
data = request.get_json()
if not data:
return jsonify({"ret": -1, "state": -1, "msg": "No JSON data provided"}), 400
required_fields = ["human_url", "cloth_url", "output_format"]
for field in required_fields:
if field not in data:
return jsonify({"ret": -1, "state": -1, "msg": f"Missing required field: {field}"}), 400
log_message(f"Forwarding do_change_cloth request: human_url={data.get('human_url')}, cloth_url={data.get('cloth_url')}")
try:
response = requests.post(
f"{CHANGE_APP_BASE_URL}/do_change_cloth",
json=data,
timeout=600
)
log_message(f"do_change_cloth response status: {response.status_code}")
return jsonify(response.json()), response.status_code
except requests.exceptions.Timeout:
log_message("do_change_cloth request timeout")
return jsonify({"ret": -1, "state": -1, "msg": "Request timeout"}), 504
except requests.exceptions.RequestException as e:
log_message(f"do_change_cloth request error: {str(e)}")
return jsonify({"ret": -1, "state": -1, "msg": f"Request failed: {str(e)}"}), 500
if __name__ == '__main__':
log_message(f"Starting change_cloth_proxy service on port 28888, forwarding to {CHANGE_APP_BASE_URL}")
app.run(host="0.0.0.0", port=28888, debug=False, threaded=True)