akarsh999 commited on
Commit
814e4ee
·
verified ·
1 Parent(s): 858ce7d

Upload 9 files

Browse files
Files changed (2) hide show
  1. app.py +209 -90
  2. athletic_performance.py +96 -0
app.py CHANGED
@@ -4,7 +4,8 @@ import os
4
  from athletic_performance import (
5
  analyze_youtube_video, analyze_video_file, get_performance_insights,
6
  get_ai_sports_coaching_analysis, test_gemini_api_connection,
7
- generate_annotated_video_from_youtube, generate_annotated_video_from_file
 
8
  )
9
 
10
  def analyze_jump_from_youtube(youtube_url, user_height_cm, user_weight_kg, progress=gr.Progress()):
@@ -62,7 +63,7 @@ def analyze_jump_from_youtube(youtube_url, user_height_cm, user_weight_kg, progr
62
 
63
  ### 📈 Performance Insights
64
  """
65
-
66
  # Add performance insights using the new function
67
  insights = get_performance_insights(result)
68
  for insight in insights:
@@ -99,11 +100,11 @@ def analyze_jump_from_file(video_file, user_height_cm, user_weight_kg, progress=
99
  # Handle errors
100
  if "error" in result:
101
  return f"❌ {result['error']}", None, None
102
-
103
- if result is None:
104
- return "⚠️ Could not analyze jump. Make sure the video shows a person clearly performing a vertical jump.", None, None
105
-
106
- # Format results (same as YouTube function)
107
  # Handle potential None values safely
108
  jump_height = result.get('jump_height_cm', 0) or 0
109
  flight_time = result.get('flight_time_s', 0) or 0
@@ -141,7 +142,7 @@ def analyze_jump_from_file(video_file, user_height_cm, user_weight_kg, progress=
141
 
142
  ### 📈 Performance Insights
143
  """
144
-
145
  # Add performance insights using the new function
146
  insights = get_performance_insights(result)
147
  for insight in insights:
@@ -396,6 +397,139 @@ Your annotated video is ready for download!
396
  return results_text, summary_df, video_path
397
 
398
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
399
  # Create Gradio interface
400
  def create_interface():
401
  with gr.Blocks(title="🏃‍♂️ Athletic Ability Analysis") as app:
@@ -411,25 +545,25 @@ def create_interface():
411
  - **🎬 Annotated Videos**: Generate training videos with pose tracking and performance overlays
412
  - **⚠️ Technique Analysis**: Real-time knee strain detection and form corrections
413
  - **🎯 Performance Insights**: Professional-grade analysis and training suggestions
 
414
 
415
  ## 📋 Instructions
416
  1. Enter your height in centimeters and weight in kilograms
417
  2. Choose your analysis type:
418
- - **📊 Standard Analysis**: Get detailed biomechanical metrics
419
- - **🤖 AI Sports Coach**: Personalized recommendations and sport suggestions
420
- - **🎬 Video Generation**: Create annotated training videos with visual overlays
421
  3. Provide a video (YouTube URL or file upload)
422
- 4. Get comprehensive results, actionable insights, or downloadable training videos
423
  """)
424
 
425
  with gr.Row():
426
  with gr.Column():
427
  user_height = gr.Number(
428
- label="Your Height (cm)",
429
- value=175,
430
- minimum=100,
431
- maximum=250
432
- )
433
  with gr.Column():
434
  user_weight = gr.Number(
435
  label="Your Weight (kg)",
@@ -458,34 +592,48 @@ def create_interface():
458
  )
459
  file_btn = gr.Button("🚀 Analyze Uploaded Video", variant="primary")
460
 
461
- # AI Coaching Tab
462
- with gr.TabItem("🤖 AI Sports Coach"):
463
  gr.Markdown("""
464
- ## 🤖 AI-Powered Sports Coaching Analysis
 
 
 
 
 
 
 
 
465
 
466
- Get personalized sports recommendations and jump technique improvement suggestions from our AI sports coach powered by Google Gemini.
 
 
 
467
 
468
- **What you'll get:**
469
- - 🏆 **Recommended Sports** (top 3 that match your athletic profile)
470
- - 🎯 **Jump Technique Analysis** with specific improvement suggestions
471
- - 📊 **Personalized Training Recommendations**
472
  """)
473
 
474
  with gr.Row():
475
  with gr.Column():
476
- ai_gender = gr.Radio(
477
  choices=["Male", "Female"],
478
  label="Gender",
479
  value="Male"
480
  )
 
 
481
  # Check if API key is available in environment
482
  default_api_key = os.getenv("GEMINI_API_KEY", "")
483
- ai_gemini_key = gr.Textbox(
484
- label="Gemini API Key",
485
- placeholder="Enter your Google Gemini API key" if not default_api_key else "API key loaded from environment",
486
  type="password",
487
  value=default_api_key
488
  )
 
489
  with gr.Row():
490
  test_api_btn = gr.Button("🧪 Test API Key", size="sm")
491
 
@@ -499,60 +647,21 @@ def create_interface():
499
  gr.Markdown("""
500
  💡 **Get your free API key**: [Google AI Studio](https://aistudio.google.com/app/apikey)
501
 
502
- 📱 **Privacy**: Your API key is only used for this analysis and not stored.
503
  """)
504
 
505
  with gr.Column():
506
- ai_youtube_url = gr.Textbox(
507
- label="YouTube URL (Optional)",
508
- placeholder="https://youtube.com/watch?v=..."
509
- )
510
- ai_video_file = gr.File(
511
- label="Upload Video File (Optional)",
512
- file_types=[".mp4", ".avi", ".mov", ".mkv", ".webm"]
513
- )
514
- gr.Markdown("*Provide either a YouTube URL or upload a video file*")
515
-
516
- ai_coaching_btn = gr.Button("🤖 Get AI Coaching Analysis", variant="primary", size="lg")
517
-
518
- # Video Generation Tab
519
- with gr.TabItem("🎬 Annotated Video"):
520
- gr.Markdown("""
521
- ## 🎬 Generate Annotated Training Video
522
-
523
- Create a professional training video with visual overlays including:
524
- - **🦴 Pose Tracking**: Real-time skeleton visualization
525
- - **📏 Performance Lines**: Average vs Professional jump heights
526
- - **⚠️ Knee Strain Detection**: Red warnings for poor form
527
- - **📊 Live Metrics**: Frame-by-frame jump analysis
528
-
529
- Perfect for coaches, athletes, and performance analysis!
530
- """)
531
-
532
- with gr.Row():
533
- with gr.Column():
534
- video_gender = gr.Radio(
535
- choices=["Male", "Female"],
536
- label="Gender (for performance references)",
537
- value="Male"
538
- )
539
- gr.Markdown("*Used to set appropriate average/pro jump height lines*")
540
-
541
- with gr.Column():
542
- gr.Markdown("### Video Input Options")
543
- video_youtube_url = gr.Textbox(
544
  label="YouTube URL (Option 1)",
545
  placeholder="https://youtube.com/watch?v=..."
546
  )
547
- video_file_upload = gr.File(
548
  label="Upload Video File (Option 2)",
549
  file_types=[".mp4", ".avi", ".mov", ".mkv", ".webm"]
550
  )
551
  gr.Markdown("*Provide either a YouTube URL or upload a video file*")
552
 
553
- with gr.Row():
554
- video_youtube_btn = gr.Button("🎬 Generate from YouTube", variant="primary", size="lg")
555
- video_file_btn = gr.Button("🎬 Generate from Upload", variant="primary", size="lg")
556
 
557
  # Results section
558
  gr.Markdown("## 📊 Analysis Results")
@@ -567,6 +676,14 @@ def create_interface():
567
  datatype=["str", "str"]
568
  )
569
 
 
 
 
 
 
 
 
 
570
  status_message = gr.Textbox(label="Status", interactive=False)
571
 
572
  # Video requirements
@@ -609,10 +726,25 @@ def create_interface():
609
  outputs=[results_text, results_table, status_message]
610
  )
611
 
612
- ai_coaching_btn.click(
613
- fn=get_ai_coaching_recommendations,
614
- inputs=[ai_youtube_url, ai_video_file, user_height, user_weight, ai_gender, ai_gemini_key],
615
- outputs=[results_text, results_table, status_message]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
616
  )
617
 
618
  # API key test handler
@@ -622,23 +754,10 @@ def create_interface():
622
 
623
  test_api_btn.click(
624
  fn=test_and_show_result,
625
- inputs=[ai_gemini_key],
626
  outputs=[api_test_result]
627
  )
628
 
629
- # Video generation event handlers
630
- video_youtube_btn.click(
631
- fn=generate_video_from_youtube,
632
- inputs=[video_youtube_url, user_height, user_weight, video_gender],
633
- outputs=[results_text, results_table, gr.File(label="Download Video")]
634
- )
635
-
636
- video_file_btn.click(
637
- fn=generate_video_from_file,
638
- inputs=[video_file_upload, user_height, user_weight, video_gender],
639
- outputs=[results_text, results_table, gr.File(label="Download Video")]
640
- )
641
-
642
  # Example section
643
  gr.Examples(
644
  examples=[
 
4
  from athletic_performance import (
5
  analyze_youtube_video, analyze_video_file, get_performance_insights,
6
  get_ai_sports_coaching_analysis, test_gemini_api_connection,
7
+ generate_annotated_video_from_youtube, generate_annotated_video_from_file,
8
+ generate_complete_analysis_with_video
9
  )
10
 
11
  def analyze_jump_from_youtube(youtube_url, user_height_cm, user_weight_kg, progress=gr.Progress()):
 
63
 
64
  ### 📈 Performance Insights
65
  """
66
+
67
  # Add performance insights using the new function
68
  insights = get_performance_insights(result)
69
  for insight in insights:
 
100
  # Handle errors
101
  if "error" in result:
102
  return f"❌ {result['error']}", None, None
103
+
104
+ if result is None:
105
+ return "⚠️ Could not analyze jump. Make sure the video shows a person clearly performing a vertical jump.", None, None
106
+
107
+ # Format results (same as YouTube function)
108
  # Handle potential None values safely
109
  jump_height = result.get('jump_height_cm', 0) or 0
110
  flight_time = result.get('flight_time_s', 0) or 0
 
142
 
143
  ### 📈 Performance Insights
144
  """
145
+
146
  # Add performance insights using the new function
147
  insights = get_performance_insights(result)
148
  for insight in insights:
 
397
  return results_text, summary_df, video_path
398
 
399
 
400
+ def complete_analysis_with_video_stream(youtube_url, video_file, user_height_cm, user_weight_kg, gender, gemini_api_key, progress=gr.Progress()):
401
+ """Complete analysis with AI coaching and video streaming."""
402
+
403
+ # Validate inputs
404
+ if not user_height_cm or user_height_cm <= 0:
405
+ return "❌ Please provide a valid height", None, None, None
406
+
407
+ if not user_weight_kg or user_weight_kg <= 0:
408
+ return "❌ Please provide a valid weight", None, None, None
409
+
410
+ if not gender:
411
+ return "❌ Please select your gender", None, None, None
412
+
413
+ # Determine video source and path
414
+ video_source = None
415
+ video_path_or_url = None
416
+
417
+ if youtube_url and youtube_url.strip():
418
+ video_source = "youtube"
419
+ video_path_or_url = youtube_url.strip()
420
+ progress(0.05, desc="Processing YouTube video...")
421
+ elif video_file:
422
+ video_source = "file"
423
+ video_path_or_url = video_file.name
424
+ progress(0.05, desc="Processing uploaded video...")
425
+ else:
426
+ return "❌ Please provide either a YouTube URL or upload a video file", None, None, None
427
+
428
+ try:
429
+ # Create progress callback
430
+ def progress_callback(prog, desc):
431
+ progress(prog, desc=desc)
432
+
433
+ # Run complete analysis
434
+ result = generate_complete_analysis_with_video(
435
+ video_source=video_source,
436
+ video_path_or_url=video_path_or_url,
437
+ user_height_cm=user_height_cm,
438
+ user_weight_kg=user_weight_kg,
439
+ gender=gender,
440
+ api_key=gemini_api_key.strip() if gemini_api_key else None,
441
+ progress_callback=progress_callback
442
+ )
443
+
444
+ # Handle errors
445
+ if "error" in result:
446
+ return f"❌ Analysis failed: {result['error']}", None, None, None
447
+
448
+ if not result.get("success"):
449
+ return "❌ Analysis failed. Please ensure the video shows a clear vertical jump.", None, None, None
450
+
451
+ # Extract results
452
+ video_path = result.get("video_path")
453
+ jump_metrics = result.get("jump_metrics", {})
454
+ jump_references = result.get("jump_references", {})
455
+ ai_coaching = result.get("ai_coaching")
456
+
457
+ # Handle potential None values safely
458
+ jump_height = jump_metrics.get('jump_height_cm', 0) or 0
459
+ flight_time = jump_metrics.get('flight_time_s', 0) or 0
460
+ peak_power = jump_metrics.get('peak_power_watts', 0) or 0
461
+ rfd = jump_metrics.get('rate_of_force_development', 0) or 0
462
+
463
+ # Format comprehensive results
464
+ results_text = f"""
465
+ # 🎬 Complete Athletic Performance Analysis
466
+
467
+ ## 📊 Performance Metrics
468
+ - **Jump Height**: {jump_height:.2f} cm
469
+ - **Relative Jump**: {(jump_height/user_height_cm*100):.1f}% of body height
470
+ - **Flight Time**: {flight_time:.3f} seconds
471
+ - **Peak Power**: {peak_power:.0f} watts
472
+ - **Rate of Force Development**: {rfd:.2f}
473
+
474
+ ## 📏 Performance Comparison
475
+ - **Your Performance**: {jump_height:.1f} cm
476
+ - **Average for {gender}**: {jump_references.get('average', 0):.1f} cm
477
+ - **Professional Level**: {jump_references.get('professional', 0):.1f} cm
478
+
479
+ ## 🎥 Video Analysis Features
480
+ - ✅ **Real-time Pose Tracking**: Skeleton overlay throughout jump
481
+ - ✅ **Performance Reference Lines**: Average vs Professional benchmarks
482
+ - ✅ **Knee Strain Detection**: Automatic form analysis with warnings
483
+ - ✅ **Live Metrics Display**: Frame-by-frame jump height tracking
484
+
485
+ """
486
+
487
+ # Add AI coaching analysis if available
488
+ if ai_coaching and ai_coaching.get("success"):
489
+ results_text += f"""
490
+ ## 🤖 AI Sports Coach Analysis
491
+
492
+ {ai_coaching.get('analysis', 'AI analysis not available')}
493
+
494
+ ---
495
+ *Analysis powered by Google Gemini AI*
496
+ """
497
+ elif gemini_api_key:
498
+ results_text += """
499
+ ## 🤖 AI Sports Coach Analysis
500
+
501
+ ❌ AI coaching analysis failed. Please check your API key and try again.
502
+ """
503
+ else:
504
+ results_text += """
505
+ ## 🤖 AI Sports Coach Analysis
506
+
507
+ 💡 **Provide a Gemini API key to get personalized sports recommendations and technique improvements!**
508
+
509
+ Get your free API key at: [Google AI Studio](https://aistudio.google.com/app/apikey)
510
+ """
511
+
512
+ # Create comprehensive summary dataframe
513
+ summary_data = [
514
+ ["Jump Height", f"{jump_height:.2f} cm"],
515
+ ["Flight Time", f"{flight_time:.3f} seconds"],
516
+ ["Peak Power", f"{peak_power:.0f} watts"],
517
+ ["Rate of Force Development", f"{rfd:.2f}"],
518
+ ["Performance vs Average", f"{((jump_height/jump_references.get('average', 1))*100):.0f}%"],
519
+ ["Performance vs Pro", f"{((jump_height/jump_references.get('professional', 1))*100):.0f}%"],
520
+ ["Video Features", "Pose + References + Strain Detection"],
521
+ ["AI Coaching", "✅ Included" if ai_coaching and ai_coaching.get("success") else "❌ Not Available"],
522
+ ]
523
+
524
+ summary_df = pd.DataFrame(summary_data, columns=["Metric", "Value"])
525
+
526
+ # Return results with video for streaming
527
+ return results_text, summary_df, video_path, "✅ Complete analysis ready!"
528
+
529
+ except Exception as e:
530
+ return f"❌ Unexpected error: {str(e)}", None, None, None
531
+
532
+
533
  # Create Gradio interface
534
  def create_interface():
535
  with gr.Blocks(title="🏃‍♂️ Athletic Ability Analysis") as app:
 
545
  - **🎬 Annotated Videos**: Generate training videos with pose tracking and performance overlays
546
  - **⚠️ Technique Analysis**: Real-time knee strain detection and form corrections
547
  - **🎯 Performance Insights**: Professional-grade analysis and training suggestions
548
+ - **📺 Video Streaming**: Watch your annotated analysis video directly in the browser
549
 
550
  ## 📋 Instructions
551
  1. Enter your height in centimeters and weight in kilograms
552
  2. Choose your analysis type:
553
+ - **📊 Standard Analysis**: Get detailed biomechanical metrics only
554
+ - **🎬 Complete Analysis**: Get annotated video + AI coaching + streaming (Recommended!)
 
555
  3. Provide a video (YouTube URL or file upload)
556
+ 4. Get comprehensive results with video streaming and AI coaching insights
557
  """)
558
 
559
  with gr.Row():
560
  with gr.Column():
561
  user_height = gr.Number(
562
+ label="Your Height (cm)",
563
+ value=175,
564
+ minimum=100,
565
+ maximum=250
566
+ )
567
  with gr.Column():
568
  user_weight = gr.Number(
569
  label="Your Weight (kg)",
 
592
  )
593
  file_btn = gr.Button("🚀 Analyze Uploaded Video", variant="primary")
594
 
595
+ # Complete Analysis Tab
596
+ with gr.TabItem("🎬 Complete Analysis + AI Coach"):
597
  gr.Markdown("""
598
+ ## 🎬 Complete Athletic Performance Analysis
599
+
600
+ Get the ultimate training analysis combining:
601
+
602
+ ### 🎥 Annotated Training Video
603
+ - **🦴 Real-time Pose Tracking**: Skeleton overlay throughout jump
604
+ - **📏 Performance Reference Lines**: Average vs Professional benchmarks
605
+ - **⚠�� Knee Strain Detection**: Automatic form analysis with red warnings
606
+ - **📊 Live Metrics Display**: Frame-by-frame jump height tracking
607
 
608
+ ### 🤖 AI Sports Coach Analysis
609
+ - **🏆 Sport Recommendations**: Top 3 sports matching your athletic profile
610
+ - **🎯 Technique Improvements**: Specific jump form corrections
611
+ - **📈 Training Insights**: Personalized performance enhancement tips
612
 
613
+ ### 📺 Video Streaming
614
+ - **Watch directly in browser**: No downloads required
615
+ - **Professional annotations**: Training-ready video output
616
+ - **Shareable results**: Perfect for coaches and athletes
617
  """)
618
 
619
  with gr.Row():
620
  with gr.Column():
621
+ complete_gender = gr.Radio(
622
  choices=["Male", "Female"],
623
  label="Gender",
624
  value="Male"
625
  )
626
+ gr.Markdown("*Used for performance references and AI analysis*")
627
+
628
  # Check if API key is available in environment
629
  default_api_key = os.getenv("GEMINI_API_KEY", "")
630
+ complete_gemini_key = gr.Textbox(
631
+ label="Gemini API Key (Optional for AI Coaching)",
632
+ placeholder="Enter your Google Gemini API key for AI coaching" if not default_api_key else "API key loaded from environment",
633
  type="password",
634
  value=default_api_key
635
  )
636
+
637
  with gr.Row():
638
  test_api_btn = gr.Button("🧪 Test API Key", size="sm")
639
 
 
647
  gr.Markdown("""
648
  💡 **Get your free API key**: [Google AI Studio](https://aistudio.google.com/app/apikey)
649
 
650
+ ⚠️ **Note**: Video generation works without API key, but AI coaching requires one
651
  """)
652
 
653
  with gr.Column():
654
+ complete_youtube_url = gr.Textbox(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
655
  label="YouTube URL (Option 1)",
656
  placeholder="https://youtube.com/watch?v=..."
657
  )
658
+ complete_video_file = gr.File(
659
  label="Upload Video File (Option 2)",
660
  file_types=[".mp4", ".avi", ".mov", ".mkv", ".webm"]
661
  )
662
  gr.Markdown("*Provide either a YouTube URL or upload a video file*")
663
 
664
+ complete_analysis_btn = gr.Button("🚀 Get Complete Analysis + Video", variant="primary", size="lg")
 
 
665
 
666
  # Results section
667
  gr.Markdown("## 📊 Analysis Results")
 
676
  datatype=["str", "str"]
677
  )
678
 
679
+ # Video streaming section
680
+ with gr.Row():
681
+ with gr.Column():
682
+ analysis_video = gr.Video(
683
+ label="📺 Annotated Training Video",
684
+ visible=False
685
+ )
686
+
687
  status_message = gr.Textbox(label="Status", interactive=False)
688
 
689
  # Video requirements
 
726
  outputs=[results_text, results_table, status_message]
727
  )
728
 
729
+ # Complete analysis with video streaming
730
+ def complete_analysis_with_video_display(youtube_url, video_file, user_height_cm, user_weight_kg, gender, gemini_api_key, progress=gr.Progress()):
731
+ # Get the complete analysis
732
+ results_text_output, summary_df, video_path, status = complete_analysis_with_video_stream(
733
+ youtube_url, video_file, user_height_cm, user_weight_kg, gender, gemini_api_key, progress
734
+ )
735
+
736
+ # Update video component visibility and content
737
+ if video_path and os.path.exists(video_path):
738
+ video_update = gr.update(value=video_path, visible=True)
739
+ else:
740
+ video_update = gr.update(visible=False)
741
+
742
+ return results_text_output, summary_df, video_update, status
743
+
744
+ complete_analysis_btn.click(
745
+ fn=complete_analysis_with_video_display,
746
+ inputs=[complete_youtube_url, complete_video_file, user_height, user_weight, complete_gender, complete_gemini_key],
747
+ outputs=[results_text, results_table, analysis_video, status_message]
748
  )
749
 
750
  # API key test handler
 
754
 
755
  test_api_btn.click(
756
  fn=test_and_show_result,
757
+ inputs=[complete_gemini_key],
758
  outputs=[api_test_result]
759
  )
760
 
 
 
 
 
 
 
 
 
 
 
 
 
 
761
  # Example section
762
  gr.Examples(
763
  examples=[
athletic_performance.py CHANGED
@@ -826,6 +826,102 @@ def generate_annotated_video_from_file(video_file_path, user_height_cm, user_wei
826
  return {"error": f"Error during video generation: {str(e)}"}
827
 
828
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
829
  def get_performance_insights(result_dict):
830
  """Generate performance insights based on comprehensive jump metrics.
831
 
 
826
  return {"error": f"Error during video generation: {str(e)}"}
827
 
828
 
829
+ def generate_complete_analysis_with_video(video_source, video_path_or_url, user_height_cm, user_weight_kg, gender, api_key=None, progress_callback=None):
830
+ """
831
+ Complete analysis combining annotated video generation + AI sports coaching.
832
+
833
+ Args:
834
+ video_source (str): "youtube" or "file"
835
+ video_path_or_url (str): YouTube URL or file path
836
+ user_height_cm (float): User's height in centimeters
837
+ user_weight_kg (float): User's weight in kilograms
838
+ gender (str): "Male" or "Female"
839
+ api_key (str, optional): Gemini API key for AI coaching
840
+ progress_callback (callable, optional): Progress tracking function
841
+
842
+ Returns:
843
+ dict: Complete analysis with video path, AI coaching, and metrics
844
+ """
845
+
846
+ try:
847
+ # Phase 1: Generate annotated video (50% of progress)
848
+ if progress_callback:
849
+ progress_callback(0.1, "Starting comprehensive analysis...")
850
+
851
+ def video_progress(prog, desc):
852
+ if progress_callback:
853
+ progress_callback(0.1 + (prog * 0.4), f"Video: {desc}")
854
+
855
+ # Generate annotated video
856
+ if video_source == "youtube":
857
+ video_result = generate_annotated_video_from_youtube(
858
+ video_path_or_url, user_height_cm, user_weight_kg, gender, video_progress
859
+ )
860
+ else:
861
+ video_result = generate_annotated_video_from_file(
862
+ video_path_or_url, user_height_cm, user_weight_kg, gender, video_progress
863
+ )
864
+
865
+ if "error" in video_result:
866
+ return video_result
867
+
868
+ # Phase 2: AI Sports Coaching Analysis (30% of progress)
869
+ if progress_callback:
870
+ progress_callback(0.5, "Generating AI sports coaching analysis...")
871
+
872
+ ai_result = None
873
+ if api_key:
874
+ jump_metrics = video_result.get("jump_metrics", {})
875
+
876
+ def ai_progress(prog, desc):
877
+ if progress_callback:
878
+ progress_callback(0.5 + (prog * 0.3), f"AI: {desc}")
879
+
880
+ ai_result = get_ai_sports_coaching_analysis(
881
+ jump_height_cm=jump_metrics.get('jump_height_cm', 0),
882
+ user_height_cm=user_height_cm,
883
+ gender=gender,
884
+ peak_power_watts=jump_metrics.get('peak_power_watts'),
885
+ flight_time_s=jump_metrics.get('flight_time_s'),
886
+ rfd=jump_metrics.get('rate_of_force_development'),
887
+ api_key=api_key
888
+ )
889
+
890
+ if progress_callback:
891
+ progress_callback(0.8, "AI analysis complete!")
892
+
893
+ # Phase 3: Combine results (20% of progress)
894
+ if progress_callback:
895
+ progress_callback(0.9, "Finalizing comprehensive analysis...")
896
+
897
+ jump_metrics = video_result.get("jump_metrics", {})
898
+ jump_references = video_result.get("jump_references", {})
899
+
900
+ # Create comprehensive result
901
+ result = {
902
+ "success": True,
903
+ "video_path": video_result.get("output_video_path"),
904
+ "jump_metrics": jump_metrics,
905
+ "jump_references": jump_references,
906
+ "ai_coaching": ai_result if ai_result and "error" not in ai_result else None,
907
+ "video_features": {
908
+ "pose_tracking": True,
909
+ "reference_lines": True,
910
+ "knee_strain_detection": True,
911
+ "live_metrics": True
912
+ },
913
+ "analysis_type": "complete_with_video"
914
+ }
915
+
916
+ if progress_callback:
917
+ progress_callback(1.0, "Complete analysis ready!")
918
+
919
+ return result
920
+
921
+ except Exception as e:
922
+ return {"error": f"Error during complete analysis: {str(e)}"}
923
+
924
+
925
  def get_performance_insights(result_dict):
926
  """Generate performance insights based on comprehensive jump metrics.
927