#!/usr/bin/env python3
"""
Web 壳 —— 让 agent.py 变成可通过浏览器访问的在线服务
参与者不需要改这个文件,只改 agent.py 即可。
启动方式(本地调试):
DASHSCOPE_API_KEY=sk-xxx python3 server.py
Deploy Skill 会自动用 gunicorn 启动:
gunicorn -b 0.0.0.0:8080 server:app
"""
import json
import os
import threading
import time
import uuid
from pathlib import Path
from flask import Flask, request, jsonify, send_from_directory
def _load_dotenv():
"""读取同目录下的 .env(KEY=VALUE 每行一条),不覆盖已有环境变量。
部署到云端后 .env 会随代码一起上传,这样服务就能拿到 DASHSCOPE_API_KEY。"""
env_file = Path(__file__).resolve().parent / ".env"
if not env_file.exists():
return
for line in env_file.read_text(encoding="utf-8").splitlines():
line = line.strip()
if not line or line.startswith("#") or "=" not in line:
continue
key, _, value = line.partition("=")
key, value = key.strip(), value.strip().strip('"').strip("'")
if key and key not in os.environ:
os.environ[key] = value
_load_dotenv() # 必须在 import agent 之前执行,agent.py 在导入时就会读环境变量
# 导入 agent.py 里的核心函数
from agent import ( # noqa: E402
read_input_data, get_product_title,
step_descriptions, step_images, step_video, step_strategy,
API_KEY, TEXT_MODEL, IMAGE_MODEL, VIDEO_MODEL
)
app = Flask(__name__)
# 任务状态存储(内存,重启丢失,demo 够用)
tasks = {} # task_id -> {status, progress, output_dir, input_dir, error}
WORK_DIR = Path("/tmp/qianwenai-agent")
WORK_DIR.mkdir(parents=True, exist_ok=True)
# ============================================================
# 前端页面
# ============================================================
INDEX_HTML = """
一键出海 · 商品素材 Agent
🌏 一键出海 · 商品素材 Agent
输入商品信息,自动生成美国🇺🇸 韩国🇰🇷 巴西🇧🇷 三国上架素材
📝 三语商品文案
🇺🇸 English
🇰🇷 한국어
🇧🇷 Português
🎬 商品视频
文本模型: MODEL_TEXT | 图像模型: MODEL_IMAGE | 视频模型: MODEL_VIDEO
""".replace('MODEL_TEXT', TEXT_MODEL).replace('MODEL_IMAGE', IMAGE_MODEL).replace('MODEL_VIDEO', VIDEO_MODEL)
# ============================================================
# API 路由
# ============================================================
@app.route('/')
def index():
return INDEX_HTML
@app.route('/api/generate', methods=['POST'])
def generate():
if not API_KEY:
return jsonify(error="DASHSCOPE_API_KEY 未设置"), 500
data = request.get_json(force=True, silent=True)
if not data:
return jsonify(error="请提供商品 JSON 数据"), 400
task_id = uuid.uuid4().hex[:8]
input_dir = str(WORK_DIR / f"input_{task_id}")
output_dir = str(WORK_DIR / f"output_{task_id}")
os.makedirs(f"{input_dir}/product_info", exist_ok=True)
os.makedirs(output_dir, exist_ok=True)
# 保存输入
with open(f"{input_dir}/product_info/product_basic.json", "w", encoding="utf-8") as f:
json.dump(data, f, ensure_ascii=False, indent=2)
tasks[task_id] = {
"status": "running",
"percent": 10,
"message": "正在生成三语文案...",
"output_dir": output_dir,
"input_dir": input_dir,
"error": None,
}
def run():
t = tasks[task_id]
try:
product_data = read_input_data(input_dir)
if not product_data:
raise RuntimeError("未读取到商品数据")
t.update(percent=15, message=f"正在生成三语文案(模型 {TEXT_MODEL})...")
step_descriptions(product_data, output_dir)
t.update(percent=40, message=f"正在生成 6 张商品图片(模型 {IMAGE_MODEL})...")
step_images(product_data, output_dir)
t.update(percent=75, message=f"正在生成商品视频(模型 {VIDEO_MODEL})...")
step_video(product_data, output_dir)
t.update(percent=90, message="正在生成策略文档...")
step_strategy(product_data, output_dir)
t.update(status="done", percent=100, message="全部完成!")
except Exception as e:
t.update(status="error", error=str(e))
threading.Thread(target=run, daemon=True).start()
return jsonify(task_id=task_id, status="running")
@app.route('/api/status/')
def status(task_id):
t = tasks.get(task_id)
if not t:
return jsonify(status="not_found"), 404
return jsonify(
status=t["status"],
percent=t.get("percent", 0),
message=t.get("message", ""),
error=t.get("error"),
)
@app.route('/files//')
def serve_file(task_id, filename):
t = tasks.get(task_id)
if not t:
return "Not found", 404
return send_from_directory(t["output_dir"], filename)
# ============================================================
# 启动
# ============================================================
if __name__ == "__main__":
port = int(os.environ.get("PORT", 8080))
print(f"🌏 Agent Web 服务启动: http://localhost:{port}")
print(f" 文本模型: {TEXT_MODEL} | 图像: {IMAGE_MODEL} | 视频: {VIDEO_MODEL}")
if not API_KEY:
print(" ⚠️ DASHSCOPE_API_KEY 未设置!请设置后重启")
app.run(host="0.0.0.0", port=port, debug=False)