SreekarB commited on
Commit
61a4c2a
·
verified ·
1 Parent(s): acb95f3

Upload casl_analysis.py

Browse files
Files changed (1) hide show
  1. casl_analysis.py +579 -149
casl_analysis.py CHANGED
@@ -1,4 +1,4 @@
1
- import gradio as gr
2
  import boto3
3
  import json
4
  import pandas as pd
@@ -11,9 +11,31 @@ import pickle
11
  import csv
12
  from PIL import Image
13
  import io
14
- import PyPDF2
15
  import uuid
16
  from datetime import datetime
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  # Configure logging
19
  logging.basicConfig(level=logging.INFO)
@@ -25,10 +47,14 @@ AWS_ACCESS_KEY = os.getenv("AWS_ACCESS_KEY", "")
25
  AWS_SECRET_KEY = os.getenv("AWS_SECRET_KEY", "")
26
  AWS_REGION = os.getenv("AWS_REGION", "us-east-1")
27
 
28
- # Initialize Bedrock client if credentials are available
29
  bedrock_client = None
 
 
 
30
  if AWS_ACCESS_KEY and AWS_SECRET_KEY:
31
  try:
 
32
  bedrock_client = boto3.client(
33
  'bedrock-runtime',
34
  aws_access_key_id=AWS_ACCESS_KEY,
@@ -36,8 +62,30 @@ if AWS_ACCESS_KEY and AWS_SECRET_KEY:
36
  region_name=AWS_REGION
37
  )
38
  logger.info("Bedrock client initialized successfully")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  except Exception as e:
40
- logger.error(f"Failed to initialize Bedrock client: {str(e)}")
 
 
 
 
41
 
42
  # Sample transcript for the demo
43
  SAMPLE_TRANSCRIPT = """*PAR: today I would &-um like to talk about &-um a fun trip I took last &-um summer with my family.
@@ -60,23 +108,38 @@ SAMPLE_TRANSCRIPT = """*PAR: today I would &-um like to talk about &-um a fun tr
60
  # ===============================
61
 
62
  # Create data directories if they don't exist
63
- DATA_DIR = "patient_data"
64
  RECORDS_FILE = os.path.join(DATA_DIR, "patient_records.csv")
65
  ANALYSES_DIR = os.path.join(DATA_DIR, "analyses")
 
 
66
 
67
  def ensure_data_dirs():
68
  """Ensure data directories exist"""
69
- os.makedirs(DATA_DIR, exist_ok=True)
70
- os.makedirs(ANALYSES_DIR, exist_ok=True)
71
-
72
- # Create records file if it doesn't exist
73
- if not os.path.exists(RECORDS_FILE):
74
- with open(RECORDS_FILE, 'w', newline='') as f:
75
- writer = csv.writer(f)
76
- writer.writerow([
77
- "ID", "Name", "Record ID", "Age", "Gender",
78
- "Assessment Date", "Clinician", "Analysis Date", "File Path"
79
- ])
 
 
 
 
 
 
 
 
 
 
 
 
 
80
 
81
  # Initialize data directories
82
  ensure_data_dirs()
@@ -278,6 +341,9 @@ def delete_patient_record(record_id):
278
 
279
  def read_pdf(file_path):
280
  """Read text from a PDF file"""
 
 
 
281
  try:
282
  with open(file_path, 'rb') as file:
283
  pdf_reader = PyPDF2.PdfReader(file)
@@ -318,7 +384,10 @@ def process_upload(file):
318
 
319
  file_path = file.name
320
  if file_path.endswith('.pdf'):
321
- return read_pdf(file_path)
 
 
 
322
  elif file_path.endswith('.cha'):
323
  return read_cha_file(file_path)
324
  else:
@@ -424,10 +493,15 @@ def generate_demo_response(prompt):
424
 
425
  return response
426
 
427
- def generate_demo_transcription(audio_path):
428
  """Generate a simulated transcription response"""
429
- # In a real app, this would process an audio file
430
- return "*PAR: today I want to tell you about my favorite toy.\n*PAR: it's a &-um teddy bear that I got for my birthday.\n*PAR: he has &-um brown fur and a red bow.\n*PAR: I like to sleep with him every night.\n*PAR: sometimes I take him to school in my backpack."
 
 
 
 
 
431
 
432
  def generate_demo_qa_response(question):
433
  """Generate a simulated Q&A response"""
@@ -877,109 +951,302 @@ def analyze_transcript(transcript, age, gender):
877
 
878
  # Instructions for the LLM analysis
879
  instructions = """
880
- You are a speech pathologist analyzing this transcription sample. Provide a detailed analysis focused on specific quotes from the transcript.
881
-
882
- The factors of speech that you need to count are:
883
-
884
- 1. Difficulty producing fluent, grammatical speech - speech that is slow, halting, with pauses while searching for words
885
- 2. Word retrieval issues - trouble thinking of specific words, use of filler words like um, circumlocution, semantically similar word substitutions
886
- 3. Grammatical errors - missing/incorrect function words, problems with verb tenses, conjugation, agreement, simplified sentences
887
- 4. Repetitions and revisions - repeating or restating words, phrases or sentences due to trouble finding the right words
888
- 5. Neologisms - creating nonexistent "new" words
889
- 6. Perseveration - unintentionally repeating words or phrases over and over
890
- 7. Comprehension issues - trouble understanding complex sentences, fast speech, relying more on context and cues
891
-
892
- For each factor, provide:
893
- - Number of occurrences
894
- - Severity percentile (estimate based on your clinical judgment)
895
- - At least 2-3 specific quotes from the transcript as examples
896
-
897
- Then evaluate using the CASL-2 Speech and Language Analysis Framework across these domains:
898
-
899
- 1. Lexical/Semantic Skills:
900
- - Assess vocabulary diversity, word-finding abilities, semantic precision
901
- - Provide Standard Score (mean=100, SD=15), percentile rank, and performance level
902
- - Include SPECIFIC QUOTES as evidence
903
 
904
- 2. Syntactic Skills:
905
- - Evaluate grammatical accuracy, sentence complexity, morphological skills
906
- - Provide Standard Score, percentile rank, and performance level
907
- - Include SPECIFIC QUOTES as evidence
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
908
 
909
- 3. Supralinguistic Skills:
910
- - Assess figurative language use, inferencing, and abstract reasoning
911
- - Provide Standard Score, percentile rank, and performance level
912
- - Include SPECIFIC QUOTES as evidence
913
-
914
- YOUR RESPONSE MUST USE THESE EXACT SECTION MARKERS FOR PARSING:
915
-
916
- <SPEECH_FACTORS_START>
917
- Difficulty producing fluent, grammatical speech: (occurrences), (percentile)
918
- Examples:
919
- - "(direct quote from transcript)"
920
- - "(direct quote from transcript)"
921
-
922
- Word retrieval issues: (occurrences), (percentile)
923
- Examples:
924
- - "(direct quote from transcript)"
925
- - "(direct quote from transcript)"
926
-
927
- (And so on for each factor)
928
- <SPEECH_FACTORS_END>
929
-
930
- <CASL_SKILLS_START>
931
- Lexical/Semantic Skills: Standard Score (X), Percentile Rank (X%), Performance Level
932
- Examples:
933
- - "(direct quote showing strength or weakness)"
934
- - "(direct quote showing strength or weakness)"
935
-
936
- Syntactic Skills: Standard Score (X), Percentile Rank (X%), Performance Level
937
- Examples:
938
- - "(direct quote showing strength or weakness)"
939
- - "(direct quote showing strength or weakness)"
940
-
941
- Supralinguistic Skills: Standard Score (X), Percentile Rank (X%), Performance Level
942
- Examples:
943
- - "(direct quote showing strength or weakness)"
944
- - "(direct quote showing strength or weakness)"
945
- <CASL_SKILLS_END>
946
-
947
- <TREATMENT_RECOMMENDATIONS_START>
948
- - (treatment recommendation)
949
- - (treatment recommendation)
950
- - (treatment recommendation)
951
- <TREATMENT_RECOMMENDATIONS_END>
952
-
953
- <EXPLANATION_START>
954
- (brief diagnostic rationale based on findings)
955
- <EXPLANATION_END>
956
-
957
- <ADDITIONAL_ANALYSIS_START>
958
- (specific insights that would be helpful for treatment planning)
959
- <ADDITIONAL_ANALYSIS_END>
960
-
961
- <DIAGNOSTIC_IMPRESSIONS_START>
962
- (summarize findings across domains using specific examples and clear explanations)
963
- <DIAGNOSTIC_IMPRESSIONS_END>
964
-
965
- <ERROR_EXAMPLES_START>
966
- (Copy all the specific quote examples here again, organized by error type or skill domain)
967
- <ERROR_EXAMPLES_END>
968
-
969
- MOST IMPORTANT:
970
- 1. Use EXACTLY the section markers provided (like <SPEECH_FACTORS_START>) to make parsing reliable
971
- 2. For EVERY factor and domain you analyze, you MUST provide direct quotes from the transcript as evidence
972
- 3. Be very specific and cite the exact text
973
- 4. Do not omit any of the required sections
974
- """
975
-
976
- # Prepare prompt for Claude with the user's role context
977
- role_context = """
978
- You are a speech pathologist, a healthcare professional who specializes in evaluating, diagnosing, and treating communication disorders, including speech, language, cognitive-communication, voice, swallowing, and fluency disorders. Your role is to help patients improve their speech and communication skills through various therapeutic techniques and exercises.
979
-
980
- You are working with a student with speech impediments.
981
-
982
- The most important thing is that you stay kind to the child. Be constructive and helpful rather than critical.
983
  """
984
 
985
  prompt = f"""
@@ -1013,19 +1280,190 @@ def analyze_transcript(transcript, age, gender):
1013
  return results, plot_image, radar_image, response
1014
 
1015
 
1016
- def transcribe_audio(audio_path, patient_age):
1017
- """Transcribe an audio recording using CHAT format"""
1018
- # In a real implementation, this would use a speech-to-text service
1019
- # For demo purposes, we'll return a simulated transcription
1020
-
1021
- if bedrock_client:
1022
- # In a real implementation, you would process the audio file and send it to a transcription service
1023
- # Here we just simulate the result
1024
- transcription = generate_demo_transcription(audio_path)
1025
- else:
1026
- transcription = generate_demo_transcription(audio_path)
1027
-
1028
- return transcription
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1029
 
1030
  def answer_slp_question(question):
1031
  """Answer a question about SLP practice or CASL assessment"""
@@ -1334,12 +1772,8 @@ def create_interface():
1334
  outputs=[patient_records_table, records_status]
1335
  )
1336
 
1337
- # Automatically load records when tab is selected
1338
- main_tabs.select(
1339
- lambda tab_id: refresh_patient_records() if tab_id == 1 else (pd.DataFrame(), ""),
1340
- inputs=[main_tabs],
1341
- outputs=[patient_records_table, records_status]
1342
- )
1343
 
1344
  # Load record when a row is selected
1345
  def handle_record_selection(evt: gr.SelectData, records):
@@ -1737,15 +2171,11 @@ def create_interface():
1737
 
1738
  # Improved PDF export functionality
1739
  def export_pdf(report_text, patient_name="Patient", record_id="", age="", gender="", assessment_date="", clinician=""):
 
 
 
 
1740
  try:
1741
- from reportlab.lib.pagesizes import letter
1742
- from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
1743
- from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
1744
- from reportlab.lib import colors
1745
- import tempfile
1746
- import webbrowser
1747
- import os
1748
- import shutil
1749
 
1750
  # Create a proper downloads directory in the app folder
1751
  downloads_dir = os.path.join(DATA_DIR, "downloads")
@@ -2060,4 +2490,4 @@ if __name__ == "__main__":
2060
 
2061
  # Launch the Gradio app
2062
  app = create_interface()
2063
- app.launch()
 
1
+ eimport gradio as gr
2
  import boto3
3
  import json
4
  import pandas as pd
 
11
  import csv
12
  from PIL import Image
13
  import io
 
14
  import uuid
15
  from datetime import datetime
16
+ import tempfile
17
+ import time
18
+
19
+ # Try to import ReportLab (needed for PDF generation)
20
+ try:
21
+ from reportlab.lib.pagesizes import letter
22
+ from reportlab.lib import colors
23
+ from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle
24
+ from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
25
+ REPORTLAB_AVAILABLE = True
26
+ except ImportError:
27
+ logger = logging.getLogger(__name__)
28
+ logger.warning("ReportLab library not available - PDF export will be disabled")
29
+ REPORTLAB_AVAILABLE = False
30
+
31
+ # Try to import PyPDF2 (needed for PDF reading)
32
+ try:
33
+ import PyPDF2
34
+ PYPDF2_AVAILABLE = True
35
+ except ImportError:
36
+ logger = logging.getLogger(__name__)
37
+ logger.warning("PyPDF2 library not available - PDF reading will be disabled")
38
+ PYPDF2_AVAILABLE = False
39
 
40
  # Configure logging
41
  logging.basicConfig(level=logging.INFO)
 
47
  AWS_SECRET_KEY = os.getenv("AWS_SECRET_KEY", "")
48
  AWS_REGION = os.getenv("AWS_REGION", "us-east-1")
49
 
50
+ # Initialize AWS clients if credentials are available
51
  bedrock_client = None
52
+ transcribe_client = None
53
+ s3_client = None
54
+
55
  if AWS_ACCESS_KEY and AWS_SECRET_KEY:
56
  try:
57
+ # Initialize Bedrock client for AI analysis
58
  bedrock_client = boto3.client(
59
  'bedrock-runtime',
60
  aws_access_key_id=AWS_ACCESS_KEY,
 
62
  region_name=AWS_REGION
63
  )
64
  logger.info("Bedrock client initialized successfully")
65
+
66
+ # Initialize Transcribe client for speech-to-text
67
+ transcribe_client = boto3.client(
68
+ 'transcribe',
69
+ aws_access_key_id=AWS_ACCESS_KEY,
70
+ aws_secret_access_key=AWS_SECRET_KEY,
71
+ region_name=AWS_REGION
72
+ )
73
+ logger.info("Transcribe client initialized successfully")
74
+
75
+ # Initialize S3 client for storing audio files
76
+ s3_client = boto3.client(
77
+ 's3',
78
+ aws_access_key_id=AWS_ACCESS_KEY,
79
+ aws_secret_access_key=AWS_SECRET_KEY,
80
+ region_name=AWS_REGION
81
+ )
82
+ logger.info("S3 client initialized successfully")
83
  except Exception as e:
84
+ logger.error(f"Failed to initialize AWS clients: {str(e)}")
85
+
86
+ # S3 bucket for storing audio files
87
+ S3_BUCKET = os.environ.get("S3_BUCKET", "casl-audio-files")
88
+ S3_PREFIX = "transcribe-audio/"
89
 
90
  # Sample transcript for the demo
91
  SAMPLE_TRANSCRIPT = """*PAR: today I would &-um like to talk about &-um a fun trip I took last &-um summer with my family.
 
108
  # ===============================
109
 
110
  # Create data directories if they don't exist
111
+ DATA_DIR = os.environ.get("DATA_DIR", "patient_data")
112
  RECORDS_FILE = os.path.join(DATA_DIR, "patient_records.csv")
113
  ANALYSES_DIR = os.path.join(DATA_DIR, "analyses")
114
+ DOWNLOADS_DIR = os.path.join(DATA_DIR, "downloads")
115
+ AUDIO_DIR = os.path.join(DATA_DIR, "audio")
116
 
117
  def ensure_data_dirs():
118
  """Ensure data directories exist"""
119
+ global DOWNLOADS_DIR, AUDIO_DIR
120
+ try:
121
+ os.makedirs(DATA_DIR, exist_ok=True)
122
+ os.makedirs(ANALYSES_DIR, exist_ok=True)
123
+ os.makedirs(DOWNLOADS_DIR, exist_ok=True)
124
+ os.makedirs(AUDIO_DIR, exist_ok=True)
125
+ logger.info(f"Data directories created: {DATA_DIR}, {ANALYSES_DIR}, {DOWNLOADS_DIR}, {AUDIO_DIR}")
126
+
127
+ # Create records file if it doesn't exist
128
+ if not os.path.exists(RECORDS_FILE):
129
+ with open(RECORDS_FILE, 'w', newline='') as f:
130
+ writer = csv.writer(f)
131
+ writer.writerow([
132
+ "ID", "Name", "Record ID", "Age", "Gender",
133
+ "Assessment Date", "Clinician", "Analysis Date", "File Path"
134
+ ])
135
+ except Exception as e:
136
+ logger.warning(f"Could not create data directories: {str(e)}")
137
+ # Fallback to tmp directory on HF Spaces
138
+ DOWNLOADS_DIR = os.path.join(tempfile.gettempdir(), "casl_downloads")
139
+ AUDIO_DIR = os.path.join(tempfile.gettempdir(), "casl_audio")
140
+ os.makedirs(DOWNLOADS_DIR, exist_ok=True)
141
+ os.makedirs(AUDIO_DIR, exist_ok=True)
142
+ logger.info(f"Using fallback directories: {DOWNLOADS_DIR}, {AUDIO_DIR}")
143
 
144
  # Initialize data directories
145
  ensure_data_dirs()
 
341
 
342
  def read_pdf(file_path):
343
  """Read text from a PDF file"""
344
+ if not PYPDF2_AVAILABLE:
345
+ return "Error: PDF reading is not available - PyPDF2 library is not installed"
346
+
347
  try:
348
  with open(file_path, 'rb') as file:
349
  pdf_reader = PyPDF2.PdfReader(file)
 
384
 
385
  file_path = file.name
386
  if file_path.endswith('.pdf'):
387
+ if PYPDF2_AVAILABLE:
388
+ return read_pdf(file_path)
389
+ else:
390
+ return "Error: PDF reading is disabled - PyPDF2 library is not installed"
391
  elif file_path.endswith('.cha'):
392
  return read_cha_file(file_path)
393
  else:
 
493
 
494
  return response
495
 
496
+ def generate_demo_transcription():
497
  """Generate a simulated transcription response"""
498
+ return """*PAR: today I want to tell you about my favorite toy.
499
+ *PAR: it's a &-um teddy bear that I got for my birthday.
500
+ *PAR: he has &-um brown fur and a red bow.
501
+ *PAR: I like to sleep with him every night.
502
+ *PAR: sometimes I take him to school in my backpack.
503
+ *INV: what's your teddy bear's name?
504
+ *PAR: his name is &-um Brownie because he's brown."""
505
 
506
  def generate_demo_qa_response(question):
507
  """Generate a simulated Q&A response"""
 
951
 
952
  # Instructions for the LLM analysis
953
  instructions = """
954
+ Advanced Linguistic Analysis Protocol for Adolescent Language Samples (Ages 14-18)
955
+ You are a highly specialized assistant supporting speech-language pathologists in conducting comprehensive linguistic analyses of adolescent language samples. Your analysis must adhere to evidence-based practice standards for secondary-level language assessment while producing results that inform both clinical decision-making and family understanding.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
956
 
957
+ Initial Sample Assessment
958
+ 1. Document sample metadata:
959
+ * Total number of utterances
960
+ * Sample collection context (conversational, narrative, expository, persuasive, procedural)
961
+ * Sample elicitation method (if indicated)
962
+ * Total duration/length of interaction
963
+ * Any transcription conventions used (e.g., SALT, CHAT)
964
+ 2. Determine analysis approach:
965
+ * For samples with ≤50 utterances: Perform complete analysis on all utterances
966
+ * For samples >50 utterances: Perform complete analysis, then select 50 representative utterances that capture key patterns across all linguistic domains while maintaining the natural distribution of features
967
+ Utterance-Level Microanalysis
968
+ For each utterance, provide detailed linguistic breakdown including:
969
+ 1. Structural Components
970
+ * Utterance number and full text (verbatim)
971
+ * Word count (excluding fillers, false starts, and repetitions)
972
+ * C-unit segmentation (when applicable)
973
+ * MLU in words and morphemes
974
+ * Syntactic classification:
975
+ * Simple, compound, complex, or compound-complex
976
+ * Complete or fragmentary
977
+ * Declarative, interrogative, imperative, or exclamatory
978
+ * Clausal density (number of clauses/utterance)
979
+ 2. Syntactic Analysis
980
+ * Constituent structure identification:
981
+ * Subject and predicate components
982
+ * Noun phrases (including pre- and post-modification)
983
+ * Verb phrases (including auxiliaries, complements)
984
+ * Adverbial phrases and clauses (including position and function)
985
+ * Prepositional phrases (including syntactic role)
986
+ * Subordinate clauses (including type and function)
987
+ * Embedding depth and recursion patterns
988
+ * Syntactic movement and transformations
989
+ * Non-canonical structures (passives, clefts, etc.)
990
+ 3. Morphological Analysis
991
+ * Bound morpheme usage (inflectional and derivational)
992
+ * Tense marking consistency
993
+ * Agreement patterns (subject-verb, pronoun-antecedent)
994
+ * Morphological errors with classification
995
+ 4. Error Analysis (for each identified error)
996
+ * Precise error location:
997
+ * Utterance number and full quotation
998
+ * Position within utterance (initial, medial, final)
999
+ * Syntactic position (e.g., main clause, subordinate clause, noun phrase)
1000
+ * Proximity to other linguistic features (e.g., complex vocabulary, disfluencies)
1001
+ * Error type classification:
1002
+ * Morphosyntactic (agreement, tense, etc.)
1003
+ * Lexical-semantic (word selection, collocational)
1004
+ * Phonological (if transcribed)
1005
+ * Pragmatic (if contextually inappropriate)
1006
+ * Error pattern (developmental vs. atypical)
1007
+ * Clinical significance of location:
1008
+ * Relationship to sentence complexity (errors increasing with complexity)
1009
+ * Patterns related to linguistic context (e.g., errors occurring after disfluencies)
1010
+ * Consistency across similar syntactic environments
1011
+ * Relationship to cognitive load (e.g., errors increasing in dense information units)
1012
+ * Error frequency and distribution across contexts
1013
+ * Self-correction attempts and success rate
1014
+ 5. Fluency Markers
1015
+ * Mazes (false starts, repetitions, reformulations)
1016
+ * Filled pauses (um, uh, like, etc.)
1017
+ * Silent pauses (duration if indicated)
1018
+ * Disruption patterns and positions
1019
+ * Impact on communicative effectiveness
1020
+ QUANTITATIVE ANALYSIS & METRICS
1021
+ Calculate the following evidence-based metrics with interpretations relevant to adolescent language development:
1022
+ Productivity Measures
1023
+ 1. Total Output Measures
1024
+ * Total number of words (TNW)
1025
+ * Total number of utterances (TNU)
1026
+ * Total number of different words (TDW)
1027
+ * Total communication units (T-units/C-units)
1028
+ 2. Length Measures
1029
+ * Mean length of utterance in words (MLU-w)
1030
+ * Mean length of utterance in morphemes (MLU-m)
1031
+ * Mean length of C-unit (MLCU)
1032
+ * Words per minute (if timing available)
1033
+ Complexity Measures
1034
+ 1. Syntactic Complexity
1035
+ * Clausal density (clauses per C-unit)
1036
+ * Subordination index (SI)
1037
+ * Coordination index
1038
+ * Embedding depth (max levels of embedding)
1039
+ * T-unit complexity ratio
1040
+ * Percentage of complex sentences
1041
+ 2. Phrase-Level Complexity
1042
+ * Mean noun phrase length
1043
+ * Mean verb phrase complexity
1044
+ * Prepositional phrase frequency
1045
+ * Adverbial complexity
1046
+ Accuracy Measures
1047
+ 1. Error Analysis Summary
1048
+ * Percentage of grammatically correct utterances
1049
+ * Errors per C-unit
1050
+ * Error pattern distribution (morphological, syntactic, lexical)
1051
+ * Most frequent error types with specific examples
1052
+ * Error location patterns:
1053
+ * Distribution across utterance positions (initial, medial, final)
1054
+ * Distribution across syntactic structures (simple vs. complex)
1055
+ * Correlation with utterance length and complexity
1056
+ * Patterns related to information density or processing demands
1057
+ * Clinical significance of error locations:
1058
+ * Interpretation of position-specific error patterns
1059
+ * Analysis of syntactic contexts where errors predominate
1060
+ * Relationship between error location and communicative impact
1061
+ Lexical Diversity & Sophistication
1062
+ 1. Vocabulary Metrics
1063
+ * Type-token ratio (TTR)
1064
+ * Moving-average type-token ratio (MATTR)
1065
+ * Number of different words (NDW)
1066
+ * Vocabulary diversity (D)
1067
+ * Lexical density (content words/total words)
1068
+ 2. Lexical Sophistication
1069
+ * Low-frequency word usage
1070
+ * Academic vocabulary presence
1071
+ * Abstract word usage
1072
+ * Word specificity analysis
1073
+ Fluency & Formulation Measures
1074
+ 1. Disruption Analysis
1075
+ * Percentage of mazes
1076
+ * Total maze words/total words
1077
+ * Revisions per utterance
1078
+ * Hesitation frequency
1079
+ * Incomplete utterance percentage
1080
+ * Word-finding difficulties (frequency and patterns)
1081
+ CASL-2 DOMAIN ALIGNMENT
1082
+ Analyze the sample according to the Comprehensive Assessment of Spoken Language (CASL-2) framework, providing detailed evidence for each domain:
1083
+ 1. Lexical/Semantic Domain
1084
+ * Vocabulary Range Assessment
1085
+ * Basic vs. precise vocabulary usage
1086
+ * Abstract vs. concrete terminology
1087
+ * Academic language presence
1088
+ * Subject-specific terminology
1089
+ * Register-appropriate lexicon
1090
+ * Word Relationships
1091
+ * Synonym/antonym usage
1092
+ * Categorical relationships
1093
+ * Part-whole relationships
1094
+ * Semantic networks
1095
+ * Word Retrieval Patterns
1096
+ * Word-finding hesitations
1097
+ * Circumlocutions
1098
+ * Semantic substitutions
1099
+ * Retrieval strategies
1100
+ * Evidence Summary
1101
+ * Provide specific examples from transcript
1102
+ * Compare to age-appropriate expectations
1103
+ * Estimate standard score range (using clinical judgment)
1104
+ * Indicate percentile rank range
1105
+ * Assign performance level category
1106
+ 2. Syntactic Domain
1107
+ * Sentence Structure Analysis
1108
+ * Distribution of sentence types
1109
+ * Complex syntax usage patterns
1110
+ * Syntactic versatility
1111
+ * Age-appropriate structures
1112
+ * Morphosyntactic Elements
1113
+ * Regular and irregular morphology
1114
+ * Verb tense system mastery
1115
+ * Complex verb forms (perfect, progressive)
1116
+ * Advanced agreement patterns
1117
+ * Syntactic Maturity Indicators
1118
+ * Clause combining strategies
1119
+ * Embedding types and frequency
1120
+ * Noun phrase elaboration
1121
+ * Adverbial complexity
1122
+ * Evidence Summary
1123
+ * Provide specific examples from transcript
1124
+ * Compare to age-appropriate expectations
1125
+ * Estimate standard score range
1126
+ * Indicate percentile rank range
1127
+ * Assign performance level category
1128
+ 3. Supralinguistic Domain
1129
+ * Figurative Language
1130
+ * Idiomatic expressions
1131
+ * Metaphors and analogies
1132
+ * Humor or wordplay
1133
+ * Understanding of non-literal content
1134
+ * Higher-Order Reasoning
1135
+ * Inferential language
1136
+ * Ambiguity recognition
1137
+ * Abstract concept expression
1138
+ * Perspective-taking indicators
1139
+ * Metalinguistic Awareness
1140
+ * Self-monitoring
1141
+ * Linguistic reflection
1142
+ * Awareness of language rules
1143
+ * Metacognitive comments
1144
+ * Evidence Summary
1145
+ * Provide specific examples from transcript
1146
+ * Note limitations of assessment from sample
1147
+ * Estimate standard score range (if sufficient evidence)
1148
+ * Indicate percentile rank range (if applicable)
1149
+ * Assign performance level category (or note insufficient evidence)
1150
+ 4. Pragmatic Domain
1151
+ * Discourse Management
1152
+ * Topic initiation, maintenance, and change
1153
+ * Turn-taking patterns
1154
+ * Response contingency
1155
+ * Conversational repair strategies
1156
+ * Social Communication
1157
+ * Perspective-taking
1158
+ * Register variation
1159
+ * Politeness conventions
1160
+ * Social inferencing
1161
+ * Narrative/Expository Skills (if applicable)
1162
+ * Coherence and cohesion
1163
+ * Organizational structure
1164
+ * Use of cohesive devices
1165
+ * Information density
1166
+ * Evidence Summary
1167
+ * Provide specific examples from transcript
1168
+ * Note contextual limitations
1169
+ * Estimate standard score range (if sufficient evidence)
1170
+ * Indicate percentile rank range (if applicable)
1171
+ * Assign performance level category (or note insufficient evidence)
1172
+ DEVELOPMENTAL PROFILE ANALYSIS
1173
+ Compare observed language features to established adolescent language development patterns:
1174
+ 1. Age-Based Comparison
1175
+ * Alignment with typical syntactic development (14-18)
1176
+ * Lexical development expectations
1177
+ * Discourse maturity indicators
1178
+ * Academic language benchmarks
1179
+ 2. Strength-Challenge Pattern Analysis
1180
+ * Identify domains of relative strength with evidence
1181
+ * Identify domains requiring support with evidence
1182
+ * Note any asynchronous development patterns
1183
+ * Document compensatory strategies observed
1184
+ 3. Developmental Trajectory Indicators
1185
+ * Features suggesting typical development
1186
+ * Features suggesting delayed development
1187
+ * Features suggesting disordered development
1188
+ * Features suggesting language difference vs. disorder
1189
+ COMPREHENSIVE REPORTING FORMAT
1190
+ 1. Professional Clinical Summary (SLP-Oriented)
1191
+ * Sample characteristics and analysis methodology
1192
+ * Key quantitative findings table with age-based interpretation
1193
+ * CASL-2 domain profiles with evidence-based rationales
1194
+ * Error pattern analysis with clinical implications
1195
+ * Identified strengths and challenges
1196
+ * Differential considerations
1197
+ * Recommendations for further assessment
1198
+ * Potential treatment targets based on evidence
1199
+ 2. Family-Friendly Summary Report
1200
+ * Introduction
1201
+ * Purpose of language sample analysis
1202
+ * Brief explanation of what was analyzed
1203
+ * How this information helps understand communication
1204
+ * Your Adolescent's Language Profile
1205
+ * Overall communication strengths (with clear examples)
1206
+ * Areas for continued growth (with supportive examples)
1207
+ * How these patterns may impact academic and social communication
1208
+ * Understanding the Assessment
1209
+ * Simple explanations of key findings
1210
+ * Comparison to typical adolescent language patterns
1211
+ * Visual representation of language profile
1212
+ * Accessible examples from the transcript
1213
+ * Supporting Language Development
1214
+ * Practical strategies aligned with findings
1215
+ * Communication opportunities that leverage strengths
1216
+ * Questions to discuss with the SLP
1217
+ * Resources for family understanding
1218
+ * Next Steps
1219
+ * Connections to academic and social communication
1220
+ * Relevance to current educational goals
1221
+ * Partnership opportunities between home and therapy
1222
+ 3. Educational Implications (if requested)
1223
+ * Connections to academic standards
1224
+ * Impact on classroom participation
1225
+ * Alignment with IEP goals (if applicable)
1226
+ * Recommendations for classroom support
1227
+ IMPLEMENTATION GUIDELINES
1228
+ 1. Analysis Integrity
1229
+ * Analyze only what is directly observable in the transcript
1230
+ * Clearly differentiate observations from interpretations
1231
+ * Note when certain domains cannot be adequately assessed
1232
+ * Document analysis limitations based on sample constraints
1233
+ 2. Clinical Reasoning
1234
+ * Apply evidence-based standards for adolescent language
1235
+ * Consider developmental appropriateness for ages 14-18
1236
+ * Document patterns rather than isolated instances
1237
+ * Provide context for interpretations
1238
+ 3. Reporting Ethics
1239
+ * Use person-first, strength-based language
1240
+ * Avoid definitive diagnostic statements
1241
+ * Focus on functional communication impact
1242
+ * Maintain appropriate scope of analysis
1243
+ 4. Flexibility Adaptations
1244
+ * For different discourse types (narrative, expository, conversational)
1245
+ * For different cultural and linguistic backgrounds
1246
+ * For various academic and social contexts
1247
+ * For potential co-occurring conditions
1248
+ This protocol produces a comprehensive linguistic analysis tailored to adolescents (14-18) that provides both clinically relevant information and family-accessible insights while maintaining the flexibility to adapt to various sample types and contexts.
1249
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1250
  """
1251
 
1252
  prompt = f"""
 
1280
  return results, plot_image, radar_image, response
1281
 
1282
 
1283
+ def transcribe_audio(audio_path, patient_age=8):
1284
+ """Transcribe an audio recording using Amazon Transcribe and format in CHAT format"""
1285
+ if not os.path.exists(audio_path):
1286
+ logger.error(f"Audio file not found: {audio_path}")
1287
+ return "Error: Audio file not found."
1288
+
1289
+ if not transcribe_client or not s3_client:
1290
+ logger.warning("AWS clients not initialized, using demo transcription")
1291
+ return generate_demo_transcription()
1292
+
1293
+ try:
1294
+ # Get file info
1295
+ file_name = os.path.basename(audio_path)
1296
+ file_size = os.path.getsize(audio_path)
1297
+ _, file_extension = os.path.splitext(file_name)
1298
+
1299
+ # Check file format
1300
+ supported_formats = ['.mp3', '.mp4', '.wav', '.flac', '.ogg', '.amr', '.webm']
1301
+ if file_extension.lower() not in supported_formats:
1302
+ logger.error(f"Unsupported audio format: {file_extension}")
1303
+ return f"Error: Unsupported audio format. Please use one of: {', '.join(supported_formats)}"
1304
+
1305
+ # Generate a unique job name
1306
+ timestamp = datetime.now().strftime('%Y%m%d%H%M%S')
1307
+ job_name = f"casl-transcription-{timestamp}"
1308
+ s3_key = f"{S3_PREFIX}{job_name}{file_extension}"
1309
+
1310
+ # Upload to S3
1311
+ logger.info(f"Uploading {file_name} to S3 bucket {S3_BUCKET}")
1312
+ try:
1313
+ with open(audio_path, 'rb') as audio_file:
1314
+ s3_client.upload_fileobj(audio_file, S3_BUCKET, s3_key)
1315
+ except Exception as e:
1316
+ logger.error(f"Failed to upload to S3: {str(e)}")
1317
+
1318
+ # If upload fails, try to create the bucket
1319
+ try:
1320
+ s3_client.create_bucket(Bucket=S3_BUCKET)
1321
+ logger.info(f"Created S3 bucket: {S3_BUCKET}")
1322
+
1323
+ # Try upload again
1324
+ with open(audio_path, 'rb') as audio_file:
1325
+ s3_client.upload_fileobj(audio_file, S3_BUCKET, s3_key)
1326
+ except Exception as bucket_error:
1327
+ logger.error(f"Failed to create bucket and upload: {str(bucket_error)}")
1328
+ return "Error: Failed to upload audio file. Please check your AWS permissions."
1329
+
1330
+ # Start transcription job
1331
+ logger.info(f"Starting transcription job: {job_name}")
1332
+ media_format = file_extension.lower()[1:] # Remove the dot
1333
+ if media_format == 'webm':
1334
+ media_format = 'webm' # Amazon Transcribe expects this
1335
+
1336
+ # Determine language settings based on patient age
1337
+ if patient_age < 10:
1338
+ # For younger children, enabling child language model is helpful
1339
+ language_options = {
1340
+ 'LanguageCode': 'en-US',
1341
+ 'Settings': {
1342
+ 'ShowSpeakerLabels': True,
1343
+ 'MaxSpeakerLabels': 2 # Typically patient + clinician
1344
+ }
1345
+ }
1346
+ else:
1347
+ language_options = {
1348
+ 'LanguageCode': 'en-US',
1349
+ 'Settings': {
1350
+ 'ShowSpeakerLabels': True,
1351
+ 'MaxSpeakerLabels': 2 # Typically patient + clinician
1352
+ }
1353
+ }
1354
+
1355
+ transcribe_client.start_transcription_job(
1356
+ TranscriptionJobName=job_name,
1357
+ Media={
1358
+ 'MediaFileUri': f"s3://{S3_BUCKET}/{s3_key}"
1359
+ },
1360
+ MediaFormat=media_format,
1361
+ **language_options
1362
+ )
1363
+
1364
+ # Wait for the job to complete (with timeout)
1365
+ logger.info("Waiting for transcription to complete...")
1366
+ max_tries = 30 # 5 minutes max wait
1367
+ tries = 0
1368
+
1369
+ while tries < max_tries:
1370
+ try:
1371
+ job = transcribe_client.get_transcription_job(TranscriptionJobName=job_name)
1372
+ status = job['TranscriptionJob']['TranscriptionJobStatus']
1373
+
1374
+ if status == 'COMPLETED':
1375
+ # Get the transcript
1376
+ transcript_uri = job['TranscriptionJob']['Transcript']['TranscriptFileUri']
1377
+
1378
+ # Download the transcript
1379
+ import urllib.request
1380
+ import json
1381
+
1382
+ with urllib.request.urlopen(transcript_uri) as response:
1383
+ transcript_json = json.loads(response.read().decode('utf-8'))
1384
+
1385
+ # Convert to CHAT format
1386
+ chat_transcript = format_as_chat(transcript_json)
1387
+ return chat_transcript
1388
+
1389
+ elif status == 'FAILED':
1390
+ reason = job['TranscriptionJob'].get('FailureReason', 'Unknown failure')
1391
+ logger.error(f"Transcription job failed: {reason}")
1392
+ return f"Error: Transcription failed - {reason}"
1393
+
1394
+ # Still in progress, wait and try again
1395
+ tries += 1
1396
+ time.sleep(10) # Check every 10 seconds
1397
+
1398
+ except Exception as e:
1399
+ logger.error(f"Error checking transcription job: {str(e)}")
1400
+ return f"Error getting transcription: {str(e)}"
1401
+
1402
+ # If we got here, we timed out
1403
+ return "Error: Transcription timed out. The process is taking longer than expected."
1404
+
1405
+ except Exception as e:
1406
+ logger.exception("Error in audio transcription")
1407
+ return f"Error transcribing audio: {str(e)}"
1408
+
1409
+ def format_as_chat(transcript_json):
1410
+ """Format the Amazon Transcribe JSON result as CHAT format"""
1411
+ try:
1412
+ # Get transcript items
1413
+ items = transcript_json['results']['items']
1414
+
1415
+ # Get speaker labels if available
1416
+ speakers = {}
1417
+ if 'speaker_labels' in transcript_json['results']:
1418
+ speaker_segments = transcript_json['results']['speaker_labels']['segments']
1419
+
1420
+ # Map each item to its speaker
1421
+ for segment in speaker_segments:
1422
+ for item in segment['items']:
1423
+ start_time = item['start_time']
1424
+ speakers[start_time] = segment['speaker_label']
1425
+
1426
+ # Build transcript by combining words into utterances by speaker
1427
+ current_speaker = None
1428
+ current_utterance = []
1429
+ utterances = []
1430
+
1431
+ for item in items:
1432
+ # Skip non-pronunciation items (like punctuation)
1433
+ if item['type'] != 'pronunciation':
1434
+ continue
1435
+
1436
+ word = item['alternatives'][0]['content']
1437
+ start_time = item.get('start_time')
1438
+
1439
+ # Determine speaker if available
1440
+ speaker = speakers.get(start_time, 'spk_0')
1441
+
1442
+ # If speaker changed, start a new utterance
1443
+ if speaker != current_speaker and current_utterance:
1444
+ utterances.append((current_speaker, ' '.join(current_utterance)))
1445
+ current_utterance = []
1446
+
1447
+ current_speaker = speaker
1448
+ current_utterance.append(word)
1449
+
1450
+ # Add the last utterance
1451
+ if current_utterance:
1452
+ utterances.append((current_speaker, ' '.join(current_utterance)))
1453
+
1454
+ # Format as CHAT
1455
+ chat_lines = []
1456
+ for speaker, text in utterances:
1457
+ # Map speakers to CHAT format
1458
+ # Assuming spk_0 is the patient (PAR) and spk_1 is the clinician (INV)
1459
+ chat_speaker = "*PAR:" if speaker == "spk_0" else "*INV:"
1460
+ chat_lines.append(f"{chat_speaker} {text}.")
1461
+
1462
+ return '\n'.join(chat_lines)
1463
+
1464
+ except Exception as e:
1465
+ logger.exception("Error formatting transcript")
1466
+ return "*PAR: (Error formatting transcript)"
1467
 
1468
  def answer_slp_question(question):
1469
  """Answer a question about SLP practice or CASL assessment"""
 
1772
  outputs=[patient_records_table, records_status]
1773
  )
1774
 
1775
+ # Note: The automatic tab selection event was removed because it's not supported in newer Gradio versions
1776
+ # Instead, we'll rely on the refresh button that's already in place
 
 
 
 
1777
 
1778
  # Load record when a row is selected
1779
  def handle_record_selection(evt: gr.SelectData, records):
 
2171
 
2172
  # Improved PDF export functionality
2173
  def export_pdf(report_text, patient_name="Patient", record_id="", age="", gender="", assessment_date="", clinician=""):
2174
+ # Check if ReportLab is available
2175
+ if not REPORTLAB_AVAILABLE:
2176
+ return "Error: ReportLab library is not installed. Please install it with 'pip install reportlab'."
2177
+
2178
  try:
 
 
 
 
 
 
 
 
2179
 
2180
  # Create a proper downloads directory in the app folder
2181
  downloads_dir = os.path.join(DATA_DIR, "downloads")
 
2490
 
2491
  # Launch the Gradio app
2492
  app = create_interface()
2493
+ app.launch()