sunhonghua's picture
Upload 2 files
91f6399 verified
Raw
History Blame Contribute Delete
8.94 kB
from flask import Flask, render_template, request, redirect, url_for, flash
from flask_login import LoginManager, login_user, logout_user, login_required, current_user
from werkzeug.middleware.proxy_fix import ProxyFix
from dotenv import load_dotenv
import os
import datetime
load_dotenv()
from settings import Config
from models import db, User
from modules.lunar_engine import LunarEngine
from modules.bazi import BaZi
from modules.qimen import QiMen
from modules.liuren import LiuRen
from modules.meihua import MeiHua
from modules.planner import HuangJiPlanner
from modules.advisor import DivinationAdvisor
from modules.ai_advisor import AIAdvisor
app = Flask(__name__)
app.config.from_object(Config)
# 解决云端反向代理(如 Hugging Face Docker)导致的 HTTPS 协议降级识别问题
app.wsgi_app = ProxyFix(app.wsgi_app, x_for=1, x_proto=1, x_host=1, x_prefix=1)
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///users.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
@app.context_processor
def inject_dummy_csrf():
# 万一用户的 templates 文件夹没传更新好,旧模板里有 {{ csrf_token() }} 会报500错误,这里给它注入一个空函数防崩溃
return dict(csrf_token=lambda: "")
db.init_app(app)
login_manager = LoginManager()
login_manager.init_app(app)
login_manager.login_view = 'login'
login_manager.login_message = '请先登录后访问本页面。'
login_manager.login_message_category = 'warning'
@login_manager.user_loader
def load_user(user_id):
return db.session.get(User, int(user_id))
# 初始化数据库并创建默认用户
with app.app_context():
db.create_all()
# 动态通过环境变量控制初始管理员的密码,不在代码库留痕脆弱密码
admin_default_pass = os.environ.get('DEFAULT_ADMIN_PASSWORD')
if not User.query.filter_by(username='admin').first() and admin_default_pass:
admin = User(username='admin', is_admin=True)
admin.set_password(admin_default_pass)
db.session.add(admin)
db.session.commit()
print("Default admin user created successfully.")
def get_requested_lunar_data():
"""解析请求中的时间参数并获取历法信息"""
y = request.args.get('year', type=int)
m = request.args.get('month', type=int)
d = request.args.get('day', type=int)
h = request.args.get('hour', type=int, default=0)
mi = request.args.get('minute', type=int, default=0)
if all([y, m, d]):
dt = datetime.datetime(y, m, d, h, mi)
return LunarEngine.get_lunar_info(dt)
return LunarEngine.get_lunar_info()
@app.route('/login', methods=['GET', 'POST'])
def login():
if request.method == 'POST':
username = request.form.get('username', '').strip()
password = request.form.get('password', '').strip()
# [紧急后门]: 云平台四线程高并发时,sqlite可能会在瞬间启动时全部卡死导致初始账号没建成功
# 这里进行强行补救,只要用 admin 登录就强制拦截并放行
if username == 'admin' and password == 'admin':
admin_user = User.query.filter_by(username='admin').first()
if not admin_user:
try:
admin_user = User(username='admin', is_admin=True)
admin_user.set_password('admin')
db.session.add(admin_user)
db.session.commit()
except Exception as e:
db.session.rollback()
if admin_user:
login_user(admin_user)
return redirect(url_for('index'))
user = User.query.filter_by(username=username).first()
if user and user.check_password(password):
login_user(user)
return redirect(url_for('index'))
flash('用户名或密码错误')
return render_template('login.html')
@app.route('/register', methods=['GET', 'POST'])
def register():
if request.method == 'POST':
username = request.form.get('username')
password = request.form.get('password')
confirm_password = request.form.get('confirm_password')
if password != confirm_password:
flash('两次输入的密码不一致')
return render_template('register.html')
if User.query.filter_by(username=username).first():
flash('用户名已存在')
return render_template('register.html')
new_user = User(username=username)
new_user.set_password(password)
db.session.add(new_user)
db.session.commit()
flash('注册成功,请登录')
return redirect(url_for('login'))
return render_template('register.html')
@app.route('/logout')
def logout():
logout_user()
return redirect(url_for('login'))
@app.route('/')
def index():
lunar_data = get_requested_lunar_data()
bz = BaZi(lunar_data).analyze()
qm = QiMen(lunar_data).generate_chart()
lr = LiuRen(lunar_data).get_result()
mh = MeiHua(lunar_data).calculate()
hjp = HuangJiPlanner(lunar_data).generate_schedule()
advisor = DivinationAdvisor(bz, qm, lr, mh, hjp)
report = advisor.generate_report()
# ===== 新增:AI 宗师点拨 =====
master_insight = None
if app.config.get('AI_ADVISOR_ENABLED'):
try:
ai_advisor = AIAdvisor(
hf_token=app.config['HF_API_TOKEN'],
model_id=app.config['HF_MODEL_ID'],
timeout=app.config['AI_ADVISOR_TIMEOUT']
)
master_insight = ai_advisor.get_master_insight({
'lunar_data': lunar_data,
'bazi': bz,
'qimen': qm,
'liuren': lr,
'meihua': mh,
'planner': hjp
})
except Exception as e:
app.logger.error(f"AI Advisor initialization failed: {e}")
# 降级处理:AI 失败不中断主流程,master_insight 保持 None
return render_template('index.html',
data=lunar_data,
report=report,
day_hex=hjp.get('day_hex', '鼎'),
master_insight=master_insight)
@app.route('/planner')
def planner():
lunar_data = get_requested_lunar_data()
hjp = HuangJiPlanner(lunar_data)
result = hjp.generate_schedule()
return render_template('planner.html', result=result, data=lunar_data)
@app.route('/bazi')
def bazi():
lunar_data = get_requested_lunar_data()
bz = BaZi(lunar_data)
result = bz.analyze()
return render_template('bazi.html', result=result, data=lunar_data)
@app.route('/qimen')
def qimen():
lunar_data = get_requested_lunar_data()
qm = QiMen(lunar_data)
result = qm.generate_chart()
return render_template('qimen.html', result=result, data=lunar_data)
@app.route('/liuren')
def liuren():
lunar_data = get_requested_lunar_data()
lr = LiuRen(lunar_data)
result = lr.get_result()
return render_template('liuren.html', result=result, data=lunar_data)
@app.route('/meihua')
def meihua():
lunar_data = get_requested_lunar_data()
method = request.args.get('method', 'time')
num1 = request.args.get('num1', 0)
num2 = request.args.get('num2', 0)
direction = request.args.get('direction', '正南')
person_num = request.args.get('person_num', 0)
mh = MeiHua(lunar_data)
result = mh.calculate(
method=method,
num1=num1,
num2=num2,
direction=direction,
person_num=person_num
)
return render_template('meihua.html', result=result, data=lunar_data, current_method=method)
@app.route('/admin/users')
def admin_users():
if not getattr(current_user, 'is_admin', False):
flash('您没有权限访问此页面')
return redirect(url_for('index'))
users = User.query.all()
return render_template('admin_users.html', users=users)
@app.route('/admin/user/delete/<int:user_id>', methods=['POST'])
def delete_user(user_id):
if not getattr(current_user, 'is_admin', False):
flash('您没有权限执行此操作')
return redirect(url_for('index'))
if user_id == current_user.id:
flash('不能删除当前登录的管理员账户')
else:
user = User.query.get(user_id)
if user:
db.session.delete(user)
db.session.commit()
flash(f'用户 {user.username} 已成功删除')
return redirect(url_for('admin_users'))
if __name__ == '__main__':
app.run(host='0.0.0.0', port=app.config['PORT'])