File size: 16,952 Bytes
f5b302e
 
 
 
 
 
fa1bef5
 
 
 
 
 
 
 
 
 
 
 
 
f5b302e
deb6f27
fa1bef5
deb6f27
 
 
 
 
 
 
 
 
 
f5b302e
 
 
 
 
fa1bef5
 
f5b302e
 
 
 
 
 
 
 
 
 
 
deb6f27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f5b302e
 
 
 
 
 
 
 
 
 
 
 
deb6f27
f5b302e
 
deb6f27
 
 
 
 
 
 
 
 
 
 
 
 
f5b302e
 
 
 
 
deb6f27
 
f5b302e
deb6f27
f5b302e
deb6f27
fa1bef5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f5b302e
deb6f27
fa1bef5
 
 
deb6f27
 
f5b302e
deb6f27
 
f5b302e
fa1bef5
 
 
 
f5b302e
deb6f27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f5b302e
deb6f27
 
 
 
 
 
 
fa1bef5
deb6f27
 
 
 
 
 
 
fa1bef5
 
 
deb6f27
 
 
fa1bef5
f5b302e
 
 
 
deb6f27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
fa1bef5
 
 
 
 
 
 
 
 
 
deb6f27
 
 
 
f5b302e
 
 
deb6f27
f5b302e
deb6f27
 
 
 
f5b302e
 
deb6f27
 
 
 
 
 
f5b302e
 
 
 
 
 
 
 
 
 
 
deb6f27
f5b302e
 
 
 
deb6f27
 
f5b302e
deb6f27
 
 
 
 
 
 
 
 
f5b302e
 
deb6f27
 
 
 
 
 
 
 
 
 
 
f5b302e
 
 
 
deb6f27
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f5b302e
 
 
deb6f27
f5b302e
 
 
 
deb6f27
 
f5b302e
 
 
 
 
 
deb6f27
f5b302e
 
 
 
 
 
 
deb6f27
 
 
 
 
 
 
 
 
f5b302e
 
fa1bef5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f5b302e
deb6f27
f5b302e
fa1bef5
 
 
 
 
 
f5b302e
 
 
deb6f27
 
f5b302e
 
 
 
deb6f27
 
 
f5b302e
 
 
deb6f27
 
 
 
 
 
 
 
 
 
fa1bef5
 
 
 
 
deb6f27
f5b302e
deb6f27
f5b302e
deb6f27
f5b302e
 
fa1bef5
 
 
 
 
 
 
deb6f27
f5b302e
 
fa1bef5
 
 
 
 
 
 
 
f5b302e
 
 
7b20b20
 
 
 
 
 
f5b302e
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
import gradio as gr
import whisper
import tempfile
import os
from utils import SocialGraphManager, SuggestionGenerator

# Define available models
AVAILABLE_MODELS = {
    "distilgpt2": "DistilGPT2 (Fast, smaller model)",
    "gpt2": "GPT-2 (Medium size, better quality)",
    "google/gemma-3-1b-it": "Gemma 3 1B-IT (Small, instruction-tuned)",
    "Qwen/Qwen1.5-0.5B": "Qwen 1.5 0.5B (Very small, efficient)",
    "Qwen/Qwen1.5-1.8B": "Qwen 1.5 1.8B (Small, good quality)",
    "TinyLlama/TinyLlama-1.1B-Chat-v1.0": "TinyLlama 1.1B (Small, chat-tuned)",
    "microsoft/phi-3-mini-4k-instruct": "Phi-3 Mini (Small, instruction-tuned)",
    "microsoft/phi-2": "Phi-2 (Small, high quality for size)",
}

# Initialize the social graph manager
social_graph = SocialGraphManager("social_graph.json")

# Initialize the suggestion generator with distilgpt2 (default)
suggestion_generator = SuggestionGenerator("distilgpt2")

# Test the model to make sure it's working
test_result = suggestion_generator.test_model()
print(f"Model test result: {test_result}")

# If the model didn't load, use the fallback responses
if not suggestion_generator.model_loaded:
    print("Model failed to load, using fallback responses...")
    # The SuggestionGenerator class has built-in fallback responses

# Initialize Whisper model (using the smallest model for speed)
try:
    whisper_model = whisper.load_model("tiny")
    whisper_loaded = True
except Exception as e:
    print(f"Error loading Whisper model: {e}")
    whisper_loaded = False


def format_person_display(person):
    """Format person information for display in the dropdown."""
    return f"{person['name']} ({person['role']})"


def get_people_choices():
    """Get formatted choices for the people dropdown."""
    people = social_graph.get_people_list()
    choices = {}
    for person in people:
        display_name = format_person_display(person)
        person_id = person["id"]
        choices[display_name] = person_id
    return choices


def get_topics_for_person(person_id):
    """Get topics for a specific person."""
    if not person_id:
        return []

    person_context = social_graph.get_person_context(person_id)
    topics = person_context.get("topics", [])
    return topics


def get_suggestion_categories():
    """Get suggestion categories from the social graph."""
    if "common_utterances" in social_graph.graph:
        return list(social_graph.graph["common_utterances"].keys())
    return []


def on_person_change(person_id):
    """Handle person selection change."""
    if not person_id:
        return "", "", []

    person_context = social_graph.get_person_context(person_id)

    # Create a more user-friendly context display
    name = person_context.get("name", "")
    role = person_context.get("role", "")
    frequency = person_context.get("frequency", "")
    context_text = person_context.get("context", "")

    context_info = f"""### I'm talking to: {name}
**Relationship:** {role}
**How often we talk:** {frequency}

**Our relationship:** {context_text}
"""

    # Get common phrases for this person
    phrases = person_context.get("common_phrases", [])
    phrases_text = "\n\n".join(phrases)

    # Get topics for this person
    topics = person_context.get("topics", [])

    return context_info, phrases_text, topics


def change_model(model_name):
    """Change the language model used for generation.

    Args:
        model_name: The name of the model to use

    Returns:
        A status message about the model change
    """
    global suggestion_generator

    print(f"Changing model to: {model_name}")

    # Check if we need to change the model
    if model_name == suggestion_generator.model_name:
        return f"Already using model: {model_name}"

    # Try to load the new model
    success = suggestion_generator.load_model(model_name)

    if success:
        return f"Successfully switched to model: {model_name}"
    else:
        return f"Failed to load model: {model_name}. Using fallback responses instead."


def generate_suggestions(
    person_id,
    user_input,
    suggestion_type,
    selected_topic=None,
    model_name="distilgpt2",
    temperature=0.7,
):
    """Generate suggestions based on the selected person and user input."""
    print(
        f"Generating suggestions with: person_id={person_id}, user_input={user_input}, "
        f"suggestion_type={suggestion_type}, selected_topic={selected_topic}, "
        f"model={model_name}, temperature={temperature}"
    )

    if not person_id:
        print("No person_id provided")
        return "Please select who you're talking to first."

    # Make sure we're using the right model
    if model_name != suggestion_generator.model_name:
        change_model(model_name)

    person_context = social_graph.get_person_context(person_id)
    print(f"Person context: {person_context}")

    # Try to infer conversation type if user input is provided
    inferred_category = None
    if user_input and suggestion_type == "auto_detect":
        # Simple keyword matching for now - could be enhanced with ML
        user_input_lower = user_input.lower()
        if any(
            word in user_input_lower
            for word in ["hi", "hello", "morning", "afternoon", "evening"]
        ):
            inferred_category = "greetings"
        elif any(
            word in user_input_lower
            for word in ["feel", "tired", "happy", "sad", "frustrated"]
        ):
            inferred_category = "emotions"
        elif any(
            word in user_input_lower
            for word in ["need", "want", "help", "water", "toilet", "loo"]
        ):
            inferred_category = "needs"
        elif any(
            word in user_input_lower
            for word in ["what", "how", "when", "where", "why", "did"]
        ):
            inferred_category = "questions"
        elif any(
            word in user_input_lower
            for word in ["remember", "used to", "back then", "when we"]
        ):
            inferred_category = "reminiscing"
        elif any(
            word in user_input_lower
            for word in ["code", "program", "software", "app", "tech"]
        ):
            inferred_category = "tech_talk"
        elif any(
            word in user_input_lower
            for word in ["plan", "schedule", "appointment", "tomorrow", "later"]
        ):
            inferred_category = "organization"

    # Add topic to context if selected
    if selected_topic:
        person_context["selected_topic"] = selected_topic

    # Format the output with multiple suggestions
    result = ""

    # If suggestion type is "model", use the language model for multiple suggestions
    if suggestion_type == "model":
        print("Using model for suggestions")
        # Generate 3 different suggestions
        suggestions = []
        for i in range(3):
            print(f"Generating suggestion {i+1}/3")
            try:
                suggestion = suggestion_generator.generate_suggestion(
                    person_context, user_input, temperature=temperature
                )
                print(f"Generated suggestion: {suggestion}")
                suggestions.append(suggestion)
            except Exception as e:
                print(f"Error generating suggestion: {e}")
                suggestions.append("Error generating suggestion")

        result = (
            f"### AI-Generated Responses (using {suggestion_generator.model_name}):\n\n"
        )
        for i, suggestion in enumerate(suggestions, 1):
            result += f"{i}. {suggestion}\n\n"

        print(f"Final result: {result[:100]}...")

    # If suggestion type is "common_phrases", use the person's common phrases
    elif suggestion_type == "common_phrases":
        phrases = social_graph.get_relevant_phrases(person_id, user_input)
        result = "### My Common Phrases with this Person:\n\n"
        for i, phrase in enumerate(phrases, 1):
            result += f"{i}. {phrase}\n\n"

    # If suggestion type is "auto_detect", use the inferred category or default to model
    elif suggestion_type == "auto_detect":
        print(f"Auto-detect mode, inferred category: {inferred_category}")
        if inferred_category:
            utterances = social_graph.get_common_utterances(inferred_category)
            print(f"Got utterances for category {inferred_category}: {utterances}")
            result = f"### Auto-detected category: {inferred_category.replace('_', ' ').title()}\n\n"
            for i, utterance in enumerate(utterances, 1):
                result += f"{i}. {utterance}\n\n"
        else:
            print("No category inferred, falling back to model")
            # Fall back to model if we couldn't infer a category
            try:
                suggestions = []
                for i in range(3):
                    suggestion = suggestion_generator.generate_suggestion(
                        person_context, user_input, temperature=temperature
                    )
                    suggestions.append(suggestion)

                result = f"### AI-Generated Responses (no category detected, using {suggestion_generator.model_name}):\n\n"
                for i, suggestion in enumerate(suggestions, 1):
                    result += f"{i}. {suggestion}\n\n"
            except Exception as e:
                print(f"Error generating fallback suggestion: {e}")
                result = "### Could not generate a response:\n\n"
                result += "1. Sorry, I couldn't generate a suggestion at this time.\n\n"

    # If suggestion type is a category from common_utterances
    elif suggestion_type in get_suggestion_categories():
        print(f"Using category: {suggestion_type}")
        utterances = social_graph.get_common_utterances(suggestion_type)
        print(f"Got utterances: {utterances}")
        result = f"### {suggestion_type.replace('_', ' ').title()} Phrases:\n\n"
        for i, utterance in enumerate(utterances, 1):
            result += f"{i}. {utterance}\n\n"

    # Default fallback
    else:
        print(f"No handler for suggestion type: {suggestion_type}")
        result = "No suggestions available. Please try a different option."

    print(f"Returning result: {result[:100]}...")
    return result


def transcribe_audio(audio_path):
    """Transcribe audio using Whisper."""
    if not whisper_loaded:
        return "Whisper model not loaded. Please check your installation."

    try:
        # Transcribe the audio
        result = whisper_model.transcribe(audio_path)
        return result["text"]
    except Exception:
        return "Could not transcribe audio. Please try again."


# Create the Gradio interface
with gr.Blocks(title="Will's AAC Communication Aid") as demo:
    gr.Markdown("# Will's AAC Communication Aid")
    gr.Markdown(
        """
    This demo simulates an AAC system from Will's perspective (a 38-year-old with MND).

    **How to use this demo:**
    1. Select who you (Will) are talking to from the dropdown
    2. Optionally select a conversation topic
    3. Enter or record what the other person said to you
    4. Get suggested responses based on your relationship with that person
    """
    )

    # Display information about Will
    with gr.Accordion("About Me (Will)", open=False):
        gr.Markdown(
            """
        I'm Will, a 38-year-old computer programmer from Manchester with MND (diagnosed 5 months ago).
        I live with my wife Emma and two children (Mabel, 4 and Billy, 7).
        Originally from South East London, I enjoy technology, Manchester United, and have fond memories of cycling and hiking.
        I'm increasingly using this AAC system as my speech becomes more difficult.
        """
        )

    with gr.Row():
        with gr.Column(scale=1):
            # Person selection
            person_dropdown = gr.Dropdown(
                choices=get_people_choices(),
                label="I'm talking to:",
                info="Select who you (Will) are talking to",
            )

            # Get topics for the selected person
            def get_filtered_topics(person_id):
                if not person_id:
                    return []
                person_context = social_graph.get_person_context(person_id)
                return person_context.get("topics", [])

            # Topic selection dropdown
            topic_dropdown = gr.Dropdown(
                choices=[],  # Will be populated when a person is selected
                label="Topic (optional):",
                info="Select a topic relevant to this person",
                allow_custom_value=True,
            )

            # Context display
            context_display = gr.Markdown(label="Relationship Context")

            # User input section
            with gr.Row():
                user_input = gr.Textbox(
                    label="What they said to me:",
                    placeholder='Examples:\n"How was your physio session today?"\n"The kids are asking if you want to watch a movie tonight"\n"I\'ve been looking at that new AAC software you mentioned"',
                    lines=3,
                )

            # Audio input
            with gr.Row():
                audio_input = gr.Audio(
                    label="Or record what they said:",
                    type="filepath",
                    sources=["microphone"],
                )
                transcribe_btn = gr.Button("Transcribe", variant="secondary")

            # Suggestion type selection
            suggestion_type = gr.Radio(
                choices=[
                    "auto_detect",
                    "model",
                    "common_phrases",
                ]
                + get_suggestion_categories(),
                value="model",  # Default to model for better results
                label="How should I respond?",
                info="Choose what kind of responses you want (model = AI-generated)",
            )

            # Model selection
            with gr.Row():
                model_dropdown = gr.Dropdown(
                    choices=list(AVAILABLE_MODELS.keys()),
                    value="distilgpt2",
                    label="Language Model",
                    info="Select which AI model to use for generating responses",
                )

                temperature_slider = gr.Slider(
                    minimum=0.1,
                    maximum=1.5,
                    value=0.7,
                    step=0.1,
                    label="Temperature",
                    info="Controls randomness (higher = more creative, lower = more focused)",
                )

            # Generate button
            generate_btn = gr.Button("Generate My Responses", variant="primary")

            # Model status
            model_status = gr.Markdown(
                value=f"Current model: {suggestion_generator.model_name}",
                label="Model Status",
            )

        with gr.Column(scale=1):
            # Common phrases
            common_phrases = gr.Textbox(
                label="My Common Phrases",
                placeholder="Common phrases I often use with this person will appear here...",
                lines=5,
            )

            # Suggestions output
            suggestions_output = gr.Markdown(
                label="My Suggested Responses",
                value="Suggested responses will appear here...",
            )

    # Set up event handlers
    def handle_person_change(person_id):
        """Handle person selection change and update UI elements."""
        context_info, phrases_text, _ = on_person_change(person_id)

        # Get topics for this person
        topics = get_filtered_topics(person_id)

        # Update the context, phrases, and topic dropdown
        return context_info, phrases_text, gr.update(choices=topics)

    def handle_model_change(model_name):
        """Handle model selection change."""
        status = change_model(model_name)
        return status

    # Set up the person change event
    person_dropdown.change(
        handle_person_change,
        inputs=[person_dropdown],
        outputs=[context_display, common_phrases, topic_dropdown],
    )

    # Set up the model change event
    model_dropdown.change(
        handle_model_change,
        inputs=[model_dropdown],
        outputs=[model_status],
    )

    # Set up the generate button click event
    generate_btn.click(
        generate_suggestions,
        inputs=[
            person_dropdown,
            user_input,
            suggestion_type,
            topic_dropdown,
            model_dropdown,
            temperature_slider,
        ],
        outputs=[suggestions_output],
    )

    # Transcribe audio to text
    transcribe_btn.click(
        transcribe_audio,
        inputs=[audio_input],
        outputs=[user_input],
    )

# Launch the app
if __name__ == "__main__":
    demo.launch()