modified: amazon/approve.py modified: amazon/asin_status.py new file: amazon/chrome_base.py modified: amazon/del_brand.py modified: amazon/detail_spider.py new file: "amazon/detail_spider_\345\244\207\344\273\275.py" modified: amazon/main.py modified: amazon/match_action.py modified: amazon/price_match.py new file: amazon/similar_asin.py modified: app.py new file: assets/appearance-patent-Br1dtmol.css new file: assets/appearance-patent-D1DgeYhe.css new file: assets/delete-brand-BfMLVSQU.css new file: assets/patrol-delete-BAzbYtgc.css new file: assets/price-track-Hozgt_em.css new file: assets/product-risk-CbX7bwZi.css new file: assets/query-asin-B4RsOiza.css new file: assets/shop-match-B2HWAgBY.css modified: main.py
107 lines
3.5 KiB
Python
107 lines
3.5 KiB
Python
"""
|
||
卖相AI - Flask 后端
|
||
按功能拆分为蓝图:认证(auth)、主页面(main)、管理员(admin)、图片(image)、品牌(brand)
|
||
"""
|
||
import os
|
||
import secrets
|
||
import logging
|
||
from datetime import timedelta, datetime
|
||
from logging.handlers import RotatingFileHandler
|
||
|
||
from flask import Flask
|
||
from flask_cors import CORS
|
||
|
||
from app_common import init_db, BASE_DIR
|
||
from blueprints.auth import auth_bp
|
||
from blueprints.main import main_bp
|
||
from blueprints.admin import admin_bp
|
||
from blueprints.image import image_bp
|
||
from blueprints.brand import brand_bp
|
||
from blueprints.communication import communication_bp
|
||
|
||
from config import cache_path, debug
|
||
|
||
|
||
def setup_flask_logging(app):
|
||
"""配置Flask访问日志,输出到独立的日志文件"""
|
||
|
||
api_cache_path = os.path.join(cache_path, "api_logs")
|
||
os.makedirs(api_cache_path, exist_ok=True)
|
||
|
||
# 只在非debug模式下配置文件日志
|
||
if not debug:
|
||
# 获取当前日期作为日志文件名的一部分
|
||
today = datetime.now().strftime("%Y_%m_%d")
|
||
log_file = os.path.join(api_cache_path, f'api_{today}.log')
|
||
|
||
# 创建文件处理器,使用RotatingFileHandler避免日志文件过大
|
||
file_handler = RotatingFileHandler(
|
||
log_file,
|
||
maxBytes=10 * 1024 * 1024, # 10MB
|
||
backupCount=5,
|
||
encoding='utf-8'
|
||
)
|
||
|
||
# 设置日志格式
|
||
formatter = logging.Formatter(
|
||
'[%(asctime)s] %(levelname)s in %(module)s: %(message)s',
|
||
datefmt='%Y-%m-%d %H:%M:%S'
|
||
)
|
||
file_handler.setFormatter(formatter)
|
||
file_handler.setLevel(logging.INFO)
|
||
|
||
# 配置Flask应用日志
|
||
app.logger.addHandler(file_handler)
|
||
app.logger.setLevel(logging.INFO)
|
||
|
||
# 配置Werkzeug日志(HTTP访问日志)
|
||
werkzeug_logger = logging.getLogger('werkzeug')
|
||
werkzeug_logger.addHandler(file_handler)
|
||
werkzeug_logger.setLevel(logging.INFO)
|
||
|
||
print(f"API 日志已配置,输出到: {log_file}")
|
||
else:
|
||
print("Debug模式下,API 日志输出到控制台")
|
||
|
||
|
||
def create_app():
|
||
app = Flask(__name__, template_folder=BASE_DIR, static_folder=BASE_DIR)
|
||
frontend_origin = os.environ.get('FRONTEND_ORIGIN', '*')
|
||
cors_origins = frontend_origin if frontend_origin != '*' else '*'
|
||
CORS(
|
||
app,
|
||
supports_credentials=True,
|
||
resources={r"/api/*": {"origins": cors_origins}, r"/login": {"origins": cors_origins}},
|
||
)
|
||
# 生产环境必须通过环境变量注入固定 SECRET_KEY;否则服务重启会使旧会话失效。
|
||
app.secret_key = os.environ.get('SECRET_KEY', 'dev-secret-key-change-me')
|
||
app.config['PERMANENT_SESSION_LIFETIME'] = timedelta(days=7)
|
||
app.config['SESSION_COOKIE_HTTPONLY'] = True
|
||
app.config['SESSION_COOKIE_SAMESITE'] = os.environ.get('SESSION_COOKIE_SAMESITE', 'Lax')
|
||
app.config['SESSION_COOKIE_SECURE'] = os.environ.get('SESSION_COOKIE_SECURE', '0') == '1'
|
||
|
||
# 注册蓝图(不设 url_prefix,保持原有 URL 路径不变,前端无需改动)
|
||
app.register_blueprint(auth_bp)
|
||
app.register_blueprint(main_bp)
|
||
app.register_blueprint(admin_bp)
|
||
app.register_blueprint(image_bp)
|
||
app.register_blueprint(brand_bp)
|
||
app.register_blueprint(communication_bp)
|
||
|
||
# 配置Flask访问日志
|
||
setup_flask_logging(app)
|
||
|
||
return app
|
||
|
||
|
||
app = create_app()
|
||
|
||
|
||
def run_app(host='127.0.0.1', port=5123):
|
||
# init_db()
|
||
app.run(host=host, port=port, threaded=True, use_reloader=False)
|
||
|
||
|
||
if __name__ == '__main__':
|
||
run_app()
|