File size: 15,880 Bytes
914c05d
af9f72d
 
 
 
914c05d
 
af9f72d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
914c05d
af9f72d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
914c05d
af9f72d
 
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
import gradio as gr
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from huggingface_hub import InferenceClient

# WHOQOL-BREF questions (Same as before)
questions = [
    {"id": "Q1", "text": "How would you rate your quality of life?", "domain": "Overall QOL", "scores": ["Very poor", "Poor", "Neither poor nor good", "Good", "Very good"]},
    {"id": "Q2", "text": "How satisfied are you with your health?", "domain": "Overall Health", "scores": ["Very dissatisfied", "Dissatisfied", "Neither satisfied nor dissatisfied", "Satisfied", "Very satisfied"]},
    {"id": "Q3", "text": "To what extent do you feel that physical pain prevents you from doing what you need to do?", "domain": "Physical", "scores": ["Not at all", "A little", "A moderate amount", "Very much", "An extreme amount"], "reverse": True},
    {"id": "Q4", "text": "How much do you need any medical treatment to function in your daily life?", "domain": "Physical", "scores": ["Not at all", "A little", "A moderate amount", "Very much", "An extreme amount"], "reverse": True},
    {"id": "Q5", "text": "How much do you enjoy life?", "domain": "Psychological", "scores": ["Not at all", "A little", "A moderate amount", "Very much", "An extreme amount"]},
    {"id": "Q6", "text": "To what extent do you feel your life to be meaningful?", "domain": "Psychological", "scores": ["Not at all", "A little", "A moderate amount", "Very much", "An extreme amount"]},
    {"id": "Q7", "text": "How well are you able to concentrate?", "domain": "Psychological", "scores": ["Not at all", "A little", "A moderate amount", "Very much", "Extremely"]},
    {"id": "Q8", "text": "How safe do you feel in your daily life?", "domain": "Environment", "scores": ["Not at all", "A little", "A moderate amount", "Very much", "Extremely"]},
    {"id": "Q9", "text": "How healthy is your physical environment?", "domain": "Environment", "scores": ["Not at all", "A little", "A moderate amount", "Very much", "Extremely"]},
    {"id": "Q10", "text": "Do you have enough energy for everyday life?", "domain": "Physical", "scores": ["Not at all", "A little", "Moderately", "Mostly", "Completely"]},
    {"id": "Q11", "text": "Are you able to accept your bodily appearance?", "domain": "Psychological", "scores": ["Not at all", "A little", "Moderately", "Mostly", "Completely"]},
    {"id": "Q12", "text": "Have you enough money to meet your needs?", "domain": "Environment", "scores": ["Not at all", "A little", "Moderately", "Mostly", "Completely"]},
    {"id": "Q13", "text": "How available to you is the information that you need in your day-to-day life?", "domain": "Environment", "scores": ["Not at all", "A little", "Moderately", "Mostly", "Completely"]},
    {"id": "Q14", "text": "To what extent do you have the opportunity for leisure activities?", "domain": "Environment", "scores": ["Not at all", "A little", "Moderately", "Mostly", "Completely"]},
    {"id": "Q15", "text": "How well are you able to get around?", "domain": "Physical", "scores": ["Very poor", "Poor", "Neither poor nor good", "Good", "Very good"]},
    {"id": "Q16", "text": "How satisfied are you with your sleep?", "domain": "Physical", "scores": ["Very dissatisfied", "Dissatisfied", "Neither satisfied nor dissatisfied", "Satisfied", "Very satisfied"]},
    {"id": "Q17", "text": "How satisfied are you with your ability to perform your daily living activities?", "domain": "Physical", "scores": ["Very dissatisfied", "Dissatisfied", "Neither satisfied nor dissatisfied", "Satisfied", "Very satisfied"]},
    {"id": "Q18", "text": "How satisfied are you with your capacity for work?", "domain": "Physical", "scores": ["Very dissatisfied", "Dissatisfied", "Neither satisfied nor dissatisfied", "Satisfied", "Very satisfied"]},
    {"id": "Q19", "text": "How satisfied are you with yourself?", "domain": "Psychological", "scores": ["Very dissatisfied", "Dissatisfied", "Neither satisfied nor dissatisfied", "Satisfied", "Very satisfied"]},
    {"id": "Q20", "text": "How satisfied are you with your personal relationships?", "domain": "Social", "scores": ["Very dissatisfied", "Dissatisfied", "Neither satisfied nor dissatisfied", "Satisfied", "Very satisfied"]},
    {"id": "Q21", "text": "How satisfied are you with your sex life?", "domain": "Social", "scores": ["Very dissatisfied", "Dissatisfied", "Neither satisfied nor dissatisfied", "Satisfied", "Very satisfied"]},
    {"id": "Q22", "text": "How satisfied are you with the support you get from your friends?", "domain": "Social", "scores": ["Very dissatisfied", "Dissatisfied", "Neither satisfied nor dissatisfied", "Satisfied", "Very satisfied"]},
    {"id": "Q23", "text": "How satisfied are you with the conditions of your living place?", "domain": "Environment", "scores": ["Very dissatisfied", "Dissatisfied", "Neither satisfied nor dissatisfied", "Satisfied", "Very satisfied"]},
    {"id": "Q24", "text": "How satisfied are you with your access to health services?", "domain": "Environment", "scores": ["Very dissatisfied", "Dissatisfied", "Neither satisfied nor dissatisfied", "Satisfied", "Very satisfied"]},
    {"id": "Q25", "text": "How satisfied are you with your transport?", "domain": "Environment", "scores": ["Very dissatisfied", "Dissatisfied", "Neither satisfied nor dissatisfied", "Satisfied", "Very satisfied"]},
    {"id": "Q26", "text": "How often do you have negative feelings such as blue mood, despair, anxiety, depression?", "domain": "Psychological", "scores": ["Never", "Seldom", "Quite often", "Very often", "Always"], "reverse": True}
]

# Domain compositions and transformation formula (Same as before)
domain_info = {
    "Physical": {
        "questions": ["Q3", "Q4", "Q10", "Q15", "Q16", "Q17", "Q18"],
        "transform": lambda raw: (raw - 7) * (100/28)
    },
    "Psychological": {
        "questions": ["Q5", "Q6", "Q7", "Q11", "Q19", "Q26"],
        "transform": lambda raw: (raw - 6) * (100/24)
    },
    "Social": {
        "questions": ["Q20", "Q21", "Q22"],
        "transform": lambda raw: (raw - 3) * (100/12)
    },
    "Environment": {
        "questions": ["Q8", "Q9", "Q12", "Q13", "Q14", "Q23", "Q24", "Q25"],
        "transform": lambda raw: (raw - 8) * (100/32)
    },
    "Overall QOL": {
        "questions": ["Q1"],
        "transform": lambda raw: (raw - 1) * (100/4)
    },
    "Overall Health": {
        "questions": ["Q2"],
        "transform": lambda raw: (raw - 1) * (100/4)
    }
}

# Map domain names to full names for display (Same as before)
domain_full_names = {
    "Physical": "Physical Health",
    "Psychological": "Psychological Well-being",
    "Social": "Social Relationships",
    "Environment": "Environment",
    "Overall QOL": "Overall Quality of Life",
    "Overall Health": "Overall Health Satisfaction"
}

# Define interpretation ranges and interventions (Same as before)
interpretation_ranges = {
    "Physical Health": {
        "high_range": 70,
        "medium_range": (50, 69),
        "low_range": 49,
        "high_inference": "Good physical well-being, minimal limitations, good energy and mobility.",
        "medium_inference": "Mild to moderate physical limitations, some pain, or reduced energy.",
        "low_inference": "Significant physical health limitations, pain, fatigue, poor mobility.",
        "high_intervention": "Maintain a healthy lifestyle, regular exercise, balanced nutrition.",
        "medium_intervention": "Increase physical activity, improve sleep, manage minor pain.",
        "low_intervention": "Medical intervention, physical therapy, chronic disease management."
    },
    "Psychological Health": {
        "high_range": 75,
        "medium_range": (50, 74),
        "low_range": 49,
        "high_inference": "Strong emotional resilience, positive self-esteem, low anxiety or stress.",
        "medium_inference": "Moderate psychological health, occasional stress, some mood fluctuations.",
        "low_inference": "High emotional distress, anxiety, depression, low self-worth.",
        "high_intervention": "Continue positive mental health practices, social engagement.",
        "medium_intervention": "Use stress reduction techniques, engage in self-care routines.",
        "low_intervention": "Psychological counseling, cognitive behavioral therapy, medication if needed."
    },
    "Social Relationships": {
        "high_range": 70,
        "medium_range": (50, 69),
        "low_range": 49,
        "high_inference": "Strong social connections, good interpersonal support, high satisfaction.",
        "medium_inference": "Moderate social interactions, may experience loneliness or minor conflicts.",
        "low_inference": "Weak social relationships, lack of support, loneliness, or isolation.",
        "high_intervention": "Sustain social connections, participate in group/community activities.",
        "medium_intervention": "Strengthen personal relationships, seek social support groups.",
        "low_intervention": "Social integration programs, mental health support, relationship therapy."
    },
    "Environment": {
        "high_range": 70,
        "medium_range": (50, 69),
        "low_range": 49,
        "high_inference": "Safe and stable environment, access to resources and healthcare, financial security.",
        "medium_inference": "Some dissatisfaction with living conditions, financial constraints, or safety concerns.",
        "low_inference": "Unstable living conditions, financial stress, poor healthcare access, safety concerns.",
        "high_intervention": "Maintain financial stability, ensure continuous access to healthcare.",
        "medium_intervention": "Identify key environmental issues, seek financial or housing support.",
        "low_intervention": "Government or NGO assistance for financial/housing needs, healthcare access."
    }
}

# Initialize the InferenceClient
client = InferenceClient("HuggingFaceH4/zephyr-7b-beta")  # Replace with a different model if desired


# Function to get interpretation from the LLM
def get_llm_interpretation(domain, score, interpretation_ranges):
    if domain not in interpretation_ranges:
        return "No interpretation available."

    range_info = interpretation_ranges[domain]

    if score >= range_info["high_range"]:
        inference = range_info["high_inference"]
        intervention = range_info["high_intervention"]
        level = "High"
    elif range_info["medium_range"][0] <= score <= range_info["medium_range"][1]:
        inference = range_info["medium_inference"]
        intervention = range_info["medium_intervention"]
        level = "Medium"
    else:
        inference = range_info["low_inference"]
        intervention = range_info["low_intervention"]
        level = "Low"

    prompt = f"""
    Based on the WHOQOL-BREF assessment results for {domain}, the score is {score}, which is categorized as {level}.
    The inference is: {inference}
    Suggested intervention: {intervention}

    Provide a more detailed and personalized interpretation, including potential causes and specific recommendations.

    Response should be concise, empathetic, and helpful.
    """

    try:
        # Call the InferenceClient
        interpretation = client.text_generation(prompt, max_new_tokens=200)  # Adjust max_new_tokens as needed
        return interpretation
    except Exception as e:
        return f"Error getting interpretation from LLM: {e}"


# Function to calculate domain scores (Same as before)
def calculate_scores(responses):
    domain_scores = {}

    for domain, info in domain_info.items():
        domain_questions = info["questions"]
        total_score = 0

        for q_id in domain_questions:
            q_index = next((i for i, q in enumerate(questions) if q["id"] == q_id), None)
            if q_index is not None and responses.get(q_id) is not None:
                if questions[q_index].get("reverse", False):
                    total_score += 6 - responses[q_id]
                else:
                    total_score += responses[q_id]

        transformed_score = info["transform"](total_score)
        domain_scores[domain] = round(transformed_score, 2)

    return domain_scores


# Function to interpret the score range
def interpret_score(domain, score):
    if domain not in interpretation_ranges:
        return "Unknown", "No interpretation available."

    range_info = interpretation_ranges[domain]
    high_range = range_info["high_range"]
    medium_range = range_info["medium_range"]
    low_range = range_info["low_range"]

    if score >= high_range:
        return (
            "High",
            f"{range_info['high_inference']} {range_info['high_intervention']}"
        )
    elif range_info["medium_range"][0] <= score <= range_info["medium_range"][1]:
        return (
            "Medium",
            f"{range_info['medium_inference']} {range_info['medium_intervention']}"
        )
    else:
        return (
            "Low",
            f"{range_info['low_inference']} {range_info['low_intervention']}"
        )

# Define the Gradio interface
def whoqol_assessment(*responses):  # *args to take variable number of responses

    # Map responses to question IDs
    responses_dict = {q["id"]: int(r) for q, r in zip(questions, responses)} # responses from gradio are strings, need convert to int

    # Calculate scores
    scores = calculate_scores(responses_dict)

    if scores is None:
        return "Please answer all questions."  # Error message if not all questions are answered

    # Prepare data for radar chart
    main_domains = ["Physical", "Psychological", "Social", "Environment"]
    main_scores = [scores[domain] for domain in main_domains]

    # Create radar chart (using Matplotlib)
    fig, ax = plt.subplots(figsize=(6, 6), subplot_kw=dict(polar=True))

    # Angle for each domain
    angles = np.linspace(0, 2 * np.pi, len(main_domains), endpoint=False).tolist()
    angles += angles[:1]  # Close the loop

    # Add scores (with loop closure)
    values = main_scores + [main_scores[0]]

    # Plot and fill the radar chart
    ax.plot(angles, values, 'o-', linewidth=2, color='blue')
    ax.fill(angles, values, color='blue', alpha=0.25)

    # Add labels
    domain_labels = [domain_full_names[domain] for domain in main_domains]
    ax.set_xticks(angles[:-1])
    ax.set_xticklabels(domain_labels, fontsize=10)

    # Set y-axis limits
    ax.set_ylim(0, 100)
    ax.set_yticks([0, 25, 50, 75, 100])
    ax.set_yticklabels(['0', '25', '50', '75', '100'], fontsize=8)  # Smaller font

    # Add grid lines
    ax.grid(True, linestyle='-', alpha=0.7)

    # Add title
    ax.set_title('WHOQOL-BREF Domain Scores', size=12, y=1.1) # Smaller Title

    # Detailed Interpretations and store them in text
    interpretations_text = ""
    for domain in ["Physical", "Psychological", "Social", "Environment", "Overall QOL", "Overall Health"]:
        score = scores[domain]
        llm_interpretation = get_llm_interpretation(domain_full_names[domain], score, interpretation_ranges)
        interpretations_text += f"**{domain_full_names[domain]}**: {llm_interpretation}\n\n"

    return fig, interpretations_text


# Create Gradio inputs
inputs = []
for q in questions:
    inputs.append(gr.Radio(choices=q["scores"], label=q["text"]))  # Use Radio instead of Checkbox

# Create Gradio outputs
radar_chart_output = gr.Plot()
interpretations_output = gr.Markdown() # markdown, because I used "**" in text. This format allow to view text in bold format.

# Create Gradio interface
iface = gr.Interface(
    fn=whoqol_assessment,
    inputs=inputs,
    outputs=[radar_chart_output, interpretations_output],
    title="WHOQOL-BREF Quality of Life Assessment",
    description="Complete the questionnaire to receive your quality of life assessment across different domains.",
)

# Launch the Gradio interface
iface.launch()