Files
hack/tools/scripts/llm-key-hunter/results/_cache/content/axdyer_welllog.json
T
OpenCode 68a9071cf1 feat: reconcile local master with origin (exa/hot-platform hunters, leaks ledger, latest results)
Local branch had diverged from origin/master (sibling commits on the same base). Rewrote local history linearly on top of origin/master, folding in all local content: exa/hot-platform discovery hunters, leaks ledger, nightly sweep orchestrator, updated .gitignore and skill docs, plus the latest hunt output and vault state. Remote-only files (vault keys, channel scripts) were restored rather than dropped, so the resulting tree is a full union of both sides.
2026-08-07 12:53:47 +08:00

1 line
21 KiB
JSON

{"repo": "axdyer/welllog", "files": {"analysis/views.py": {"26014bd3015739b6334839dd9569892eccdf761b": {"t": 1786068483.9009764, "n": 20969, "h": "cad9210816cdf91b", "c": "import os\nfrom django.shortcuts import render\nfrom django.http import JsonResponse\nfrom django.contrib.auth.decorators import login_required\nfrom django.utils import timezone\nfrom datetime import timedelta\nimport json\nimport asyncio\nfrom openai import AsyncOpenAI\nfrom asgiref.sync import sync_to_async\nfrom .models import HealthAdvice\n\nfrom health.models import (\n RunningRecord, \n StepsRecord, \n SleepRecord, \n DietRecord, \n MoodRecord,\n TrainingRecord,\n HealthGoal,\n WeightRecord\n)\n\ndef get_running_data(user, start_date):\n \"\"\"Get running records data for a user since start_date\"\"\"\n return list(RunningRecord.objects.filter(\n user=user, \n date__gte=start_date\n ).order_by('-date').values('id', 'date', 'distance', 'duration_minutes', 'calories_burned'))\n\ndef get_sleep_data(user, start_date):\n \"\"\"Get sleep records data for a user since start_date\"\"\"\n return list(SleepRecord.objects.filter(\n user=user, \n date__gte=start_date\n ).order_by('-date').values('id', 'date', 'hours', 'minutes', 'quality'))\n\ndef get_steps_data(user, start_date):\n \"\"\"Get steps records data for a user since start_date\"\"\"\n return list(StepsRecord.objects.filter(\n user=user, \n date__gte=start_date\n ).order_by('-date').values('id', 'date', 'steps_count'))\n\ndef get_diet_data(user, start_date):\n \"\"\"Get diet records data for a user since start_date\"\"\"\n return list(DietRecord.objects.filter(\n user=user, \n date__gte=start_date\n ).order_by('-date').values('id', 'date', 'calories', 'protein', 'carbs', 'fat'))\n\ndef get_mood_data(user, start_date):\n \"\"\"Get mood records data for a user since start_date\"\"\"\n return list(MoodRecord.objects.filter(\n user=user, \n date__gte=start_date\n ).order_by('-date').values('id', 'date', 'mood', 'stress_level'))\n\ndef get_training_data(user, start_date):\n \"\"\"Get training records data for a user since start_date\"\"\"\n return list(TrainingRecord.objects.filter(\n user=user, \n date__gte=start_date\n ).order_by('-date').values('id', 'date', 'exercise_type', 'sets', 'reps', 'weight', 'duration_minutes'))\n\ndef get_weight_data(user, start_date):\n \"\"\"Get weight records data for a user since start_date\"\"\"\n weight_records = list(WeightRecord.objects.filter(\n user=user, \n date__gte=start_date\n ).order_by('-date').values('id', 'date', 'weight', 'height', 'notes'))\n \n # Calculate BMI\n for record in weight_records:\n if record['height'] and record['weight']:\n # BMI = weight(kg) / (height(m))^2\n height_in_meters = record['height'] / 100\n record['bmi'] = round(record['weight'] / (height_in_meters * height_in_meters), 1)\n \n return weight_records\n\n@login_required\ndef ai_advice(request):\n \"\"\"Main AI Advice page view\"\"\"\n # Ensure user has a profile\n try:\n profile = request.user.profile\n except Exception:\n # If user has no profile, create one\n from accounts.models import Profile\n Profile.objects.create(user=request.user)\n \n # Get the last 30 days of health records for data overview\n last_30_days = timezone.now().date() - timedelta(days=30)\n \n running_records = RunningRecord.objects.filter(user=request.user, date__gte=last_30_days).order_by('-date')\n steps_records = StepsRecord.objects.filter(user=request.user, date__gte=last_30_days).order_by('-date')\n sleep_records = SleepRecord.objects.filter(user=request.user, date__gte=last_30_days).order_by('-date')\n diet_records = DietRecord.objects.filter(user=request.user, date__gte=last_30_days).order_by('-date')\n mood_records = MoodRecord.objects.filter(user=request.user, date__gte=last_30_days).order_by('-date')\n training_records = TrainingRecord.objects.filter(user=request.user, date__gte=last_30_days).order_by('-date')\n \n # Get the latest saved health advice\n latest_advice = HealthAdvice.objects.filter(user=request.user).first()\n \n context = {\n 'running_records': running_records,\n 'steps_records': steps_records,\n 'sleep_records': sleep_records,\n 'diet_records': diet_records,\n 'mood_records': mood_records,\n 'training_records': training_records,\n 'latest_advice': latest_advice,\n 'active_section': 'ai_advice'\n }\n \n return render(request, 'analysis/ai_advice.html', context)\n\n@login_required\nasync def generate_advice_async(request):\n \"\"\"Asynchronously generate health advice\"\"\"\n if request.method != 'POST':\n return JsonResponse({'error': 'Only POST requests allowed'}, status=405)\n \n try:\n # Get the last 30 days of health records\n last_30_days = timezone.now().date() - timedelta(days=30)\n \n try:\n # Wrap synchronous database queries with sync_to_async\n running_data = await sync_to_async(get_running_data)(request.user, last_30_days)\n sleep_data = await sync_to_async(get_sleep_data)(request.user, last_30_days)\n steps_data = await sync_to_async(get_steps_data)(request.user, last_30_days)\n diet_data = await sync_to_async(get_diet_data)(request.user, last_30_days)\n mood_data = await sync_to_async(get_mood_data)(request.user, last_30_days)\n training_data = await sync_to_async(get_training_data)(request.user, last_30_days)\n weight_data = await sync_to_async(get_weight_data)(request.user, last_30_days)\n except Exception as db_error:\n print(f\"Database query error: {str(db_error)}\")\n return JsonResponse({\n 'error': 'Failed to retrieve your health data',\n 'advice': '<p>We encountered an error while retrieving your health data. Please try again later.</p>',\n 'generated_time': timezone.now().strftime('%Y-%m-%d %H:%M:%S')\n }, status=200)\n \n # Convert date objects to strings\n for data_list in [running_data, sleep_data, steps_data, diet_data, mood_data, training_data, weight_data]:\n for item in data_list:\n if 'date' in item:\n item['date'] = item['date'].strftime('%Y-%m-%d')\n \n # Prepare user data for the prompt\n user_data = {\n 'running': running_data,\n 'sleep': sleep_data,\n 'steps': steps_data,\n 'diet': diet_data,\n 'mood': mood_data,\n 'training': training_data,\n 'weight_records': weight_data\n }\n \n # Calculate user data statistics to fill in the prompt\n # Get user information\n try:\n user_profile = await sync_to_async(lambda: request.user.profile)()\n except Exception:\n # If user has no profile, create one\n from accounts.models import Profile\n await sync_to_async(Profile.objects.create)(user=request.user)\n user_profile = await sync_to_async(lambda: request.user.profile)()\n \n user_age = user_profile.age if hasattr(user_profile, 'age') else \"Unknown\"\n user_gender = user_profile.get_gender_display() if hasattr(user_profile, 'gender') else \"Unknown\"\n \n # Get the latest weight record\n latest_weight = None\n height = None\n bmi = None\n if len(user_data['weight_records']) > 0:\n latest_weight = user_data['weight_records'][0].get('weight', None)\n height = user_data['weight_records'][0].get('height', None)\n bmi = user_data['weight_records'][0].get('bmi', None)\n \n # Calculate average steps\n avg_steps = 0\n if len(steps_data) > 0:\n avg_steps = sum(item.get('steps_count', 0) for item in steps_data) // len(steps_data)\n \n # Calculate average sleep\n avg_sleep_hours = 0\n if len(sleep_data) > 0:\n avg_sleep_hours = sum(item.get('hours', 0) for item in sleep_data) / len(sleep_data)\n avg_sleep_minutes = sum(item.get('minutes', 0) for item in sleep_data) / len(sleep_data)\n avg_sleep_hours += avg_sleep_minutes / 60\n avg_sleep_hours = round(avg_sleep_hours, 1)\n \n # Calculate running data\n avg_running_distance = 0\n avg_running_pace = 0\n running_sessions = len(running_data)\n if running_sessions > 0:\n avg_running_distance = sum(item.get('distance', 0) for item in running_data) / running_sessions\n avg_running_distance = round(avg_running_distance, 1)\n # Calculate average pace (minutes/km)\n if sum(item.get('distance', 0) for item in running_data) > 0:\n total_minutes = sum(item.get('duration_minutes', 0) for item in running_data)\n total_distance = sum(item.get('distance', 0) for item in running_data)\n avg_running_pace = total_minutes / total_distance\n avg_running_pace = round(avg_running_pace, 1)\n \n # Calculate diet data\n avg_calories = 0\n avg_protein = 0\n if len(diet_data) > 0:\n avg_calories = sum(item.get('calories', 0) for item in diet_data) // len(diet_data)\n protein_values = [item.get('protein', 0) for item in diet_data if item.get('protein') is not None]\n if protein_values:\n avg_protein = sum(protein_values) / len(protein_values)\n avg_protein = round(avg_protein, 1)\n \n # Calculate training frequency\n training_sessions = len(training_data)\n \n # Calculate active days (any one activity record day)\n all_dates = set()\n for data_list in [running_data, steps_data, training_data]:\n all_dates.update(item.get('date') for item in data_list)\n active_days = len(all_dates)\n \n # Get main mood status\n predominant_mood = \"Not recorded\"\n if len(mood_data) > 0:\n mood_counts = {}\n for item in mood_data:\n mood = item.get('mood')\n if mood:\n mood_counts[mood] = mood_counts.get(mood, 0) + 1\n if mood_counts:\n predominant_mood = max(mood_counts.items(), key=lambda x: x[1])[0]\n \n # Get target value\n try:\n health_goal = await sync_to_async(lambda: HealthGoal.objects.get(user=request.user))()\n weight_target = health_goal.target_weight\n steps_target = health_goal.daily_steps_goal\n sleep_target_hours = health_goal.daily_sleep_hours_goal\n sleep_target_minutes = health_goal.daily_sleep_minutes_goal\n running_distance_goal = health_goal.weekly_running_distance_goal\n training_sessions_goal = health_goal.weekly_training_sessions_goal\n calories_goal = health_goal.daily_calories_goal\n \n # Calculate the difference from the target\n weight_diff = \"\"\n if latest_weight and weight_target:\n diff = latest_weight - weight_target\n weight_diff = f\"+{diff:.1f}\" if diff > 0 else f\"{diff:.1f}\"\n except:\n weight_target = \"Not set\"\n steps_target = \"Not set\"\n sleep_target_hours = \"Not set\"\n sleep_target_minutes = \"Not set\"\n running_distance_goal = \"Not set\"\n training_sessions_goal = \"Not set\"\n calories_goal = \"Not set\"\n weight_diff = \"Unknown\"\n \n # Calculate sleep target complete representation\n sleep_target = \"Not set\"\n if sleep_target_hours != \"Not set\":\n sleep_target = f\"{sleep_target_hours}h {sleep_target_minutes}min\"\n \n # Determine user achievements\n achievements = []\n if avg_steps > 0 and steps_target != \"Not set\" and avg_steps >= steps_target:\n achievements.append(f\"Average steps reached target ({avg_steps} steps/day)\")\n if running_sessions > 0:\n achievements.append(f\"Maintain running habit (Weekly {running_sessions} times)\")\n if avg_sleep_hours > 7:\n achievements.append(f\"Good sleep time (Average {avg_sleep_hours} hours/night)\")\n if latest_weight and weight_target and abs(latest_weight - weight_target) < 3:\n achievements.append(f\"Weight close to target value ({latest_weight} kg)\")\n if avg_calories > 0 and calories_goal != \"Not set\":\n achievements.append(f\"Maintain diet record habit\")\n if active_days >= 5:\n achievements.append(f\"Weekly maintain {active_days}/7 active days\")\n \n # If there are not enough achievements, add some default ones\n if len(achievements) < 2:\n if len(steps_data) > 0:\n achievements.append(\"Continuous record steps data\")\n if len(sleep_data) > 0:\n achievements.append(\"Continuous record sleep data\")\n if len(running_data) > 0:\n achievements.append(\"Stick to running exercise\")\n if len(training_data) > 0:\n achievements.append(\"Stick to strength training\")\n \n # Select top 3 achievements\n achievements = achievements[:3]\n achievements_text = \", \".join(achievements)\n \n # Create prompt for DeepSeek API with actual user data\n prompt = f\"\"\"\n Generate a personalized fitness recommendation based on the following user data in 200-300 English words. Structure it in 2-3 cohesive paragraphs without any markdown formatting.\n \n Begin by positively acknowledging their recent achievements in {achievements_text}. Then provide specific suggestions addressing these key areas:\n \n Goal Alignment: Current goals are weight target: {weight_target} kg, daily steps goal: {steps_target} steps, sleep goal: {sleep_target}, weekly running distance goal: {running_distance_goal} km, weekly training sessions goal: {training_sessions_goal}, suggest incremental improvements based on their height: {height} cm, weight: {latest_weight} kg, and consistency.\n \n Activity Optimization: Recommend exercise types/duration considering their running sessions: {running_sessions} per week, running pace: {avg_running_pace} min/km, training sessions: {training_sessions} per week.\n \n Diet & Recovery Strategy: Address sleep patterns (current {avg_sleep_hours} hours/night), diet (current {avg_calories} calories/day, {avg_protein} g protein/day), predominant mood: {predominant_mood}, and rest days.\n \n Progress Tracking: Suggest 2-3 measurable metrics to monitor across different health aspects.\n \n Maintain an encouraging tone using phrases like \"Great job with...\" and \"You might consider...\". Include 1-2 motivational quotes from famous athletes. Conclude by emphasizing sustainable habit-building. Add brief disclaimer to consult healthcare provider before major changes.\n \n User Data:\n Demographics: Age: {user_age}, Gender: {user_gender}, Height: {height} cm, Weight: {latest_weight} kg, BMI: {bmi}\n Current Goals: Weight target: {weight_target} kg, Daily steps target: {steps_target}, Sleep target: {sleep_target}, Weekly running distance: {running_distance_goal} km, Weekly training sessions: {training_sessions_goal}, Daily calories target: {calories_goal}\n \n Weekly Average:\n Steps: {avg_steps} steps/day\n Exercise: {training_sessions} training sessions, {running_sessions} running sessions\n Running: {avg_running_distance} km, {avg_running_pace} min/km pace\n Sleep: {avg_sleep_hours} hours/night\n Diet: {avg_calories} calories/day, {avg_protein} g protein/day\n Mood: {predominant_mood}\n Weight: {latest_weight} kg, {weight_diff} kg from target\n Active Days: {active_days}/7\n \n Recent Progress: {achievements_text}\n \"\"\"\n \n try:\n api_key = os.environ.get('AI_API_KEY')\n \n # Initialize OpenAI client (using DeepSeek's API base URL)\n client = AsyncOpenAI(api_key=api_key, base_url=\"https://api.deepseek.com\")\n \n # Build request parameters\n messages = [\n {\"role\": \"system\", \"content\": \"You are a health and fitness advisor with expertise in analyzing health data patterns and providing personalized recommendations.\"},\n {\"role\": \"user\", \"content\": prompt}\n ]\n \n # Send request to DeepSeek API with timeout handling\n response = await asyncio.wait_for(\n client.chat.completions.create(\n model=\"deepseek-chat\",\n messages=messages,\n temperature=1.0,\n max_tokens=2000\n ),\n timeout=30.0 # Set a reasonable timeout of 30 seconds\n )\n \n # Get reply content\n advice = response.choices[0].message.content\n generated_time = timezone.now()\n \n # Format advice content as HTML with identical structure to database content\n formatted_advice = \"\"\n paragraphs = advice.split('\\n\\n')\n for para in paragraphs:\n if para.strip():\n # Remove possible Markdown or HTML tags\n clean_para = para.strip()\n # Wrap paragraph in p tags with exact same styling as database-retrieved content\n formatted_advice += f\"<p>{clean_para}</p>\"\n \n # Save advice to database\n save_success = await sync_to_async(save_advice_to_db)(request.user, formatted_advice)\n \n # Even if save fails, still return the advice to the user with exact same format\n if not save_success:\n print(\"Warning: Failed to save advice to database, but returning it to user anyway\")\n \n return JsonResponse({\n 'advice': formatted_advice,\n 'generated_time': generated_time.strftime('%Y-%m-%d %H:%M:%S')\n })\n \n except asyncio.TimeoutError:\n print(\"API request timed out\")\n return JsonResponse({\n 'error': 'The request to our AI service timed out. Please try again later.',\n 'advice': '<p>Sorry, our AI service is taking longer than expected. Please try again later.</p>',\n 'generated_time': timezone.now().strftime('%Y-%m-%d %H:%M:%S')\n }, status=200)\n \n except Exception as api_error:\n print(f\"API call error: {str(api_error)}\")\n return JsonResponse({\n 'error': f'AI service error: {str(api_error)}',\n 'advice': '<p>We encountered an issue generating your health advice. Our team has been notified. Please try again later.</p>',\n 'generated_time': timezone.now().strftime('%Y-%m-%d %H:%M:%S')\n }, status=200)\n \n except Exception as e:\n print(f\"General error in generate_advice_async: {str(e)}\")\n return JsonResponse({\n 'error': str(e),\n 'advice': '<p>Sorry, we encountered an unexpected error. Please try again later.</p>',\n 'generated_time': timezone.now().strftime('%Y-%m-%d %H:%M:%S')\n }, status=200)\n\ndef save_advice_to_db(user, advice_content):\n \"\"\"Save generated advice to database\"\"\"\n try:\n # Content is already formatted as HTML during generation, no need to process again\n HealthAdvice.objects.create(\n user=user,\n content=advice_content\n )\n # Keep latest 5 pieces of advice, delete older ones\n old_advice = HealthAdvice.objects.filter(user=user).order_by('-created_at')[5:]\n if old_advice.exists():\n for advice in old_advice:\n advice.delete()\n return True\n except Exception as e:\n print(f\"Error saving advice to database: {str(e)}\")\n return False\n\n# Convert sync view to async view\ndef generate_advice(request):\n \"\"\"Synchronous wrapper for the async generate_advice view\"\"\"\n if request.method != 'POST':\n return JsonResponse({'error': 'Only POST requests allowed'}, status=405)\n \n try:\n result = asyncio.run(generate_advice_async(request))\n return result\n except Exception as e:\n error_msg = f'Processing request failed: {str(e)}'\n print(error_msg) # Add server-side logging\n return JsonResponse({\n 'error': error_msg,\n 'advice': '<p>Sorry, we encountered an error while generating your health advice. Please try again later.</p>',\n 'generated_time': timezone.now().strftime('%Y-%m-%d %H:%M:%S')\n }, status=200) # Return 200 status with error message instead of 500\n"}}}}