不知名提交
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -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
|
||||
@@ -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接口==========================
|
||||
@@ -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接口==========================
|
||||
100
InfoGenie-backend/test/test_add_coins.py
Normal file
100
InfoGenie-backend/test/test_add_coins.py
Normal 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('✅ 测试完成!')
|
||||
81
InfoGenie-backend/test/test_user_list.py
Normal file
81
InfoGenie-backend/test/test_user_list.py
Normal 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('✅ 测试完成!')
|
||||
Reference in New Issue
Block a user