walk_dogs.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472
  1. from math import floor
  2. from django.db import models
  3. from django.db.models import Sum
  4. from django.http import HttpResponse,JsonResponse
  5. from django.views.decorators.csrf import csrf_exempt
  6. from datetime import datetime, timedelta
  7. from django.core import serializers
  8. import time
  9. import json
  10. import os
  11. import jwt
  12. from .models import DogTrainingNew, WalkDogsScore
  13. os.environ.setdefault("DJANGO_SETTINGS_MODULE", "aiDogProject.settings")
  14. import django
  15. django.setup()
  16. from aiDogApp.models import *
  17. from . import aidog_tools,aidog_request_tools
  18. #遛狗结果提交接口:客户端上传user_id、access_token,score,maxCombo,perfect,good,poor,miss,coin,date_time
  19. # POST /api/walkdogs/score/
  20. # 2025/6/6
  21. # 这个接口返回的是重置结果。{
  22. # "status": "string",
  23. # "message": "string",
  24. # "user_info": {},
  25. # "dogs": {}
  26. # }
  27. @csrf_exempt
  28. def walk_dogs_score(request):
  29. # 记录请求时间
  30. current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  31. # 清理30天前的WalkDogsScore记录
  32. thirty_days_ago = datetime.now().date() - timedelta(days=30)
  33. try:
  34. deleted_count, _ = WalkDogsScore.objects.filter(walk_time__lt=thirty_days_ago).delete()
  35. if deleted_count > 0:
  36. print(f"Cleaned up {deleted_count} WalkDogsScore records older than 30 days")
  37. except Exception as cleanup_error:
  38. print(f"Error during WalkDogsScore cleanup: {str(cleanup_error)}")
  39. # 清理失败不影响主要功能,继续执行
  40. try:
  41. # 获取请求参数
  42. params = aidog_request_tools.handle_post_request_parameters(
  43. request,
  44. ["access_token", "user_id", "score", "maxCombo",
  45. "perfect", "good", "poor", "miss","coin"]
  46. )
  47. date_time = request.POST.get("date_time", '')
  48. access_token = params["access_token"]
  49. user_id = params["user_id"]
  50. score = int(params["score"])
  51. maxCombo = int(params["maxCombo"])
  52. perfect = int(params["perfect"])
  53. good = int(params["good"])
  54. poor = int(params["poor"])
  55. miss = int(params["miss"])
  56. coin = int(params["coin"])
  57. print(f"Error during WalkDogsScore access_token: {access_token}")
  58. # 验证访问令牌
  59. token_validation = aidog_tools.validate_access_token(access_token)
  60. if isinstance(token_validation, JsonResponse):
  61. return token_validation
  62. user_id = token_validation['user_id']
  63. try:
  64. #计算总分=perfect次数*100+good次数*30+poor次数*10是否与score一致,不一致报错,
  65. # 奖励计算方式:用户金币+=floor(总分/1000)
  66. # 每次请求接口,所有的狗:快乐 + 20,体力 - 10,口渴 - 15,健康 + 10,好奇心 + 10,活泼度 + 5,敏捷度 + 5,如果maxCombo >= 15,跑步速度 + 5,如果maxCombo >= 30,跑步速度 + 15,肥胖程度 - 10
  67. #一天最多奖励2次
  68. # 计算总分验证
  69. calculated_score = int(perfect) * 100 + int(good) * 30 + int(poor) * 10
  70. if score != calculated_score:
  71. return JsonResponse({
  72. "status": "error",
  73. "date": current_time,
  74. "message": f"Score calculation mismatch! Expected: {calculated_score}, Got: {score}",
  75. "end_time": current_time
  76. })
  77. # 计算奖励金币
  78. reward_coins = floor(calculated_score / 1000)
  79. if reward_coins != coin:
  80. return JsonResponse({
  81. "status": "error",
  82. "date": current_time,
  83. "message": f"Coin calculation mismatch! Expected: {reward_coins}, Got: {coin}",
  84. "end_time": current_time
  85. })
  86. # 获取今天的日期(年-月-日)
  87. today = datetime.now().date()
  88. # 检查今天已经获得奖励的次数
  89. today_rewards = WalkDogsScore.objects.filter(
  90. uid=user_id,
  91. walk_time=today
  92. ).aggregate(total_count=Sum('walk_count'))['total_count'] or 0
  93. # 检查是否达到每日上限
  94. if today_rewards< 2:
  95. # 创建新的遛狗记录
  96. walk_dog_record = WalkDogsScore.objects.create(
  97. uid=user_id,
  98. score=score,
  99. maxcombo=maxCombo,
  100. perfect=perfect,
  101. good=good,
  102. poor=poor,
  103. miss=miss,
  104. walk_time=today,
  105. walk_count=1 # 每次记录计数为1
  106. )
  107. # 更新用户金币
  108. try:
  109. user = User.objects.get(uid=user_id)
  110. user.coin = (user.coin or 0) + reward_coins
  111. user.save()
  112. except User.DoesNotExist:
  113. return JsonResponse({
  114. "status": "error",
  115. "date": current_time,
  116. "message": "User not found"
  117. })
  118. # 获取用户的所有狗列表
  119. dog_info = Doginfo.objects.filter(owner_id=user_id)
  120. for dog in dog_info:
  121. # dog_id=dog.dog_id
  122. dog_serialized = serializers.serialize('json', [dog])
  123. dog_data = json.loads(dog_serialized)[0]['fields']
  124. dog_id = dog_data['d_id']
  125. print(f"dog_id for ------------- {dog_id}")
  126. # 更新狗的状态
  127. try:
  128. dog_status = DogStatus.objects.get(d_id=dog_id)
  129. dog_status.happiness = min((dog_status.happiness or 0) + 20, 100) # 最大值100
  130. dog_status.stamina = max((dog_status.stamina or 0) - 10, 0) # 最小值0
  131. dog_status.thirsty = max((dog_status.thirsty or 0) - 15, 0) # 最小值0
  132. dog_status.healthy = min((dog_status.healthy or 0) + 10, 100) # 最大值100
  133. dog_status.clean = max((dog_status.clean or 0) - 10, 0) # 最小值0
  134. dog_status.satiety = max((dog_status.satiety or 0) - 10, 0) # 最小值0
  135. print(f"happiness for ------------- {dog_status.happiness}")
  136. dog_status.save()
  137. except DogStatus.DoesNotExist:
  138. continue # 如果状态不存在,跳过这只狗
  139. # 更新狗的身体属性
  140. try:
  141. dog_body_attr = DogBodyAttributes.objects.get(d_id=dog_id)
  142. dog_body_attr.curiosity = min((dog_body_attr.curiosity or 0) + 10, 100)
  143. dog_body_attr.liveliness = min((dog_body_attr.liveliness or 0) + 5, 100)
  144. dog_body_attr.agility = min((dog_body_attr.agility or 0) + 5, 100)
  145. dog_body_attr.obesity = max((dog_body_attr.obesity or 0) - 10, 0)
  146. # 根据maxCombo调整跑步速度
  147. speed_bonus = 0
  148. if maxCombo >= 30:
  149. speed_bonus = 20 # 15 + 5
  150. elif maxCombo >= 15:
  151. speed_bonus = 5
  152. if speed_bonus > 0:
  153. dog_body_attr.runSpeed = min((dog_body_attr.runSpeed or 0) + speed_bonus, 100)
  154. print(f"dog_body_attr.curiosity for ------------- {dog_body_attr.curiosity }")
  155. dog_body_attr.save()
  156. except DogBodyAttributes.DoesNotExist:
  157. continue # 如果属性不存在,跳过这只狗
  158. except Exception as e:
  159. # 全局异常处理
  160. import traceback
  161. traceback.print_exc()
  162. return JsonResponse({
  163. "status": "error",
  164. "message": f"Server processing exception: {str(e)}",
  165. "date": current_time
  166. })
  167. # 获取用户信息
  168. try:
  169. user = User.objects.get(uid=user_id)
  170. user_info = aidog_tools._build_user_info(user)
  171. except User.DoesNotExist:
  172. user_info = {}
  173. # 获取用户的所有狗列表
  174. try:
  175. dog_info = Doginfo.objects.filter(owner_id=user_id)
  176. dog_list = []
  177. for dog in dog_info:
  178. dog_serialized = serializers.serialize('json', [dog])
  179. dog_data = json.loads(dog_serialized)[0]['fields']
  180. dog_id = dog_data['d_id']
  181. # 获取狗的信息并转换为字典
  182. new_dog_status = aidog_tools.model_to_dict_without_id(DogStatus.objects.filter(d_id=dog_id).first())
  183. new_dog_training = aidog_tools.model_to_dict_without_id(
  184. DogTrainingNew.objects.filter(d_id=dog_id).first())
  185. new_dog_body_attributes = aidog_tools.model_to_dict_without_id(
  186. DogBodyAttributes.objects.filter(d_id=dog_id).first())
  187. new_dog_personality_relationship = aidog_tools.model_to_dict_without_id(
  188. DogPersonalityRelationship.objects.filter(d_id=dog_id).first())
  189. # 合并所有相关信息
  190. dog_info_combined = {
  191. **dog_data,
  192. **new_dog_status,
  193. **new_dog_training,
  194. **new_dog_body_attributes,
  195. **new_dog_personality_relationship,
  196. }
  197. # 只保留字段而不是数据库内部的元数据(如 '_state')
  198. dog_info_clean = {key: value for key, value in dog_info_combined.items() if not key.startswith('_')}
  199. dog_list.append(dog_info_clean)
  200. except Exception as e:
  201. dog_list = []
  202. # 返回包含所有voice得分的结果
  203. return JsonResponse({
  204. "status": "success",
  205. "code":200,
  206. "date": current_time,
  207. "message": 'Walk dog score uploaded successfully',
  208. "reward_coins": reward_coins,
  209. "today_rewards": today_rewards + 1,
  210. "user_info":user_info,
  211. "dogs": dog_list,
  212. })
  213. except Exception as e:
  214. # 全局异常处理
  215. import traceback
  216. traceback.print_exc()
  217. return JsonResponse({
  218. "status": "error",
  219. "message": f"Server processing exception: {str(e)}",
  220. "date": current_time
  221. })
  222. #遛狗结果提交接口:客户端上传user_id、access_token,item_id,dog_id,catch,distance,date_time
  223. # 考虑到未来有多个飞盘的设定 示例值:toy_00001
  224. # catch true接到飞盘,false没有接到
  225. # POST /api/frisbee/score/
  226. # 2025/6/13
  227. # 这个接口返回的是重置结果。{
  228. # "status": "string",
  229. # "message": "string",
  230. # "user_info": {},
  231. # "dogs": {}
  232. # }
  233. @csrf_exempt
  234. def frisbee_dogs_score(request):
  235. # 记录请求时间
  236. current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  237. # 清理30天前的WalkDogsScore记录
  238. thirty_days_ago = datetime.now().date() - timedelta(days=30)
  239. try:
  240. deleted_count, _ = FrisbeeDogsScore.objects.filter(frisbee_time__lt=thirty_days_ago).delete()
  241. if deleted_count > 0:
  242. print(f"Cleaned up {deleted_count} WalkDogsScore records older than 30 days")
  243. except Exception as cleanup_error:
  244. print(f"Error during WalkDogsScore cleanup: {str(cleanup_error)}")
  245. # 清理失败不影响主要功能,继续执行
  246. try:
  247. # 获取请求参数
  248. params = aidog_request_tools.handle_post_request_parameters(
  249. request,
  250. ["access_token", "user_id", "item_id", "dog_id",
  251. "catch", "distance"]
  252. )
  253. date_time = request.POST.get("date_time", '')
  254. access_token = params["access_token"]
  255. user_id = params["user_id"]
  256. item_id = params["item_id"]
  257. dog_id = params["dog_id"]
  258. distance = float(params["distance"])
  259. # 转换 catch 参数
  260. catch_str = params["catch"]
  261. if isinstance(catch_str, str):
  262. catch = 1 if catch_str.lower() == 'true' else 0
  263. else:
  264. catch = int(bool(catch_str))
  265. # 验证访问令牌
  266. token_validation = aidog_tools.validate_access_token(access_token)
  267. if isinstance(token_validation, JsonResponse):
  268. return token_validation
  269. user_id = token_validation['user_id']
  270. try:
  271. #计算总分=飞行距离是否与score一致,不一致报错,
  272. # 奖励计算方式:用户金币+=floor(总分/1000)
  273. # 每次请求接口,单一狗:无论成功是否:快乐 + 2,体力 - 6,口渴 - 5,健康 + 3,活泼度 + 2,敏捷度 + 2,肥胖程度 - 2,干净 - 3,饱腹度 - 5
  274. # 如果成功跑步速度 + 2,跳跃高度 + 2,叼飞盘熟练度 + 2
  275. #一天最多奖励5次
  276. # 计算奖励金币
  277. reward_coins = floor(distance)
  278. # 获取今天的日期(年-月-日)
  279. today = datetime.now().date()
  280. # 检查今天已经获得奖励的次数
  281. today_rewards = FrisbeeDogsScore.objects.filter(
  282. uid=user_id,
  283. frisbee_time=today
  284. ).aggregate(total_count=Sum('frisbee_count'))['total_count'] or 0
  285. # 检查是否达到每日上限
  286. if today_rewards< 5:
  287. # 创建新的丢飞盘记录
  288. frisbee_dog_record = FrisbeeDogsScore.objects.create(
  289. uid=user_id,
  290. d_id=dog_id,
  291. item_id=item_id,
  292. catch=catch,
  293. distance=distance,
  294. frisbee_time=today,
  295. frisbee_count=1 # 每次记录计数为1
  296. )
  297. # 更新用户金币
  298. try:
  299. user = User.objects.get(uid=user_id)
  300. user.coin = (user.coin or 0) + reward_coins
  301. user.save()
  302. except User.DoesNotExist:
  303. return JsonResponse({
  304. "status": "error",
  305. "date": current_time,
  306. "message": "User not found"
  307. })
  308. # 更新该狗状态
  309. try:
  310. dog_status = DogStatus.objects.get(d_id=dog_id)
  311. dog_status.happiness = min((dog_status.happiness or 0) + 2, 100) # 最大值100
  312. dog_status.stamina = max((dog_status.stamina or 0) - 6, 0) # 最小值0
  313. dog_status.thirsty = max((dog_status.thirsty or 0) - 5, 0) # 最小值0
  314. dog_status.healthy = min((dog_status.healthy or 0) + 3, 100) # 最大值100
  315. dog_status.clean = max((dog_status.clean or 0) - 3, 0) # 最小值0
  316. dog_status.satiety = max((dog_status.satiety or 0) - 5, 0) # 最小值0
  317. print(f"happiness for ------------- {dog_status.happiness}")
  318. dog_status.save()
  319. except DogStatus.DoesNotExist:
  320. return JsonResponse({
  321. "status": "error",
  322. "message": f"Server processing exception: {str(e)}",
  323. "date": current_time
  324. })
  325. # 更新狗的身体属性
  326. try:
  327. dog_body_attr = DogBodyAttributes.objects.get(d_id=dog_id)
  328. dog_body_attr.liveliness = min((dog_body_attr.liveliness or 0) + 2, 100)
  329. dog_body_attr.agility = min((dog_body_attr.agility or 0) + 2, 100)
  330. dog_body_attr.obesity = max((dog_body_attr.obesity or 0) - 2, 0)
  331. if catch:
  332. dog_body_attr.runSpeed = min((dog_body_attr.runSpeed or 0) + 2, 100)
  333. dog_body_attr.jumpHeight = min((dog_body_attr.jumpHeight or 0) + 2, 100)
  334. dog_body_attr.frisbeeSkill = min((dog_body_attr.frisbeeSkill or 0) + 2, 100)
  335. dog_body_attr.save()
  336. except DogBodyAttributes.DoesNotExist:
  337. return JsonResponse({
  338. "status": "error",
  339. "message": f"Server processing exception: {str(e)}",
  340. "date": current_time
  341. })
  342. except Exception as e:
  343. # 全局异常处理
  344. import traceback
  345. traceback.print_exc()
  346. return JsonResponse({
  347. "status": "error",
  348. "message": f"Server processing exception: {str(e)}",
  349. "date": current_time
  350. })
  351. # 获取用户信息
  352. try:
  353. user = User.objects.get(uid=user_id)
  354. user_info = aidog_tools._build_user_info(user)
  355. except User.DoesNotExist:
  356. user_info = {}
  357. # 获取用户的所有狗列表
  358. try:
  359. dog_info = Doginfo.objects.filter(owner_id=user_id)
  360. dog_list = []
  361. for dog in dog_info:
  362. dog_serialized = serializers.serialize('json', [dog])
  363. dog_data = json.loads(dog_serialized)[0]['fields']
  364. dog_id = dog_data['d_id']
  365. # 获取狗的信息并转换为字典
  366. new_dog_status = aidog_tools.model_to_dict_without_id(DogStatus.objects.filter(d_id=dog_id).first())
  367. new_dog_training = aidog_tools.model_to_dict_without_id(
  368. DogTrainingNew.objects.filter(d_id=dog_id).first())
  369. new_dog_body_attributes = aidog_tools.model_to_dict_without_id(
  370. DogBodyAttributes.objects.filter(d_id=dog_id).first())
  371. new_dog_personality_relationship = aidog_tools.model_to_dict_without_id(
  372. DogPersonalityRelationship.objects.filter(d_id=dog_id).first())
  373. # 合并所有相关信息
  374. dog_info_combined = {
  375. **dog_data,
  376. **new_dog_status,
  377. **new_dog_training,
  378. **new_dog_body_attributes,
  379. **new_dog_personality_relationship,
  380. }
  381. # 只保留字段而不是数据库内部的元数据(如 '_state')
  382. dog_info_clean = {key: value for key, value in dog_info_combined.items() if not key.startswith('_')}
  383. dog_list.append(dog_info_clean)
  384. except Exception as e:
  385. dog_list = []
  386. # 返回包含所有voice得分的结果
  387. return JsonResponse({
  388. "status": "success",
  389. "code":200,
  390. "date": current_time,
  391. "message": 'Frisbee score uploaded successfully',
  392. "reward_coins": reward_coins,
  393. "today_total_count": today_rewards + 1,
  394. "user_info":user_info,
  395. "dogs": dog_list,
  396. })
  397. except Exception as e:
  398. # 全局异常处理
  399. import traceback
  400. traceback.print_exc()
  401. return JsonResponse({
  402. "status": "error",
  403. "message": f"Server processing exception: {str(e)}",
  404. "date": current_time
  405. })