AI-RESEARCHER-2024 commited on
Commit
4200b0d
Β·
verified Β·
1 Parent(s): a9fb336

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +131 -38
app.py CHANGED
@@ -1,7 +1,6 @@
1
  #!/usr/bin/env python3
2
  """
3
  CICE 2.0 Healthcare Assessment Tool - Gradio Version (Fixed)
4
- Simplified version with working recording and upload functionality
5
  """
6
 
7
  import gradio as gr
@@ -254,8 +253,42 @@ def process_video_assessment(video_file):
254
 
255
  return assessment_result, summary_html, audio_path
256
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
257
  def create_video_recorder_html():
258
- """Create the HTML/JavaScript for video recording interface - SIMPLIFIED VERSION"""
259
 
260
  recorder_html = """
261
  <div id="video-recorder-container" style="text-align: center; padding: 20px; background-color: #f0f0f0; border-radius: 10px;">
@@ -264,11 +297,16 @@ def create_video_recorder_html():
264
  <div style="margin: 15px 0;">
265
  <button id="start" class="btn" style="background-color: #4CAF50; color: white; padding: 10px 20px; margin: 5px; border: none; border-radius: 4px; cursor: pointer; font-size: 16px;">πŸ”΄ Start Recording</button>
266
  <button id="stop" class="btn" disabled style="background-color: #f44336; color: white; padding: 10px 20px; margin: 5px; border: none; border-radius: 4px; cursor: pointer; opacity: 0.5; font-size: 16px;">⏹️ Stop Recording</button>
 
267
  <button id="reset" class="btn" style="background-color: #2196F3; color: white; padding: 10px 20px; margin: 5px; border: none; border-radius: 4px; cursor: pointer; font-size: 16px;">πŸ”„ Reset</button>
268
  </div>
269
  <div id="timer" style="margin-top: 10px; font-size: 18px; font-weight: bold; color: #333;">Ready to record</div>
270
  <div id="status" style="margin-top: 10px; color: #666; font-size: 14px;"></div>
271
  <div id="fileStatus" style="margin-top: 10px; color: #0066cc; font-weight: bold;"></div>
 
 
 
 
272
  </div>
273
 
274
  <script>
@@ -276,10 +314,13 @@ def create_video_recorder_html():
276
  var video = document.querySelector('#video');
277
  var startBtn = document.querySelector('#start');
278
  var stopBtn = document.querySelector('#stop');
 
279
  var resetBtn = document.querySelector('#reset');
280
  var timerDiv = document.querySelector('#timer');
281
  var statusDiv = document.querySelector('#status');
282
  var fileStatusDiv = document.querySelector('#fileStatus');
 
 
283
 
284
  var mediaRecorder;
285
  var recordedBlobs = [];
@@ -287,6 +328,7 @@ def create_video_recorder_html():
287
  var startTime;
288
  var timerInterval;
289
  var recordingCount = 0;
 
290
 
291
  // Clear any previous status
292
  fileStatusDiv.textContent = '';
@@ -346,6 +388,7 @@ def create_video_recorder_html():
346
 
347
  // Clear previous recording data
348
  recordedBlobs = [];
 
349
  recordingCount++;
350
 
351
  fileStatusDiv.textContent = 'πŸ“Ή Recording in progress...';
@@ -378,6 +421,8 @@ def create_video_recorder_html():
378
  startBtn.style.opacity = '0.5';
379
  stopBtn.disabled = false;
380
  stopBtn.style.opacity = '1';
 
 
381
 
382
  startTime = Date.now();
383
  timerInterval = setInterval(updateTimer, 1000);
@@ -393,48 +438,30 @@ def create_video_recorder_html():
393
  mediaRecorder.onstop = function() {
394
  clearInterval(timerInterval);
395
  timerDiv.textContent = '⏹️ Recording stopped - Processing...';
396
- statusDiv.textContent = 'Processing and preparing video for download...';
397
- fileStatusDiv.textContent = 'πŸ’Ύ Creating video file...';
398
  fileStatusDiv.style.color = '#0066cc';
399
 
400
  // Process the recorded video
401
  setTimeout(function() {
402
  try {
403
  // Combine all recorded chunks into a single blob
404
- var blob = new Blob(recordedBlobs, {type: 'video/webm'});
405
- console.log('Total video size:', blob.size, 'bytes');
406
-
407
- // Create download link
408
- var downloadUrl = URL.createObjectURL(blob);
409
- var downloadLink = document.createElement('a');
410
- downloadLink.href = downloadUrl;
411
- downloadLink.download = 'recorded_video.webm';
412
- downloadLink.style.display = 'none';
413
- document.body.appendChild(downloadLink);
414
-
415
  timerDiv.textContent = 'βœ… Recording complete!';
416
- statusDiv.innerHTML = '<strong>βœ… Recording successful!</strong><br>Your video will download automatically.';
417
  statusDiv.style.color = 'green';
418
  fileStatusDiv.innerHTML = 'βœ… Video recorded successfully (' +
419
- (blob.size / 1024 / 1024).toFixed(2) + ' MB)<br>' +
420
- '<span style="color: #0066cc;">⬇️ Auto-downloading...</span><br>' +
421
- '<span style="color: #666; font-size: 12px;">After download, use the "Upload Video & Assess" tab to analyze.</span>';
422
  fileStatusDiv.style.color = 'green';
423
 
424
- // Auto-download the video file
425
- setTimeout(function() {
426
- downloadLink.click();
427
- document.body.removeChild(downloadLink);
428
- URL.revokeObjectURL(downloadUrl);
429
-
430
- // Update status after download
431
- setTimeout(function() {
432
- fileStatusDiv.innerHTML = 'βœ… Video downloaded as "recorded_video.webm"<br>' +
433
- '<span style="color: #0066cc;">πŸ“ Go to "Upload Video & Assess" tab and upload your downloaded video.</span>';
434
- }, 1000);
435
- }, 500);
436
-
437
- // Clear recorded data to free memory
438
  recordedBlobs = [];
439
  } catch (e) {
440
  console.error('Error processing video:', e);
@@ -463,17 +490,49 @@ def create_video_recorder_html():
463
  }
464
  });
465
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
466
  resetBtn.addEventListener('click', function() {
467
  // Reset the interface
468
  if (mediaRecorder && mediaRecorder.state === 'recording') {
469
  mediaRecorder.stop();
470
  }
471
  recordedBlobs = [];
 
 
472
 
473
  startBtn.disabled = false;
474
  startBtn.style.opacity = '1';
475
  stopBtn.disabled = true;
476
  stopBtn.style.opacity = '0.5';
 
 
477
  timerDiv.textContent = 'Ready to record';
478
  statusDiv.textContent = 'βœ… Camera and microphone ready! Click Start to begin recording.';
479
  statusDiv.style.color = '#666';
@@ -566,20 +625,20 @@ def create_gradio_app():
566
  - πŸ’¬ Interactive Q&A about results
567
 
568
  **πŸ“ Workflow:**
569
- 1. **Record Tab:** Record your video β†’ Video auto-downloads
570
- 2. **Upload Tab:** Upload the downloaded video β†’ Analyze with CICE 2.0
571
  3. **Q&A Tab:** Ask specific questions about the assessment
572
  """)
573
 
574
- with gr.Tab("πŸŽ₯ Record Video"):
575
  gr.Markdown("""
576
  ### Record Live Healthcare Team Interaction
577
 
578
  **Instructions:**
579
  1. Click "Start Recording" to begin recording
580
  2. Click "Stop Recording" when finished
581
- 3. The video will automatically download as 'recorded_video.webm'
582
- 4. Go to the "πŸ“ Upload Video & Assess" tab to upload and analyze your recording
583
  """)
584
 
585
  # Video recorder interface
@@ -587,6 +646,33 @@ def create_gradio_app():
587
  value=create_video_recorder_html(),
588
  label="Video Recorder"
589
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
590
 
591
  with gr.Tab("πŸ“ Upload Video & Assess"):
592
  gr.Markdown("### Upload Healthcare Team Video for CICE 2.0 Analysis")
@@ -705,6 +791,13 @@ def create_gradio_app():
705
  outputs=[assessment_output, summary_output, audio_output]
706
  )
707
 
 
 
 
 
 
 
 
708
  # Q&A handlers
709
  ask_btn.click(
710
  fn=qa_wrapper,
 
1
  #!/usr/bin/env python3
2
  """
3
  CICE 2.0 Healthcare Assessment Tool - Gradio Version (Fixed)
 
4
  """
5
 
6
  import gradio as gr
 
253
 
254
  return assessment_result, summary_html, audio_path
255
 
256
+ def process_recorded_video(video_data_base64):
257
+ """Process recorded video data directly without download/upload"""
258
+
259
+ if not video_data_base64:
260
+ return "❌ No video data received", "", None
261
+
262
+ try:
263
+ # Decode base64 video data
264
+ video_bytes = base64.b64decode(video_data_base64)
265
+
266
+ # Save to temporary file
267
+ with tempfile.NamedTemporaryFile(delete=False, suffix=".webm") as tmp_file:
268
+ tmp_file.write(video_bytes)
269
+ temp_video_path = tmp_file.name
270
+
271
+ # Process the video using our assessment tool
272
+ assessor = CICEAssessment()
273
+ assessment_result = assessor.analyze_video(temp_video_path)
274
+
275
+ if assessment_result.startswith("❌"):
276
+ return assessment_result, "", None
277
+
278
+ # Create summary and audio
279
+ summary_html = assessor.create_summary_report(assessment_result)
280
+ audio_path = assessor.generate_audio_feedback(assessment_result)
281
+
282
+ # Clean up temp file
283
+ os.unlink(temp_video_path)
284
+
285
+ return assessment_result, summary_html, audio_path
286
+
287
+ except Exception as e:
288
+ return f"❌ Error processing recorded video: {str(e)}", "", None
289
+
290
  def create_video_recorder_html():
291
+ """Create the HTML/JavaScript for video recording interface with direct analysis"""
292
 
293
  recorder_html = """
294
  <div id="video-recorder-container" style="text-align: center; padding: 20px; background-color: #f0f0f0; border-radius: 10px;">
 
297
  <div style="margin: 15px 0;">
298
  <button id="start" class="btn" style="background-color: #4CAF50; color: white; padding: 10px 20px; margin: 5px; border: none; border-radius: 4px; cursor: pointer; font-size: 16px;">πŸ”΄ Start Recording</button>
299
  <button id="stop" class="btn" disabled style="background-color: #f44336; color: white; padding: 10px 20px; margin: 5px; border: none; border-radius: 4px; cursor: pointer; opacity: 0.5; font-size: 16px;">⏹️ Stop Recording</button>
300
+ <button id="analyze" class="btn" disabled style="background-color: #FF9800; color: white; padding: 10px 20px; margin: 5px; border: none; border-radius: 4px; cursor: pointer; opacity: 0.5; font-size: 16px;">πŸ” Analyze Recording</button>
301
  <button id="reset" class="btn" style="background-color: #2196F3; color: white; padding: 10px 20px; margin: 5px; border: none; border-radius: 4px; cursor: pointer; font-size: 16px;">πŸ”„ Reset</button>
302
  </div>
303
  <div id="timer" style="margin-top: 10px; font-size: 18px; font-weight: bold; color: #333;">Ready to record</div>
304
  <div id="status" style="margin-top: 10px; color: #666; font-size: 14px;"></div>
305
  <div id="fileStatus" style="margin-top: 10px; color: #0066cc; font-weight: bold;"></div>
306
+
307
+ <!-- Hidden elements for Gradio communication -->
308
+ <input type="hidden" id="videoDataInput" />
309
+ <button id="hiddenAnalyzeBtn" style="display: none;"></button>
310
  </div>
311
 
312
  <script>
 
314
  var video = document.querySelector('#video');
315
  var startBtn = document.querySelector('#start');
316
  var stopBtn = document.querySelector('#stop');
317
+ var analyzeBtn = document.querySelector('#analyze');
318
  var resetBtn = document.querySelector('#reset');
319
  var timerDiv = document.querySelector('#timer');
320
  var statusDiv = document.querySelector('#status');
321
  var fileStatusDiv = document.querySelector('#fileStatus');
322
+ var videoDataInput = document.querySelector('#videoDataInput');
323
+ var hiddenAnalyzeBtn = document.querySelector('#hiddenAnalyzeBtn');
324
 
325
  var mediaRecorder;
326
  var recordedBlobs = [];
 
328
  var startTime;
329
  var timerInterval;
330
  var recordingCount = 0;
331
+ var recordedVideoBlob = null;
332
 
333
  // Clear any previous status
334
  fileStatusDiv.textContent = '';
 
388
 
389
  // Clear previous recording data
390
  recordedBlobs = [];
391
+ recordedVideoBlob = null;
392
  recordingCount++;
393
 
394
  fileStatusDiv.textContent = 'πŸ“Ή Recording in progress...';
 
421
  startBtn.style.opacity = '0.5';
422
  stopBtn.disabled = false;
423
  stopBtn.style.opacity = '1';
424
+ analyzeBtn.disabled = true;
425
+ analyzeBtn.style.opacity = '0.5';
426
 
427
  startTime = Date.now();
428
  timerInterval = setInterval(updateTimer, 1000);
 
438
  mediaRecorder.onstop = function() {
439
  clearInterval(timerInterval);
440
  timerDiv.textContent = '⏹️ Recording stopped - Processing...';
441
+ statusDiv.textContent = 'Processing video for analysis...';
442
+ fileStatusDiv.textContent = 'πŸ’Ύ Preparing video for analysis...';
443
  fileStatusDiv.style.color = '#0066cc';
444
 
445
  // Process the recorded video
446
  setTimeout(function() {
447
  try {
448
  // Combine all recorded chunks into a single blob
449
+ recordedVideoBlob = new Blob(recordedBlobs, {type: 'video/webm'});
450
+ console.log('Total video size:', recordedVideoBlob.size, 'bytes');
451
+
 
 
 
 
 
 
 
 
452
  timerDiv.textContent = 'βœ… Recording complete!';
453
+ statusDiv.textContent = 'βœ… Recording successful! Click "Analyze Recording" to start assessment.';
454
  statusDiv.style.color = 'green';
455
  fileStatusDiv.innerHTML = 'βœ… Video recorded successfully (' +
456
+ (recordedVideoBlob.size / 1024 / 1024).toFixed(2) + ' MB)<br>' +
457
+ '<span style="color: #0066cc;">Ready for CICE 2.0 analysis!</span>';
 
458
  fileStatusDiv.style.color = 'green';
459
 
460
+ // Enable analyze button
461
+ analyzeBtn.disabled = false;
462
+ analyzeBtn.style.opacity = '1';
463
+
464
+ // Clear recorded blobs to free memory
 
 
 
 
 
 
 
 
 
465
  recordedBlobs = [];
466
  } catch (e) {
467
  console.error('Error processing video:', e);
 
490
  }
491
  });
492
 
493
+ analyzeBtn.addEventListener('click', function() {
494
+ if (!recordedVideoBlob) {
495
+ alert('No recording available. Please record a video first.');
496
+ return;
497
+ }
498
+
499
+ analyzeBtn.disabled = true;
500
+ analyzeBtn.style.opacity = '0.5';
501
+ fileStatusDiv.textContent = 'πŸ€– Starting CICE 2.0 analysis...';
502
+ fileStatusDiv.style.color = '#ff6600';
503
+
504
+ // Convert blob to base64
505
+ var reader = new FileReader();
506
+ reader.onload = function() {
507
+ var base64Data = reader.result.split(',')[1]; // Remove data:video/webm;base64, prefix
508
+ console.log('Video converted to base64, length:', base64Data.length);
509
+
510
+ // Set the video data in hidden input
511
+ videoDataInput.value = base64Data;
512
+
513
+ // Trigger the hidden Gradio button
514
+ hiddenAnalyzeBtn.click();
515
+
516
+ fileStatusDiv.textContent = 'πŸ€– Analysis in progress... This may take 1-2 minutes.';
517
+ };
518
+ reader.readAsDataURL(recordedVideoBlob);
519
+ });
520
+
521
  resetBtn.addEventListener('click', function() {
522
  // Reset the interface
523
  if (mediaRecorder && mediaRecorder.state === 'recording') {
524
  mediaRecorder.stop();
525
  }
526
  recordedBlobs = [];
527
+ recordedVideoBlob = null;
528
+ videoDataInput.value = '';
529
 
530
  startBtn.disabled = false;
531
  startBtn.style.opacity = '1';
532
  stopBtn.disabled = true;
533
  stopBtn.style.opacity = '0.5';
534
+ analyzeBtn.disabled = true;
535
+ analyzeBtn.style.opacity = '0.5';
536
  timerDiv.textContent = 'Ready to record';
537
  statusDiv.textContent = 'βœ… Camera and microphone ready! Click Start to begin recording.';
538
  statusDiv.style.color = '#666';
 
625
  - πŸ’¬ Interactive Q&A about results
626
 
627
  **πŸ“ Workflow:**
628
+ 1. **Record & Assess Tab:** Record video β†’ Click "Analyze Recording" β†’ Get immediate CICE 2.0 assessment
629
+ 2. **Upload Tab:** Upload existing videos β†’ Analyze with CICE 2.0
630
  3. **Q&A Tab:** Ask specific questions about the assessment
631
  """)
632
 
633
+ with gr.Tab("πŸŽ₯ Record Video & Assess"):
634
  gr.Markdown("""
635
  ### Record Live Healthcare Team Interaction
636
 
637
  **Instructions:**
638
  1. Click "Start Recording" to begin recording
639
  2. Click "Stop Recording" when finished
640
+ 3. Click "Analyze Recording" to automatically analyze with CICE 2.0
641
+ 4. View your assessment results below
642
  """)
643
 
644
  # Video recorder interface
 
646
  value=create_video_recorder_html(),
647
  label="Video Recorder"
648
  )
649
+
650
+ # Hidden components for JavaScript communication
651
+ with gr.Row(visible=False):
652
+ video_data_hidden = gr.Textbox(elem_id="videoDataInput")
653
+ analyze_hidden_btn = gr.Button("Hidden Analyze", elem_id="hiddenAnalyzeBtn")
654
+
655
+ # Assessment results from recording
656
+ with gr.Row():
657
+ with gr.Column(scale=2):
658
+ recording_summary_output = gr.HTML(
659
+ label="Recording Assessment Summary",
660
+ value="<p>Record a video and click 'Analyze Recording' to see the summary.</p>"
661
+ )
662
+
663
+ with gr.Row():
664
+ recording_assessment_output = gr.Textbox(
665
+ label="Detailed Recording Assessment Report",
666
+ lines=20,
667
+ max_lines=30,
668
+ placeholder="Detailed CICE 2.0 assessment will appear here..."
669
+ )
670
+
671
+ with gr.Row():
672
+ recording_audio_output = gr.Audio(
673
+ label="πŸ”Š Audio Feedback from Recording",
674
+ visible=True
675
+ )
676
 
677
  with gr.Tab("πŸ“ Upload Video & Assess"):
678
  gr.Markdown("### Upload Healthcare Team Video for CICE 2.0 Analysis")
 
791
  outputs=[assessment_output, summary_output, audio_output]
792
  )
793
 
794
+ # Event handler for recorded video analysis
795
+ analyze_hidden_btn.click(
796
+ fn=lambda video_data: store_assessment_state(None, *process_recorded_video(video_data)),
797
+ inputs=[video_data_hidden],
798
+ outputs=[recording_assessment_output, recording_summary_output, recording_audio_output]
799
+ )
800
+
801
  # Q&A handlers
802
  ask_btn.click(
803
  fn=qa_wrapper,