更新了项目文件

This commit is contained in:
Your Name
2024-10-18 21:17:49 +08:00
parent bec6766f03
commit 15e91c30b7
121 changed files with 588585 additions and 163 deletions

View File

@@ -44,7 +44,7 @@ def call_bailian_app(request):
prompt = data.get("prompt")
x = request.headers.get('X', '')
t = request.headers.get('T', '')
increment = -1
increment = -0
function_type = 'call_bailian_app'
result = update_usage_count(openid, increment, function_type)
if decrypt_param(x, t):

299
MyApi/app_login_pay.py Executable file
View File

@@ -0,0 +1,299 @@
import base64
import json
import string
from datetime import datetime
from decimal import Decimal
import requests
import time
import random
from xml.etree import ElementTree as ET
from Crypto.Hash import SHA256
from Crypto.PublicKey import RSA
from Crypto.Signature import pkcs1_15
from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from django.http import JsonResponse, HttpResponse, HttpResponseRedirect
from django.views.decorators.csrf import csrf_exempt
from django.conf import settings
from .models import TransactionLog, MembershipType, User
from .API_Log import get_logger
log_file = '支付日志demo.log'
logger = get_logger('支付日志demo', log_file, when='midnight', backup_count=7)
def get_sign(sign_str, key_path):
rsa_key = RSA.importKey(open(key_path).read())
signer = pkcs1_15.new(rsa_key)
digest = SHA256.new(sign_str.encode('utf8'))
sign = base64.b64encode(signer.sign(digest)).decode('utf-8')
return sign
def decrypt(nonce, ciphertext, associated_data, api_key):
key_bytes = str.encode(api_key)
nonce_bytes = str.encode(nonce)
ad_bytes = str.encode(associated_data)
data = base64.b64decode(ciphertext)
aesgcm = AESGCM(key_bytes)
return aesgcm.decrypt(nonce_bytes, data, ad_bytes)
def update_user_membership_or_quota(openid, membership_type):
current_time = int(time.time())
try:
user = User.objects.get(openid=openid)
if membership_type.is_quota:
user.coins += membership_type.coins
logger.info(f'用户 {user.id} (openid: {openid}) 充值额度卡,增加金币 {membership_type.coins}')
else:
user.is_member = True
if user.member_start_time is None:
user.member_start_time = current_time
elif user.member_end_time is None or user.member_end_time < current_time:
user.member_start_time = current_time
if user.member_end_time is None or user.member_end_time < current_time:
user.member_end_time = current_time + membership_type.duration_days * 24 * 3600
else:
user.member_end_time += membership_type.duration_days * 24 * 3600
user.coins += membership_type.coins
user.save()
return True
except User.DoesNotExist:
logger.error(f'用户 {openid} 不存在')
return False
except Exception as e:
logger.error(f'更新会员或额度充值时出错: {str(e)}')
return False
@csrf_exempt
def wx_pay(request):
request_data = json.loads(request.body)
logger.info(f"生成订单{request_data}")
type = request_data.get('type', 'default')
wx_price = request_data['total_fee']
openid = request_data['openid']
uuid = request_data.get('uuid')
transaction_type = request_data['transaction_type']
up_time = datetime.now()
membership_types = MembershipType.objects.all()
body_map = {membership_type.type: membership_type.title for membership_type in membership_types}
body_description = body_map.get(type)
transactionNo = str(up_time).replace('.', '').replace('-', '').replace(':', '').replace(' ', '')
membership_type = MembershipType.objects.get(type=type)
price = membership_type.price
newTransaction = TransactionLog.objects.create(
transaction_no=transactionNo,
transaction_status='pending',
user_openid=openid,
transaction_type=transaction_type,
transaction_amount=price,
remark=type,
created_at=up_time
)
logger.info("生成订单:")
logger.info(f"商户订单号:{transactionNo}")
logger.info(f"用户OpenID{openid}")
logger.info(f"用户UUID{uuid}")
logger.info(f"type{type}")
logger.info(f"transaction_type{transaction_type}")
logger.info(f"成功时间:{up_time}")
logger.info(f"金额(前端):{wx_price}")
logger.info(f"金额(后端):{price}")
url = 'https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi'
body = {
"appid": settings.LOGIN_APP_ID,
"mchid": settings.LOGIN_WX_MCH_ID,
"description": body_description,
"out_trade_no": transactionNo,
"notify_url": settings.LOGIN_WX_NOTIFY_URL,
"amount": {"total": int(float(price) * 100), "currency": "CNY"},
"payer": {"openid": openid},
"attach": json.dumps({"type": type, "transaction_type": transaction_type,"uuid":uuid})
}
data = json.dumps(body)
logger.info(f'生成支付请求体: {body}')
random_str = ''.join(random.choice(string.ascii_uppercase + string.digits) for _ in range(32))
time_stamps = str(int(time.time()))
sign_str = f"POST\n/v3/pay/transactions/jsapi\n{time_stamps}\n{random_str}\n{data}\n"
sign = get_sign(sign_str, settings.LOGIN_WX_KEY_PATH)
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json',
'User-Agent': '*/*',
'Authorization': 'WECHATPAY2-SHA256-RSA2048 ' + f'mchid="{settings.LOGIN_WX_MCH_ID}",nonce_str="{random_str}",signature="{sign}",timestamp="{time_stamps}",serial_no="{settings.LOGIN_WX_SERIAL_NO}"',
'Wechatpay-Serial': '66DB35F836EFD4CBEC66F3815D283A2892310324'
}
logger.info(f'生成请求头: {headers}')
response = requests.post(url, data=data, headers=headers)
response_dict = response.json()
logger.info(f'响应头: {response.headers}')
logger.info(f'响应体: {response_dict}')
if response.status_code == 200:
res = {
'appid': settings.LOGIN_APP_ID,
'partnerid': settings.LOGIN_WX_MCH_ID,
'prepayid': response_dict['prepay_id'],
'package': f'prepay_id={response_dict["prepay_id"]}',
'nonceStr': random_str,
'timeStamp': time_stamps,
'paySign': get_sign(
f"{settings.LOGIN_APP_ID}\n{time_stamps}\n{random_str}\n{'prepay_id=' + response_dict['prepay_id']}\n",
settings.LOGIN_WX_KEY_PATH
),
'signType': 'MD5'
}
logger.info(f'签名有效: {res}')
return HttpResponse(json.dumps(res), content_type='application/json')
else:
logger.error(f"支付请求失败:{response_dict}")
return HttpResponse(json.dumps({'msg': "支付失败"}), content_type='application/json', status=400)
@csrf_exempt
def wx_pay_notify(request):
try:
# 确保请求体被正确解码
request_body = request.body.decode('utf-8')
webData = json.loads(request_body)
logger.info(f'回调返回信息:{webData}')
# 提取加密数据
resource = webData.get('resource', {})
ciphertext = resource.get('ciphertext', '')
nonce = resource.get('nonce', '')
associated_data = resource.get('associated_data', '')
if not ciphertext or not nonce or not associated_data:
logger.error('回调数据不完整')
return HttpResponse(json.dumps({"code": "FAIL", "message": "回调数据不完整"}), content_type='application/json')
# 解密回调数据
callback_data = decrypt(nonce, ciphertext, associated_data, settings.LOGIN_V3_KEY)
callback_data_str = callback_data.decode('utf-8') # 将字节对象解码为字符串
callback_data = json.loads(callback_data_str) # 将字符串解析为字典对象
logger.info(f'解密后的回调数据:{callback_data}')
# 提取必要信息
mchid = callback_data.get('mchid', '')
appid = callback_data.get('appid', '')
out_trade_no = callback_data.get('out_trade_no', '')
transaction_id = callback_data.get('transaction_id', '')
trade_state = callback_data.get('trade_state', '')
payer = callback_data.get('payer', {})
openid = payer.get('openid', '')
attach = callback_data.get('attach', '').replace("'", "\"")
attach = json.loads(attach) if attach else {}
type = attach.get('type', '')
transaction_type = attach.get('transaction_type', '')
uuid = attach.get('uuid', '')
success_time_str = callback_data.get('success_time', '')
amount = callback_data.get('amount', {})
amount_total = amount.get('total', 0)
success_time = datetime.strptime(success_time_str, "%Y-%m-%dT%H:%M:%S%z") if success_time_str else None
logger.info("交易结果:")
logger.info(f"商户号:{mchid}")
logger.info(f"AppID{appid}")
logger.info(f"商户订单号:{out_trade_no}")
logger.info(f"微信订单号:{transaction_id}")
logger.info(f"交易状态:{trade_state}")
logger.info(f"用户OpenID{openid}")
logger.info(f"type{type}")
logger.info(f"transaction_type{transaction_type}")
logger.info(f"成功时间:{success_time}")
logger.info(f"金额(分):{amount_total}")
# 获取交易记录、会员类型和用户
try:
transaction_log = TransactionLog.objects.get(transaction_no=out_trade_no)
except TransactionLog.DoesNotExist:
logger.error('交易记录不存在')
return HttpResponse(json.dumps({"code": "FAIL", "message": "交易记录不存在"}), content_type='application/json')
try:
membership_type = MembershipType.objects.get(type=type)
except MembershipType.DoesNotExist:
logger.error('会员类型不存在')
return HttpResponse(json.dumps({"code": "FAIL", "message": "会员类型不存在"}), content_type='application/json')
try:
user = User.objects.get(nickname=uuid)
except User.DoesNotExist:
logger.error('用户不存在')
return HttpResponse(json.dumps({"code": "FAIL", "message": "用户不存在"}), content_type='application/json')
# 验证交易信息
if (transaction_log.user_openid == openid) and (transaction_log.transaction_amount * 100 == amount_total) and (
membership_type.price * 100 == amount_total):
transaction_log.transaction_status = 'completed'
transaction_log.save()
logger.info(f'交易记录更新成功:{transaction_log}')
# 更新用户会员或配额
success = update_user_membership_or_quota(user.openid, membership_type)
# 如果用户有邀请人,则处理返利
if user.inviter_nickname:
inviter = User.objects.filter(nickname=user.inviter_nickname).first()
if inviter:
rebate_amount = round(Decimal(amount_total) * Decimal(0.35) / Decimal(100), 2)
inviter.balance += rebate_amount
inviter.save()
logger.info(f'邀请人{inviter.nickname}返利{rebate_amount}元成功')
return HttpResponse(json.dumps({"code": "SUCCESS", "message": "成功"}))
else:
logger.warning('回调数据与订单记录不一致')
return HttpResponse(json.dumps({"code": "FAIL", "message": "回调数据与订单记录不一致"}))
except Exception as e:
logger.error(f'处理回调时出错:{str(e)}')
return HttpResponse(json.dumps({"code": "FAIL", "message": "处理回调时出错"}))
def wx_resource(nonce, ciphertext, associated_data):
key_bytes = str.encode(settings.LOGIN_V3_KEY)
nonce_bytes = str.encode(nonce)
ad_bytes = str.encode(associated_data)
data = base64.b64decode(ciphertext)
aesgcm = AESGCM(key_bytes)
plaintext = aesgcm.decrypt(nonce_bytes, data, ad_bytes)
plaintext_str = bytes.decode(plaintext)
return eval(plaintext_str)
def wechat_login(request):
redirect_uri = settings.LOGIN_REDIRECT_URI
appid = settings.LOGIN_APP_ID
state = 'random_string' # 可以随机生成字符串,保持安全性
wechat_auth_url = (
f"https://open.weixin.qq.com/connect/oauth2/authorize?"
f"appid={appid}&redirect_uri={redirect_uri}&response_type=code&scope=snsapi_base&state={state}#wechat_redirect"
)
return HttpResponseRedirect(wechat_auth_url)
def wechat_callback(request):
code = request.GET.get('code')
if not code:
return JsonResponse({'error': '缺少code参数'}, status=400)
appid = settings.LOGIN_APP_ID
secret = settings.LOGIN_APP_SECRET
token_url = (
f"https://api.weixin.qq.com/sns/oauth2/access_token?"
f"appid={appid}&secret={secret}&code={code}&grant_type=authorization_code"
)
response = requests.get(token_url)
token_info = response.json()
if 'errcode' in token_info:
logger.error(f"获取access_token失败: {token_info}")
return JsonResponse({'error': '获取access_token失败'}, status=400)
access_token = token_info['access_token']
openid = token_info['openid']
frontend_url = settings.LOGIN_WEB_URI # 替换为您的前端地址
redirect_url = f"{frontend_url}?openid={openid}"
return HttpResponseRedirect(redirect_url)

View File

@@ -28,7 +28,7 @@ class MembershipType(models.Model):
type = models.CharField(max_length=50, unique=True, verbose_name="卡类型") # 卡类型,如天卡、周卡等 coins 额度卡
title = models.CharField(max_length=100, verbose_name="标题") # 卡的标题
description = models.TextField(verbose_name="描述") # 卡的描述
price = models.DecimalField(max_digits=10, decimal_places=2, verbose_name="价格") # 卡的价格
price = models.DecimalField(max_digits=5, decimal_places=2, verbose_name="价格") # 卡的价格
duration_days = models.IntegerField(verbose_name="有效天数") # 卡的有效期,以天为单位
coins = models.IntegerField(default=0, verbose_name="赠送金币数量") # 赠送金币的数量
is_quota = models.BooleanField(default=False, verbose_name="是否为额度充值") # 是否为额度充值
@@ -59,7 +59,7 @@ class User(models.Model):
member_end_time = models.BigIntegerField(blank=True, null=True) # 存储会员到期时间的时间戳
is_active = models.BooleanField(default=True) # 状态,启用/禁用,默认启用
usage_count = models.IntegerField(default=0, blank=True, null=True) # 用户使用次数
coins = models.IntegerField(default=30, verbose_name='金币数量') # 用户金币数量
coins = models.IntegerField(default=10, verbose_name='金币数量') # 用户金币数量
balance = models.DecimalField(max_digits=10, decimal_places=2, default=0.00, verbose_name='用户余额') # 用户余额
inviter_nickname = models.CharField(max_length=150, blank=True, null=True, verbose_name='邀请人昵称') # 用户邀请人昵称
invitees_count = models.IntegerField(default=0, verbose_name='邀请人数量') # 邀请人数量

View File

@@ -4,6 +4,7 @@ from . import views
from . import video_text
from . import wxpay
from . import AiMssage
from . import app_login_pay
urlpatterns = [
path('login/', views.miniapp_login, name='miniapp_login'),
path('video/', views.video_extraction, name='video_extraction'),
@@ -26,8 +27,8 @@ urlpatterns = [
path('task_status/<str:task_id>/', views.TaskStatusView.as_view(), name='task_status'),
path('extend_video/', views.ExtendVideoView.as_view(), name='extend_video'),
path('generate_image_video/', views.GenerateImageVideoView.as_view(), name='generate_image_video'),
path('user/<int:user_id>/video_tasks/', views.UserVideoTaskListView.as_view(), name='user_video_tasks'),
path('user/<int:user_id>/delete_task/<str:task_id>/', views.DeleteVideoTaskView.as_view(), name='delete_task'),
path('user/<user_id>/video_tasks/', views.UserVideoTaskListView.as_view(), name='user_video_tasks'),
path('user/<user_id>/delete_task/<str:task_id>/', views.DeleteVideoTaskView.as_view(), name='delete_task'),
path('call_bailian_app/', AiMssage.call_bailian_app, name='call_bailian_app'),
path('get_recent_chat_records/', AiMssage.get_recent_chat_records, name='get_recent_chat_records'),
path('asset_library/', views.AssetLibraryView.as_view(), name='asset_library'),
@@ -35,6 +36,9 @@ urlpatterns = [
path('increment-download-count/', views.increment_download_count, name='increment_download_count'),
path('reset-daily-quota/', views.DailyCoinsBonusView.as_view(), name='reset_daily_quota'),
path('video-generation-callback/', views.VideoGenerationCallbackView.as_view(), name='VideoGenerationCallbackView'),
path('app_login/', app_login_pay.wechat_login, name='wechat_login'),
path('app_callback/', app_login_pay.wechat_callback, name='wechat_callback'),
path('app_wx_pay/', app_login_pay.wx_pay, name='wx_pay'),
path('wpp_pay_notify/', app_login_pay.wx_pay_notify, name='wx_pay_notify'),
]

View File

@@ -97,7 +97,7 @@ def transcribe_audio(request):
else:
return JsonResponse({'task_id': existing_task.task_id})
else:
increment = -1 # 假设每次生成视频需要消耗一次使用次数
increment = -2 # 假设每次生成视频需要消耗一次使用次数
function_type = 'transcribe_audio'
result = update_usage_count(openid, increment, function_type)
if not result['success']:

View File

@@ -189,16 +189,16 @@ def log_api_call(source, openid, nickname, wxid, wechat_alias, api_name, is_succ
remarks=remarks
)
# log_api_call(
# source='weixin',
# openid='用户的openid',
# nickname='用户昵称',
# wxid='用户微信ID',
# wechat_alias='用户微信号',
# api_name='调用的API名称',
# is_successful=True,
# remarks='备注信息'
# )
# log_api_call(
# source='weixin',
# openid='用户的openid',
# nickname='用户昵称',
# wxid='用户微信ID',
# wechat_alias='用户微信号',
# api_name='调用的API名称',
# is_successful=True,
# remarks='备注信息'
# )
def generate_short_id():
# 使用IDCounter模型获取下一个ID
@@ -265,31 +265,34 @@ def userinfo(request):
if contains_sql_or_xss(openid):
logger.error(f'{openid} 用户触发威胁字符检测: {data}')
return JsonResponse({'status': 'error', 'message': '你的国际行为已被记录,我们将保留追责权利'})
return JsonResponse({'status': 'error', 'message': '你的行为已被记录,我们将保留追责权利'})
if not openid:
return JsonResponse({"status": "error", 'body': '缺少openid参数'})
membership_types = MembershipType.objects.all().values('type', 'title', 'description', 'price', 'coins', 'is_quota')
membership_type_list = list(membership_types)
return JsonResponse({"status": "success",'membershipTypeList': membership_type_list})
else:
try:
user = User.objects.get(openid=openid)
except User.DoesNotExist:
return JsonResponse({"status": "error", 'userInfo': None})
try:
user = User.objects.get(openid=openid)
except User.DoesNotExist:
return JsonResponse({"status": "error", 'userInfo': None})
increment = -0
function_type = 'luserinfo'
result = update_usage_count(openid, increment, function_type)
membership_types = MembershipType.objects.all().values('type', 'title', 'description', 'price', 'coins', 'is_quota')
increment = -0
function_type = 'luserinfo'
result = update_usage_count(openid, increment, function_type)
membership_types = MembershipType.objects.all().values('type', 'title', 'description', 'price', 'coins', 'is_quota')
user_info = model_to_dict(user)
try:
user_info['member_start_time'] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(user.member_start_time))
user_info['member_end_time'] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(user.member_end_time))
except:
user_info['member_start_time'] = user.member_start_time
user_info['member_end_time'] = user.member_end_time
user_info = model_to_dict(user)
try:
user_info['member_start_time'] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(user.member_start_time))
user_info['member_end_time'] = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(user.member_end_time))
except:
user_info['member_start_time'] = user.member_start_time
user_info['member_end_time'] = user.member_end_time
membership_type_list = list(membership_types)
return JsonResponse({"status": "success", 'userInfo': user_info, 'membershipTypeList': membership_type_list})
membership_type_list = list(membership_types)
return JsonResponse({"status": "success", 'userInfo': user_info, 'membershipTypeList': membership_type_list})
def generate_token_for_user(openid):
# 定义密钥,你应该将其保存在配置文件或环境变量中
@@ -316,46 +319,46 @@ SECRET_KEY = "7801ffd6cceaff579812214a93b948b4"
#提取视频
def video_extraction(request):
# 解析POST请求体
data = json.loads(request.body)
x = request.headers.get('X', '')
t = request.headers.get('T', '')
if decrypt_param(x, t):
data = json.loads(request.body)
x = request.headers.get('X', '')
t = request.headers.get('T', '')
if decrypt_param(x, t):
try:
logger.info(f'视频提取data: {data} ')
video_url = data.get('url')
uuid = data.get('uuid')
openid = data.get('openid')
increment = - 1
function_type = 'video_extraction'
result = update_usage_count(openid, increment, function_type)
if result['success']:
encoded_video_url = quote(video_url, safe='')
# 这里简化了token验证逻辑实际应用中应根据项目需求进行相应的安全校验
if not uuid or not video_url:
logger.error(f'{encoded_video_url}视频提取失败--未登录-uuid{uuid}--openid{openid}')
return JsonResponse({'error': '未登录'})
# 调用视频提取API
response = requests.post(API_URL, data={
'url': video_url,
'userId': USER_ID,
'secretKey': SECRET_KEY
})
try:
logger.info(f'视频提取data: {data} ')
video_url = data.get('url')
uuid = data.get('uuid')
openid = data.get('openid')
increment = -1
function_type = 'video_extraction'
result = update_usage_count(openid, increment, function_type)
if result['success']:
encoded_video_url = quote(video_url, safe='')
# 这里简化了token验证逻辑实际应用中应根据项目需求进行相应的安全校验
if not uuid or not video_url:
logger.error(f'{encoded_video_url}视频提取失败--未登录-uuid{uuid}--openid{openid}')
return JsonResponse({'error': '未登录'})
# 调用视频提取API
response = requests.post(API_URL, data={
'url': video_url,
'userId': USER_ID,
'secretKey': SECRET_KEY
})
if response.status_code == 200:
logger.info(f'{encoded_video_url}视频提取成功--uuid{uuid}--openid{openid}')
return JsonResponse(response.json())
else:
logger.error(f'提取链接无效{response.text}')
return JsonResponse({'error': '视频提取失败'}, status=response.status_code)
if response.status_code == 200:
logger.info(f'{encoded_video_url}视频提取成功--uuid{uuid}--openid{openid}')
return JsonResponse(response.json())
else:
print(f'使用次数更新失败: {result}')
return JsonResponse(result)
except json.JSONDecodeError:
logger.error(f'视频提取出错')
return JsonResponse({'error': '无效的请求'})
else:
return JsonResponse({'error': '非法参数'}, status=400)
logger.error(f'提取链接无效{response.text}')
return JsonResponse({'error': '视频提取失败'}, status=response.status_code)
else:
print(f'使用次数更新失败: {result}')
return JsonResponse(result)
except json.JSONDecodeError:
logger.error(f'视频提取出错')
return JsonResponse({'error': '无效的请求'})
else:
return JsonResponse({'error': '非法参数'}, status=400)
@@ -365,19 +368,19 @@ def video_extraction(request):
#储存好友请求数据
def add_friend_request(request):
if request.method == 'POST':
data = json.loads(request.body)
# 解析申请时间字符串为datetime对象
fromusername = data.get('fromusername')
friend_request = FriendRequest.objects.filter(fromusername=fromusername).first()
if friend_request:
print('已存在')
return JsonResponse({"status": "success", "message": "已存在数据"}, status=200)
else:
data['time'] = datetime.strptime(data['time'], '%Y-%m-%d %H:%M:%S')
friend_request = FriendRequest.objects.create(**data)
friend_request.save()
print('入库成功')
return JsonResponse({"status": "success", "message": "添加好友请求已保存"}, status=200)
data = json.loads(request.body)
# 解析申请时间字符串为datetime对象
fromusername = data.get('fromusername')
friend_request = FriendRequest.objects.filter(fromusername=fromusername).first()
if friend_request:
print('已存在')
return JsonResponse({"status": "success", "message": "已存在数据"}, status=200)
else:
data['time'] = datetime.strptime(data['time'], '%Y-%m-%d %H:%M:%S')
friend_request = FriendRequest.objects.create(**data)
friend_request.save()
print('入库成功')
return JsonResponse({"status": "success", "message": "添加好友请求已保存"}, status=200)
else:
return JsonResponse({"status": "error", "message": "只支持POST请求"}, status=405)
@@ -556,7 +559,7 @@ def redeem_card(request):
return JsonResponse({'error': '卡密激活失败,请联系管理员'})
elif card.card_type == 'quota':
# 如果是额度卡,调用更新使用次数函数
success = update_usage_count(openid, increment=+card.validity_period,function_type='redeem_card')
if success.get('success'):
card.used_by_openid = openid
@@ -595,39 +598,28 @@ def reward_invitation(request):
uuid = data.get('uuid', '')
if openid and uuid:
# 查找uuid对应的用户确保是新用户
try:
invited_user = User.objects.get(nickname=uuid)
logger.info(f'用户 {uuid} 已经存在,不能重复邀请')
return JsonResponse({'success': False, 'message': '用户已存在,不能重复邀请'})
except User.DoesNotExist:
# 被邀请用户不存在,说明是新用户,可以发放奖励
try:
inviter_user = User.objects.get(openid=openid)
except User.DoesNotExist:
logger.error(f'邀请人用户 {openid} 不存在')
return JsonResponse({'success': False, 'error': '邀请人用户不存在'})
invited_user = User.objects.get(nickname=uuid)
# 更新邀请人信息
inviter_user.invitees_count += 1
inviter_user.coins += 10
inviter_user.save()
# 创建被邀请用户并设置邀请人信息
new_user = User(nickname=uuid, inviter_nickname=inviter_user.nickname)
new_user.save()
inviter_user = User.objects.get(openid=openid)
if inviter_user.inviter_nickname:
logger.info(f'用户 {openid} 邀请新用户 {uuid} 成功,奖励已发放')
return JsonResponse({'success': True, 'message': '奖励发放成功'})
else:
logger.error(f'用户邀请奖励接口 缺少必要参数')
logger.error(f'已经被邀请过')
return JsonResponse({'success': False, 'error': '缺少必要参数'})
else:
invited_user.invitees_count += 1
invited_user.coins += 1
invited_user.save()
# 创建被邀请用户并设置邀请人信息
inviter_user.inviter_nickname = uuid
inviter_user.save()
logger.info(f'用户 {uuid} 邀请新用户 {inviter_user.nickname} 成功,奖励已发放')
return JsonResponse({'success': True, 'message': '奖励发放成功'})
else:
return JsonResponse({'success': False, 'error': '非法参数'})
except User.DoesNotExist:
logger.error(f'用户不存在')
return JsonResponse({'success': False, 'error': '用户不存在'})
except Exception as e:
logger.error(f'发放奖励时出错: {str(e)}')
return JsonResponse({'success': False, 'error': '服务器内部错误'})
@@ -1085,50 +1077,20 @@ class GenerateImageVideoView(View):
class TaskStatusView(View):
def get(self, request, task_id):
if not task_id:
return JsonResponse({"message": "缺少任务ID"}, status=400)
try:
# 从数据库中获取任务
task = VideoTask.objects.get(task_id=task_id)
except VideoTask.DoesNotExist:
task = self.get_task(task_id)
if not task:
return JsonResponse({"message": "任务不存在"}, status=404)
url = f"https://api.aivideoapi.com/status?uuid={task_id}"
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
response_data = response.json()
print(response_data)
except requests.exceptions.RequestException as e:
logger.error(f"查询任务状态时出错: {e}")
return JsonResponse({"message": "查询任务状态失败", "error": str(e)}, status=500)
progress = float(response_data.get('progress', 0)) if response_data.get('progress') is not None else 0.0
task.progress = progress
if task.progress >= 1.0:
if response_data.get('status', task.status) == 'success':
task.status = 'success'
task.result_url = response_data.get('url', task.result_url)
task.gif_url = response_data.get('gif_url', task.gif_url)
AssetLibrary.objects.create(
original_url=task.result_url,
duration=task.seconds,
category=task.style,
description=task.text_prompt,
description_zh=task.description_zh,
generated_by=task.nickname,
gif_url=task.gif_url,
is_approved=True # 假设任务成功的素材自动审核通过
)
elif response_data.get('status', task.status) == 'failed':
task.status = 'failed'
elif progress==0.0:
task.status = 'pending'
else:
task.status = 'running'
# 保存更新后的任务
task.save()
response_data = self.query_task_status(task_id)
if not response_data:
return JsonResponse({"message": "查询任务状态失败"}, status=500)
self.update_task_status(task, response_data)
return JsonResponse({
"task_id": task.task_id,
@@ -1138,6 +1100,79 @@ class TaskStatusView(View):
"gif_url": task.gif_url
}, status=200)
def get_task(self, task_id):
try:
return VideoTask.objects.get(task_id=task_id)
except VideoTask.DoesNotExist:
return None
def query_task_status(self, task_id):
url = f"https://api.aivideoapi.com/status?uuid={task_id}"
try:
response = requests.get(url, headers=headers)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
logger.error(f"查询任务状态时出错: {e}")
return None
def update_task_status(self, task, response_data):
progress = float(response_data.get('progress', 0)) if response_data.get('progress') is not None else 0.0
task.progress = progress
if task.progress >= 1.0:
if response_data.get('status', task.status) == 'success':
print(response_data)
logger.info(response_data)
result_url = self.handle_file_upload(response_data.get('result_url') or response_data.get('url', ''))
gif_url = self.handle_file_upload(response_data.get('gif_url', ''))
task.status = 'success'
task.result_url = result_url
task.gif_url = gif_url
task.save()
self.create_asset_library_entry(task)
elif response_data.get('status', task.status) == 'failed':
task.status = 'failed'
elif progress == 0.0:
task.status = 'pending'
task.save()
else:
task.status = 'running'
task.save()
def handle_file_upload(self, file_url):
if not file_url:
logger.error("文件URL为空无法下载")
return ""
local_file_path = f"/tmp/{os.path.basename(file_url)}"
try:
r = requests.get(file_url, stream=True)
r.raise_for_status()
with open(local_file_path, 'wb') as f:
for chunk in r.iter_content(chunk_size=8192):
f.write(chunk)
qiniu_url = upload_to_qiniu(local_file_path, os.path.basename(local_file_path))
except requests.exceptions.RequestException as e:
logger.error(f"下载文件时出错: {e}")
return ""
finally:
if os.path.exists(local_file_path) and os.path.isfile(local_file_path):
os.remove(local_file_path)
return qiniu_url
def create_asset_library_entry(self, task):
AssetLibrary.objects.create(
original_url=task.result_url,
duration=task.seconds,
category=task.style,
description=task.description_zh,
description_zh=task.description_zh,
generated_by=task.nickname,
gif_url=task.gif_url,
is_approved=False # 假设任务成功的素材自动审核通过
)
class UpdatePendingTasksView(View):
def get(self, request):
@@ -1250,4 +1285,29 @@ class VideoGenerationCallbackView(View):
return JsonResponse({'success': False, 'message': '服务器内部错误'}, status=500)
def post(self, request):
return JsonResponse({'success': False, 'message': '请求方法不支持'}, status=405)
return JsonResponse({'success': False, 'message': '请求方法不支持'}, status=405)
def wechat_config(request):
if request.method == 'GET':
url = request.GET.get('url')
if not url:
return JsonResponse({'error': 'URL is required'}, status=400)
# 生成签名的逻辑
timestamp = int(time.time())
nonceStr = ''.join(random.choices('abcdefghijklmnopqrstuvwxyz0123456789', k=16))
jsapi_ticket = 'your_jsapi_ticket' # 需要从微信服务器获取
string1 = f'jsapi_ticket={jsapi_ticket}&noncestr={nonceStr}&timestamp={timestamp}&url={url}'
signature = hashlib.sha1(string1.encode('utf-8')).hexdigest()
config = {
'appId': 'your_app_id',
'timestamp': timestamp,
'nonceStr': nonceStr,
'signature': signature,
}
return JsonResponse(config)
else:
return JsonResponse({'error': 'Invalid request method'}, status=405)