Spaces:
Running
Running
File size: 9,072 Bytes
59b983d | 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 | """Small, curated diabetes education knowledge base.
The application uses deterministic keyword retrieval so the language model receives
short summaries from reputable public-health sources. This is intentionally simple
and transparent for a course project; it is not a clinical retrieval system.
"""
from __future__ import annotations
from dataclasses import dataclass
import re
from typing import Iterable
@dataclass(frozen=True)
class Source:
source_id: str
title: str
organization: str
url: str
summary: str
keywords: tuple[str, ...]
SOURCES: tuple[Source, ...] = (
Source(
source_id="S1",
title="What Is Diabetes?",
organization="National Institute of Diabetes and Digestive and Kidney Diseases (NIDDK)",
url="https://www.niddk.nih.gov/health-information/diabetes/overview/what-is-diabetes",
summary=(
"Diabetes occurs when blood glucose is too high because the body does not make "
"enough insulin, makes no insulin, or does not use insulin properly. The main types "
"include type 1, type 2, and gestational diabetes."
),
keywords=(
"diabetes", "type 1", "type one", "type 2", "type two", "gestational",
"insulin", "blood sugar", "blood glucose", "glucose", "prediabetes",
"diabetes tipo", "azúcar en la sangre", "glucosa",
),
),
Source(
source_id="S2",
title="Diabetes Tests & Diagnosis",
organization="NIDDK",
url="https://www.niddk.nih.gov/health-information/diabetes/overview/tests-diagnosis",
summary=(
"Health professionals diagnose diabetes and prediabetes with blood tests. Home blood "
"glucose meters cannot diagnose diabetes, and abnormal results may need confirmation."
),
keywords=(
"a1c", "hba1c", "test", "diagnosis", "diagnose", "screen", "fasting",
"oral glucose", "lab", "laboratory", "prediabetes range", "prueba", "diagnóstico",
),
),
Source(
source_id="S3",
title="About Insulin Resistance and Type 2 Diabetes",
organization="Centers for Disease Control and Prevention (CDC)",
url="https://www.cdc.gov/diabetes/about/insulin-resistance-type-2-diabetes.html",
summary=(
"Insulin resistance means cells do not respond well to insulin. The pancreas may make "
"more insulin at first, but blood glucose can rise over time and lead to prediabetes "
"or type 2 diabetes."
),
keywords=(
"insulin resistance", "resistant", "prediabetes", "type 2", "metabolic",
"resistencia a la insulina", "prediabetes",
),
),
Source(
source_id="S4",
title="Diabetes Meal Planning",
organization="CDC",
url="https://www.cdc.gov/diabetes/healthy-eating/diabetes-meal-planning.html",
summary=(
"Meal planning can support nutrition and blood glucose management. Common educational "
"tools include carbohydrate awareness and the plate method. Individual plans should be "
"created with a qualified clinician or diabetes educator."
),
keywords=(
"food", "meal", "diet", "carb", "carbohydrate", "plate method", "portion",
"breakfast", "lunch", "dinner", "snack", "nutrition", "eat", "eating",
"comida", "alimentación", "carbohidrato", "plato", "nutrición",
),
),
Source(
source_id="S5",
title="Healthy Living with Diabetes",
organization="NIDDK",
url="https://www.niddk.nih.gov/health-information/diabetes/overview/healthy-living-with-diabetes",
summary=(
"Healthy living with diabetes may include balanced eating, physical activity, adequate "
"sleep, stress management, and collaboration with a health care team. Plans should be "
"adapted to the person's health status and treatment."
),
keywords=(
"exercise", "activity", "walking", "workout", "sleep", "stress", "lifestyle",
"weight", "healthy living", "physical activity", "ejercicio", "actividad", "sueño",
),
),
Source(
source_id="S6",
title="Low Blood Sugar (Hypoglycemia)",
organization="CDC",
url="https://www.cdc.gov/diabetes/about/low-blood-sugar-hypoglycemia.html",
summary=(
"Low blood glucose can be dangerous and requires prompt attention. People at risk should "
"know their care plan, recognize warning signs, and discuss prevention and treatment with "
"their health care team."
),
keywords=(
"low blood sugar", "low glucose", "hypoglycemia", "hypoglycaemia", "shaky",
"sweating", "confused", "glucagon", "azúcar baja", "hipoglucemia", "temblor",
),
),
Source(
source_id="S7",
title="Manage Blood Sugar",
organization="CDC",
url="https://www.cdc.gov/diabetes/treatment/index.html",
summary=(
"Blood glucose can become too high or too low for many reasons. Monitoring frequency and "
"target ranges should be determined with a health professional, especially for people "
"using insulin or medicines that can cause hypoglycemia."
),
keywords=(
"high blood sugar", "high glucose", "hyperglycemia", "ketone", "monitor", "meter",
"cgm", "continuous glucose", "target range", "azúcar alta", "hiperglucemia", "cetona",
),
),
Source(
source_id="S8",
title="Insulin, Medicines, & Other Diabetes Treatments",
organization="NIDDK",
url="https://www.niddk.nih.gov/health-information/diabetes/overview/insulin-medicines-treatments",
summary=(
"Diabetes treatment may involve lifestyle measures, oral medicines, injectable medicines, "
"or insulin. The appropriate treatment depends on diabetes type, other health conditions, "
"side effects, cost, access, and individual circumstances. Medication changes require a clinician."
),
keywords=(
"medicine", "medication", "drug", "insulin", "metformin", "glp-1", "glp1",
"side effect", "dose", "dosage", "injection", "medicina", "medicamento", "dosis",
),
),
Source(
source_id="S9",
title="Preventing Diabetes Problems",
organization="NIDDK",
url="https://www.niddk.nih.gov/health-information/diabetes/overview/preventing-problems",
summary=(
"Diabetes can affect the heart, blood vessels, kidneys, eyes, nerves, and feet. Routine "
"care and management of blood glucose, blood pressure, cholesterol, and smoking status "
"can help reduce complication risks."
),
keywords=(
"complication", "heart", "kidney", "eye", "vision", "nerve", "neuropathy", "foot",
"feet", "stroke", "cholesterol", "blood pressure", "complicación", "riñón", "pie",
),
),
)
def _tokenize(text: str) -> set[str]:
return set(re.findall(r"[a-záéíóúñ0-9-]+", text.lower()))
def retrieve_sources(query: str, limit: int = 3) -> list[Source]:
"""Return the most relevant curated sources for a user query.
Scores use exact phrase matches plus token overlap. A general diabetes source
is always available as a fallback.
"""
normalized = query.lower().strip()
query_tokens = _tokenize(normalized)
ranked: list[tuple[float, Source]] = []
for source in SOURCES:
score = 0.0
for keyword in source.keywords:
key = keyword.lower()
if key in normalized:
score += 4.0 if " " in key else 2.0
key_tokens = _tokenize(key)
score += 0.35 * len(query_tokens.intersection(key_tokens))
ranked.append((score, source))
ranked.sort(key=lambda item: item[0], reverse=True)
selected = [source for score, source in ranked if score > 0][:limit]
if not selected:
selected = [SOURCES[0], SOURCES[4]][:limit]
elif SOURCES[0] not in selected and len(selected) < limit:
selected.append(SOURCES[0])
return selected[:limit]
def format_context(sources: Iterable[Source]) -> str:
"""Format source summaries for inclusion in the model prompt."""
blocks = []
for source in sources:
blocks.append(
f"[{source.source_id}] {source.title} — {source.organization}\n"
f"Summary: {source.summary}\n"
f"URL: {source.url}"
)
return "\n\n".join(blocks)
def format_reference_list(sources: Iterable[Source]) -> str:
"""Format deterministic Markdown references appended to each answer."""
items = [
f"- [{source.source_id}] [{source.title}]({source.url}) — {source.organization}"
for source in sources
]
return "\n".join(items)
|