norhan12 commited on
Commit
65e5cc2
·
verified ·
1 Parent(s): dcdfb5f

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +21 -36
app.py CHANGED
@@ -13,8 +13,7 @@ from concurrent.futures import ThreadPoolExecutor
13
  # Setup logging
14
  logging.basicConfig(
15
  level=logging.INFO,
16
- format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
17
- )
18
  logger = logging.getLogger(__name__)
19
  logging.getLogger("nemo_logging").setLevel(logging.ERROR)
20
  logging.getLogger("nemo").setLevel(logging.ERROR)
@@ -27,7 +26,6 @@ os.makedirs(OUTPUT_DIR, exist_ok=True)
27
  VALID_EXTENSIONS = ('.wav', '.mp3', '.m4a', '.flac')
28
  MAX_FILE_SIZE = 300 * 1024 * 1024 # 300MB
29
 
30
-
31
  def check_health() -> str:
32
  """Check system health, similar to FastAPI /health endpoint"""
33
  try:
@@ -39,42 +37,39 @@ def check_health() -> str:
39
  logger.error(f"Health check failed: {str(e)}")
40
  return f"System is unhealthy: {str(e)}"
41
 
42
-
43
  # A helper function to process a single audio file
44
  def process_single_audio(file_path_or_url: str) -> Dict:
45
  """Processes a single audio file and returns its analysis."""
46
  try:
47
  if not file_path_or_url:
48
  return {"error": "No audio provided for processing."}
49
-
50
- # Gradio will download the file if it's a URL and provide a local path.
51
- # So, 'file_path_or_url' will always be a local path when it reaches this function.
52
  temp_audio_path = Path(file_path_or_url)
53
-
54
  file_ext = temp_audio_path.suffix.lower()
 
55
  if file_ext not in VALID_EXTENSIONS:
56
  return {"error": f"Invalid file format: {file_ext}. Supported formats: {', '.join(VALID_EXTENSIONS)}"}
57
-
58
  file_size = os.path.getsize(temp_audio_path)
59
  if file_size > MAX_FILE_SIZE:
60
  return {
61
  "error": f"File too large: {file_size / (1024 * 1024):.2f}MB. Max size: {MAX_FILE_SIZE // (1024 * 1024)}MB"}
62
-
63
  logger.info(f"Processing audio from: {temp_audio_path}")
64
  result = process_interview(str(temp_audio_path))
65
-
66
  if not result or 'pdf_path' not in result or 'json_path' not in result:
67
  return {"error": "Processing failed - invalid result format."}
68
-
69
  pdf_path = Path(result['pdf_path'])
70
  json_path = Path(result['json_path'])
71
-
72
  if not pdf_path.exists() or not json_path.exists():
73
  return {"error": "Processing failed - output files not found."}
74
-
75
  with json_path.open('r') as f:
76
  analysis_data = json.load(f)
77
-
78
  voice_analysis = analysis_data.get('voice_analysis', {})
79
  summary = (
80
  f"Speakers: {', '.join(analysis_data['speakers'])}\n"
@@ -82,21 +77,18 @@ def process_single_audio(file_path_or_url: str) -> Dict:
82
  f"Confidence Level: {voice_analysis.get('interpretation', {}).get('confidence_level', 'Unknown')}\n"
83
  f"Anxiety Level: {voice_analysis.get('interpretation', {}).get('anxiety_level', 'Unknown')}"
84
  )
85
-
86
  json_data = json.dumps(analysis_data, indent=2)
87
-
88
  return {
89
  "summary": summary,
90
  "json_data": json_data,
91
  "pdf_path": str(pdf_path),
92
- "original_input": file_path_or_url # Optionally return the original URL/path for mapping
93
  }
94
-
95
  except Exception as e:
96
  logger.error(f"Error processing single audio: {str(e)}", exc_info=True)
97
  return {"error": f"Error during processing: {str(e)}"}
98
 
99
-
100
  # Main function to handle multiple audio files/URLs
101
  def analyze_multiple_audios(file_paths_or_urls: List[str]) -> Tuple[str, str, List[str]]:
102
  """
@@ -105,23 +97,19 @@ def analyze_multiple_audios(file_paths_or_urls: List[str]) -> Tuple[str, str, Li
105
  """
106
  if not file_paths_or_urls:
107
  return "No audio files/URLs provided.", "[]", []
108
-
109
  all_summaries = []
110
  all_json_data = []
111
  all_pdf_paths = []
112
 
113
- # Use ThreadPoolExecutor for parallel processing
114
- # Adjust max_workers based on available resources and expected load
115
  with ThreadPoolExecutor(max_workers=5) as executor:
116
  futures = {executor.submit(process_single_audio, item): item for item in file_paths_or_urls}
117
-
118
  for future in futures:
119
- item = futures[future] # Get the original item (URL/path) that was processed
120
  try:
121
- result = future.result() # Get the result of the processing
122
  if "error" in result:
123
  all_summaries.append(f"Error processing {item}: {result['error']}")
124
- # Include error in JSON output for clarity
125
  all_json_data.append(json.dumps({"input": item, "error": result['error']}, indent=2))
126
  else:
127
  all_summaries.append(f"Analysis for {os.path.basename(item)}:\n{result['summary']}")
@@ -131,14 +119,12 @@ def analyze_multiple_audios(file_paths_or_urls: List[str]) -> Tuple[str, str, Li
131
  logger.error(f"Item {item} generated an unexpected exception: {exc}", exc_info=True)
132
  all_summaries.append(f"Error processing {item}: An unexpected error occurred.")
133
  all_json_data.append(json.dumps({"input": item, "error": str(exc)}, indent=2))
134
-
135
  combined_summary = "\n\n---\n\n".join(all_summaries)
136
- # Ensure the combined_json_list is a valid JSON array string
137
  combined_json_list = "[\n" + ",\n".join(all_json_data) + "\n]"
138
-
139
  return combined_summary, combined_json_list, all_pdf_paths
140
 
141
-
142
  # Gradio interface
143
  with gr.Blocks(title="EvalBot Interview Analysis System", theme=gr.themes.Soft()) as demo:
144
  gr.Markdown("""
@@ -146,17 +132,15 @@ with gr.Blocks(title="EvalBot Interview Analysis System", theme=gr.themes.Soft()
146
  Provide multiple audio file URLs or upload multiple audio files to analyze speaker performance.
147
  Supported formats: WAV, MP3, M4A, FLAC (max 300MB per file).
148
  """)
149
-
150
  with gr.Row():
151
  with gr.Column():
152
  health_status = gr.Textbox(label="System Status", value=check_health(), interactive=False)
153
  audio_inputs = gr.File(
154
  label="Provide Audio URLs or Upload Files (Multiple allowed)",
155
- type="filepath", # هذا يسمح بـ URLs
156
- file_count="multiple" # السماح بأكثر من URL/ملف
157
  )
158
  submit_btn = gr.Button("Start Analysis", variant="primary")
159
-
160
  with gr.Column():
161
  output_summary = gr.Textbox(label="Combined Analysis Summary", interactive=False, lines=10)
162
  output_json = gr.Textbox(label="Detailed Analysis (JSON Array)", interactive=False, lines=20)
@@ -165,7 +149,8 @@ with gr.Blocks(title="EvalBot Interview Analysis System", theme=gr.themes.Soft()
165
  submit_btn.click(
166
  fn=analyze_multiple_audios,
167
  inputs=audio_inputs,
168
- outputs=[output_summary, output_json, pdf_outputs]
 
169
  )
170
 
171
  # Run the interface
 
13
  # Setup logging
14
  logging.basicConfig(
15
  level=logging.INFO,
16
+ format='%(asctime)s - %(name)s - %(levelname)s - %(message)s')
 
17
  logger = logging.getLogger(__name__)
18
  logging.getLogger("nemo_logging").setLevel(logging.ERROR)
19
  logging.getLogger("nemo").setLevel(logging.ERROR)
 
26
  VALID_EXTENSIONS = ('.wav', '.mp3', '.m4a', '.flac')
27
  MAX_FILE_SIZE = 300 * 1024 * 1024 # 300MB
28
 
 
29
  def check_health() -> str:
30
  """Check system health, similar to FastAPI /health endpoint"""
31
  try:
 
37
  logger.error(f"Health check failed: {str(e)}")
38
  return f"System is unhealthy: {str(e)}"
39
 
 
40
  # A helper function to process a single audio file
41
  def process_single_audio(file_path_or_url: str) -> Dict:
42
  """Processes a single audio file and returns its analysis."""
43
  try:
44
  if not file_path_or_url:
45
  return {"error": "No audio provided for processing."}
46
+
 
 
47
  temp_audio_path = Path(file_path_or_url)
 
48
  file_ext = temp_audio_path.suffix.lower()
49
+
50
  if file_ext not in VALID_EXTENSIONS:
51
  return {"error": f"Invalid file format: {file_ext}. Supported formats: {', '.join(VALID_EXTENSIONS)}"}
52
+
53
  file_size = os.path.getsize(temp_audio_path)
54
  if file_size > MAX_FILE_SIZE:
55
  return {
56
  "error": f"File too large: {file_size / (1024 * 1024):.2f}MB. Max size: {MAX_FILE_SIZE // (1024 * 1024)}MB"}
57
+
58
  logger.info(f"Processing audio from: {temp_audio_path}")
59
  result = process_interview(str(temp_audio_path))
60
+
61
  if not result or 'pdf_path' not in result or 'json_path' not in result:
62
  return {"error": "Processing failed - invalid result format."}
63
+
64
  pdf_path = Path(result['pdf_path'])
65
  json_path = Path(result['json_path'])
66
+
67
  if not pdf_path.exists() or not json_path.exists():
68
  return {"error": "Processing failed - output files not found."}
69
+
70
  with json_path.open('r') as f:
71
  analysis_data = json.load(f)
72
+
73
  voice_analysis = analysis_data.get('voice_analysis', {})
74
  summary = (
75
  f"Speakers: {', '.join(analysis_data['speakers'])}\n"
 
77
  f"Confidence Level: {voice_analysis.get('interpretation', {}).get('confidence_level', 'Unknown')}\n"
78
  f"Anxiety Level: {voice_analysis.get('interpretation', {}).get('anxiety_level', 'Unknown')}"
79
  )
 
80
  json_data = json.dumps(analysis_data, indent=2)
81
+
82
  return {
83
  "summary": summary,
84
  "json_data": json_data,
85
  "pdf_path": str(pdf_path),
86
+ "original_input": file_path_or_url
87
  }
 
88
  except Exception as e:
89
  logger.error(f"Error processing single audio: {str(e)}", exc_info=True)
90
  return {"error": f"Error during processing: {str(e)}"}
91
 
 
92
  # Main function to handle multiple audio files/URLs
93
  def analyze_multiple_audios(file_paths_or_urls: List[str]) -> Tuple[str, str, List[str]]:
94
  """
 
97
  """
98
  if not file_paths_or_urls:
99
  return "No audio files/URLs provided.", "[]", []
100
+
101
  all_summaries = []
102
  all_json_data = []
103
  all_pdf_paths = []
104
 
 
 
105
  with ThreadPoolExecutor(max_workers=5) as executor:
106
  futures = {executor.submit(process_single_audio, item): item for item in file_paths_or_urls}
 
107
  for future in futures:
108
+ item = futures[future]
109
  try:
110
+ result = future.result()
111
  if "error" in result:
112
  all_summaries.append(f"Error processing {item}: {result['error']}")
 
113
  all_json_data.append(json.dumps({"input": item, "error": result['error']}, indent=2))
114
  else:
115
  all_summaries.append(f"Analysis for {os.path.basename(item)}:\n{result['summary']}")
 
119
  logger.error(f"Item {item} generated an unexpected exception: {exc}", exc_info=True)
120
  all_summaries.append(f"Error processing {item}: An unexpected error occurred.")
121
  all_json_data.append(json.dumps({"input": item, "error": str(exc)}, indent=2))
122
+
123
  combined_summary = "\n\n---\n\n".join(all_summaries)
 
124
  combined_json_list = "[\n" + ",\n".join(all_json_data) + "\n]"
125
+
126
  return combined_summary, combined_json_list, all_pdf_paths
127
 
 
128
  # Gradio interface
129
  with gr.Blocks(title="EvalBot Interview Analysis System", theme=gr.themes.Soft()) as demo:
130
  gr.Markdown("""
 
132
  Provide multiple audio file URLs or upload multiple audio files to analyze speaker performance.
133
  Supported formats: WAV, MP3, M4A, FLAC (max 300MB per file).
134
  """)
 
135
  with gr.Row():
136
  with gr.Column():
137
  health_status = gr.Textbox(label="System Status", value=check_health(), interactive=False)
138
  audio_inputs = gr.File(
139
  label="Provide Audio URLs or Upload Files (Multiple allowed)",
140
+ type="filepath",
141
+ file_count="multiple"
142
  )
143
  submit_btn = gr.Button("Start Analysis", variant="primary")
 
144
  with gr.Column():
145
  output_summary = gr.Textbox(label="Combined Analysis Summary", interactive=False, lines=10)
146
  output_json = gr.Textbox(label="Detailed Analysis (JSON Array)", interactive=False, lines=20)
 
149
  submit_btn.click(
150
  fn=analyze_multiple_audios,
151
  inputs=audio_inputs,
152
+ outputs=[output_summary, output_json, pdf_outputs],
153
+ api_name="analyze_multiple_audios" # <-- هذا هو السطر الجديد والمهم
154
  )
155
 
156
  # Run the interface