|
|
@@ -1,203 +0,0 @@
|
|
|
-from config import load_service_config
|
|
|
-from fastapi import FastAPI, Request, status, BackgroundTasks, HTTPException
|
|
|
-from fastapi.exceptions import RequestValidationError
|
|
|
-from fastapi.responses import JSONResponse
|
|
|
-from database.dao.mysql_dao import MySqlDao
|
|
|
-from models import Recommend
|
|
|
-import os
|
|
|
-from pydantic import BaseModel
|
|
|
-import uvicorn
|
|
|
-from utils import ReportUtils, FileUploadUtils
|
|
|
-import requests
|
|
|
-from typing import List, Dict
|
|
|
-
|
|
|
-app = FastAPI()
|
|
|
-dao = MySqlDao()
|
|
|
-
|
|
|
-cfgs = load_service_config()
|
|
|
-# 添加全局异常处理器
|
|
|
-@app.exception_handler(RequestValidationError)
|
|
|
-async def validation_exception_handler(request: Request, exc: RequestValidationError):
|
|
|
- return JSONResponse(
|
|
|
- status_code=status.HTTP_400_BAD_REQUEST,
|
|
|
- content={
|
|
|
- "code": 400,
|
|
|
- "msg": "请求参数错误",
|
|
|
- "data": {
|
|
|
- "detail": exc.errors(),
|
|
|
- "body": exc.body
|
|
|
- }
|
|
|
- },
|
|
|
- )
|
|
|
-
|
|
|
-# 定义请求体
|
|
|
-class RecommendRequest(BaseModel):
|
|
|
- city_uuid: str # 城市id
|
|
|
- product_code: str # 卷烟编码
|
|
|
- recall_cust_count: int # 推荐的商户数量
|
|
|
- delivery_count: int # 投放的品规数量
|
|
|
- cultivacation_id: str # 投放策略id
|
|
|
- limit_cycle_name: str # 投放周期名称
|
|
|
-
|
|
|
-class ReportRequest(BaseModel):
|
|
|
- city_uuid: str # 城市id
|
|
|
- product_code: str # 卷烟编码
|
|
|
-
|
|
|
-class EvalReportRequest(BaseModel):
|
|
|
- city_uuid: str # 城市id
|
|
|
- product_code: str # 卷烟编码
|
|
|
- start_time: str # 开始投放时间
|
|
|
- end_time: str # 结束投放时间
|
|
|
-
|
|
|
-@app.post("/brandcultivation/api/v1/recommend")
|
|
|
-async def recommend(request: RecommendRequest, backgroundTasks: BackgroundTasks):
|
|
|
- gbdtlr_model_path = os.path.join("./models/rank/weights", request.city_uuid, "gbdtlr_model.pkl")
|
|
|
- if not os.path.exists(gbdtlr_model_path):
|
|
|
- return {"code": 200, "msg": "model not defined", "data": {"recommendationInfo": "该城市的模型未训练,请先进行训练"}}
|
|
|
-
|
|
|
- # 初始化模型
|
|
|
- recommend_model = Recommend(request.city_uuid)
|
|
|
-
|
|
|
- # 判断该品规是否是新品规
|
|
|
- products_in_oreder = dao.get_product_from_order(request.city_uuid)["product_code"].unique().tolist()
|
|
|
- if request.product_code in products_in_oreder:
|
|
|
- recommend_list = recommend_model.get_recommend_list_by_gbdtlr(request.product_code, recall_count=request.recall_cust_count)
|
|
|
- else:
|
|
|
- recommend_list = recommend_model.get_recommend_list_by_item2vec(request.product_code, recall_count=request.recall_cust_count)
|
|
|
- recommend_data = recommend_model.get_recommend_and_delivery(recommend_list, delivery_count=request.delivery_count)
|
|
|
- request_data = []
|
|
|
- for index, data in enumerate(recommend_data):
|
|
|
- id = index + 1
|
|
|
- request_data.append(
|
|
|
- {
|
|
|
- "id": id,
|
|
|
- "cust_code": data["cust_code"],
|
|
|
- "recommend_score": data["recommend_score"],
|
|
|
- "delivery_count": data["delivery_count"]
|
|
|
- }
|
|
|
- )
|
|
|
-
|
|
|
- # 异步执行报告生成任务
|
|
|
- backgroundTasks.add_task(
|
|
|
- generate_and_upload_report,
|
|
|
- request
|
|
|
- )
|
|
|
-
|
|
|
- return {"code": 200, "msg": "success", "data": {"recommendationInfo": request_data}}
|
|
|
-
|
|
|
-def generate_and_upload_report(request: RecommendRequest):
|
|
|
- """生成并上传报告到阿里云文件数据库"""
|
|
|
- # 生成相关报告
|
|
|
- report_util = ReportUtils(request.city_uuid, request.product_code)
|
|
|
- report_util.generate_all_data(request.recall_cust_count, request.delivery_count)
|
|
|
-
|
|
|
- # 上传报告
|
|
|
- reports_dir = os.path.join('./data/reports', request.city_uuid, request.product_code)
|
|
|
- report_files = [
|
|
|
- '卷烟信息表',
|
|
|
- '品规商户特征关系表',
|
|
|
- '相似卷烟表',
|
|
|
- '商户售卖推荐表'
|
|
|
- ]
|
|
|
- file_id_map = FileUploadUtils.upload_files(reports_dir, report_files)
|
|
|
-
|
|
|
- # 将返回的file_id保存到数据库中
|
|
|
- data_dict = {
|
|
|
- 'cultivacation_id': request.cultivacation_id,
|
|
|
- 'city_uuid': request.city_uuid,
|
|
|
- 'limit_cycle_name': request.limit_cycle_name,
|
|
|
- 'product_code': request.product_code,
|
|
|
- 'product_info_table': file_id_map.get('卷烟信息表'),
|
|
|
- 'relation_table': file_id_map.get('品规商户特征关系表'),
|
|
|
- 'similarity_product_table': file_id_map.get('相似卷烟表'),
|
|
|
- 'recommend_table': file_id_map.get('商户售卖推荐表'),
|
|
|
- }
|
|
|
- dao.insert_report(data_dict)
|
|
|
-
|
|
|
-@app.post("/brandcultivation/api/v1/report")
|
|
|
-async def get_file_id(request: ReportRequest):
|
|
|
- files_id_path = os.path.join("./data/reports", request.city_uuid, request.product_code, "files_id.txt")
|
|
|
- if not os.path.exists(files_id_path):
|
|
|
- raise HTTPException(
|
|
|
- status_code=status.HTTP_404_NOT_FOUND,
|
|
|
- detail="Reports not found"
|
|
|
- )
|
|
|
-
|
|
|
- with open(files_id_path, 'r', encoding="utf-8") as file:
|
|
|
- lines = file.readlines()
|
|
|
-
|
|
|
- if lines[0].strip() == "failed":
|
|
|
- raise HTTPException(
|
|
|
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
|
- detail="reports upload failed"
|
|
|
- )
|
|
|
-
|
|
|
- request_data = []
|
|
|
- for index, line in enumerate(lines):
|
|
|
- filename, file_id = line.strip().split(",")
|
|
|
- request_data.append(
|
|
|
- {
|
|
|
- "id": index+1,
|
|
|
- "filename": filename,
|
|
|
- "file_id": file_id
|
|
|
- }
|
|
|
- )
|
|
|
-
|
|
|
- return {"code": 200, "msg": "success", "data": {"reportInfo": request_data}}
|
|
|
-
|
|
|
-@app.post("/brandcultivation/api/v1/eval_report")
|
|
|
-async def get_eval_report(request: EvalReportRequest):
|
|
|
- """获取验证报告"""
|
|
|
- reports_dir = os.path.join('./data/reports', request.city_uuid, request.product_code)
|
|
|
- # 首先生成验证报告
|
|
|
- report_util = ReportUtils(request.city_uuid, request.product_code)
|
|
|
- report_util.generate_eval_data(request.start_time, request.end_time)
|
|
|
-
|
|
|
- # 其次上传验证报告到阿里云
|
|
|
- base_url = cfgs["aliyun"]["upload_url"]
|
|
|
-
|
|
|
- headers = {
|
|
|
- "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36",
|
|
|
- "Accept": "*/*",
|
|
|
- }
|
|
|
-
|
|
|
- cookies = {
|
|
|
- "expires_in": "10800000",
|
|
|
- "ecp_token": "ZXlKamIyUmxJam9pT1dZNFltRTNOVGhrTW1WbVpUYzRaR05oWkRZME5ERTRPREU1TkRObU9EY2lMQ0p6WTI5d1pTSTZJbkJ5YjNSbFkzUmxaQ0lzSW1Oc2FXVnVkQ0k2SW1Oc2FXVnVkRjlzYjI1bmFta2lmUT09",
|
|
|
- "acw_tc": "0a067c4317466919842786603e2653311180a2a4fa0fd05acb99cf0458b890",
|
|
|
- "isg": "BDAwNyXyI9cQD__-0PkIodjTAfiCeRTD-vUtYyqmIw3d5bGP0Y0nUayWOe2F3syb",
|
|
|
- "dd-ztna-token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiIwNTAwMzQzMDM4MjYxNDMwOTQiLCJjb3JwSWQiOiJkaW5nYzc2YTJhMzdiMjRhODYwYTRhYzVkNjk4MDg2NGQzMzUiLCJkZXB0SWRzIjoiW1s4Mzk0NzIxNjAsODM2MjQ1MTUzLDFdXSIsInJvbGVJZHMiOiJbMjEwNDk3MDY1OF0iLCJ1bmlvbklkIjoiVXFyYTB4U0VQcWNxdFNhQTFqSzRzZ2lFaUUiLCJleHAiOjE3NDcxODQ3MjksImlhdCI6MTc0NjU3OTkyOX0.dfv612-LwnIdoKL2G73gg7LYy8SBmvr3Zaan97Q5wGUbEFdWw0JUqOQQ1jdeom_Nd9FNCHlkZM32DvwyUrNnvbg1QQy2JeYEpAgysG4h0MT_OghE6-xGVQBIkg72GPTo_cvdMYG9SMfaCo5H-73zFfwMFASFoXCDoIPha6NioIskOJMmvQVsDkHtRXYh_gv0XaJxSWirDWhKC9vxPGaIwDff8doHwPdi9uO-tO9LFy9RXdyIsBXWem31rBSD3D6FmqZLZjOOZhCKMym1VenfIKC10Oa1zm8-Y8bGyMHG0LO_68AJstKYT4alJoBVDHXpMp3zvSXXQB6da_fIthQD4A"
|
|
|
- }
|
|
|
-
|
|
|
- eval_file_path = os.path.join(reports_dir, "投放验证报告.xlsx")
|
|
|
- try:
|
|
|
- with open(eval_file_path, 'rb') as f:
|
|
|
- files = {'file': (os.path.basename(eval_file_path), f)}
|
|
|
-
|
|
|
- response = requests.post(
|
|
|
- base_url,
|
|
|
- headers=headers,
|
|
|
- files=files,
|
|
|
- verify=True
|
|
|
- )
|
|
|
-
|
|
|
- if response.json()["success"]:
|
|
|
- file_id = response.json()["data"]["file_info"]["fileid"]
|
|
|
- return {"code": 200, "msg": "success", "data": {"reportInfo": {"id": 1, "filename": "投放验证报告", "file_id": file_id}}}
|
|
|
-
|
|
|
- else:
|
|
|
- raise HTTPException(
|
|
|
- status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
|
|
|
- detail="reports upload failed"
|
|
|
- )
|
|
|
-
|
|
|
- except requests.exceptions.RequestException as e:
|
|
|
- print("请求出错:", e)
|
|
|
- except Exception as e:
|
|
|
- print("发生错误:", e)
|
|
|
- # 最后将file_id返回给前端
|
|
|
-
|
|
|
-if __name__ == "__main__":
|
|
|
- uvicorn.run(app, host="0.0.0.0", port=7960)
|
|
|
- # report_dir = "./data/reports/00000000000000000000000011445301/440298"
|
|
|
- # upload_file(report_dir)
|