不知名提交

This commit is contained in:
2025-12-13 20:53:50 +08:00
parent c147502b4d
commit 1221d6faf1
120 changed files with 11005 additions and 1092 deletions

View File

@@ -855,6 +855,56 @@ def linux_command_generator():
except Exception as e:
return jsonify({'error': f'Linux命令生成失败: {str(e)}'}), 500
#AI文章排版Markdown格式化接口
@aimodelapp_bp.route('/markdown_formatting', methods=['POST'])
@verify_user_coins
def markdown_formatting():
"""AI文章排版Markdown格式化接口"""
try:
data = request.get_json()
article_text = data.get('article_text', '').strip()
emoji_style = data.get('emoji_style', 'balanced').strip()
markdown_option = data.get('markdown_option', 'standard').strip()
if not article_text:
return jsonify({'error': '文章内容不能为空'}), 400
# 构建Markdown排版的提示词
prompt = f"""你是一位专业的文档排版助手。请将用户提供的全文按“标准Markdown格式”进行排版并在不改变任何原文内容的前提下进行结构化呈现。严格遵守以下规则
1) 保留所有原始内容,严禁改写、删减或添加新内容。
2) 使用合理的Markdown结构标题、分节、段落、列表、引用、表格如有必要、代码块仅当原文包含
3) 智能添加适量Emoji以增强可读性{emoji_style}),在标题、关键句、列表项等处点缀;避免过度使用,保持专业。
4) 保持语言与语气不变,只优化排版和表现形式。
5) 输出“纯Markdown文本”不要包含任何JSON、HTML、XML、解释文字、或代码块围栏标记例如不要在最外层使用```)。
如果原文本较长,可在开头自动生成简洁的“目录”以便阅读。
原文如下:
{article_text}
"""
messages = [{"role": "user", "content": prompt}]
# 使用DeepSeek进行排版生成
content, error = call_deepseek_api(messages)
if error:
return jsonify({'error': error}), 500
# 返回AI生成的Markdown文本
return jsonify({
'success': True,
'formatted_markdown': content,
'source_text': article_text,
'emoji_style': emoji_style,
'markdown_option': markdown_option,
'timestamp': datetime.now().isoformat()
})
except Exception as e:
return jsonify({'error': f'文章排版失败: {str(e)}'}), 500
#获取用户萌芽币余额
@aimodelapp_bp.route('/coins', methods=['GET'])
def get_user_coins():
@@ -951,4 +1001,87 @@ def get_available_models():
})
except Exception as e:
return jsonify({'error': f'获取模型列表失败: {str(e)}'}), 500
return jsonify({'error': f'获取模型列表失败: {str(e)}'}), 500
#中国亲戚称呼计算器接口(普通话版 + 方言)
@aimodelapp_bp.route('/kinship-calculator', methods=['POST'])
@verify_user_coins
def kinship_calculator():
"""中国亲戚称呼计算器接口"""
try:
data = request.get_json() or {}
relation_chain = (data.get('relation_chain') or '').strip()
dialects = data.get('dialects') # 可选,指定方言列表
if not relation_chain:
return jsonify({'error': '亲属关系链不能为空'}), 400
# 组装提示词要求严格JSON输出
requested_dialects = dialects if isinstance(dialects, list) and dialects else [
'粤语', '闽南语', '上海话', '四川话', '东北话', '客家话'
]
prompt = f"""你是一位中国亲属称呼专家。请解析下面的亲属关系链,给出最终的亲属称呼。
输入的关系链会用“的”连接,如“妈妈的爸爸”“爸爸的姐姐的儿子”。
请遵循:
1) 以中国大陆通行的标准普通话称呼为准,给出最常用、规范的最终称呼。
2) 同时给出若干方言的对应称呼:{', '.join(requested_dialects)}
3) 如存在地区差异或性别歧义请在notes中说明但最终给出一个最常用称呼。
4) 不要展示推理过程只输出JSON。
严格按以下JSON结构输出
{{
"mandarin_title": "标准普通话称呼",
"dialect_titles": {{
"粤语": {{"title": "称呼", "romanization": "粤拼或发音", "notes": "可选说明"}},
"闽南语": {{"title": "称呼", "romanization": "白话字或发音", "notes": "可选说明"}},
"上海话": {{"title": "称呼", "romanization": "拟音或IPA", "notes": "可选说明"}},
"四川话": {{"title": "称呼", "romanization": "拟音或IPA", "notes": "可选说明"}},
"东北话": {{"title": "称呼", "romanization": "拟音或IPA", "notes": "可选说明"}},
"客家话": {{"title": "称呼", "romanization": "客家话拟音", "notes": "可选说明"}}
}},
"notes": "总体说明(如地区差异、辈分方向、父系/母系等提示)"
}}
关系链:
{relation_chain}
"""
messages = [{"role": "user", "content": prompt}]
content, error = call_deepseek_api(messages)
if error:
return jsonify({'error': error}), 500
# 解析AI返回的JSON
try:
result = json.loads(content)
except json.JSONDecodeError:
import re
m = re.search(r'\{[\s\S]*\}', content)
if not m:
return jsonify({'error': 'AI返回的数据中未找到有效JSON'}), 500
try:
result = json.loads(m.group())
except Exception:
return jsonify({'error': 'AI返回的JSON格式无法解析'}), 500
mandarin_title = result.get('mandarin_title')
dialect_titles = result.get('dialect_titles', {})
notes = result.get('notes', '')
if not mandarin_title:
return jsonify({'error': '未获得标准普通话称呼'}), 500
return jsonify({
'success': True,
'relation_chain': relation_chain,
'mandarin_title': mandarin_title,
'dialect_titles': dialect_titles,
'notes': notes,
'timestamp': datetime.now().isoformat()
})
except Exception as e:
return jsonify({'error': f'亲戚称呼计算失败: {str(e)}'}), 500

View File

@@ -70,6 +70,8 @@ def validate_password(password):
"""验证密码格式6-20位"""
return 6 <= len(password) <= 20
#==========================对外暴露的HTTP接口==========================
#发送验证码邮件
@auth_bp.route('/send-verification', methods=['POST'])
def send_verification():
@@ -450,3 +452,4 @@ def check_login():
'success': False,
'message': f'服务器错误: {str(e)}'
}), 500
#==========================对外暴露的HTTP接口==========================

View File

@@ -51,6 +51,8 @@ def login_required(f):
return decorated_function
return decorated_function
#==========================对外暴露的HTTP接口==========================
# 获取用户资料
@user_bp.route('/profile', methods=['GET'])
@login_required
@@ -102,6 +104,127 @@ def get_profile():
'message': f'服务器错误: {str(e)}'
}), 500
# 为指定账号增加萌芽币
@user_bp.route('/add-coins', methods=['POST'])
@login_required
def add_coins():
"""为指定账号增加萌芽币支持email或username指定账号amount为正整数"""
try:
data = request.get_json() or {}
email = (data.get('email') or '').strip()
username = (data.get('username') or '').strip()
amount = data.get('amount')
# 参数校验
if not email and not username:
return jsonify({
'success': False,
'message': '请提供email或username其中之一'
}), 400
if amount is None:
return jsonify({
'success': False,
'message': 'amount不能为空'
}), 400
try:
amount_int = int(amount)
except Exception:
return jsonify({
'success': False,
'message': 'amount必须为整数'
}), 400
if amount_int <= 0:
return jsonify({
'success': False,
'message': 'amount必须为正整数'
}), 400
users_collection = current_app.mongo.db.userdata
query = {'邮箱': email} if email else {'用户名': username}
user = users_collection.find_one(query)
if not user:
return jsonify({
'success': False,
'message': '用户不存在'
}), 404
before_coins = user.get('萌芽币', 0)
update_result = users_collection.update_one(query, {'$inc': {'萌芽币': amount_int}})
if update_result.modified_count == 0:
return jsonify({
'success': False,
'message': '更新失败,请稍后重试'
}), 500
updated = users_collection.find_one({'_id': user['_id']})
new_coins = updated.get('萌芽币', before_coins)
return jsonify({
'success': True,
'message': f"已为账户{email or username}增加{amount_int}萌芽币",
'data': {
'before_coins': before_coins,
'added': amount_int,
'new_coins': new_coins,
'user': {
'id': str(updated.get('_id')),
'email': updated.get('邮箱'),
'username': updated.get('用户名'),
'avatar': updated.get('头像'),
'register_time': updated.get('注册时间'),
'last_login': updated.get('最后登录'),
'login_count': updated.get('登录次数', 0),
'status': updated.get('用户状态', 'active'),
'level': updated.get('等级', 0),
'experience': updated.get('经验', 0),
'coins': new_coins
}
}
}), 200
except Exception as e:
return jsonify({
'success': False,
'message': f'服务器错误: {str(e)}'
}), 500
# 列出所有用户
@user_bp.route('/list', methods=['GET'])
@login_required
def list_users():
"""列出所有用户(不返回密码)"""
try:
users_collection = current_app.mongo.db.userdata
cursor = users_collection.find({}, {'密码': 0})
users = []
for u in cursor:
users.append({
'id': str(u.get('_id')),
'email': u.get('邮箱'),
'username': u.get('用户名'),
'avatar': u.get('头像'),
'register_time': u.get('注册时间'),
'last_login': u.get('最后登录'),
'login_count': u.get('登录次数', 0),
'status': u.get('用户状态', 'active'),
'level': u.get('等级', 0),
'experience': u.get('经验', 0),
'coins': u.get('萌芽币', 0)
})
return jsonify({
'success': True,
'count': len(users),
'data': users
}), 200
except Exception as e:
return jsonify({
'success': False,
'message': f'服务器错误: {str(e)}'
}), 500
# 修改密码
@user_bp.route('/change-password', methods=['POST'])
@login_required
@@ -424,3 +547,4 @@ def delete_account():
'success': False,
'message': f'服务器错误: {str(e)}'
}), 500
#==========================对外暴露的HTTP接口==========================

View File

@@ -0,0 +1,100 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
测试为指定账号增加萌芽币接口 (/api/user/add-coins)
"""
import os
import sys
import json
from datetime import datetime
# 加入后端根目录到路径导入create_app
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from app import create_app
from modules.auth import generate_token
from werkzeug.security import generate_password_hash
def run_test():
"""运行加币接口测试,打印真实响应并断言结果"""
app = create_app()
with app.app_context():
db = app.mongo.db
users = db.userdata
# 构造一个临时测试用户(真实写库,测试结束删除)
test_email = "infogenie.test.addcoins@foxmail.com"
users.delete_many({'邮箱': test_email})
test_user = {
'邮箱': test_email,
'用户名': '测试用户_加币',
'密码': generate_password_hash('AddCoins123!'),
'头像': None,
'注册时间': datetime.now().isoformat(),
'最后登录': None,
'登录次数': 0,
'用户状态': 'active',
'等级': 0,
'经验': 0,
'萌芽币': 0,
'签到系统': {
'连续签到天数': 0,
'今日是否已签到': False,
'签到时间': datetime.now().strftime('%Y-%m-%d')
}
}
insert_result = users.insert_one(test_user)
test_user_id = str(insert_result.inserted_id)
# 生成有效JWT用于认证
token = generate_token({
'user_id': test_user_id,
'email': test_email,
'username': test_user['用户名']
})
client = app.test_client()
# 第一次加币: +500
resp1 = client.post(
'/api/user/add-coins',
headers={'Authorization': f'Bearer {token}'},
json={'email': test_email, 'amount': 500}
)
print('第一次加币 状态码:', resp1.status_code)
data1 = resp1.get_json()
print('第一次加币 响应:')
print(json.dumps(data1, ensure_ascii=False, indent=2))
assert resp1.status_code == 200
assert data1.get('success') is True
assert data1['data']['before_coins'] == 0
assert data1['data']['added'] == 500
assert data1['data']['new_coins'] == 500
# 第二次加币: +200
resp2 = client.post(
'/api/user/add-coins',
headers={'Authorization': f'Bearer {token}'},
json={'email': test_email, 'amount': 200}
)
print('第二次加币 状态码:', resp2.status_code)
data2 = resp2.get_json()
print('第二次加币 响应:')
print(json.dumps(data2, ensure_ascii=False, indent=2))
assert resp2.status_code == 200
assert data2.get('success') is True
assert data2['data']['before_coins'] == 500
assert data2['data']['added'] == 200
assert data2['data']['new_coins'] == 700
# 清理临时测试用户
users.delete_many({'邮箱': test_email})
if __name__ == '__main__':
print('🔧 开始测试 /api/user/add-coins 接口...')
run_test()
print('✅ 测试完成!')

View File

@@ -0,0 +1,81 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""
测试列出所有用户的HTTP接口 (/api/user/list)
"""
import os
import sys
import json
from datetime import datetime
# 将后端根目录加入路径便于导入app
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from app import create_app
from modules.auth import generate_token
from werkzeug.security import generate_password_hash
def run_test():
"""运行用户列表接口测试,输出真实数据"""
# 使用.env中的真实Mongo配置不造假
app = create_app()
with app.app_context():
db = app.mongo.db
users = db.userdata
# 插入一个测试用户(真实写入后再删除),确保可验证接口输出
test_email = "infogenie.test.user@foxmail.com"
users.delete_many({'邮箱': test_email})
test_user = {
'邮箱': test_email,
'用户名': '测试用户_列表',
'密码': generate_password_hash('TestPass123!'),
'头像': None,
'注册时间': datetime.now().isoformat(),
'最后登录': None,
'登录次数': 0,
'用户状态': 'active',
'等级': 0,
'经验': 0,
'萌芽币': 0,
'签到系统': {
'连续签到天数': 0,
'今日是否已签到': False,
'签到时间': datetime.now().strftime('%Y-%m-%d')
}
}
insert_result = users.insert_one(test_user)
test_user_id = str(insert_result.inserted_id)
# 生成有效JWT满足认证要求
token = generate_token({
'user_id': test_user_id,
'email': test_email,
'username': test_user['用户名']
})
client = app.test_client()
resp = client.get('/api/user/list', headers={'Authorization': f'Bearer {token}'})
print("状态码:", resp.status_code)
data = resp.get_json()
print("响应内容:")
print(json.dumps(data, ensure_ascii=False, indent=2))
# 基本断言,确保返回真实列表数据且包含刚插入的测试用户
assert resp.status_code == 200
assert data.get('success') is True
assert isinstance(data.get('data'), list)
assert any(u.get('email') == test_email for u in data['data'])
# 清理测试数据
users.delete_many({'邮箱': test_email})
if __name__ == '__main__':
print('🔎 开始测试 /api/user/list 接口...')
run_test()
print('✅ 测试完成!')