Files
JieXi/routes/apikey.py
2025-11-30 19:49:25 +08:00

175 lines
5.0 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from flask import Blueprint, request, jsonify, render_template
from flask_login import login_required, current_user
from models import db, UserApiKey, ApiKeyDailyStat
from datetime import datetime, date
import secrets
apikey_bp = Blueprint('apikey', __name__, url_prefix='/user/apikey')
def generate_api_key():
"""生成 API Key"""
return f"sk_{secrets.token_hex(24)}"
@apikey_bp.route('/')
@login_required
def manage_page():
"""API Key 管理页面"""
return render_template('apikey/manage.html')
@apikey_bp.route('/list', methods=['GET'])
@login_required
def list_keys():
"""获取用户的 API Key 列表"""
keys = UserApiKey.query.filter_by(user_id=current_user.id).order_by(UserApiKey.created_at.desc()).all()
result = []
for key in keys:
# 获取今日调用次数
today_stat = ApiKeyDailyStat.query.filter_by(
api_key_id=key.id,
date=date.today()
).first()
result.append({
'id': key.id,
'name': key.name,
'api_key': key.api_key[:12] + '...' + key.api_key[-4:], # 隐藏中间部分
'is_active': key.is_active,
'daily_limit': key.daily_limit,
'total_calls': key.total_calls,
'today_calls': today_stat.call_count if today_stat else 0,
'last_used_at': key.last_used_at.strftime('%Y-%m-%d %H:%M:%S') if key.last_used_at else None,
'created_at': key.created_at.strftime('%Y-%m-%d %H:%M:%S')
})
return jsonify({
'success': True,
'data': result
})
@apikey_bp.route('/create', methods=['POST'])
@login_required
def create_key():
"""创建新的 API Key"""
data = request.get_json()
name = data.get('name', '').strip()
if not name:
return jsonify({'success': False, 'message': '请输入 Key 名称'}), 400
if len(name) > 100:
return jsonify({'success': False, 'message': 'Key 名称不能超过100个字符'}), 400
# 检查用户已有的 Key 数量限制每个用户最多5个
key_count = UserApiKey.query.filter_by(user_id=current_user.id).count()
if key_count >= 5:
return jsonify({'success': False, 'message': '每个用户最多创建5个 API Key'}), 400
# 生成新的 API Key
api_key = generate_api_key()
# 根据用户等级设置每日限制
daily_limit = 100 # 默认
if current_user.group:
if current_user.group.id == 3: # VIP
daily_limit = 500
elif current_user.group.id == 4: # SVIP
daily_limit = 2000
new_key = UserApiKey(
user_id=current_user.id,
name=name,
api_key=api_key,
daily_limit=daily_limit
)
db.session.add(new_key)
db.session.commit()
return jsonify({
'success': True,
'message': 'API Key 创建成功',
'data': {
'id': new_key.id,
'name': new_key.name,
'api_key': api_key, # 只在创建时返回完整的 Key
'daily_limit': new_key.daily_limit
}
})
@apikey_bp.route('/delete/<int:key_id>', methods=['DELETE'])
@login_required
def delete_key(key_id):
"""删除 API Key"""
key = UserApiKey.query.filter_by(id=key_id, user_id=current_user.id).first()
if not key:
return jsonify({'success': False, 'message': 'API Key 不存在'}), 404
db.session.delete(key)
db.session.commit()
return jsonify({
'success': True,
'message': 'API Key 已删除'
})
@apikey_bp.route('/toggle/<int:key_id>', methods=['POST'])
@login_required
def toggle_key(key_id):
"""启用/禁用 API Key"""
key = UserApiKey.query.filter_by(id=key_id, user_id=current_user.id).first()
if not key:
return jsonify({'success': False, 'message': 'API Key 不存在'}), 404
key.is_active = not key.is_active
db.session.commit()
return jsonify({
'success': True,
'message': f"API Key 已{'启用' if key.is_active else '禁用'}",
'is_active': key.is_active
})
@apikey_bp.route('/stats/<int:key_id>', methods=['GET'])
@login_required
def get_stats(key_id):
"""获取 API Key 统计数据"""
key = UserApiKey.query.filter_by(id=key_id, user_id=current_user.id).first()
if not key:
return jsonify({'success': False, 'message': 'API Key 不存在'}), 404
# 获取最近7天的统计
from datetime import timedelta
stats = ApiKeyDailyStat.query.filter(
ApiKeyDailyStat.api_key_id == key_id,
ApiKeyDailyStat.date >= date.today() - timedelta(days=6)
).order_by(ApiKeyDailyStat.date.asc()).all()
result = []
for stat in stats:
result.append({
'date': stat.date.strftime('%Y-%m-%d'),
'call_count': stat.call_count,
'success_count': stat.success_count,
'fail_count': stat.fail_count
})
return jsonify({
'success': True,
'data': {
'key_name': key.name,
'total_calls': key.total_calls,
'daily_stats': result
}
})