yyh1112's picture
Upload 4 files
e4a5715 verified
Raw
History Blame Contribute Delete
7.96 kB
from pathlib import Path
from flask import Flask, jsonify, render_template, request, send_file
from werkzeug.exceptions import RequestEntityTooLarge
from aging_tool.service import (
AgingSummaryError,
AnalysisTaskNotFound as AgingTaskNotFound,
get_task_status as get_aging_task_status,
start_analysis_task as start_aging_analysis_task,
)
from keyword_tool.service import (
AnalysisTaskNotFound as KeywordTaskNotFound,
KeywordSummaryError,
get_task_status as get_keyword_task_status,
start_analysis_task as start_keyword_analysis_task,
)
from sguid_tool.processor import ProcessingError
from sguid_tool.service import (
AnalysisTaskNotFound as SguidTaskNotFound,
get_task_status as get_sguid_task_status,
start_analysis_task as start_sguid_analysis_task,
)
from sguid_tool.stats import get_usage_stats, record_usage
BASE_DIR = Path(__file__).resolve().parent
def create_app() -> Flask:
app = Flask(__name__)
app.config["MAX_CONTENT_LENGTH"] = 100 * 1024 * 1024
app.config["UPLOAD_FOLDER"] = BASE_DIR / "uploads"
app.config["OUTPUT_FOLDER"] = BASE_DIR / "saved_outputs"
app.config["DATA_FOLDER"] = BASE_DIR / "data"
app.config["KEYWORD_UPLOAD_FOLDER"] = BASE_DIR / "uploads" / "keyword_summary"
app.config["KEYWORD_OUTPUT_FOLDER"] = BASE_DIR / "saved_outputs" / "keyword_summary"
app.config["AGING_UPLOAD_FOLDER"] = BASE_DIR / "uploads" / "aging_stock_summary"
app.config["AGING_OUTPUT_FOLDER"] = BASE_DIR / "saved_outputs" / "aging_stock_summary"
for key in [
"UPLOAD_FOLDER",
"OUTPUT_FOLDER",
"DATA_FOLDER",
"KEYWORD_UPLOAD_FOLDER",
"KEYWORD_OUTPUT_FOLDER",
"AGING_UPLOAD_FOLDER",
"AGING_OUTPUT_FOLDER",
]:
app.config[key].mkdir(parents=True, exist_ok=True)
@app.get("/")
def index():
return render_template("index.html", active_nav="sgu")
@app.get("/keyword-summary")
def keyword_summary():
return render_template("keyword_summary.html", active_nav="keyword")
@app.get("/placement-summary")
def placement_summary():
return render_template("keyword_summary.html", active_nav="placement")
@app.get("/aging-stock")
def aging_stock():
return render_template("aging_stock.html", active_nav="aging")
@app.get("/api/stats")
def stats():
return jsonify(get_usage_stats(app.config["DATA_FOLDER"]))
@app.post("/api/process")
def process_file():
uploaded_file = request.files.get("file")
if not uploaded_file or not uploaded_file.filename:
return jsonify({"success": False, "error": "请选择一个 .xlsx 或 .csv 文件。"}), 400
record_usage(app.config["DATA_FOLDER"])
try:
task_id = start_sguid_analysis_task(
uploaded_file=uploaded_file,
upload_dir=app.config["UPLOAD_FOLDER"],
output_dir=app.config["OUTPUT_FOLDER"],
)
except ProcessingError as exc:
return jsonify({"success": False, "error": str(exc)}), 400
return jsonify({"success": True, "task_id": task_id, "message": "文件上传成功,正在生成 SGU 汇总结果..."})
@app.get("/api/process/status/<task_id>")
def process_file_status(task_id: str):
try:
return jsonify(get_sguid_task_status(task_id))
except SguidTaskNotFound as exc:
return jsonify({"success": False, "error": str(exc)}), 404
@app.get("/api/process/download/<filename>")
def process_file_download(filename: str):
file_path = app.config["OUTPUT_FOLDER"] / filename
if not file_path.exists():
return jsonify({"success": False, "error": "结果文件不存在。"}), 404
return send_file(
file_path,
as_attachment=True,
download_name=filename,
mimetype="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
)
@app.post("/keyword-summary/api/upload")
@app.post("/placement-summary/api/upload")
def keyword_summary_upload():
uploaded_file = request.files.get("file")
if not uploaded_file or not uploaded_file.filename:
return jsonify({"success": False, "error": "请选择一个 Excel 或 CSV 文件。"}), 400
record_usage(app.config["DATA_FOLDER"])
try:
task_id = start_keyword_analysis_task(
uploaded_file=uploaded_file,
upload_dir=app.config["KEYWORD_UPLOAD_FOLDER"],
output_dir=app.config["KEYWORD_OUTPUT_FOLDER"],
)
except KeywordSummaryError as exc:
return jsonify({"success": False, "error": str(exc)}), 400
return jsonify(
{
"success": True,
"task_id": task_id,
"message": "文件上传成功,正在生成搜索词与投放词汇总...",
}
)
@app.get("/keyword-summary/api/status/<task_id>")
@app.get("/placement-summary/api/status/<task_id>")
def keyword_summary_status(task_id: str):
try:
return jsonify(get_keyword_task_status(task_id))
except KeywordTaskNotFound as exc:
return jsonify({"success": False, "error": str(exc)}), 404
@app.get("/keyword-summary/api/download/<filename>")
@app.get("/placement-summary/api/download/<filename>")
def keyword_summary_download(filename: str):
file_path = app.config["KEYWORD_OUTPUT_FOLDER"] / filename
if not file_path.exists():
return jsonify({"success": False, "error": "结果文件不存在。"}), 404
return send_file(
file_path,
as_attachment=True,
download_name=filename,
mimetype="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
)
@app.post("/aging-stock/api/upload")
def aging_stock_upload():
uploaded_file = request.files.get("file")
if not uploaded_file or not uploaded_file.filename:
return jsonify({"success": False, "error": "请选择库龄 Excel 或 CSV 文件。"}), 400
record_usage(app.config["DATA_FOLDER"])
try:
task_id = start_aging_analysis_task(
uploaded_file=uploaded_file,
upload_dir=app.config["AGING_UPLOAD_FOLDER"],
output_dir=app.config["AGING_OUTPUT_FOLDER"],
)
except AgingSummaryError as exc:
return jsonify({"success": False, "error": str(exc)}), 400
return jsonify({"success": True, "task_id": task_id, "message": "文件上传成功,正在汇总超龄库存数据..."})
@app.get("/aging-stock/api/status/<task_id>")
def aging_stock_status(task_id: str):
try:
return jsonify(get_aging_task_status(task_id))
except AgingTaskNotFound as exc:
return jsonify({"success": False, "error": str(exc)}), 404
@app.get("/aging-stock/api/download/<filename>")
def aging_stock_download(filename: str):
file_path = app.config["AGING_OUTPUT_FOLDER"] / filename
if not file_path.exists():
return jsonify({"success": False, "error": "结果文件不存在。"}), 404
return send_file(
file_path,
as_attachment=True,
download_name=filename,
mimetype="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
)
@app.errorhandler(RequestEntityTooLarge)
def handle_large_file(_error):
return jsonify({"message": "上传文件过大,当前限制为 100MB,请压缩源文件后重试。"}), 413
return app
app = create_app()
if __name__ == "__main__":
app.run(host="0.0.0.0", port=5001, debug=True)