amitashukla commited on
Commit
62ff3c4
·
0 Parent(s):

initial commit for HF Space

Browse files
.DS_Store ADDED
Binary file (10.2 kB). View file
 
LICENSE ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Sarah Bentley
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
README.md ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ title: Harbor
3
+ emoji: 🚢
4
+ colorFrom: blue
5
+ colorTo: green
6
+ sdk: gradio
7
+ sdk_version: 5.23.3
8
+ python_version: "3.10"
9
+ app_file: app.py
10
+ pinned: false
11
+ ---
12
+
app.py ADDED
@@ -0,0 +1,452 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """
2
+ Gradio Web Interface for Harbor Treatment Navigation Chatbot
3
+
4
+ Landing page offers three paths:
5
+ 1. Quick Recommendations — enter a zip code, get nearby options inline
6
+ 2. Talk to a Human — compact crisis callout with phone number
7
+ 3. Get Personalized Advice — leads to the AI chatbot
8
+
9
+ Run locally:
10
+ python app.py
11
+
12
+ Access in browser:
13
+ http://localhost:7860
14
+ """
15
+
16
+ import os
17
+ import re
18
+
19
+ import gradio as gr
20
+ from src.chat import Chatbot
21
+ from src.utils.profile import create_empty_profile
22
+ from src.utils.resources import load_resources, filter_resources, score_resources
23
+
24
+
25
+ # ── CSS ───────────────────────────────────────────────────────────────────────
26
+
27
+ CSS = """
28
+ /* ── Layout ── */
29
+ .harbor-wrap {
30
+ max-width: 680px;
31
+ margin: 0 auto;
32
+ padding: 2.5rem 1.25rem 1.5rem;
33
+ font-family: 'Inter', sans-serif;
34
+ }
35
+
36
+ /* ── Header ── */
37
+ .harbor-logo {
38
+ text-align: center;
39
+ font-size: 2.75rem;
40
+ font-weight: 800;
41
+ letter-spacing: -1px;
42
+ color: #0d6e6e;
43
+ margin-bottom: 0.2rem;
44
+ line-height: 1;
45
+ }
46
+ .harbor-tagline {
47
+ text-align: center;
48
+ font-size: 1.1rem;
49
+ color: #5a7a7a;
50
+ margin-bottom: 2.25rem;
51
+ font-style: italic;
52
+ }
53
+
54
+ /* ── Cards ── */
55
+ .harbor-card {
56
+ background: #ffffff;
57
+ border: 1.5px solid #c8e6e6;
58
+ border-radius: 16px;
59
+ padding: 1.5rem 1.75rem;
60
+ margin-bottom: 1.1rem;
61
+ box-shadow: 0 2px 12px rgba(13, 110, 110, 0.06);
62
+ }
63
+ .harbor-card-title {
64
+ font-size: 1.15rem;
65
+ font-weight: 700;
66
+ color: #0d6e6e;
67
+ margin-bottom: 0.6rem;
68
+ display: flex;
69
+ align-items: center;
70
+ gap: 0.5rem;
71
+ }
72
+ .harbor-card p {
73
+ color: #3d5a5a;
74
+ line-height: 1.65;
75
+ margin: 0 0 0.75rem;
76
+ font-size: 0.97rem;
77
+ }
78
+ .harbor-card p:last-child { margin-bottom: 0; }
79
+
80
+ /* ── Quick Rec card — larger, featured ── */
81
+ .harbor-card-featured {
82
+ background: linear-gradient(145deg, #f0fafa, #e6f7f7);
83
+ border: 2px solid #0d9e8f;
84
+ }
85
+ .harbor-card-featured .harbor-card-title {
86
+ font-size: 1.25rem;
87
+ }
88
+
89
+ /* ── Crisis callout — compact ── */
90
+ .harbor-callout {
91
+ background: #f8fffd;
92
+ border: 1.5px solid #c8e6e6;
93
+ border-radius: 12px;
94
+ padding: 0.9rem 1.25rem;
95
+ margin-bottom: 1.1rem;
96
+ display: flex;
97
+ align-items: center;
98
+ gap: 1rem;
99
+ flex-wrap: wrap;
100
+ box-shadow: 0 1px 6px rgba(13, 110, 110, 0.05);
101
+ }
102
+ .harbor-callout-text {
103
+ flex: 1;
104
+ min-width: 200px;
105
+ font-size: 0.9rem;
106
+ color: #3d5a5a;
107
+ line-height: 1.5;
108
+ }
109
+ .harbor-callout-text strong { color: #0d6e6e; }
110
+ .harbor-phone-inline {
111
+ font-size: 1.2rem;
112
+ font-weight: 800;
113
+ color: #0d6e6e;
114
+ white-space: nowrap;
115
+ }
116
+ .harbor-phone-inline a { color: inherit; text-decoration: none; }
117
+ .harbor-phone-inline a:hover { text-decoration: underline; }
118
+
119
+ /* ── Zip results area ── */
120
+ .harbor-results {
121
+ margin-top: 1rem;
122
+ padding-top: 1rem;
123
+ border-top: 1px solid #c8e6e6;
124
+ }
125
+ .harbor-results-title {
126
+ font-size: 1rem;
127
+ font-weight: 600;
128
+ color: #0d6e6e;
129
+ margin-bottom: 0.5rem;
130
+ }
131
+ .harbor-error {
132
+ color: #c0392b;
133
+ font-size: 0.9rem;
134
+ margin-top: 0.4rem;
135
+ }
136
+ #zip-results .pending,
137
+ #zip-results .generating,
138
+ #zip-results > .wrap,
139
+ #zip-results > .svelte-spinner,
140
+ #zip-results .eta-bar {
141
+ display: none !important;
142
+ }
143
+
144
+ /* ── Buttons ── */
145
+ .harbor-start-btn button,
146
+ .harbor-zip-btn button {
147
+ background: linear-gradient(135deg, #0d9e8f, #0d6e6e) !important;
148
+ border: none !important;
149
+ border-radius: 12px !important;
150
+ font-size: 1.05rem !important;
151
+ font-weight: 600 !important;
152
+ letter-spacing: 0.2px !important;
153
+ padding: 0.85rem 1.5rem !important;
154
+ transition: opacity 0.2s ease !important;
155
+ box-shadow: 0 4px 14px rgba(13, 110, 110, 0.25) !important;
156
+ }
157
+ .harbor-start-btn button:hover,
158
+ .harbor-zip-btn button:hover { opacity: 0.9 !important; }
159
+
160
+ /* ── Footer ── */
161
+ .harbor-footer {
162
+ text-align: center;
163
+ font-size: 0.8rem;
164
+ color: #8fa8a8;
165
+ margin-top: 1.75rem;
166
+ line-height: 1.6;
167
+ }
168
+
169
+ /* ── Chat page ── */
170
+ .chat-header {
171
+ max-width: 680px;
172
+ margin: 0 auto;
173
+ padding: 1.25rem 1.25rem 0;
174
+ }
175
+ .chat-back-btn button {
176
+ background: transparent !important;
177
+ border: 1.5px solid #c8e6e6 !important;
178
+ color: #0d6e6e !important;
179
+ border-radius: 8px !important;
180
+ font-size: 0.9rem !important;
181
+ font-weight: 500 !important;
182
+ padding: 0.4rem 0.9rem !important;
183
+ }
184
+ .chat-back-btn button:hover { background: #f0fafa !important; }
185
+ """
186
+
187
+ # ── Theme ─────────────────────────────────────────────────────────────────────
188
+
189
+ THEME = gr.themes.Soft(
190
+ primary_hue="teal",
191
+ secondary_hue="cyan",
192
+ neutral_hue="slate",
193
+ font=[gr.themes.GoogleFont("Inter"), "sans-serif"],
194
+ ).set(
195
+ button_primary_background_fill="linear-gradient(135deg, #0d9e8f, #0d6e6e)",
196
+ button_primary_background_fill_hover="linear-gradient(135deg, #0bb8a8, #0d9e8f)",
197
+ button_primary_text_color="#ffffff",
198
+ block_border_color="#c8e6e6",
199
+ block_shadow="0 2px 12px rgba(13,110,110,0.06)",
200
+ )
201
+
202
+ # ── Static HTML snippets ───────────────────────────────────────────────────────
203
+
204
+ HEADER_MD = """
205
+ <div class='harbor-logo'>⚓ Harbor</div>
206
+ <div class='harbor-tagline'>Come in from the storm.</div>
207
+ """
208
+
209
+ CRISIS_CALLOUT_HTML = """
210
+ <div class='harbor-callout'>
211
+ <div class='harbor-callout-text'>
212
+ <strong>🤝 Talk to a Human</strong> — Trained counselors available
213
+ <strong>24/7</strong> through the Behavioral Health Help Line.<br>
214
+ <span style='font-size:0.82rem; color:#6b8e8e;'>
215
+ In immediate danger? <strong style='color:#6b4e4e;'>Call 911.</strong>
216
+ </span>
217
+ </div>
218
+ <div class='harbor-phone-inline'><a href='tel:8337732445'>📞 833-773-2445</a></div>
219
+ </div>
220
+ """
221
+
222
+ CHATBOT_CARD_MD = """
223
+ <div class='harbor-card-title'>💬 Get Personalized Guidance</div>
224
+ <p>
225
+ Want to explore options in more depth? Our chatbot can factor in your insurance,
226
+ preferences, treatment history, and more — no judgment, no pressure.
227
+ </p>
228
+ """
229
+
230
+ FOOTER_MD = """
231
+ <div class='harbor-footer'>
232
+ Harbor does not provide medical advice, diagnosis, or treatment.<br>
233
+ If you are in crisis, please call 911 or the BHHL at 833-773-2445.
234
+ </div>
235
+ """
236
+
237
+ # ── Helpers ───────────────────────────────────────────────────────────────────
238
+
239
+ ZIPCODE_RE = re.compile(r"^\d{5}$")
240
+
241
+
242
+ def is_valid_zip(zipcode: str) -> bool:
243
+ """Return True if zipcode is exactly 5 digits."""
244
+ return bool(ZIPCODE_RE.match(zipcode.strip()))
245
+
246
+
247
+ def _load_resources_once():
248
+ """Load resource CSVs once and cache."""
249
+ if not hasattr(_load_resources_once, "_cache"):
250
+ current_dir = os.path.dirname(os.path.abspath(__file__))
251
+ paths = [
252
+ os.path.join(current_dir, "references", "knowledge", "ma_resources.csv"),
253
+ os.path.join(current_dir, "references", "knowledge", "boston_resources.csv"),
254
+ ]
255
+ _load_resources_once._cache = load_resources(paths)
256
+ return _load_resources_once._cache
257
+
258
+
259
+ def get_recommendations(zipcode: str) -> list[dict]:
260
+ """
261
+ Return a list of treatment recommendations for the given zip code.
262
+
263
+ Uses the same filter/score logic as the chatbot, but with a minimal
264
+ profile containing only the zipcode.
265
+ """
266
+ profile = create_empty_profile()
267
+ profile["logistics"]["zipcode"] = zipcode.strip()
268
+
269
+ resources = _load_resources_once()
270
+ filtered = filter_resources(resources, profile)
271
+ top = score_resources(filtered, profile)
272
+ return top
273
+
274
+
275
+ def format_recommendations(zipcode: str, results: list[dict]) -> str:
276
+ """Render recommendations as an HTML snippet for display."""
277
+ if not results:
278
+ return (
279
+ f"<div class='harbor-results'>"
280
+ f"<div class='harbor-results-title'>Results near {zipcode}</div>"
281
+ f"<p style='color:#5a7a7a; font-size:0.93rem;'>"
282
+ f"No results found for that zip code yet. Try the chatbot below for "
283
+ f"more personalised help.</p>"
284
+ f"</div>"
285
+ )
286
+
287
+ items_html = ""
288
+ for r in results:
289
+ name = r.get("name", "Unknown Facility")
290
+ # Build address from parts
291
+ addr_parts = [r.get("address", ""), r.get("city", ""),
292
+ r.get("state", ""), r.get("zip", "")]
293
+ address = ", ".join(p.strip() for p in addr_parts if p.strip())
294
+ phone = r.get("phone", "").strip()
295
+ # Type from primary_focus
296
+ focus = r.get("primary_focus", "").strip()
297
+ type_label = ", ".join(
298
+ v.strip().replace("_", " ").title() for v in focus.split("|")
299
+ ) if focus else ""
300
+
301
+ items_html += (
302
+ f"<div style='margin-bottom:0.75rem; padding:0.75rem; background:#f8fffd; "
303
+ f"border-radius:10px; border:1px solid #c8e6e6;'>"
304
+ f"<strong style='color:#0d6e6e;'>{name}</strong><br>"
305
+ )
306
+ if type_label or address:
307
+ items_html += (
308
+ f"<span style='font-size:0.88rem; color:#5a7a7a;'>"
309
+ f"{type_label + ' · ' if type_label else ''}{address}</span><br>"
310
+ )
311
+ if phone:
312
+ items_html += (
313
+ f"<a href='tel:{phone}' style='font-size:0.88rem; color:#0d9e8f;'>{phone}</a>"
314
+ )
315
+ items_html += "</div>"
316
+ return (
317
+ f"<div class='harbor-results'>"
318
+ f"<div class='harbor-results-title'>📍 Options near {zipcode}</div>"
319
+ f"{items_html}"
320
+ f"</div>"
321
+ )
322
+
323
+
324
+ # ── App ───────────────────────────────────────────────────────────────────────
325
+
326
+ def create_chatbot():
327
+ """Creates the Harbor interface with a landing page and chatbot."""
328
+ _load_resources_once() # pre-load CSVs so first zip lookup is fast
329
+ chatbot = Chatbot()
330
+
331
+ def chat(message, history):
332
+ """
333
+ Generate a response for the current message.
334
+
335
+ Args:
336
+ message (str): The current message from the user
337
+ history (list): List of previous [user, assistant] message pairs
338
+
339
+ Returns:
340
+ str: The assistant's response
341
+ """
342
+ return chatbot.get_response(message)
343
+
344
+ def handle_zip_submit(zipcode: str):
345
+ """Validate zip and return inline results HTML."""
346
+ zipcode = zipcode.strip()
347
+ if not is_valid_zip(zipcode):
348
+ return gr.update(
349
+ value="<div class='harbor-error'>⚠️ Please enter a valid 5-digit zip code.</div>",
350
+ visible=True,
351
+ )
352
+ results = get_recommendations(zipcode)
353
+
354
+ # Log recommendations to console
355
+ if results:
356
+ print(f"[Harbor] Zip lookup ({zipcode}) — {len(results)} recommendation(s):")
357
+ for i, r in enumerate(results, 1):
358
+ print(f" {i}. {r.get('name', 'Unknown')} — {r.get('city', '')}, {r.get('state', '')} {r.get('zip', '')}")
359
+ else:
360
+ print(f"[Harbor] Zip lookup ({zipcode}) — no results found.")
361
+
362
+ return gr.update(value=format_recommendations(zipcode, results), visible=True)
363
+
364
+ def show_chat():
365
+ return gr.update(visible=False), gr.update(visible=True)
366
+
367
+ def show_landing():
368
+ return gr.update(visible=True), gr.update(visible=False)
369
+
370
+ with gr.Blocks(title="Harbor", theme=THEME, css=CSS) as demo:
371
+
372
+ # ── Landing Page ──────────────────────────────────────────────
373
+ with gr.Column(visible=True) as landing_page:
374
+ with gr.Column(elem_classes="harbor-wrap"):
375
+ gr.HTML(HEADER_MD)
376
+
377
+ # Card 1 — Quick Recommendations (featured)
378
+ with gr.Group(elem_classes="harbor-card harbor-card-featured"):
379
+ gr.HTML("<div class='harbor-card-title'>📍 Find Options Near You</div>")
380
+ gr.HTML(
381
+ "<p>Enter your zip code and we'll show you nearby treatment "
382
+ "programs right away — no account needed.</p>"
383
+ )
384
+ with gr.Row():
385
+ zip_input = gr.Textbox(
386
+ placeholder="e.g. 02134",
387
+ max_lines=1,
388
+ show_label=False,
389
+ container=False,
390
+ scale=3,
391
+ )
392
+ zip_btn = gr.Button(
393
+ "Find Options →",
394
+ variant="primary",
395
+ scale=1,
396
+ elem_classes="harbor-zip-btn",
397
+ )
398
+ # Results rendered outside the card so the loading spinner
399
+ # does not overlay the input card above.
400
+ results_html = gr.HTML(visible=False, elem_id="zip-results")
401
+
402
+ # Card 2 — Crisis callout (compact)
403
+ gr.HTML(CRISIS_CALLOUT_HTML)
404
+
405
+ # Card 3 — Chatbot
406
+ with gr.Group(elem_classes="harbor-card"):
407
+ gr.HTML(CHATBOT_CARD_MD)
408
+ start_chat_btn = gr.Button(
409
+ "Start a Conversation →",
410
+ variant="primary",
411
+ size="lg",
412
+ elem_classes="harbor-start-btn",
413
+ )
414
+
415
+ gr.HTML(FOOTER_MD)
416
+
417
+ # ── Chat Page ─────────────────────────────────────────────────
418
+ with gr.Column(visible=False) as chat_page:
419
+ with gr.Column(elem_classes="chat-header"):
420
+ back_btn = gr.Button(
421
+ "← Back to Home",
422
+ size="sm",
423
+ variant="secondary",
424
+ elem_classes="chat-back-btn",
425
+ )
426
+ gr.ChatInterface(
427
+ chat,
428
+ title="⚓ Harbor",
429
+ description=(
430
+ "Tell me a little about your situation and I'll help you find "
431
+ "treatment options that match your needs. Everything is confidential."
432
+ ),
433
+ examples=[
434
+ "What treatment options are available near me?",
435
+ "I'm looking for outpatient help with alcohol use.",
436
+ "I need support but I don't have insurance.",
437
+ "How do I know which type of program is right for me?",
438
+ ],
439
+ )
440
+
441
+ # ── Events ────────────────────────────────────────────────────
442
+ zip_btn.click(handle_zip_submit, inputs=zip_input, outputs=results_html)
443
+ zip_input.submit(handle_zip_submit, inputs=zip_input, outputs=results_html)
444
+ start_chat_btn.click(show_chat, outputs=[landing_page, chat_page])
445
+ back_btn.click(show_landing, outputs=[landing_page, chat_page])
446
+
447
+ return demo
448
+
449
+
450
+ if __name__ == "__main__":
451
+ demo = create_chatbot()
452
+ demo.launch()
data/.DS_Store ADDED
Binary file (6.15 kB). View file
 
data/system_prompt.md ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+
3
+ Treatment Navigation Chatbot — System Prompt
4
+
5
+ Role / Identity
6
+
7
+ You are a supportive assistant that helps people find treatment options for substance use or mental health care and guides them toward contacting appropriate treatment facilities.
8
+
9
+ Scope / Boundaries
10
+
11
+ Only assist with discovering and accessing mental health or substance use treatment services. If users ask unrelated questions, politely redirect the conversation back to treatment support.
12
+
13
+ If a user indicates they may be in immediate crisis or danger, pause the normal conversation and encourage them to contact the Behavioral Health Help Line (BHHL).
14
+
15
+ Crisis support information:
16
+
17
+ Behavioral Health Help Line (BHHL)
18
+
19
+ Call or text: 833-773-2445
20
+
21
+ Available 24 hours a day, 7 days a week, 365 days a year.
22
+
23
+ Anyone may contact the Help Line if they or a family member are experiencing a mental health or substance use disorder crisis.
24
+
25
+ Tone / Style
26
+
27
+ Be warm, patient, supportive, and non-judgmental. Use plain language and avoid clinical jargon.
28
+
29
+ Use motivational interviewing techniques:
30
+
31
+ \- Ask open-ended questions
32
+
33
+ \- Reflect the user’s concerns
34
+
35
+ \- Affirm their effort in seeking help
36
+
37
+ \- Avoid lecturing, pushing, or shaming
38
+
39
+ Respect the user’s autonomy and pace.
40
+
41
+ Key Facts
42
+
43
+ Users often hesitate to seek treatment due to stigma, fear, cost concerns, or uncertainty about what treatment involves.
44
+
45
+ Treatment settings may include:
46
+
47
+ \- outpatient care
48
+
49
+ \- intensive outpatient care
50
+
51
+ \- residential/inpatient programs
52
+
53
+ \- telehealth services
54
+
55
+ Matching users to facilities requires understanding:
56
+
57
+ \- type of help needed
58
+
59
+ \- preferred treatment setting
60
+
61
+ \- payment method or insurance
62
+
63
+ \- location
64
+
65
+ \- special preferences such as language, LGBTQ+ affirming care, veterans services, adolescent services, or pregnancy-related care
66
+
67
+ Behavior Rules
68
+
69
+ 1\. Engage
70
+
71
+ Build rapport and understand the user’s situation with open-ended questions.
72
+
73
+ 2\. Educate
74
+
75
+ If the user is uncertain about treatment, normalize help-seeking and explain what treatment typically involves.
76
+
77
+ 3\. Assess
78
+
79
+ Ask a short set of questions to understand their needs:
80
+
81
+ \- type of help
82
+
83
+ \- treatment setting
84
+
85
+ \- payment method
86
+
87
+ \- location
88
+
89
+ \- optional preferences
90
+
91
+ 4\. Match
92
+
93
+ Present 3–5 treatment facilities that best match the user’s needs. Explain why each facility fits.
94
+
95
+ 5\. Empower
96
+
97
+ Explain what happens when contacting a facility and what the intake process usually looks like.
98
+
99
+ 6\. Plan
100
+
101
+ Encourage a concrete next step, such as calling a facility. Provide a simple call script.
102
+
103
+ 7\. Follow-through
104
+
105
+ Offer encouragement and help the user make a plan for when they will contact the facility.
106
+
107
+ Guardrails
108
+
109
+ Source of Truth
110
+
111
+ Only recommend facilities that come from an approved, up-to-date treatment directory or database provided to the assistant. Do not invent, infer, or guess facility names, addresses, phone numbers, hours, or services. If verified facility data is unavailable, say so clearly and offer general guidance instead.
112
+
113
+ Verification and Uncertainty
114
+
115
+ Do not claim that a facility has current availability, accepts a specific insurance plan, or offers a specific service unless that information is present in the source data. Remind the user to call the facility before visiting to confirm services, eligibility, hours, and payment details.
116
+
117
+ Crisis Escalation
118
+
119
+ If the user describes immediate danger, overdose risk, suicidal intent, intent to harm others, severe withdrawal, or another urgent behavioral health crisis, do not continue with routine matching questions until safety is addressed. First encourage immediate contact with the Behavioral Health Help Line at 833-773-2445 by call or text. If the situation appears life-threatening or time-sensitive, urge the user to call emergency services right away.
120
+
121
+ Crisis Threshold Protocol
122
+
123
+ The assistant must switch to crisis support mode if the user indicates:
124
+
125
+ Self-harm or suicide risk
126
+
127
+ \- expressing suicidal thoughts
128
+
129
+ \- wanting to die
130
+
131
+ \- planning or considering self-harm
132
+
133
+ \- expressing hopelessness about continuing
134
+
135
+ Risk of harming others
136
+
137
+ \- stating intent to harm another person
138
+
139
+ \- describing imminent violent behavior
140
+
141
+ Overdose or severe substance use emergency
142
+
143
+ \- possible overdose
144
+
145
+ \- severe withdrawal symptoms
146
+
147
+ \- loss of consciousness
148
+
149
+ \- inability to breathe normally
150
+
151
+ Acute mental health crisis
152
+
153
+ \- panic that feels uncontrollable
154
+
155
+ \- hallucinations or extreme confusion
156
+
157
+ \- inability to stay safe
158
+
159
+ Third-party crisis
160
+
161
+ \- the user says a family member or friend is currently in danger or crisis
162
+
163
+ Crisis Response Template
164
+
165
+ I'm really sorry you're going through something this difficult. You don't have to handle it alone.
166
+
167
+ If you or someone near you may be in immediate danger, please call 911 right now.
168
+
169
+ You can also reach the Behavioral Health Help Line (BHHL) for immediate support. They are available 24 hours a day, 7 days a week, 365 days a year.
170
+
171
+ Call or text: 833-773-2445
172
+
173
+ Trained counselors can talk with you and help figure out the next step.
174
+
175
+ If you'd like, you can also tell me a little about what's happening and I can help you think through what to do next.
176
+
177
+ Output Format
178
+
179
+ When recommending facilities, present them clearly:
180
+
181
+ Facility Name
182
+
183
+ Address
184
+
185
+ Phone number
186
+
187
+ Why this matches you:
188
+
189
+ Short explanation referencing the user’s needs.
190
+
191
+ Services:
192
+
193
+ Key treatment services offered.
194
+
195
+ After listing facilities, ask whether the user would like help contacting one of them or making a plan for next steps.
196
+
data/user_profile_schema.json ADDED
@@ -0,0 +1,191 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "demographics": {
3
+ "population": {
4
+ "description": "User's age group or life stage",
5
+ "type": "single",
6
+ "options": [
7
+ {"value": "adolescent", "label": "Adolescent / Minor", "keywords": ["teen", "teenager", "adolescent", "minor", "kid", "child", "youth", "young", "high school", "middle school"], "cite": [7, 627]},
8
+ {"value": "young_adult", "label": "Young Adult / College Student", "keywords": ["college", "university", "student", "young adult", "campus", "dorm", "undergrad", "graduate student"], "cite": [120, 346]},
9
+ {"value": "adult", "label": "General Adult", "keywords": [], "cite": [212]},
10
+ {"value": "older_adult", "label": "Older Adult", "keywords": ["older", "elderly", "senior", "retired", "retirement", "aging"], "cite": [446, 967]}
11
+ ]
12
+ },
13
+ "identity_factors": {
14
+ "description": "Core identity factors relevant to treatment matching",
15
+ "type": "multi",
16
+ "options": [
17
+ {"value": "veteran", "label": "Veteran", "keywords": ["veteran", "military", "army", "navy", "marines", "air force", "service member", "deployed", "combat", "VA"], "cite": [65]},
18
+ {"value": "lgbtq", "label": "LGBTQ+", "keywords": ["lgbtq", "gay", "lesbian", "bisexual", "transgender", "trans", "queer", "nonbinary", "non-binary"], "cite": [258]},
19
+ {"value": "wheelchair_user", "label": "Wheelchair User", "keywords": ["wheelchair", "mobility aid", "mobility impairment"], "cite": [918]},
20
+ {"value": "woman", "label": "Woman", "keywords": ["woman", "female", "mother", "mom", "daughter", "wife", "girl"], "cite": []},
21
+ {"value": "homeless", "label": "Homeless / Unhoused", "keywords": ["homeless", "unhoused", "shelter", "no place to stay", "living on the street", "couch surfing"], "cite": [860]},
22
+ {"value": "autistic", "label": "Autistic / Neurodivergent", "keywords": ["autistic", "autism", "neurodivergent", "adhd", "on the spectrum"], "cite": []}
23
+ ]
24
+ },
25
+ "language": {
26
+ "description": "Preferred language for treatment",
27
+ "type": "single",
28
+ "options": [
29
+ {"value": "english", "label": "English", "keywords": ["english"], "cite": [173]},
30
+ {"value": "spanish", "label": "Spanish", "keywords": ["spanish", "español", "espanol", "habla español"], "cite": [171, 173]}
31
+ ]
32
+ },
33
+ "pronouns": {
34
+ "description": "User's pronouns",
35
+ "type": "single",
36
+ "options": [
37
+ {"value": "he", "label": "He/Him", "keywords": ["he/him"], "cite": []},
38
+ {"value": "she", "label": "She/Her", "keywords": ["she/her"], "cite": []},
39
+ {"value": "they", "label": "They/Them", "keywords": ["they/them"], "cite": [267]}
40
+ ]
41
+ }
42
+ },
43
+ "logistics": {
44
+ "zipcode": {
45
+ "description": "User's ZIP code for proximity-based facility matching",
46
+ "type": "extracted",
47
+ "pattern": "\\b\\d{5}\\b"
48
+ },
49
+ "region": {
50
+ "description": "Broader region or area description (city, county, state, or rural designation)",
51
+ "type": "extracted",
52
+ "examples": ["Boston", "Pocahontas County", "rural West Virginia"]
53
+ },
54
+ "profession": {
55
+ "description": "Long-term profession relevant to treatment (e.g., licensing fears, scheduling)",
56
+ "type": "single",
57
+ "options": [
58
+ {"value": "healthcare_worker", "label": "Healthcare Worker / Nurse", "keywords": ["nurse", "doctor", "healthcare worker", "hospital", "medical professional", "EMT", "paramedic", "physician"], "cite": [793]},
59
+ {"value": "mental_health_professional", "label": "Mental Health Professional / Therapist", "keywords": ["therapist", "counselor", "psychologist", "psychiatrist", "social worker", "mental health professional"], "cite": [1021]},
60
+ {"value": "first_responder", "label": "First Responder", "keywords": ["firefighter", "police", "officer", "first responder", "law enforcement"], "cite": []}
61
+ ]
62
+ },
63
+ "accessibility_needs": {
64
+ "description": "Physical accessibility requirements for facilities",
65
+ "type": "multi",
66
+ "options": [
67
+ {"value": "wheelchair_accessible", "label": "Wheelchair Accessible / ADA", "keywords": ["wheelchair accessible", "ada accessible", "accessibility", "ramp", "elevator"], "cite": [918]}
68
+ ]
69
+ },
70
+ "insurance": {
71
+ "description": "Payment or insurance method",
72
+ "type": "single",
73
+ "options": [
74
+ {"value": "private", "label": "Private Insurance", "keywords": ["insurance", "blue cross", "aetna", "cigna", "united health", "anthem", "humana", "private insurance", "employer insurance", "work insurance"], "cite": [26, 527, 607]},
75
+ {"value": "medicaid_medicare", "label": "Medicaid / Medicare", "keywords": ["medicaid", "medicare", "masshealth", "state insurance"], "cite": [171, 464, 527]},
76
+ {"value": "va_tricare", "label": "VA Benefits / TRICARE", "keywords": ["va benefits", "tricare", "veterans affairs", "va insurance", "military insurance"], "cite": [84, 89]},
77
+ {"value": "uninsured", "label": "Uninsured / Self-Pay", "keywords": ["uninsured", "no insurance", "self-pay", "self pay", "pay out of pocket", "can't afford", "sliding scale", "free"], "cite": [120, 527]}
78
+ ]
79
+ },
80
+ "treatment_history": {
81
+ "description": "Previous treatment experiences",
82
+ "type": "extracted",
83
+ "examples": ["prior 12-step residential", "been to rehab before", "tried outpatient"],
84
+ "cite": [752, 759, 762]
85
+ }
86
+ },
87
+ "status": {
88
+ "current_state": {
89
+ "description": "User's current sobriety or intoxication state",
90
+ "type": "single",
91
+ "options": [
92
+ {"value": "sober", "label": "Sober", "keywords": ["sober", "clean", "not using", "in recovery"], "cite": [459]},
93
+ {"value": "intoxicated", "label": "Currently Intoxicated / Incoherent", "keywords": ["drunk", "high", "intoxicated", "wasted", "messed up", "using right now"], "cite": [564, 567]}
94
+ ]
95
+ },
96
+ "crisis_level": {
97
+ "description": "Level of distress or crisis",
98
+ "type": "single",
99
+ "options": [
100
+ {"value": "general_distress", "label": "General Distress", "keywords": ["stressed", "overwhelmed", "struggling", "having a hard time", "not doing well"], "cite": [122]},
101
+ {"value": "acute_crisis", "label": "Acute Distress / Suicidal Ideation", "keywords": ["suicidal", "kill myself", "want to die", "end it", "overdose", "can't go on", "hurt myself", "self-harm", "no reason to live"], "cite": [212, 215]}
102
+ ]
103
+ },
104
+ "temporary_factors": {
105
+ "description": "Temporary life circumstances affecting treatment needs",
106
+ "type": "multi",
107
+ "options": [
108
+ {"value": "pregnant", "label": "Pregnant / Postpartum", "keywords": ["pregnant", "pregnancy", "postpartum", "expecting", "baby on the way", "just had a baby"], "cite": [300]},
109
+ {"value": "homeless", "label": "Homeless / Unhoused", "keywords": ["homeless", "unhoused", "shelter", "no place to stay", "living on the street"], "cite": [860]},
110
+ {"value": "court_mandated", "label": "Court-Mandated", "keywords": ["court", "mandated", "judge", "probation", "parole", "court-ordered", "legal requirement"], "cite": [828, 831]}
111
+ ]
112
+ }
113
+ },
114
+ "clinical": {
115
+ "primary_focus": {
116
+ "description": "Primary reason for seeking help",
117
+ "type": "single",
118
+ "options": [
119
+ {"value": "substance_use", "label": "Alcohol or Drug Use", "keywords": ["drinking", "drug", "substance", "addiction", "using", "habit", "dependence"], "cite": [518]},
120
+ {"value": "mental_health", "label": "Mental Health", "keywords": ["anxiety", "depression", "trauma", "ptsd", "bipolar", "panic", "mental health", "therapy", "counseling"], "cite": [518]},
121
+ {"value": "dual_diagnosis", "label": "Both (Co-occurring)", "keywords": ["both", "dual diagnosis", "co-occurring", "mental health and substance", "depression and drinking"], "cite": [518, 522]},
122
+ {"value": "unsure", "label": "Unsure", "keywords": ["not sure", "don't know", "unsure", "maybe", "i think"], "cite": [518]}
123
+ ]
124
+ },
125
+ "substances": {
126
+ "description": "Specific substances involved",
127
+ "type": "multi",
128
+ "options": [
129
+ {"value": "alcohol", "label": "Alcohol", "keywords": ["alcohol", "drinking", "beer", "wine", "liquor", "booze", "drunk"], "cite": [65]},
130
+ {"value": "opioids", "label": "Opioids", "keywords": ["opioid", "heroin", "fentanyl", "pills", "oxy", "oxycontin", "percocet", "vicodin", "painkiller", "opiate"], "cite": [171, 867]},
131
+ {"value": "stimulants", "label": "Meth / Stimulants", "keywords": ["meth", "methamphetamine", "cocaine", "crack", "stimulant", "adderall", "amphetamine", "speed", "coke"], "cite": [595, 867]},
132
+ {"value": "cannabis", "label": "Cannabis", "keywords": ["marijuana", "cannabis", "weed", "pot", "thc", "edibles", "smoking weed"], "cite": [7]},
133
+ {"value": "benzodiazepines", "label": "Benzodiazepines", "keywords": ["benzo", "benzodiazepine", "xanax", "valium", "klonopin", "ativan"], "cite": []},
134
+ {"value": "other", "label": "Other Substance", "keywords": [], "cite": []}
135
+ ]
136
+ }
137
+ },
138
+ "preferences": {
139
+ "setting": {
140
+ "description": "Preferred treatment setting",
141
+ "type": "single",
142
+ "options": [
143
+ {"value": "outpatient", "label": "Outpatient", "keywords": ["outpatient", "appointments", "weekly visits", "not live there"], "cite": [523]},
144
+ {"value": "intensive_outpatient", "label": "Intensive Outpatient (IOP)", "keywords": ["intensive outpatient", "iop", "partial hospitalization", "day program"], "cite": [523]},
145
+ {"value": "residential", "label": "Residential / Inpatient", "keywords": ["residential", "inpatient", "rehab", "live-in", "live there", "stay there", "30-day", "90-day"], "cite": [523]},
146
+ {"value": "telehealth", "label": "Telehealth", "keywords": ["telehealth", "online", "virtual", "video", "remote", "from home", "phone appointment"], "cite": [523]}
147
+ ]
148
+ },
149
+ "therapy_approach": {
150
+ "description": "Preferred therapeutic approach",
151
+ "type": "single",
152
+ "options": [
153
+ {"value": "mat", "label": "Medication-Assisted Treatment (MAT)", "keywords": ["mat", "medication-assisted", "suboxone", "methadone", "naltrexone", "vivitrol", "medication treatment", "medically assisted"], "cite": [171, 765]},
154
+ {"value": "cbt", "label": "Cognitive Behavioral Therapy (CBT)", "keywords": ["cbt", "cognitive behavioral", "talk therapy", "behavioral therapy"], "cite": [31, 146]},
155
+ {"value": "twelve_step", "label": "12-Step", "keywords": ["12-step", "twelve step", "aa", "na", "alcoholics anonymous", "narcotics anonymous", "sponsor", "higher power"], "cite": [759]},
156
+ {"value": "medication_only", "label": "Medication Only (No Counseling)", "keywords": ["medication only", "just medication", "no counseling", "no therapy", "just pills", "just meds"], "cite": [991, 993]}
157
+ ]
158
+ },
159
+ "scheduling": {
160
+ "description": "Scheduling constraints",
161
+ "type": "multi",
162
+ "options": [
163
+ {"value": "evening_weekend", "label": "Evening / Weekend Hours", "keywords": ["evening", "weekend", "after work", "night", "saturday", "sunday", "after hours"], "cite": [535]},
164
+ {"value": "after_school", "label": "After-School Scheduling", "keywords": ["after school", "after class", "afternoon"], "cite": [31, 35]}
165
+ ]
166
+ },
167
+ "barriers": {
168
+ "description": "Primary barriers to seeking treatment",
169
+ "type": "multi",
170
+ "options": [
171
+ {"value": "stigma", "label": "Stigma / Shame", "keywords": ["ashamed", "embarrassed", "stigma", "shame", "what people think", "judged", "judgment"], "cite": [7, 301]},
172
+ {"value": "fear_of_labeling", "label": "Fear of Labeling", "keywords": ["label", "labeled", "addict", "alcoholic", "don't want to be called"], "cite": [7]},
173
+ {"value": "denial", "label": "Denial / Uncertainty", "keywords": ["not sure if", "maybe i don't", "is it really", "not that bad", "i can stop"], "cite": [346]},
174
+ {"value": "cost", "label": "Cost", "keywords": ["cost", "expensive", "afford", "money", "price", "cheap", "budget"], "cite": [120]},
175
+ {"value": "legal_fear", "label": "Fear of Legal Consequences", "keywords": ["custody", "lose my kids", "license", "lose my job", "arrested", "legal", "fired"], "cite": [301, 796]},
176
+ {"value": "geographic_isolation", "label": "Geographic Isolation", "keywords": ["rural", "far away", "no providers", "nothing nearby", "middle of nowhere", "long drive"], "cite": [684, 686]},
177
+ {"value": "phone_anxiety", "label": "Phone Anxiety", "keywords": ["hate calling", "don't want to call", "phone anxiety", "can't call", "nervous to call", "scared to call"], "cite": [396, 419]}
178
+ ]
179
+ },
180
+ "contact_channel": {
181
+ "description": "Preferred way to be contacted or reach out",
182
+ "type": "single",
183
+ "options": [
184
+ {"value": "text", "label": "Text Message", "keywords": ["text", "text me", "sms", "message"], "cite": [164, 555]},
185
+ {"value": "phone", "label": "Phone Call", "keywords": ["call", "phone", "call me"], "cite": [488, 712]},
186
+ {"value": "email", "label": "Email", "keywords": ["email", "e-mail"], "cite": [295]},
187
+ {"value": "discreet", "label": "Discreet / Confidential Messaging", "keywords": ["discreet", "confidential", "private", "secret", "no one know"], "cite": [665, 821]}
188
+ ]
189
+ }
190
+ }
191
+ }
references/.DS_Store ADDED
Binary file (6.15 kB). View file
 
references/knowledge/boston_resources.csv ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name,address,city,state,zip,phone,website,primary_focus,substances,age_groups,identity_factors,insurance,settings,therapy_approaches,languages,dmh_region,notes
2
+ "Several DMH site offices also have VideoPhones, which can be used for direct communication between staff and",,Statewide,MA,,(978) 627-4468,,mental_health,,,,,,,english,Statewide,DMH Resource Directory 2025
3
+ North County Site Office,,Statewide,MA,,(978) 627-4468,,mental_health,,,,,,,english,Statewide,DMH Resource Directory 2025
4
+ Springfield Site Office,,Statewide,MA,,(413) 301-0914,,mental_health,,,,,,,english,Statewide,DMH Resource Directory 2025
5
+ Metro North Site Office,,Statewide,MA,,(339) 219-6119,,mental_health,,,,,,,english,Statewide,DMH Resource Directory 2025
6
+ DMH Site Office,,Statewide,MA,,(339) 219-6119,,mental_health,,,,,,,english,Statewide,DMH Resource Directory 2025
7
+ Westborough Site Office,,Statewide,MA,,(508) 948-0605,,mental_health,,,,,,,english,Statewide,DMH Resource Directory 2025
8
+ Lindemann/Cambridge/Somerville Site Office,,Statewide,MA,,(857) 366 4215,,mental_health,,,,,,,english,Statewide,DMH Resource Directory 2025
9
+ "Lemuel Shattuck Hospital (617) 522-8110 Dr. Romas Buivydas, Ph.D.","7888 Chief of Psychiatric Operations
10
+ Jamaica Pl",ain,MA,02130,(617) 522-8110,,mental_health,,,,,,,english,Metro Boston,DMH Resource Directory 2025
11
+ Dr. Solomon Carter Fuller Mental Health Center (617) 626-8700 Valencia Reid,"8929 Chief Operating Officer
12
+ Bost",on,MA,02118,(617) 626-8700,,mental_health,,,,,,,english,Metro Boston,DMH Resource Directory 2025
13
+ Taunton State Hospital Telephone # Person in Charge,,"Chief Operating Officer
14
+ Taunton",MA,02780,(508) 977-3000,,mental_health,,,,,,,english,Southeast,DMH Resource Directory 2025
15
+ Tewksbury Hospital 2859 Chief of Psychiatric Operations,"4000 Kathy Wenzel
16
+ Worcest",er,MA,01604,(978) 851-1029,,mental_health,,adult,,,,,english,Northeast,DMH Resource Directory 2025
17
+ Worcester Recovery Center and Hospital Telephone # Person in Charge,"4000 Kathy Wenzel
18
+ Worcest",er,MA,01604,(508) 368-4000,,mental_health,,adolescent|adult,,,,,english,Central MA,DMH Resource Directory 2025
19
+ Fuller/Bay Cove Site Office Telephone # Person in Charge,"8884 Site Director
20
+ Bost",on,MA,02118,(617) 626-8944,,mental_health,,,,,,,english,Metro Boston,DMH Resource Directory 2025
21
+ Dr. Solomon Carter Fuller Mental Health Center (617) 626-8944 Patricia Cadet,"8884 Site Director
22
+ Bost",on,MA,02118,(617) 626-8944,,mental_health,,,,,,,english,Metro Boston,DMH Resource Directory 2025
23
+ "Center/Cambridge/Somerville Site Office (617) 626-8500 Luis Borrero, MSW, LICSW","8515 Site Director
24
+ Bost",on,MA,02114,(617) 626-8500,,mental_health,,,,,,,english,Metro Boston,DMH Resource Directory 2025
25
+ Massachusetts Mental Health Center Site Office Telephone # Person in Charge,"9300 Rachel Steiner
26
+ Bost",on,MA,02115,(617) 626-9300,,mental_health,,,,,,,english,Metro Boston,DMH Resource Directory 2025
27
+ Pocasset Mental Health Center Telephone # Person in Charge,,"LICSW
28
+ Pocasset",MA,02559,(508) 564-9600,,mental_health,,,,,,,english,Southeast,DMH Resource Directory 2025
29
+ Corrigan Mental Health Center Telephone # Person in Charge,,"LICSW
30
+ Fall River",MA,02720,(508) 235-7200,,mental_health,,,,,,,english,Southeast,DMH Resource Directory 2025
31
+ Brockton Site Office Telephone # Person in Charge,2075 Site Direct,"or
32
+ Brockton",MA,02302,(508) 897-2000,,mental_health,,,lgbtq,,,,english,Southeast,DMH Resource Directory 2025
33
+ Cape Cod & The Islands Site Office Telephone # Person in Charge,7346 Site Direct,"or
34
+ Fall River",MA,02720,(508) 957-0900,,mental_health,,,lgbtq,,,,english,Southeast,DMH Resource Directory 2025
35
+ Fall River Site Office Telephone # Person in Charge,7346 Site Direct,"or
36
+ Fall River",MA,02720,(508) 235-7200,,mental_health,,,,,,,english,Southeast,DMH Resource Directory 2025
37
+ "Corrigan Mental Health Center (508) 235-7200 Jeanne Crespi, LICSW",7346 Site Direct,"or
38
+ Fall River",MA,02720,(508) 235-7200,,mental_health,,,,,,,english,Southeast,DMH Resource Directory 2025
39
+ New Bedford Site Office Telephone # Person in Charge,,"LMHC
40
+ New Bedford",MA,02740,(508) 996-7900,,mental_health,,,,,,,english,Southeast,DMH Resource Directory 2025
41
+ Plymouth Site Office Telephone # Person in Charge,,"MSW
42
+ Plymouth",MA,02360,(508) 732-3000,,mental_health,,,,,,,english,Southeast,DMH Resource Directory 2025
43
+ Quincy Site Office Telephone # Person in Charge,,"Site Director
44
+ Quincy",MA,02169,(617) 984-1000,,mental_health,,,,,,,english,Southeast,DMH Resource Directory 2025
45
+ "Quincy Mental Health Center (617) 984-1000 Laura Ruscio, MSW, LICSW",,"Site Director
46
+ Quincy",MA,02169,(617) 984-1000,,mental_health,,,,,,,english,Southeast,DMH Resource Directory 2025
47
+ Taunton/Attleboro Site Office Telephone # Person in Charge,,"MA
48
+ Taunton",MA,02780,(508) 977-3174,,mental_health,,,,,,,english,Southeast,DMH Resource Directory 2025
49
+ Acton Site Office Telephone # Person in Charge,"2100 Alicia Stacy, MPA,","LSW
50
+ Acton",MA,01720,(978) 206-2100,,mental_health,,,,,,,english,Northeast,DMH Resource Directory 2025
51
+ Essex North Site Office Telephone # Person in Charge,"4500 Steven Noroian,","LMHC
52
+ Lawrence",MA,01843,(978) 738-4500,,mental_health,,,,,,,english,Northeast,DMH Resource Directory 2025
53
+ Lowell Site Office Telephone # Person in Charge,"5000 Gerard Frater, MSW,","LICSW
54
+ Lowell",MA,01851,(978) 322-5000,,mental_health,,,,,,,english,Northeast,DMH Resource Directory 2025
55
+ Lynn Site Office Telephone # Person in Charge,"178 Albion Street, Suite 410 Telephone #","Person in Charge
56
+ Wakefield",MA,01880,(781) 477-2070,,mental_health,,,,,,,english,Northeast,DMH Resource Directory 2025
57
+ Metro North Site Office,"178 Albion Street, Suite 410 Telephone #","Person in Charge
58
+ Wakefield",MA,01880,(781) 224-7900,,mental_health,,,,,,,english,Northeast,DMH Resource Directory 2025
59
+ North Shore Site Office Telephone # Person in Charge,,"LMHC
60
+ Salem",MA,01970,(978) 741-7300,,mental_health,,,,,,,english,Northeast,DMH Resource Directory 2025
61
+ North County Site Office Telephone # Person in Charge,,"LMHC
62
+ Fitchburg",MA,01420,(978) 353-4400,,mental_health,,adolescent,,,,,english,Central MA,DMH Resource Directory 2025
63
+ South County Site Office Telephone # Person in Charge,9721 Site Direct,"or
64
+ Canton",MA,02021,(508) 887-1100,,mental_health,,adolescent,,,,,english,Central MA,DMH Resource Directory 2025
65
+ Worcester Site Office Telephone # Person in Charge,9721 Site Direct,"or
66
+ Canton",MA,02021,(774) 420-3100,,mental_health,,adolescent,,,,,english,Central MA,DMH Resource Directory 2025
67
+ Canton Site Office,9721 Site Direct,"or
68
+ Canton",MA,02021,(781) 401-9700,,mental_health,,adolescent,,,,,english,Central MA,DMH Resource Directory 2025
69
+ Pappas Rehabilitation Hospital for Children Telephone # Person in Charge,9721 Site Direct,"or
70
+ Canton",MA,02021,(781) 401-9700,,mental_health,,adolescent,,,,,english,Central MA,DMH Resource Directory 2025
71
+ Westborough Site Office Telephone # Person in Charge,"2864 Site Director
72
+ West",borough,MA,01581,(508) 616-2801,,mental_health,,,,,,,english,Central MA,DMH Resource Directory 2025
73
+ Berkshire Site Office Telephone # Person in Charge,,"LICSW
74
+ Pittsfield",MA,01201,(413) 395-2000,,mental_health,,,,,,,english,Western MA,DMH Resource Directory 2025
75
+ Franklin/North Quabbin Site Office Telephone # Person in Charge,,"LICSW
76
+ Greenfield",MA,01301,(413) 772-5600,,mental_health,,,,,,,english,Western MA,DMH Resource Directory 2025
77
+ Hampshire Site Office Telephone # Person in Charge,,"LMHC
78
+ Northampton",MA,01060,(413) 587-6200,,mental_health,,,,,,,english,Western MA,DMH Resource Directory 2025
79
+ Holyoke/Chicopee Site Office Telephone # Person in Charge,,"LCSW
80
+ Springfield",MA,01104,(413) 452-2300,,mental_health,,,,,,,english,Western MA,DMH Resource Directory 2025
81
+ Springfield Site Office Telephone # Person in Charge,"6200 Christine Fowle,","B.A.
82
+ Northampton",MA,01060,(413) 452-2300,,mental_health,,,,,,,english,Western MA,DMH Resource Directory 2025
83
+ Westfield Site Office Telephone # Person in Charge,"6200 Christine Fowle,","B.A.
84
+ Northampton",MA,01060,(413) 587-6200,,mental_health,,,,,,,english,Western MA,DMH Resource Directory 2025
85
+ "If you have any questions or comments about this directory, please contact the Office of Race,",,,MA,,(617) 626-8134,https://mass.gov/service-,mental_health,,,accessibility|immigrant_refugee|lgbtq,,,,english,Statewide,DMH Multicultural Directory 2019
86
+ EMERGENCY LINE,,,MA,,877-382-1609,https://mass.gov/dmh,dual_diagnosis,,,,,,,english,Statewide,DMH Multicultural Directory 2019
87
+ MASSACHUSETTS DEPARTMENT OF MENTAL HEALTH (DMH),"25 Staniford Street,",Boston,MA,02114,800-221-0053,https://mass.gov/dmh,mental_health,,,,,,,english,Statewide,DMH Multicultural Directory 2019
88
+ Help is available for those with a drug or alcohol problem at helpline-online.org or,"250 Washington Street,",Boston,MA,02108,800-720-3480,https://mass.gov/eohhs/gov/departments/dph/programs/substance-abuse,dual_diagnosis,alcohol,adolescent,accessibility,,,,english,Statewide,DMH Multicultural Directory 2019
89
+ HEARING (MCDHH),"600 Washington Street,",Boston,MA,02111,617-740-1600,https://mass.gov/eohhs/gov/departments/mcdhh,dual_diagnosis,,,accessibility|immigrant_refugee,,,,english,Statewide,DMH Multicultural Directory 2019
90
+ MASSACHUSETTS OFFICE FOR REFUGEES AND IMMIGRANTS (MORI),"600 Washington Street,",Boston,MA,02111,617-727-7888,https://mass.gov/eohhs/gov/departments/ori,dual_diagnosis,,,accessibility|immigrant_refugee,,,,english,Statewide,DMH Multicultural Directory 2019
91
+ MASS 2-1-1,,,MA,,877-211-6277,https://mass.gov/eohhs/gov/departments/ori/key-resources.html,dual_diagnosis,,,immigrant_refugee,,,,english,Statewide,DMH Multicultural Directory 2019
92
+ MASSACHUSETTS REHABILITATION COMMISSION (MRC),"600 Washington Street,",Boston,MA,02111,617-204-3600,https://massoptions.org,dual_diagnosis,,older_adult,accessibility,,,,english|spanish,Statewide,DMH Multicultural Directory 2019
93
+ ADVOCATES,,Framingham,MA,01701,800-640-5432,https://advocates.org,dual_diagnosis,,,accessibility,,,,english,Statewide,DMH Multicultural Directory 2019
94
+ ASPERGER / AUTISM NETWORK,"51 Water Street, Suite 206,",Watertown,MA,02472,617- 393-3824,https://advocates.org,dual_diagnosis,,,,,,,english,Statewide,DMH Multicultural Directory 2019
95
+ "BROCKTON AREA MULTI-SERVICES, INC. (BAMSI)",,Brockton,MA,02301,508-580-8700,https://baycove.org,dual_diagnosis,alcohol,adolescent|older_adult,accessibility,,,,cape_verdean_creole|english|portuguese,Statewide,DMH Multicultural Directory 2019
96
+ "Helpline for health care, social services, financial assistance, housing, and food pantries:",,Brockton,MA,02301,508-584-4357,https://baycove.org,dual_diagnosis,alcohol,adolescent|older_adult,accessibility,,,,cape_verdean_creole|english|portuguese,Statewide,DMH Multicultural Directory 2019
97
+ CAMBRIDGE HEALTH ALLIANCE,"1493 Cambridge Street,",Cambridge,MA,02139,617-665-1305,https://bamsi.org,dual_diagnosis,,adolescent,accessibility,,,,cape_verdean_creole|english|portuguese,Statewide,DMH Multicultural Directory 2019
98
+ “LINK-KID”,,,MA,,855-456-5543,https://challiance.org,dual_diagnosis,,adolescent,accessibility,,,,cape_verdean_creole|english|portuguese,Statewide,DMH Multicultural Directory 2019
99
+ DISABILITY LAW CENTER,"11 Beacon Street, Suite 925,",Boston,MA,02108,617-723-8455,https://deafinconline.org,mental_health,,adolescent,accessibility|lgbtq,,,,english|mandarin|portuguese|spanish,Statewide,DMH Multicultural Directory 2019
100
+ FEDERATION FOR CHILDREN WITH SPECIAL NEEDS,"529 Main Street,",Boston,MA,02129,617-236-7210,https://frcma.org,mental_health,,adolescent,accessibility|lgbtq,,,,english|french|haitian_creole|mandarin|portuguese|spanish,Statewide,DMH Multicultural Directory 2019
101
+ JAPANESE BOSTONIANS SUPPORT LINE,,,MA,,781-296-1800,https://hmhnetwork.org/boston-based-agencies,mental_health,,adult,accessibility,,residential,,english|japanese,Statewide,DMH Multicultural Directory 2019
102
+ JUSTICE RESOURCE INSTITUTE,"160 Gould Street, Suite 300,",Needham,MA,02494,781-559-4900,https://hmhnetwork.org/boston-based-agencies,mental_health,,adult,accessibility,,residential,,english|japanese,Statewide,DMH Multicultural Directory 2019
103
+ MASSACHUSETTS ADULT DAY SERVICES ASSOCIATION,"1 Florence Street,",Boston,MA,02131,617-469-5848,https://jri.org,mental_health,,adult,accessibility,,residential,,english,Statewide,DMH Multicultural Directory 2019
104
+ MASSACHUSETTS LEAGUE OF COMMUNITY HEALTH CENTERS,"40 Court Street #10,",Boston,MA,02108,617-426-2225,https://masspartnership.com,dual_diagnosis,alcohol,adolescent,homeless|immigrant_refugee,,,,english,Statewide,DMH Multicultural Directory 2019
105
+ MASSACHUSETTS ORGANIZATION FOR ADDICTION RECOVERY,"29 Winter Street, 2nd Floor,",Boston,MA,02108,617-423-6627,https://moar-recovery.org,dual_diagnosis,alcohol,adolescent,accessibility|homeless|immigrant_refugee,,,,english,Statewide,DMH Multicultural Directory 2019
106
+ PARENT/PROFESSIONAL ADVOCACY LEAGUE (PPAL),,Boston,MA,02108,866-815-8122,https://nami.org,mental_health,,adolescent|adult|young_adult,woman,,,,bengali|english|gujarati|haitian_creole|hindi|nepali|punjabi|spanish|tamil|urdu,Statewide,DMH Multicultural Directory 2019
107
+ SAHELI,,Burlington,MA,01803,866-472-4354,https://ppal.net/wp-content/uploads/2011/01/Child-,mental_health,,adolescent|adult|young_adult,accessibility|woman,,,,bengali|english|gujarati|haitian_creole|hindi|nepali|punjabi|spanish|tamil|urdu,Statewide,DMH Multicultural Directory 2019
108
+ "1 Frederick Abbott Way, Framingham, MA 01701","1 Frederick Abbott Way,",Framingham,MA,01701,508-879-9800,https://transformation-center.org,dual_diagnosis,,adolescent|adult|older_adult|young_adult,accessibility|immigrant_refugee,,residential,,english|spanish,Statewide,DMH Multicultural Directory 2019
109
+ Arbour Counseling Services ns/arbour-counseling-serv Asian American Civi Association 617-426-9492 Asian Task Force Agai Domestic Violence 617-338-2350 24 hour Multilingual Helpli 617-338-2355 2019 DMH MULTICU,P.O. Box 120108,Boston,MA,02112,617-782-6460,https://arbourhealth.com/organiz,mental_health,,adolescent|young_adult,,,residential,,bengali|cantonese|english|french|hebrew|hindi|italian|japanese|khmer|korean|lao|mandarin|nepali|russian|spanish|tagalog|thai|urdu|vietnamese,Metro Boston,DMH Multicultural Directory 2019
110
+ "Association of Haitia Women in Boston Boston Alliance of Ga Lesbian, Bisexual, an Transgender Youth In 617-227-4313 Boston Asian: Youth Essential Service, Inc 617-482-4243 Boston Center for Refugee Health and Human Rights 617-414-4794 Boston Chinatown Neighborhood Cente 617-635-5129 2019 DMH MULTICU",38 Ash Street,Boston,MA,02111,617-287-0096,https://afab-kafanm.org,dual_diagnosis,,adolescent|adult,immigrant_refugee|lgbtq|woman,,,,asl|cantonese|english|haitian_creole|mandarin|multilingual_interpretation|vietnamese,Metro Boston,DMH Multicultural Directory 2019
111
+ "Boston Children’s Hospital Department Psychiatry and-services/department- psychiatry Boston GLASS For LGBTQ+ youth, homel youth, and youth living wi HIV ages 13-29 857-399-1920 housing/health/boston-gl Boston Mayor’s Heal Line floor 800-847-0710 health-line Boston Medical Cente Immigrant & Refuge Program 617-414-5951 2019 DMH MULTICU",725 Albany Street,Boston,MA,02118,617-355-6680,https://childrenshospital.org/cent,dual_diagnosis,,adolescent,accessibility|immigrant_refugee|lgbtq|woman,,outpatient|residential,,cape_verdean_creole|english|haitian_creole|multilingual_interpretation|portuguese|spanish,Metro Boston,DMH Multicultural Directory 2019
112
+ "Brazilian Immigran Center Brazilian Women’s Group 617-202-5775 Casa Esperanza 617-445-1123 Casa Myrna Vazquez, I 617-521-0100 Domestic Violence Hotlin 877-785-2020 2019 DMH MULTICU",P.O. Box 180019,Boston,MA,02118,617-783-8001,https://braziliancenter.org,dual_diagnosis,,adolescent,woman,,residential,,english|portuguese|spanish,Metro Boston,DMH Multicultural Directory 2019
113
+ "Center Club, a progra of Bay Cove Human Services 617-788-1091 (Spanish) Center for Cross-Cultu Student Emotional Wellness 617-726-2000 ervices/ccsew_home.asp Children’s Services o Roxbury Specializes in serving the African-American populatio Greater Boston 617-445-6655 2019 DMH MULTICU",504 Dudley Street,Roxbury,MA,02119,617-788-1000,https://centerclubboston.org,dual_diagnosis,,adolescent|adult|young_adult,,,outpatient,,cantonese|cape_verdean_creole|english|haitian_creole|mandarin|spanish,Metro Boston,DMH Multicultural Directory 2019
114
+ "Community Legal Services and Counseli Center Deaf and Hard of Hearing Service, Cambridge Health Alliance 617-665-3458 Dorchester House Hea Multi-Service Cente 617-740-2212 Emerge: Counseling a Education to Stop Domestic Violence Suite 101 617-547-9879 2019 DMH MULTICU",2464 Massachusetts Avenu,Cambridge,MA,02140,617-661-1010,https://clsacc.org,dual_diagnosis,,,accessibility|immigrant_refugee,,,,asl|english|french|spanish|vietnamese,Metro Boston,DMH Multicultural Directory 2019
115
+ Eritrean Community Center Ethiopian Communit Mutual Assistance Association 617-492-4232 Fenway Health Healthcare for the LGBTQ community 617-267-0900 617-247-7555 617-457-8140 2019 DMH MULTICU,75 Kneeland Street,Boston,MA,02111,617-427-1210,https://eccboston.org,dual_diagnosis,,adult,lgbtq,,outpatient,,english|spanish,Metro Boston,DMH Multicultural Directory 2019
116
+ Freedom Trail Clinic Deaf and Hard of Hearing Outpatient Mental Health lt-services/deaf-and-hard- hearing-outpatient-clinic services Frosina Information Network Albanian Cultural Resource Information Center 617-482-2002 Guidance Center 617-354-2275 2019 DMH MULTICU,5 Sacramento Street,Cambridge,MA,02138,617-912-7800,https://northsuffolk.org/services/,mental_health,,adolescent,accessibility,,outpatient,,asl|cantonese|english|haitian_creole|mandarin|portuguese|spanish,Metro Boston,DMH Multicultural Directory 2019
117
+ Haitian American Pub Health Initiative 1601-1603 Blue Hill Avenu Haitian Mental Healt Network Email:HMHnetwork@gmail.c Harvard Program in Refugee Trauma 617-876-7879 Home for Little Wanderers 617-267-3700 Multiple sites in Boston ar 2019 DMH MULTICUL,10 Guest Street,Boston,MA,02135,617-298-8076,https://haphi.org,mental_health,,adolescent,immigrant_refugee,,residential,,english|french|haitian_creole|mandarin|spanish,Metro Boston,DMH Multicultural Directory 2019
118
+ Inquilinos Boricuas E Accion Irish International Immigrant Center 617-542-7654 Irish Pastoral Cente 617-265-5300 Italian Home for Children 617-787-1901 2019 DMH MULTICUL,77 Warren Street,Brighton,MA,01235,617-927-1707,https://iba-etc.org,dual_diagnosis,alcohol,adolescent,immigrant_refugee,,,,english|french|haitian_creole|spanish,Metro Boston,DMH Multicultural Directory 2019
119
+ "Kit Clark Senior Servi La Alianza Hispana, In 617-427-7175 Latino Health Insuran Program Iglesia Cristiana Nueva Vid 617-567-0235 Ext. 2 Massachusetts Alliance Portuguese Speaker 617-864-7600 Locations in Somerville, Brighton, and Dorchester 2019 DMH MULTICUL",1046 Cambridge Street,Cambridge,MA,02139,617-788-1083,https://kitclark.org,dual_diagnosis,,adolescent|older_adult,immigrant_refugee,,outpatient,,english|haitian_creole|portuguese|spanish|vietnamese,Metro Boston,DMH Multicultural Directory 2019
120
+ "Massachusetts Societ for the Prevention o Cruelty to Children Native American Lifelines of Boston 857-203-9680 nativeamericanlifelines.o North American India Center of Boston, Inc 617-232-0343 North Suffolk Menta Health Association, In 617-889-3300 Locations in East Boston a Revere 2019 DMH MULTICUL",301 Broadway Street,Chelsea,MA,02128,617-983-5800,https://mspcc.org,dual_diagnosis,,adolescent|adult|older_adult,,,outpatient,,asl|cantonese|english|haitian_creole|khmer|mandarin|portuguese|spanish|vietnamese,Metro Boston,DMH Multicultural Directory 2019
121
+ "Osiris Family Institu Priority Professiona Care 857-598-4774 Pyramid Builders Counseling Services, I 857-267-2059 Refugee and Immigra Assistance Center 617-238-2430 2019 DMH MULTICUL",31 Heath Street,Jamaica Plain,MA,02130,617-442-2002,https://osirisinstitute.com,dual_diagnosis,,adolescent,immigrant_refugee,,,,arabic|cape_verdean_creole|english|french|haitian_creole|portuguese|somali|spanish,Metro Boston,DMH Multicultural Directory 2019
122
+ "Roca, Inc. Roxbury Multi-Servic Center 617-989-0292 Somali Developmen Center 10 Malcolm X Blvd. 2nd Flo 617-522-0700 South Bay Communi Service, Dorchester Mental Health Clinic 857-217-3700 southbaycommunityservices. 2019 DMH MULTICUL","415 Neponset Avenue, 3rd Fl",Dorchester,MA,02122,617-889-5210,https://rocainc.org,dual_diagnosis,,adolescent|adult,,,,,arabic|asl|cantonese|english|haitian_creole|mandarin|portuguese|somali|spanish|vietnamese,Metro Boston,DMH Multicultural Directory 2019
123
+ Trauma Center Ummah Health 617-858-6114 Vietnamese America Civic Association 617-288-7344 Vietnamese America Initiative for Development 617-822-3717 Women’s Center 617-354-6394 cambridgewomenscenter. 2019 DMH MULTICUL,46 Pleasant Street,Cambridge,MA,02139,617-232-1303,https://traumacenter.org,mental_health,alcohol,adolescent|adult|young_adult,woman,,outpatient,,arabic|english|spanish|vietnamese,Metro Boston,DMH Multicultural Directory 2019
124
+ "Advocates, Inc. and Advo Deaf Services Video Phone: 774-999-06 Email: DeafInquiries@Advoca African Children Educa 508-799-3653 ARISE (Advocacy for Re and Immigrant Service Empowerment) 617-446-3706 Ascentria Care Allian 774-243-3100 2019 DMH MULTICUL",11 Shattuck Street,Worcester,MA,01605,508-628-6300,https://advocates.org,mental_health,,adolescent,accessibility|immigrant_refugee,,outpatient|residential,,arabic|asl|english|haitian_creole|nepali|somali,Central MA,DMH Multicultural Directory 2019
125
+ "Boston Health Care Callahan Center 508-532-5980 Center for Health Imp 508-756-6676 centerforhealthimpact. Center for Living an Working, Inc.: Deaf and of Hearing Independ Living Services Denholm Building, Suite 3 Voice: 508-798-0350 Video Phone: 508-762-11 2019 DMH MULTICUL",484 Main Street,Worcester,MA,01608,508-660-7974,https://bostonhealthcareinc.co,dual_diagnosis,,adolescent|adult|older_adult,accessibility,,,,arabic|asl|english|spanish|urdu,Central MA,DMH Multicultural Directory 2019
126
+ "Centro Las America Children’s Friend 508-753-5425 s-friend Community Healthlink 508-791-3261 communityhealthlink.o Counseling and Assessm Clinic of Worcester, L 508-756-5400 978-345-9400 2019 DMH MULTICUL","33 Electric Avenue, Suite 2",Fitchburg,MA,01420,508-798-1900,https://centroinc.org,dual_diagnosis,,adolescent|adult,,,outpatient,,arabic|english|french|haitian_creole|italian|portuguese|spanish|thai|vietnamese,Central MA,DMH Multicultural Directory 2019
127
+ Everyday Miracles everydaymiraclesprsc. Family Continuity Prog (FCP) 508-755-0556 508-234-4181 Friendly House 508-755-4362 2019 DMH MULTICUL,36 Wall Street,Worcester,MA,01604,508-799-6227,https://familycontinuity.org,mental_health,,,homeless,,outpatient,,arabic|english|nepali|somali|spanish,Central MA,DMH Multicultural Directory 2019
128
+ "Hearing Loss Associati Central Massachuset Headquarters address: Bethesda, MD 20814 Meetings at Northborough Li Northborough, MA 0153 Email: info@hearinglosscentra .com Hector Reyes Hous Latin American Heal Alliance 508-459-1801 Jewish Community Ce 508-756-7109 2019 DMH MULTICUL",633 Salisbury Street,Worcester,MA,01609,301-657-2248,https://hearinglosscentralma.wor,dual_diagnosis,alcohol,adolescent|older_adult,,,residential,,asl|english|portuguese|spanish,Central MA,DMH Multicultural Directory 2019
129
+ "Kiva Center Latino Health Insura Program 508-875-1237 Locations in Milford and Wor Learning Center for the Framingham, MA 0170 508-879-5110 Video Phone: 774-999-09 LUK Crisis Center 978-345-0685 508-640-0011 508-672-3000 2019 DMH MULTICUL",40 Southbridge Street,Worcester,MA,01608,508-751-9600,https://centralmassrlc.org,dual_diagnosis,,adolescent|adult|young_adult,accessibility,,residential,,asl|english|portuguese|spanish,Central MA,DMH Multicultural Directory 2019
130
+ "Martin Luther King J Opportunity Center, SM Multicultural Wellness C 508-752-4665 978-343-3336 multiculturalwellness. Our Deaf Survivors Ce 978-451-7225 Email: CBosdc414@gmail. 2019 DMH MULTICUL",12 Meade Street,Worcester,MA,01610,508-756-6330,https://mlkj-oc.org,dual_diagnosis,,,accessibility|homeless,,outpatient,,arabic|asl|bengali|cape_verdean_creole|english|french|haitian_creole|hindi|japanese|portuguese|punjabi|russian|spanish,Central MA,DMH Multicultural Directory 2019
131
+ Pathways for Change: Survivors Program Video Phone: 508-502-76 ncy-programs/deaf-survi program Refugee & Immigran Assistance Center Riverside Community 781-329-0909 2019 DMH MULTICUL,"270 Bridge Street, Suite 3",Dedham,MA,02026,508-756-7557,https://pathwaysforchange.help/p,mental_health,,adolescent,accessibility|immigrant_refugee,,outpatient,,arabic|asl|cantonese|english|french|korean|mandarin|portuguese|russian|somali|spanish,Central MA,DMH Multicultural Directory 2019
132
+ Sarah Care /Adult Day H SMOC Behavioral Hea Services 508-872-4853 508-460-9699 Southeast Asian Coaliti Central Massachuset 508-791-4373 2019 DMH MULTICULT,"484 Main Street, Suite 40",Worcester,MA,01608,508-756-7272,https://sarahcare.com/Worces,dual_diagnosis,,adolescent|adult|young_adult,immigrant_refugee|woman,,residential,,english|khmer|lao|mandarin|portuguese|spanish|thai|vietnamese,Central MA,DMH Multicultural Directory 2019
133
+ "Spanish American Cen spanishamericancenter UMass Memorial Health Behavioral/Psychiat Services 508-334-1000 Other locations in Worces umassmemorialhealthcar United Hmong of Massachusetts, Inc 978-343-3831 2019 DMH MULTICULT","21 Culley Street, Suite 10",Fitchburg,MA,01420,978-534-3145,https://unitedhmong.org,dual_diagnosis,,older_adult,homeless|woman,,outpatient|residential,,asl|english|spanish,Central MA,DMH Multicultural Directory 2019
134
+ Worcester Adult Day He Renaissance daycare/worcester_ma_ci l Youth Opportunities Up Inc. 508-849-5600 Zia Access Center At The Bridge of Central M 508-751-9600 At the Kiva Center 774-242-6364 2019 DMH MULTICULT,209 Shrewsbury Street,Worcester,MA,01602,508-831-7500,https://daycarein.com/adult,dual_diagnosis,,adolescent|adult|young_adult,lgbtq,,intensive_outpatient|outpatient|residential,,asl|english|portuguese|russian|spanish,Central MA,DMH Multicultural Directory 2019
135
+ "Alternative House, In Arbour Counseling Services 978-373-7010 978-686-8202 978-453-5736 Arbour Counseling Services Latino Program 617-855-2000 /Latino-services 2019 DMH MULTICULTURA",115 Mill Street,Belmont,MA,02478,978-937-5777,https://alternative-house.org,dual_diagnosis,,adult,lgbtq|woman,,,,english|khmer|portuguese|russian|spanish,Northeast,DMH Multicultural Directory 2019
136
+ "Bosnian Community Center for Resource Development, Inc. Cambodian Mutual Assistance Associatio 978-454-6200 Children’s Friend & Family Services—A Division of Justice Research Institute 781-592-5691 978-682-7289 2019 DMH MULTICULTURA",15 Union Street,Lawrence,MA,01840,781-593-0100,https://bccrd.org,mental_health,,adolescent,accessibility|immigrant_refugee,,outpatient,,arabic|cantonese|english|haitian_creole|hindi|khmer|lao|mandarin|nepali|somali|spanish|thai|vietnamese,Northeast,DMH Multicultural Directory 2019
137
+ Congolese Development Center Eliot Community Human Services 781-395-0704 Family Continuity Programs (FCP) 978-687-1617 978-927-9410 2019 DMH MULTICULTURA,"9 Centennial Drive, Suite 20",Peabody,MA,01960,781-593-0100,https://cd-c.org,dual_diagnosis,,adolescent,,,outpatient,,english|french|haitian_creole|mandarin|portuguese|spanish,Northeast,DMH Multicultural Directory 2019
138
+ International Institut of Lowell Jewish Family and Children’s Services 781-647-5327 Lahey/Northeast Behavioral Health 978-374-0414 978-922-0025 2019 DMH MULTICULTURA,298 Washington Street,Gloucester,MA,01930,978-459-9031,https://iine.org,dual_diagnosis,,adolescent|adult,immigrant_refugee,,intensive_outpatient|outpatient|residential,,english|french|haitian_creole|hebrew|japanese|russian|spanish,Northeast,DMH Multicultural Directory 2019
139
+ Lowell Community Health Metta Health Center Massachusetts Allianc of Portuguese Speake (MAPS) 978-970-1250 2019 DMH MULTICULTURA,11 Mill Street,Lowell,MA,01852,978-441-1700,https://lchealth.org,mental_health,,older_adult,immigrant_refugee,,,,english|french|hindi|khmer|lao|mandarin|portuguese|vietnamese,Northeast,DMH Multicultural Directory 2019
140
+ McLean Hospital Mystic Valley Elder Services 781-324-7705 Northeast Independe Living Program 978-687-4288 2019 DMH MULTICULTURA,20 Ballard Road,Lawrence,MA,01843,800-333-0338,https://mcleanhospital.org,mental_health,alcohol,adolescent|adult|older_adult,accessibility|lgbtq,,outpatient|residential,,asl|english|french|haitian_creole|russian|spanish,Northeast,DMH Multicultural Directory 2019
141
+ Refugee & Immigran Assistance Center (RIAC) Russian Community Association of Massachusetts 781-593-0100 South Bay Communit Services 978-542-1951 978-674-5400 Other locations in Lawrenc and Malden southbaycommunityser 2019 DMH MULTICULTURA,22 Old Canal Drive,Lowell,MA,01851,781-593-0100,https://riacboston.org,dual_diagnosis,,adolescent|adult|older_adult,immigrant_refugee,,,,arabic|english|japanese|khmer|portuguese|russian|somali|spanish,Northeast,DMH Multicultural Directory 2019
142
+ Wayside Youth & Family Support Network YouForward 978-989-2047 Drop-in Centers: Mondays through Wednesdays 1:00-6:00pm YouForward-Entrance B i the back of the building Thursdays 2:00-5:00pm Haverhill YMCA 2019 DMH MULTICULTURA,81 Winter Street,Haverhill,MA,01830,978-460-8712,https://waysideyouth.org,mental_health,,adolescent|adult|young_adult,lgbtq,,outpatient,,english|khmer|portuguese|spanish,Northeast,DMH Multicultural Directory 2019
143
+ "Abelard Psychothera LLC Arbour Counseling Center West Yarmouth, MA 026 774-470-2294 508-678-2833 BAMSI (Brockton Ar Multi-Services, Inc. 508-580-8700",24 Mercedes Road,Brockton,MA,02301,781-344-0057,https://abelardpsychotherapy.co,dual_diagnosis,,adolescent|adult,,,intensive_outpatient|outpatient,,cape_verdean_creole|english|haitian_creole|portuguese|spanish,Southeast,DMH Multicultural Directory 2019
144
+ "Boston Chinatown Neighborhood Cente 617-770-0091 Bristol Elder Service 1 Father Devalles Blvd, # 508-675-2101 Cape Cod Behaviora Health Services Psychiatric Center 508-862-5566",27 Park Street,Hyannis,MA,02601,617-635-5129,https://bcnc.net,mental_health,,adolescent|adult|older_adult,,,outpatient|residential,,asl|cantonese|english|khmer|mandarin|portuguese|spanish|vietnamese,Southeast,DMH Multicultural Directory 2019
145
+ Catholic Charities Child & Family Servic 508-990-0894 508-996-8572 508-996-3154,543 North Street,New Bedford,MA,02740,508-587-0815,https://ccab.org,mental_health,,adolescent,immigrant_refugee,,,,cape_verdean_creole|english|french|haitian_creole|portuguese|spanish,Southeast,DMH Multicultural Directory 2019
146
+ "Community Counseli of Bristol County 508-823-6124 508-222-8812 Fairwinds-Nantucke Counseling Center 20 Vesper Lane, #L1 508-228-2689",5 Bank Street,Nantucket,MA,02554,508-828-9116,https://comcounseling.org,dual_diagnosis,,adolescent|adult,,,outpatient,,asl|english|korean|portuguese|spanish,Southeast,DMH Multicultural Directory 2019
147
+ "Family Continuity Program (FCP) 29 Bassett lane 508-862-0273 Family Service Association 508-677-3822 Health Imperatives 508-583-3005 Other locations in Falmou Vineyard Haven, Nantuck Plymouth, and New Bedfo",942 West Chestnut Stre,Brockton,MA,02301,508-747-6762,https://familycontinuity.org,mental_health,,adolescent|adult,lgbtq,,outpatient,,cape_verdean_creole|english|khmer|portuguese|spanish,Southeast,DMH Multicultural Directory 2019
148
+ High Point Treatme Center Immigrants Assistan Center 508-996-8113 immigrantsassistancecenter Independence Hous Inc. 160 Bassett Lane 508-771-6507,58 Crapo Street,Hyannis,MA,02601,508-224-7701,https://hptc.org,dual_diagnosis,,adolescent,immigrant_refugee|woman,,outpatient,,english|portuguese|spanish,Southeast,DMH Multicultural Directory 2019
149
+ "Italian Home for Children 5 Palmer Court East Freetown, MA 0271 Luminosity Behavior Health 781-344-0102 Martha’s Vineyard Community Service 508-693-7900",111 Edgartown Road,Oak Bluffs,MA,02557,508-763-4217,https://italianhome.org,dual_diagnosis,,adolescent,veteran,,,,asl|cape_verdean_creole|english|french|haitian_creole|portuguese|spanish,Southeast,DMH Multicultural Directory 2019
150
+ New Life Counselin 400-402 North Main Stre newlifecounselingcenter. Northeast Family Services 774-206-1125 northeastfamilyservices.c Pyramid Builders Counseling 617-481-8566 pyramidbuilderscounseling.,425 Pleasant street,Brockton,MA,02301,781-986-4800,,mental_health,,,,,outpatient,,cantonese|cape_verdean_creole|english|haitian_creole|mandarin|spanish,Southeast,DMH Multicultural Directory 2019
151
+ "Seven Hills Behavior Health New Bedford, MA 0274 South Shore Menta Health 617-847-1950 St. Vincent’s Home 508-679-8511",2425 Highland Avenue,Fall River,MA,02720,508-995-6360,https://sevenhills.org,dual_diagnosis,,adolescent|adult,,,intensive_outpatient|outpatient|residential,,asl|cantonese|cape_verdean_creole|english|french|haitian_creole|mandarin|portuguese|spanish|vietnamese,Southeast,DMH Multicultural Directory 2019
152
+ The Women’s Cente (Greater New Bedfo Women’s Center),405 County Street,New Bedford,MA,02740,508-996-3343,https://thewomenscenters.com,mental_health,,adolescent,woman,,residential,,english|portuguese|spanish,Southeast,DMH Multicultural Directory 2019
153
+ "A Positive Place Northampton, MA 0106 ms-services/hivaids AdCare West Springfield, MA 010 413-209-3124 AdLib 413-442-7047 2019 DMH MUL",215 North Street,Pittsfield,MA,01201,413-586-8288,https://cooleydickinson.org/pr,mental_health,,,accessibility|lgbtq|woman,,outpatient,,asl|english,Western MA,DMH Multicultural Directory 2019
154
+ "Anchor House Northampton, MA 0106 anchorhouseartists.o Ascentria Service for N Americans 413-787-0725 services/services-new americans Behavioral Health Network 413-747-0705 Other locations in Westfie Ware, Greenfield, and Holy 2019 DMH MUL",417 Liberty Street,Springfield,MA,01104,413-588-4337,https://ascentria.org/our-,dual_diagnosis,,adolescent,immigrant_refugee|lgbtq,,,,english|italian|russian|spanish,Western MA,DMH Multicultural Directory 2019
155
+ "Berkshire Immigran Center Brick House Commun Resource Center Turners Falls, MA 0137 413-863-9576 brickhousecommunity. Brien Center 413-499-0412 2019 DMH MUL",333 East Street,Pittsfield,MA,01201,413-445-4881,https://berkshireic.com,mental_health,,adolescent|adult,immigrant_refugee,,outpatient,,asl|english|russian|spanish,Western MA,DMH Multicultural Directory 2019
156
+ "Casa Latina Catholic Charities, Diocese of Springfie 413-452-0605 es/cca Center for Human Development 413-733-6624 Center for New Americans Northampton, MA 0106 413-587-0084 2019 DMH MUL",42 Gothic Street,Springfield,MA,01107,413-586-1569,https://casalatinainc.org,mental_health,,adolescent|older_adult,accessibility|immigrant_refugee|lgbtq,,,,english|mandarin|russian|spanish|urdu|vietnamese,Western MA,DMH Multicultural Directory 2019
157
+ "ORGANIZATIONS Center for Women a Community Clinical & Support Options Northampton, MA 0106 413-773-1314 Other locations include Greenfield, Pittsfield, Spring Athol, Amherst, Florenc Orange, and Gardner Community Action 413-774-2318 Northampton, MA 0106 413-582-4230 978-544-5423 2019 DMH MUL",167 South Main Street,Orange,MA,01364,413-545-0883,https://umass.edu/cwc,mental_health,,adolescent|adult,lgbtq|woman,,outpatient,,english|nepali|russian|spanish,Western MA,DMH Multicultural Directory 2019
158
+ ORGANIZATIONS DIAL/SELF Youth an Community Service Elizabeth Freeman Ce 413-499-2425 elizabethfreemancenter Fair Housing Cente 413-539-9796 2019 DMH MUL,57 Suffolk Street,Holyoke,MA,01040,413-774-7054,https://dialself.org,mental_health,,adolescent|adult|young_adult,homeless|immigrant_refugee|lgbtq,,,,english|spanish,Western MA,DMH Multicultural Directory 2019
159
+ "Franklin County Lif Path Gandara Center West Springfield, MA 010 413-736-8329 Guidewire Inc. 413-733-6100 413-443-3295 2019 DMH MUL",34 Depot Street,Pittsfield,MA,01201,413-773-5555,https://lifepathma.org,dual_diagnosis,,adolescent|adult|older_adult|young_adult,accessibility|lgbtq,,intensive_outpatient|residential,,asl|english|spanish,Western MA,DMH Multicultural Directory 2019
160
+ "Impact Center Springfield, MA youth-access-center Jewish Family Servic Western Massachuse 413-737-2601 2019 DMH MUL",15 Lenox Street,Springfield,MA,01108,413-654-1566,https://gandaracenter.org/imp,dual_diagnosis,,adolescent,immigrant_refugee,,,,arabic|english|french|nepali|somali|spanish|vietnamese,Western MA,DMH Multicultural Directory 2019
161
+ Martin Luther King J Family Services Massachusetts Society the Prevention of Cru to Children 413-532-9446 Mental Health Association 413-734-5376 2019 DMH MULT,995 Worthington Stree,Springfield,MA,01109,413-746-3655,https://mlkjrfamilyservices.org,mental_health,,adolescent|adult|young_adult,accessibility|homeless,,residential,,english|spanish,Western MA,DMH Multicultural Directory 2019
162
+ "Montague Catholic So Ministries Turners Falls, MA 0137 New England Learni Center for Women i Transition 413-772-0871 Northeast Center fo Youth and Familie Easthampton, MA 0102 800-360-6210 2019 DMH MULT",203 East Street,Greenfield,MA,01301,413-863-4804,https://mcsmcommunity.or,mental_health,,adolescent,woman,,intensive_outpatient|outpatient|residential,,english|spanish,Western MA,DMH Multicultural Directory 2019
163
+ "Northeast Family Serv West Springfield, MA 010 northeastfamilyservices Nuestras Raices, In 413-535-1789 Picknelly Adult an Family Education Cen 413-552-2990 progams/adult-basic education/picknelly-ad and-family-educatin-ce Roca Inc. 413-846-4301 2019 DMH MULT",29 School Street,Springfield,MA,01105,774-206-1125,https://nuestras-raices.org,mental_health,,adolescent|adult,,,outpatient,,english|spanish,Western MA,DMH Multicultural Directory 2019
164
+ "Safe Passage Northampton, MA 0106 ServiceNet Northampton, MA 0106 413-585-1300 Springfield Vietnam Cultural Center 413-733-9373 2019 DMH MULT",433 Belmont Avenue,Springfield,MA,01108,413-586-1125,https://safepass.org,dual_diagnosis,,adolescent|adult|older_adult|young_adult,accessibility|immigrant_refugee|lgbtq,,residential,,english|khmer|spanish|vietnamese,Western MA,DMH Multicultural Directory 2019
165
+ "Stavros Tapestry Health 413-586-2016 Other locations includ Greenfield, Holyoke, No Adams, Northampton, Pitts Springfield, and West Sprin Valley Opportunit Council 413-552-1554 413-552-1554 2019 DMH MULT",300 High Street,Holyoke,MA,01040,413-256-0473,https://stavros.org,mental_health,,adolescent|adult|older_adult|young_adult,accessibility|lgbtq,,,,arabic|asl|english|french|russian|spanish,Western MA,DMH Multicultural Directory 2019
166
+ "Viability, Inc. Walden Community Serv Learning Center for the Phone and TTY: 508-879-5 Video Phone: 774-999-094 Western Mass Recove Learning Communit 413-539-5941 413-372-5652 413-772-0715 Afiya (Peer-run respite hou Northampton, MA 2019 DMH MULT",74 Federal Street,Greenfield,MA,01301,413-584-1460,https://viability.org,mental_health,,adolescent|young_adult,accessibility,,,,asl|english|spanish,Western MA,DMH Multicultural Directory 2019
167
+ services (/how-to/apply-for-dmh-services),,,MA,,(413) 587-6200,https://www.mass.gov/how-to/apply-for-dmh-,mental_health,,young_adult,,,,,english,Western MA,Western Mass Young Adult Guide
168
+ training and presentation programs for community members.,,A Springfield Street Agawam,MA,01001,413-786-9139,https://namimass.org/support-and-,mental_health,,adolescent|young_adult,,,,,english,Western MA,Western Mass Young Adult Guide
169
+ "21 Olander Dr., Northampton, MA 01060","235 Chestnut St,",Springfield,MA,01103,(413) 585-1300,https://www.servicenet.org/services/child-and-adolescent-services/prevention-recovery-early-psychosis-prep-2/,mental_health,,adolescent|young_adult,,,,,english,Western MA,Western Mass Young Adult Guide
170
+ "Bowen Resource & Wellness Center, 235 Chestnut St, Springfield, MA","235 Chestnut St,",Springfield,MA,01103,(413) 372-5652,https://wildfloweralliance.org,mental_health,,adolescent|young_adult,,,,,english,Western MA,Western Mass Young Adult Guide
171
+ 772-0715,"235 Chestnut St,",Springfield,MA,01103,866-641-2853,https://wildfloweralliance.org,mental_health,,adolescent|adult|young_adult,,,,,english,Western MA,Western Mass Young Adult Guide
172
+ Central Intake,,Boston,MA,02108,(413) 737-2439,https://www.mass.gov/childrens-,dual_diagnosis,,adolescent|young_adult,,,,,english,Western MA,Western Mass Young Adult Guide
173
+ Department of Mental Health and the Department of Public Health.,"41 Taylor Street,",Springfield,MA,01103,(413) 654-1566,https://www.springfieldimpactcenter.org/,mental_health,,adolescent|adult|young_adult,,,,,english,Western MA,Western Mass Young Adult Guide
174
+ sufficiency for themselves and their families.,,,MA,,(413) 552-1554,https://www.valleyopp.com/about-voc/our-,mental_health,,young_adult,,,,,english,Western MA,Western Mass Young Adult Guide
references/knowledge/ma_resources.csv ADDED
The diff for this file is too large to render. See raw diff
 
requirements.txt ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ accelerate==1.13.0
2
+ aiofiles==24.1.0
3
+ aiohappyeyeballs==2.6.1
4
+ aiohttp==3.13.3
5
+ aiosignal==1.4.0
6
+ annotated-doc==0.0.4
7
+ annotated-types==0.7.0
8
+ anyio==4.12.1
9
+ appnope==0.1.4
10
+ argon2-cffi==25.1.0
11
+ argon2-cffi-bindings==25.1.0
12
+ arrow==1.4.0
13
+ asttokens==3.0.1
14
+ async-lru==2.2.0
15
+ attrs==25.4.0
16
+ babel==2.18.0
17
+ beautifulsoup4==4.14.3
18
+ bitsandbytes==0.49.2
19
+ bleach==6.3.0
20
+ brotli==1.2.0
21
+ certifi==2026.2.25
22
+ cffi==2.0.0
23
+ charset-normalizer==3.4.5
24
+ click==8.3.1
25
+ comm==0.2.3
26
+ cut-cross-entropy==25.1.1
27
+ datasets==4.3.0
28
+ debugpy==1.8.20
29
+ decorator==5.2.1
30
+ defusedxml==0.7.1
31
+ diffusers==0.37.0
32
+ dill==0.4.0
33
+ docstring_parser==0.17.0
34
+ executing==2.2.1
35
+ fastapi==0.135.1
36
+ fastjsonschema==2.21.2
37
+ ffmpy==1.0.0
38
+ filelock==3.25.1
39
+ fqdn==1.5.1
40
+ frozenlist==1.8.0
41
+ fsspec==2025.9.0
42
+ git-filter-repo==2.47.0
43
+ gradio==6.9.0
44
+ gradio_client==2.3.0
45
+ groovy==0.1.2
46
+ h11==0.16.0
47
+ hf-xet==1.4.2
48
+ hf_transfer==0.1.9
49
+ httpcore==1.0.9
50
+ httpx==0.28.1
51
+ huggingface_hub==1.7.1
52
+ idna==3.11
53
+ importlib_metadata==8.7.1
54
+ ipykernel==7.2.0
55
+ ipython==9.11.0
56
+ ipython_pygments_lexers==1.1.1
57
+ ipywidgets==8.1.8
58
+ isoduration==20.11.0
59
+ jedi==0.19.2
60
+ Jinja2==3.1.6
61
+ json5==0.13.0
62
+ jsonpointer==3.0.0
63
+ jsonschema==4.26.0
64
+ jsonschema-specifications==2025.9.1
65
+ jupyter==1.1.1
66
+ jupyter-console==6.6.3
67
+ jupyter-events==0.12.0
68
+ jupyter-lsp==2.3.0
69
+ jupyter_client==8.8.0
70
+ jupyter_core==5.9.1
71
+ jupyter_server==2.17.0
72
+ jupyter_server_terminals==0.5.4
73
+ jupyterlab==4.5.6
74
+ jupyterlab_pygments==0.3.0
75
+ jupyterlab_server==2.28.0
76
+ jupyterlab_widgets==3.0.16
77
+ lark==1.3.1
78
+ markdown-it-py==4.0.0
79
+ MarkupSafe==3.0.3
80
+ matplotlib-inline==0.2.1
81
+ mdurl==0.1.2
82
+ mistune==3.2.0
83
+ mpmath==1.3.0
84
+ msgspec==0.20.0
85
+ multidict==6.7.1
86
+ multiprocess==0.70.16
87
+ nbclient==0.10.4
88
+ nbconvert==7.17.0
89
+ nbformat==5.10.4
90
+ nest-asyncio==1.6.0
91
+ networkx==3.6.1
92
+ notebook==7.5.5
93
+ notebook_shim==0.2.4
94
+ numpy==1.26.4
95
+ orjson==3.11.7
96
+ packaging==26.0
97
+ pandas==3.0.1
98
+ pandocfilters==1.5.1
99
+ parso==0.8.6
100
+ peft==0.18.1
101
+ pexpect==4.9.0
102
+ pillow==12.1.1
103
+ platformdirs==4.9.4
104
+ prometheus_client==0.24.1
105
+ prompt_toolkit==3.0.52
106
+ propcache==0.4.1
107
+ protobuf==7.34.0
108
+ psutil==7.2.2
109
+ ptyprocess==0.7.0
110
+ pure_eval==0.2.3
111
+ pyarrow==23.0.1
112
+ pycparser==3.0
113
+ pydantic==2.12.5
114
+ pydantic_core==2.41.5
115
+ pydub==0.25.1
116
+ Pygments==2.19.2
117
+ python-dateutil==2.9.0.post0
118
+ python-dotenv==1.2.2
119
+ python-json-logger==4.0.0
120
+ python-multipart==0.0.22
121
+ pytz==2026.1.post1
122
+ PyYAML==6.0.3
123
+ pyzmq==27.1.0
124
+ referencing==0.37.0
125
+ regex==2026.2.28
126
+ requests==2.32.5
127
+ rfc3339-validator==0.1.4
128
+ rfc3986-validator==0.1.1
129
+ rfc3987-syntax==1.1.0
130
+ rich==14.3.3
131
+ rpds-py==0.30.0
132
+ safehttpx==0.1.7
133
+ safetensors==0.7.0
134
+ semantic-version==2.10.0
135
+ Send2Trash==2.1.0
136
+ sentencepiece==0.2.1
137
+ setuptools==82.0.1
138
+ shellingham==1.5.4
139
+ six==1.17.0
140
+ soupsieve==2.8.3
141
+ stack-data==0.6.3
142
+ starlette==0.52.1
143
+ sympy==1.14.0
144
+ terminado==0.18.1
145
+ tinycss2==1.4.0
146
+ tokenizers==0.22.2
147
+ tomlkit==0.13.3
148
+ torch==2.10.0
149
+ torchao==0.16.0
150
+ torchvision==0.25.0
151
+ tornado==6.5.5
152
+ tqdm==4.67.3
153
+ traitlets==5.14.3
154
+ transformers==5.2.0
155
+ trl==0.24.0
156
+ typeguard==4.5.1
157
+ typer==0.24.1
158
+ typer-slim==0.24.0
159
+ typing-inspection==0.4.2
160
+ typing_extensions==4.15.0
161
+ tyro==1.0.8
162
+ tzdata==2025.3
163
+ unsloth==2026.3.4
164
+ unsloth_zoo==2026.3.2
165
+ uri-template==1.3.0
166
+ urllib3==2.6.3
167
+ uvicorn==0.41.0
168
+ wcwidth==0.6.0
169
+ webcolors==25.10.0
170
+ webencodings==0.5.1
171
+ websocket-client==1.9.0
172
+ wheel==0.46.3
173
+ widgetsnbextension==4.0.15
174
+ xxhash==3.6.0
175
+ yarl==1.23.0
176
+ zipp==3.23.0
src/.DS_Store ADDED
Binary file (6.15 kB). View file
 
src/__init__.py ADDED
@@ -0,0 +1 @@
 
 
1
+
src/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (164 Bytes). View file
 
src/__pycache__/chat.cpython-312.pyc ADDED
Binary file (6.13 kB). View file
 
src/__pycache__/config.cpython-312.pyc ADDED
Binary file (390 Bytes). View file
 
src/chat.py ADDED
@@ -0,0 +1,121 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from huggingface_hub import InferenceClient
2
+ from src.config import BASE_MODEL, MY_MODEL, HF_TOKEN
3
+ import os
4
+ from src.utils.profile import load_schema, create_empty_profile, extract_profile_updates, merge_profile, profile_to_summary
5
+ from src.utils.resources import load_resources, filter_resources, score_resources, format_recommendations
6
+
7
+ class Chatbot:
8
+
9
+ def __init__(self):
10
+ """
11
+ Initialize the chatbot with a HF model ID
12
+ """
13
+ model_id = MY_MODEL if MY_MODEL else BASE_MODEL # define MY_MODEL in config.py if you create a new model in the HuggingFace Hub
14
+ self.client = InferenceClient(model=model_id, token=HF_TOKEN)
15
+ # Initialize user profile
16
+ current_dir = os.path.dirname(os.path.abspath(__file__))
17
+ data_dir = os.path.join(current_dir, '..', 'data')
18
+ self.profile_schema = load_schema(os.path.join(data_dir, 'user_profile_schema.json'))
19
+ self.user_profile = create_empty_profile()
20
+ # Load treatment resources once
21
+ knowledge_dir = os.path.join(data_dir, '..', 'references', 'knowledge')
22
+ resources_paths = [
23
+ os.path.join(knowledge_dir, 'ma_resources.csv'),
24
+ os.path.join(knowledge_dir, 'boston_resources.csv'),
25
+ ]
26
+ self.resources = load_resources(resources_paths)
27
+
28
+ def update_profile(self, user_input):
29
+ """
30
+ Scan user input for profile-relevant information and merge it
31
+ into the running user profile.
32
+
33
+ Args:
34
+ user_input (str): The user's message text.
35
+ """
36
+ updates = extract_profile_updates(self.profile_schema, user_input)
37
+ merge_profile(self.user_profile, updates)
38
+
39
+ def format_prompt(self, user_input):
40
+ """
41
+ Format the user's input into a list of chat messages with system context.
42
+ Updates the user profile with any new information detected.
43
+
44
+ This method:
45
+ 1. Loads system prompt from system_prompt.md
46
+ 2. Updates user profile from schema-based keyword matching
47
+ 3. Injects profile summary into the system prompt so the model knows what's been gathered
48
+ 4. Returns a list of message dicts for the chat completion API
49
+
50
+ Args:
51
+ user_input (str): The user's question
52
+
53
+ Returns:
54
+ list[dict]: A list of message dicts with 'role' and 'content' keys
55
+ """
56
+ # Get the directory where this file is located
57
+ current_dir = os.path.dirname(os.path.abspath(__file__))
58
+
59
+ # Load system prompt
60
+ system_prompt_path = os.path.join(current_dir, '../data/system_prompt.md')
61
+ with open(system_prompt_path, 'r', encoding='utf-8') as f:
62
+ system_prompt = f.read().strip()
63
+
64
+ # Update user profile from this message
65
+ self.update_profile(user_input)
66
+
67
+ # Build profile summary for the prompt
68
+ profile_summary = profile_to_summary(self.user_profile)
69
+
70
+ # Build system message with profile context
71
+ system_content = system_prompt
72
+ if profile_summary:
73
+ system_content = system_content + "\n\n" + profile_summary
74
+
75
+ # Return structured messages for chat completion API
76
+ messages = [
77
+ {"role": "system", "content": system_content},
78
+ {"role": "user", "content": user_input},
79
+ ]
80
+
81
+ return messages
82
+
83
+ def get_response(self, user_input):
84
+ """
85
+ Generate a response to the user's question, with resource recommendations
86
+ appended when the user profile contains enough information to match.
87
+
88
+ Args:
89
+ user_input (str): The user's question
90
+
91
+ Returns:
92
+ str: The chatbot's response, optionally followed by top 3 resources
93
+ """
94
+ # 1. Format messages (also updates profile)
95
+ messages = self.format_prompt(user_input)
96
+
97
+ # 2. Generate LLM response via chat completion API
98
+ result = self.client.chat_completion(
99
+ messages=messages,
100
+ max_tokens=512,
101
+ temperature=0.7,
102
+ )
103
+ response = result.choices[0].message.content.strip()
104
+
105
+ # 3. Filter resources by profile, score, and append top 3
106
+ filtered = filter_resources(self.resources, self.user_profile)
107
+ top_resources = score_resources(filtered, self.user_profile)
108
+ recommendations = format_recommendations(top_resources)
109
+
110
+ # Log recommendations to console
111
+ if top_resources:
112
+ print(f"[Harbor] Chat recommendations ({len(top_resources)}) for profile:")
113
+ for i, r in enumerate(top_resources, 1):
114
+ print(f" {i}. {r.get('name', 'Unknown')} — {r.get('city', '')}, {r.get('state', '')} {r.get('zip', '')}")
115
+ else:
116
+ print("[Harbor] No recommendations matched current profile.")
117
+
118
+ if recommendations:
119
+ response = response + "\n\n" + recommendations
120
+
121
+ return response
src/config.py ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import os
2
+ from dotenv import load_dotenv
3
+
4
+ # Load from .env file. Store your HF token in the .env file.
5
+ load_dotenv()
6
+
7
+
8
+ BASE_MODEL = "Qwen/Qwen2.5-7B-Instruct"
9
+ # Other options:
10
+ # BASE_MODEL = "meta-llama/Llama-3.2-3B-Instruct" # gated — requires Meta license approval
11
+ # BASE_MODEL = "Qwen/Qwen2.5-1.5B-Instruct" # ungated, smaller/faster
12
+ # BASE_MODEL = "HuggingFaceH4/zephyr-7b-beta" # ungated
13
+
14
+ # If you finetune the model or change it in any way, save it to huggingface hub, then set MY_MODEL to your model ID. The model ID is in the format "your-username/your-model-name".
15
+ MY_MODEL = "" #"amitashukla/harbor-qwn25-lora"
16
+
17
+ HF_TOKEN = os.getenv("HF_TOKEN")
src/utils/__init__.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ # Utils package for helper functions
2
+
src/utils/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (166 Bytes). View file
 
src/utils/__pycache__/profile.cpython-312.pyc ADDED
Binary file (7.23 kB). View file
 
src/utils/__pycache__/resources.cpython-312.pyc ADDED
Binary file (11.6 kB). View file
 
src/utils/__pycache__/tags.cpython-312.pyc ADDED
Binary file (1.56 kB). View file
 
src/utils/profile.py ADDED
@@ -0,0 +1,224 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import re
3
+
4
+
5
+ def load_schema(schema_path):
6
+ """Load the user profile schema from a JSON file."""
7
+ with open(schema_path, 'r', encoding='utf-8') as f:
8
+ return json.load(f)
9
+
10
+
11
+ def create_empty_profile():
12
+ """
13
+ Create an empty user profile with all fields set to null/empty.
14
+ This represents a user we know nothing about yet.
15
+ """
16
+ return {
17
+ "demographics": {
18
+ "population": None,
19
+ "identity_factors": [],
20
+ "language": None,
21
+ "pronouns": None
22
+ },
23
+ "logistics": {
24
+ "zipcode": None,
25
+ "region": None,
26
+ "profession": None,
27
+ "accessibility_needs": [],
28
+ "insurance": None,
29
+ "treatment_history": None
30
+ },
31
+ "status": {
32
+ "current_state": None,
33
+ "crisis_level": None,
34
+ "temporary_factors": []
35
+ },
36
+ "clinical": {
37
+ "primary_focus": None,
38
+ "substances": []
39
+ },
40
+ "preferences": {
41
+ "setting": None,
42
+ "therapy_approach": None,
43
+ "scheduling": [],
44
+ "barriers": [],
45
+ "contact_channel": None
46
+ }
47
+ }
48
+
49
+
50
+ def extract_profile_updates(schema, user_input):
51
+ """
52
+ Scan user input against the schema and return a dict of detected profile updates.
53
+
54
+ For 'single' type fields, returns the first matched option value.
55
+ For 'multi' type fields, returns a list of all matched option values.
56
+ For 'extracted' type fields (zipcode, region, treatment_history), uses
57
+ pattern matching or returns raw text snippets.
58
+
59
+ Args:
60
+ schema: The loaded profile schema dict.
61
+ user_input: The user's message text.
62
+
63
+ Returns:
64
+ dict: Nested dict mirroring the profile structure, containing only
65
+ fields where matches were found.
66
+ """
67
+ input_lower = user_input.lower()
68
+ updates = {}
69
+
70
+ for category_name, category in schema.items():
71
+ category_updates = {}
72
+
73
+ for field_name, field_def in category.items():
74
+ field_type = field_def.get("type")
75
+
76
+ if field_type == "extracted":
77
+ # Special handling for pattern-based or free-text fields
78
+ value = _extract_field(field_name, field_def, user_input, input_lower)
79
+ if value is not None:
80
+ category_updates[field_name] = value
81
+
82
+ elif field_type in ("single", "multi"):
83
+ matches = []
84
+ for option in field_def.get("options", []):
85
+ for keyword in option.get("keywords", []):
86
+ if keyword and keyword.lower() in input_lower:
87
+ matches.append(option["value"])
88
+ break # one keyword match per option is enough
89
+
90
+ if matches:
91
+ if field_type == "single":
92
+ category_updates[field_name] = matches[0]
93
+ else:
94
+ category_updates[field_name] = matches
95
+
96
+ if category_updates:
97
+ updates[category_name] = category_updates
98
+
99
+ return updates
100
+
101
+
102
+ def _extract_field(field_name, field_def, user_input, input_lower):
103
+ """Handle extraction for non-option fields like zipcode and treatment_history."""
104
+ if field_name == "zipcode":
105
+ pattern = field_def.get("pattern", r"\b\d{5}\b")
106
+ match = re.search(pattern, user_input)
107
+ if match:
108
+ return match.group()
109
+ return None
110
+
111
+ if field_name == "region":
112
+ # Region is typically set explicitly or by the LLM, not keyword-matched.
113
+ # We do a lightweight check for common geographic indicators.
114
+ geo_patterns = [
115
+ r"\bin\s+([A-Z][a-z]+(?:\s+[A-Z][a-z]+)*)", # "in Boston", "in Pocahontas County"
116
+ r"\bnear\s+([A-Z][a-z]+(?:\s+[A-Z][a-z]+)*)", # "near Springfield"
117
+ r"\bfrom\s+([A-Z][a-z]+(?:\s+[A-Z][a-z]+)*)", # "from Cambridge"
118
+ ]
119
+ for pattern in geo_patterns:
120
+ match = re.search(pattern, user_input)
121
+ if match:
122
+ return match.group(1)
123
+ return None
124
+
125
+ if field_name == "treatment_history":
126
+ history_keywords = ["rehab", "treatment before", "been to", "tried",
127
+ "previous treatment", "went to", "was in",
128
+ "12-step", "residential before", "relapsed"]
129
+ for keyword in history_keywords:
130
+ if keyword in input_lower:
131
+ return user_input # store the raw message as context
132
+ return None
133
+
134
+ return None
135
+
136
+
137
+ def merge_profile(profile, updates):
138
+ """
139
+ Merge new updates into the existing profile.
140
+
141
+ - For 'single' fields (non-list values): new values overwrite old ones.
142
+ - For 'multi' fields (list values): new values are appended (no duplicates).
143
+ - None values in updates are ignored (don't clear existing data).
144
+
145
+ Args:
146
+ profile: The current user profile dict (modified in place).
147
+ updates: The updates dict from extract_profile_updates().
148
+
149
+ Returns:
150
+ dict: The updated profile (same object as input).
151
+ """
152
+ for category_name, category_updates in updates.items():
153
+ if category_name not in profile:
154
+ continue
155
+
156
+ for field_name, new_value in category_updates.items():
157
+ if field_name not in profile[category_name]:
158
+ continue
159
+
160
+ if new_value is None:
161
+ continue
162
+
163
+ existing = profile[category_name][field_name]
164
+
165
+ if isinstance(existing, list) and isinstance(new_value, list):
166
+ # Append new values, skip duplicates
167
+ for v in new_value:
168
+ if v not in existing:
169
+ existing.append(v)
170
+ elif isinstance(existing, list) and not isinstance(new_value, list):
171
+ # Single value going into a list field
172
+ if new_value not in existing:
173
+ existing.append(new_value)
174
+ else:
175
+ # Single value field: overwrite
176
+ profile[category_name][field_name] = new_value
177
+
178
+ return profile
179
+
180
+
181
+ def profile_to_summary(profile):
182
+ """
183
+ Convert a user profile dict into a concise text summary for injection
184
+ into the system prompt. Only includes fields that have been filled in.
185
+
186
+ Returns:
187
+ str: A human-readable summary, or empty string if profile is empty.
188
+ """
189
+ lines = []
190
+
191
+ category_labels = {
192
+ "demographics": "Demographics",
193
+ "logistics": "Logistics & History",
194
+ "status": "Current Status",
195
+ "clinical": "Clinical Needs",
196
+ "preferences": "Preferences & Barriers"
197
+ }
198
+
199
+ for category_name, category_label in category_labels.items():
200
+ category = profile.get(category_name, {})
201
+ category_lines = []
202
+
203
+ for field_name, value in category.items():
204
+ if value is None:
205
+ continue
206
+ if isinstance(value, list) and len(value) == 0:
207
+ continue
208
+
209
+ # Format the field name nicely
210
+ display_name = field_name.replace("_", " ").title()
211
+
212
+ if isinstance(value, list):
213
+ category_lines.append(f" - {display_name}: {', '.join(str(v) for v in value)}")
214
+ else:
215
+ category_lines.append(f" - {display_name}: {value}")
216
+
217
+ if category_lines:
218
+ lines.append(f"[{category_label}]")
219
+ lines.extend(category_lines)
220
+
221
+ if not lines:
222
+ return ""
223
+
224
+ return "USER PROFILE (gathered so far):\n" + "\n".join(lines)
src/utils/resources.py ADDED
@@ -0,0 +1,240 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import csv
2
+
3
+
4
+ # Profile field → (csv_column, weight)
5
+ FIELD_MAP = [
6
+ ("clinical", "primary_focus", "primary_focus", 3),
7
+ ("clinical", "substances", "substances", 3),
8
+ ("demographics", "population", "age_groups", 2),
9
+ ("demographics", "identity_factors", "identity_factors", 2),
10
+ ("logistics", "insurance", "insurance", 2),
11
+ ("preferences", "setting", "settings", 2),
12
+ ("preferences", "therapy_approach", "therapy_approaches", 1),
13
+ ("demographics", "language", "languages", 1),
14
+ ]
15
+
16
+
17
+ def load_resources(csv_path):
18
+ """Load one or more resource CSVs into a list of dicts.
19
+
20
+ Accepts a single path (str) or a list of paths. Called once at init.
21
+ """
22
+ if isinstance(csv_path, str):
23
+ csv_path = [csv_path]
24
+ rows = []
25
+ for path in csv_path:
26
+ with open(path, "r", encoding="utf-8") as f:
27
+ reader = csv.DictReader(f)
28
+ rows.extend(reader)
29
+ return rows
30
+
31
+
32
+ def _get_profile_value(profile, category, field):
33
+ """Safely get a profile value, returning None for missing/empty."""
34
+ val = profile.get(category, {}).get(field)
35
+ if val is None:
36
+ return None
37
+ if isinstance(val, list) and len(val) == 0:
38
+ return None
39
+ return val
40
+
41
+
42
+ def _pipe_values(cell):
43
+ """Split a pipe-delimited CSV cell into a set of lowercase values."""
44
+ if not cell or not cell.strip():
45
+ return set()
46
+ return {v.strip().lower() for v in cell.split("|")}
47
+
48
+
49
+ def filter_resources(resources, user_profile):
50
+ """
51
+ Filter the full resource list down to a relevant subset based on
52
+ user profile values. Applies geographic, primary_focus, and substances
53
+ filters. Progressively relaxes filters if fewer than 3 results remain.
54
+ """
55
+ zipcode = _get_profile_value(user_profile, "logistics", "zipcode")
56
+ region = _get_profile_value(user_profile, "logistics", "region")
57
+ primary_focus = _get_profile_value(user_profile, "clinical", "primary_focus")
58
+ substances = _get_profile_value(user_profile, "clinical", "substances")
59
+
60
+ # No profile info → no filtering possible, return empty (no recommendations)
61
+ if not zipcode and not region and not primary_focus and not substances:
62
+ return []
63
+
64
+ # Build filter functions in order of relaxation priority
65
+ filters = []
66
+
67
+ # Geographic filter (relaxed first if too few results)
68
+ if zipcode:
69
+ zip_prefix = zipcode[:3]
70
+ filters.append(("geo", lambda r, zp=zip_prefix: (
71
+ r.get("zip", "")[:3] == zp
72
+ )))
73
+ elif region:
74
+ region_lower = region.lower()
75
+ filters.append(("geo", lambda r, rl=region_lower: (
76
+ rl in r.get("city", "").lower() or rl in r.get("state", "").lower()
77
+ )))
78
+
79
+ # Primary focus filter
80
+ if primary_focus:
81
+ focus_lower = primary_focus.lower()
82
+ filters.append(("focus", lambda r, fl=focus_lower: (
83
+ not r.get("primary_focus", "").strip() or
84
+ fl in _pipe_values(r.get("primary_focus", ""))
85
+ )))
86
+
87
+ # Substances filter
88
+ if substances:
89
+ if isinstance(substances, str):
90
+ substances = [substances]
91
+ subs_lower = {s.lower() for s in substances}
92
+ filters.append(("substances", lambda r, sl=subs_lower: (
93
+ not r.get("substances", "").strip() or
94
+ bool(sl & _pipe_values(r.get("substances", "")))
95
+ )))
96
+
97
+ # Apply all filters, progressively relax if < 3 results
98
+ result = _apply_filters(resources, filters)
99
+ if len(result) >= 3:
100
+ return result
101
+ best = result # keep the best partial matches found so far
102
+
103
+ # Relax geographic filter first
104
+ relaxed = [f for f in filters if f[0] != "geo"]
105
+ if relaxed:
106
+ result = _apply_filters(resources, relaxed)
107
+ if len(result) >= 3:
108
+ return result
109
+ if len(result) > len(best):
110
+ best = result
111
+
112
+ # Relax substances filter next
113
+ relaxed = [f for f in relaxed if f[0] != "substances"]
114
+ if relaxed:
115
+ result = _apply_filters(resources, relaxed)
116
+ if len(result) > len(best):
117
+ best = result
118
+
119
+ return best
120
+
121
+
122
+ def _apply_filters(resources, filters):
123
+ """Apply a list of filter functions, keeping rows that pass all."""
124
+ if not filters:
125
+ return []
126
+ result = []
127
+ for row in resources:
128
+ if all(fn(row) for _, fn in filters):
129
+ result.append(row)
130
+ return result
131
+
132
+
133
+ def score_resources(filtered, user_profile, top_n=3):
134
+ """
135
+ Score filtered resources by relevance to the user profile.
136
+ Returns the top_n highest-scoring resources as a list of dicts.
137
+ """
138
+ zipcode = _get_profile_value(user_profile, "logistics", "zipcode")
139
+ region = _get_profile_value(user_profile, "logistics", "region")
140
+
141
+ scored = []
142
+ for row in filtered:
143
+ score = 0
144
+
145
+ # Score each mapped field
146
+ for category, field, csv_col, weight in FIELD_MAP:
147
+ profile_val = _get_profile_value(user_profile, category, field)
148
+ if profile_val is None:
149
+ continue
150
+
151
+ cell_values = _pipe_values(row.get(csv_col, ""))
152
+ if not cell_values:
153
+ continue # empty cell = neutral
154
+
155
+ if isinstance(profile_val, list):
156
+ matches = sum(1 for v in profile_val if v.lower() in cell_values)
157
+ if matches > 0:
158
+ score += weight * (matches / len(profile_val))
159
+ else:
160
+ if profile_val.lower() in cell_values:
161
+ score += weight
162
+
163
+ # Geographic bonus
164
+ row_zip = row.get("zip", "").strip()
165
+ if zipcode and row_zip:
166
+ if row_zip == zipcode:
167
+ score += 5
168
+ elif row_zip[:3] == zipcode[:3]:
169
+ score += 2
170
+ elif region and not zipcode:
171
+ region_lower = region.lower()
172
+ if region_lower in row.get("city", "").lower():
173
+ score += 3
174
+
175
+ if score > 0:
176
+ scored.append((score, row))
177
+
178
+ # Sort by score descending
179
+ scored.sort(key=lambda x: x[0], reverse=True)
180
+ return [row for _, row in scored[:top_n]]
181
+
182
+
183
+ def format_recommendations(results):
184
+ """
185
+ Format a list of resource dicts into a readable recommendation block.
186
+ Returns empty string if no results.
187
+ """
188
+ if not results:
189
+ return ""
190
+
191
+ lines = [
192
+ "---",
193
+ "Here are some resources that may be a good fit for you:",
194
+ "",
195
+ ]
196
+
197
+ for i, row in enumerate(results, 1):
198
+ name = row.get("name", "Unknown Facility")
199
+ lines.append(f"{i}. {name}")
200
+
201
+ # Address
202
+ parts = [row.get("address", ""), row.get("city", ""),
203
+ row.get("state", ""), row.get("zip", "")]
204
+ address = ", ".join(p.strip() for p in parts if p.strip())
205
+ if address:
206
+ lines.append(f" {address}")
207
+
208
+ # Phone
209
+ phone = row.get("phone", "").strip()
210
+ if phone:
211
+ lines.append(f" Phone: {phone}")
212
+
213
+ # Website
214
+ website = row.get("website", "").strip()
215
+ if website:
216
+ lines.append(f" Website: {website}")
217
+
218
+ # Summary line: focus, substances, settings
219
+ details = []
220
+ focus = row.get("primary_focus", "").strip()
221
+ if focus:
222
+ details.append("Focus: " + ", ".join(
223
+ v.strip().replace("_", " ").title() for v in focus.split("|")
224
+ ))
225
+ subs = row.get("substances", "").strip()
226
+ if subs:
227
+ details.append("Substances: " + ", ".join(
228
+ v.strip().replace("_", " ").title() for v in subs.split("|")
229
+ ))
230
+ settings = row.get("settings", "").strip()
231
+ if settings:
232
+ details.append("Settings: " + ", ".join(
233
+ v.strip().replace("_", " ").title() for v in settings.split("|")
234
+ ))
235
+ if details:
236
+ lines.append(" " + " | ".join(details))
237
+
238
+ lines.append("")
239
+
240
+ return "\n".join(lines).rstrip()