model-optimizer / app_flask_old.py
wangyiyi666's picture
Upload folder using huggingface_hub
a030c8b verified
Raw
History Blame Contribute Delete
6.54 kB
"""
模型优化服务 - Flask 前端
第一版:本地测试模式(先跑通完整通路)
后续部署到 HF Space 时可切换为 Gradio 版本
"""
from flask import Flask, request, render_template_string, send_file, jsonify
import os
import uuid
import shutil
from datetime import datetime
app = Flask(__name__)
# === 配置 ===
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
INBOX = os.path.join(BASE_DIR, "..", "local", "tmp", "inbox")
OUTBOX = os.path.join(BASE_DIR, "..", "local", "tmp", "outbox")
os.makedirs(INBOX, exist_ok=True)
os.makedirs(OUTBOX, exist_ok=True)
SUPPORTED_FORMATS = [".glb", ".gltf", ".fbx", ".obj"]
def log(msg):
timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
print(f"[{timestamp}] [WEB] {msg}")
HTML_TEMPLATE = """
<!DOCTYPE html>
<html>
<head>
<title>3D 模型优化服务</title>
<meta charset="utf-8">
<style>
body { font-family: -apple-system, sans-serif; max-width: 700px; margin: 50px auto; padding: 20px; background: #f5f5f5; }
.card { background: white; border-radius: 12px; padding: 30px; margin: 20px 0; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
h1 { text-align: center; color: #333; }
.upload-area { border: 2px dashed #ccc; border-radius: 8px; padding: 40px; text-align: center; margin: 20px 0; }
.upload-area:hover { border-color: #667eea; }
input[type="file"] { margin: 10px 0; }
button { background: #667eea; color: white; border: none; padding: 12px 30px; border-radius: 6px; cursor: pointer; font-size: 16px; }
button:hover { background: #5a67d8; }
.result { padding: 15px; border-radius: 8px; margin: 15px 0; }
.success { background: #d4edda; color: #155724; }
.waiting { background: #fff3cd; color: #856404; }
.error { background: #f8d7da; color: #721c24; }
input[type="text"] { padding: 10px; width: 200px; border: 1px solid #ddd; border-radius: 6px; font-size: 16px; }
.info { color: #666; font-size: 14px; }
a.download { display: inline-block; background: #28a745; color: white; padding: 10px 20px; border-radius: 6px; text-decoration: none; margin-top: 10px; }
</style>
</head>
<body>
<h1>🛠️ 3D 模型优化服务</h1>
<div class="card">
<h2>📤 上传模型</h2>
<form action="/upload" method="post" enctype="multipart/form-data">
<div class="upload-area">
<p>选择 3D 模型文件</p>
<input type="file" name="model" accept=".glb,.gltf,.fbx,.obj">
<p class="info">支持格式: GLB, GLTF, FBX, OBJ</p>
</div>
<button type="submit">🚀 提交优化</button>
</form>
{% if upload_msg %}
<div class="result {{ upload_class }}">{{ upload_msg }}</div>
{% endif %}
</div>
<div class="card">
<h2>🔍 查询结果</h2>
<form action="/status" method="get">
<input type="text" name="task_id" placeholder="输入任务ID" value="{{ query_id or '' }}">
<button type="submit">查询</button>
</form>
{% if status_msg %}
<div class="result {{ status_class }}">{{ status_msg }}</div>
{% endif %}
{% if download_ready %}
<a class="download" href="/download/{{ download_id }}">⬇️ 下载优化结果</a>
{% endif %}
</div>
<div class="info" style="text-align:center; margin-top: 30px;">
输出格式: GLB | Worker 每30秒检查一次任务
</div>
</body>
</html>
"""
@app.route("/")
def index():
return render_template_string(HTML_TEMPLATE)
@app.route("/upload", methods=["POST"])
def upload():
file = request.files.get("model")
if not file or file.filename == "":
return render_template_string(HTML_TEMPLATE,
upload_msg="请选择文件", upload_class="error")
filename = file.filename
ext = os.path.splitext(filename)[1].lower()
log(f"收到上传: {filename}")
if ext not in SUPPORTED_FORMATS:
log(f"格式不支持: {ext}")
return render_template_string(HTML_TEMPLATE,
upload_msg=f"不支持的格式: {ext}", upload_class="error")
# 生成任务ID并保存文件
task_id = str(uuid.uuid4())[:8]
target_path = os.path.join(INBOX, f"{task_id}{ext}")
file.save(target_path)
file_size = os.path.getsize(target_path)
log(f"文件已保存: {task_id}{ext} ({file_size} bytes), 任务ID: {task_id}")
return render_template_string(HTML_TEMPLATE,
upload_msg=f"✅ 上传成功!任务ID: {task_id} (请保存此ID用于查询结果)",
upload_class="success")
@app.route("/status")
def status():
task_id = request.args.get("task_id", "").strip()
if not task_id:
return render_template_string(HTML_TEMPLATE,
status_msg="请输入任务ID", status_class="error", query_id=task_id)
log(f"查询状态: {task_id}")
# 检查 outbox
result_file = os.path.join(OUTBOX, f"{task_id}_optimized.glb")
if os.path.exists(result_file):
size = os.path.getsize(result_file)
log(f"任务 {task_id} 已完成 ({size} bytes)")
return render_template_string(HTML_TEMPLATE,
status_msg=f"✅ 优化完成!文件大小: {size} bytes",
status_class="success", download_ready=True,
download_id=task_id, query_id=task_id)
# 检查 inbox
for f in os.listdir(INBOX):
if f.startswith(task_id):
log(f"任务 {task_id} 仍在队列中")
return render_template_string(HTML_TEMPLATE,
status_msg="⏳ 处理中,请稍后再查询...",
status_class="waiting", query_id=task_id)
log(f"任务 {task_id} 未找到")
return render_template_string(HTML_TEMPLATE,
status_msg="❌ 未找到该任务,请检查ID是否正确",
status_class="error", query_id=task_id)
@app.route("/download/<task_id>")
def download(task_id):
result_file = os.path.join(OUTBOX, f"{task_id}_optimized.glb")
if os.path.exists(result_file):
log(f"用户下载: {task_id}_optimized.glb")
return send_file(result_file, as_attachment=True,
download_name=f"{task_id}_optimized.glb")
return "文件不存在", 404
if __name__ == "__main__":
log("=" * 40)
log("Web 前端启动")
log(f" Inbox: {INBOX}")
log(f" Outbox: {OUTBOX}")
log("=" * 40)
app.run(host="0.0.0.0", port=5000, debug=True)