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

logger = logging.getLogger(__name__)


def clean_json_string(json_str: str) -> str:
    """
    Clean a JSON string by properly escaping control characters within string values.
    This handles cases where LLMs generate JSON with literal newlines, tabs, etc.
    
    Args:
        json_str: Raw JSON string that may contain unescaped control characters
        
    Returns:
        Cleaned JSON string with properly escaped control characters
    """
    # First, try to identify string values in the JSON and escape control characters within them
    # We need to be careful not to break the JSON structure itself
    
    # Replace common control characters that appear in string values
    # but preserve the JSON structure (newlines between key-value pairs are OK)
    
    # Strategy: Parse character by character, track if we're inside a string value
    result = []
    in_string = False
    escape_next = False
    
    for i, char in enumerate(json_str):
        if escape_next:
            result.append(char)
            escape_next = False
            continue
            
        if char == '\\':
            result.append(char)
            escape_next = True
            continue
            
        if char == '"':
            in_string = not in_string
            result.append(char)
            continue
        
        # If we're inside a string value, escape control characters
        if in_string:
            if char == '\n':
                result.append('\\n')
            elif char == '\r':
                result.append('\\r')
            elif char == '\t':
                result.append('\\t')
            elif char == '\b':
                result.append('\\b')
            elif char == '\f':
                result.append('\\f')
            elif ord(char) < 32:  # Other control characters
                result.append(f'\\u{ord(char):04x}')
            else:
                result.append(char)
        else:
            result.append(char)
    
    return ''.join(result)


def normalize_recommendations(text: str) -> str:
    """
    Normalize the recommendations string for concise, consistent formatting.
    - Remove extra blank lines
    - Trim trailing/leading whitespace on each line
    - Add single blank line before section headers for readability
    - Optionally cap length to avoid overly long outputs
    """
    if not text:
        return ""
    # Normalize newlines
    text = text.replace('\r\n', '\n').replace('\r', '\n')
    # Split, strip, and drop empty lines
    lines = [ln.strip() for ln in text.split('\n')]
    lines = [ln for ln in lines if ln]
    
    # Add spacing before section headers (lines ending with ':')
    # but not before the first line
    formatted_lines = []
    section_headers = [
        'Eligibility and Rationale:',
        'Treatment Recommendations:',
        'Monitoring and Follow-up:',
        'Special Considerations:',
        'References:'
    ]
    
    for i, line in enumerate(lines):
        # Add blank line before section headers (except first line)
        if i > 0 and any(line.startswith(header) for header in section_headers):
            formatted_lines.append('')  # Add blank line
        formatted_lines.append(line)
    
    normalized = '\n'.join(formatted_lines)
    # Soft cap length (keep whole content if already short)
    max_len = 1800
    if len(normalized) > max_len:
        normalized = normalized[:max_len].rstrip()
    return normalized

# SASLT 2021 Guidelines - Hardcoded Page Contents
SASLT_GUIDELINES = """
===== SASLT 2021 GUIDELINES: TREATMENT & MANAGEMENT =====

### 1. INITIATION OF TREATMENT [SASLT 2021, p. 6]

• Treatment indications should also take into account patient's age, health status, risk of HBV transmission, family history of HCC or cirrhosis and extrahepatic manifestations [SASLT 2021, p. 6]
• All patients with chronic hepatitis B (HBV DNA > 2,000 IU/mL, ALT > ULN), regardless of HBeAg status, and/or at least moderate liver necroinflammation or fibrosis (Grade A) [SASLT 2021, p. 6]
• Patients with cirrhosis (compensated or decompensated), with any detectable HBV DNA level and regardless of ALT levels (Grade A) [SASLT 2021, p. 6]
• Patients with HBV DNA > 20,000 IU/mL and ALT > 2xULN, regardless of the degree of fibrosis (Grade B) [SASLT 2021, p. 6]
• Patients with HBeAg-positive chronic HBV infection (persistently normal ALT and high HBV DNA levels) may be treated if they are > 30 years, regardless of the severity of liver histological lesions (Grade D) [SASLT 2021, p. 6]
• Patients with chronic HBV infection (HBV DNA > 2,000 IU/mL, ALT > ULN), regardless of HBeAg status, and a family history of HCC or cirrhosis and extrahepatic manifestations (Grade D) [SASLT 2021, p. 6]
• Non‑cirrhotic patients should be considered for treatment if they have HBV DNA levels >2,000 IU/mL, serum ALT >~40 IU/L and severity of liver disease assessed by liver biopsy showing at least moderate necroinflammation and/or at least moderate fibrosis. 
Patients with HBV DNA greater than 20,000 IU/mL and ALT greater than 2x ULN can begin treatment without a liver biopsy. 
Patients with HBV DNA >2,000 IU/mL and at least moderate fibrosis may initiate treatment even if ALT levels are normal.

### 2. MANAGEMENT ALGORITHM [SASLT 2021, p. 6]

• HBsAg positive with chronic HBV infection and no signs of chronic hepatitis → Monitor (HBsAg, HBeAg, HBV DNA, ALT, fibrosis assessment). Consider: risk of HCC, risk of HBV reactivation, extrahepatic manifestations, risk of HBV transmission [SASLT 2021, p. 6]
• CHB (with/without cirrhosis) → Start antiviral treatment if indicated, otherwise return to monitoring [SASLT 2021, p. 6]
• HBsAg negative, anti-HBc positive → No specialist follow-up (inform about HBV reactivation risk). In case of immunosuppression: start oral antiviral prophylaxis or monitor [SASLT 2021, p. 6]


### 3. MONITORING OF UNTREATED PATIENTS [SASLT 2021, p. 6-7]

• Patients with HBeAg-positive chronic HBV infection who are younger than 30 years should be followed at least every 3-6 months (Grade B) [SASLT 2021, p. 7]
• Patients with HBeAg-negative chronic HBV infection and serum HBV DNA <2,000 IU/ml should be followed every 6-12 months (Grade B) [SASLT 2021, p. 7]
• Patients with HBeAg-negative chronic HBV infection and serum HBV DNA ≥2,000 IU/ml should be followed every 3 months for the first year and thereafter every 6 months (Grade D) [SASLT 2021, p. 7]


### 4. CHRONIC HEPATITIS B (CHB) TREATMENT [SASLT 2021, p. 7-8]

• The treatment of choice is the long-term administration of a potent nucleos(t)ide analogue NA with a high barrier to resistance, regardless of the severity of liver disease (Grade A) [SASLT 2021, p. 8]
• Preferred regimens are ETV, TDF and TAF as monotherapies (Grade A) [SASLT 2021, p. 8]
• LAM, ADV and TBV are not recommended in the treatment of CHB (Grade A) [SASLT 2021, p. 8]
• TAF has demonstrated superior renal and bone density safety profiles compared with TDF in head-to-head trials [SASLT 2021, p. 8]
• International guidelines recommend switching individuals at high risk for bone or renal disease from TDF to either TAF or ETV [SASLT 2021, p. 8]
• TAF maintains a better safety profile unless the patient's creatinine clearance (CrCl) is less than 15 mL/minute [SASLT 2021, p. 8]

### 5. HBV-HCV COINFECTION [SASLT 2021, p. 8-9]

• Treatment of HCV through DAAs may lead to reactivation of HBV. Patients who meet the criteria for HBV treatment should be treated concurrently or before initiation of DAA (Grade A) [SASLT 2021, p. 9]
• HBV DNA and ALT should be monitored every four to eight weeks while on DAA and three months after completion of therapy (Grade D) [SASLT 2021, p. 9]
• ALT level should be monitored every four weeks while on DAA for patients who are HBsAg-negative but HBcAb-positive. If ALT starts to rise, HBsAg and HBV DNA must be obtained to determine the need to start HBV treatment (Grade D) [SASLT 2021, p. 9]


### 6. HBV-HDV COINFECTION [SASLT 2021, p. 9]

• HDV is a defective virus that requires HBsAg to envelop its delta antigen, causing coinfection with HBV or superinfection in chronic HBV patients [SASLT 2021, p. 9]
• Active HDV infection is defined by HDV IgM and RNA presence with unexplained LFT elevation [SASLT 2021, p. 9]
• Treatment goal: Suppression of HDV replication [SASLT 2021, p. 9]
• PEG-IFN for 1 year shows long-term benefits despite post-treatment viral relapse [SASLT 2021, p. 9]
• NA monotherapy is ineffective against HDV replication [SASLT 2021, p. 9]


### 7. HBV-HIV COINFECTION [SASLT 2021, p. 9]

• All HIV-positive patients with HBV co-infection should start ART irrespective of CD4 cell count (Grade A) [SASLT 2021, p. 9]
• HBV-HIV co-infected patients should be treated with TDF- or TAF-based ART regimen (Grade A) [SASLT 2021, p. 9]


### 8. IMMUNOCOMPROMISED PATIENTS [SASLT 2021, p. 9]

• Prophylaxis for all HBsAg-positive patients before chemotherapy or immunosuppressive therapy (Grade A) [SASLT 2021, p. 9]
• HBsAg-negative/anti-HBc-positive patients need HBV prophylaxis if receiving anti-CD20 or stem cell transplantation [SASLT 2021, p. 9]
• Continue prophylaxis for ≥6 months after immunosuppression (12 months for anti-CD20) [SASLT 2021, p. 9]
• All patients undergoing immunosuppressive treatment or chemotherapy, even short‑term courses, should be screened for HBsAg, anti‑HBc, and anti‑HBs (and HBV DNA, if HBsAg is already positive). [SASLT 2021, p. 9]
• We recommend prophylaxis for all patients with positive HBsAg before initiating chemotherapy or other immunosuppressive agents. [SASLT 2021, p. 9]
• For HBsAg-negative and anti-HBc positive patients, we recommend HBV prophylaxis if they are candidates for anti CD20 or are undergoing stem cell transplantation. [SASLT 2021, p. 9]
• We recommend starting HBV prophylaxis for HBsAg or anti‑HBc positive patients undergoing treatment with tumor necrosis factor (TNF) inhibitors. [SASLT 2021, p. 9]
• We recommend HBV prophylaxis for all patients who are HBsAg or anti-HBc positive before initiation of immunotherapy such as anti‑programmed cell death (PD) ‑1 and anti‑programmed cell death‑ligand 1 (PD‑L1) therapy. [SASLT 2021, p. 9]


### 9. PREGNANCY [SASLT 2021, p. 9-10]

• Screen all pregnant women for HBV in first trimester (Grade A) [SASLT 2021, p. 9]
• HBV vaccine is safe in pregnancy for non-immune women without chronic HBV. [SASLT 2021, p. 9]
• Treat pregnant women meeting standard therapy indications [SASLT 2021, p. 9]
• Start antiviral prophylaxis with TDF (or TAF) for HBV DNA >100,000 IU/mL at 24-28 weeks (Grade D) [SASLT 2021, p. 10]
• Switch to TDF/TAF if on ETV, ADV, or interferon during pregnancy (Grade D) [SASLT 2021, p. 10]
• Delivery mode based on obstetric indications only [SASLT 2021, p. 10]
• Breastfeeding permitted for HBsAg+ women on TDF (Grade B) [SASLT 2021, p. 10]

### KEY DEFINITIONS & CONTEXT

* **ALT (Alanine Aminotransferase):** Normal range in Adults falls between 4-42 units/L (U/L).
* **ULN (Upper Limit of Normal):** ULN means Upper Limit of Normal for ALT which is set at 40 units/L for the purpose of these guidelines.
* ** Necroinflammatory activity scale; A1 = mild, A2 = moderate, A3 = severe
Liver fibrosis is usually classified into five stages: 
F0—no fibrosis; F1—mild fibrosis, pericellular collagen deposits; F2—moderate fibrosis, beginning bridging fibrosis; F3—severe fibrosis, defined as presence of numerous bridges and septa; F4—cirrhosis
"""



def assess_hbv_eligibility(patient_data: Dict[str, Any]) -> Dict[str, Any]:
    """
    Assess patient eligibility for HBV treatment based on SASLT 2021 guidelines
    using hardcoded guideline pages (3, 4, 6, 7, 8, 9, 10) and LLM analysis
    
    Args:
        patient_data: Dictionary containing patient clinical parameters
        
    Returns:
        Dictionary with assessment results:
        - eligible: bool
        - recommendations: str (comprehensive narrative with inline citations in format [SASLT 2021, Page X])
    """
    try:
        # # Check if HBsAg is positive (required for treatment consideration)
        # if patient_data.get("hbsag_status") != "Positive":
        #     return {
        #         "eligible": False,
        #         "recommendations": "Patient is HBsAg negative. HBV treatment is not indicated. HBsAg positivity is required for HBV treatment consideration according to SASLT 2021 guidelines."
        #     }
        
        # Use hardcoded SASLT 2021 guidelines instead of RAG retrieval
        logger.info("Using hardcoded SASLT 2021 guidelines (Pages 3, 4, 6, 7, 8, 9, 10)")
        
        # Define ALT ULN for context
        sex = patient_data.get("sex", "Male")
        #alt_uln = 35 if sex == "Male" else 25
        
        # Format patient data for prompt
        age = patient_data.get("age", "N/A")
        pregnancy_status = patient_data.get("pregnancy_status", "N/A")
        hbsag_status = patient_data.get("hbsag_status", "N/A")
        duration_hbsag = patient_data.get("duration_hbsag_months", "N/A")
        hbv_dna = patient_data.get("hbv_dna_level", 0)
        hbeag_status = patient_data.get("hbeag_status", "N/A")
        alt_level = patient_data.get("alt_level", 0)
        fibrosis_stage = patient_data.get("fibrosis_stage", "N/A")
        necroinflammatory = patient_data.get("necroinflammatory_activity", "N/A")
        extrahepatic = patient_data.get("extrahepatic_manifestations", False)
        immunosuppression = patient_data.get("immunosuppression_status", "None")
        coinfections = patient_data.get("coinfections", [])
        family_history = patient_data.get("family_history_cirrhosis_hcc", False)
        comorbidities = patient_data.get("other_comorbidities", [])
        
        # Create prompt for LLM to analyze patient against guidelines
        analysis_prompt = f"""You are an HBV treatment eligibility assessment system. Analyze the patient data against the SASLT 2021 guidelines.
PATIENT DATA:
- Sex: {sex}
- Age: {age} years
- Pregnancy Status: {pregnancy_status}
- HBsAg Status: {hbsag_status}
- HBsAg Duration: {duration_hbsag} months
- HBV DNA Level: {hbv_dna:,.0f} IU/mL
- HBeAg Status: {hbeag_status}
- ALT Level: {alt_level} 
- Fibrosis Stage: {fibrosis_stage}
- Necroinflammatory Activity: {necroinflammatory}
- Extrahepatic Manifestations: {extrahepatic}
- Immunosuppression: {immunosuppression}
- Coinfections: {', '.join(coinfections) if coinfections else 'None'}
- Family History (Cirrhosis/HCC): {family_history}
- Other Comorbidities: {', '.join(comorbidities) if comorbidities else 'None'}


SASLT 2021 GUIDELINES (Retrieved Context):
{SASLT_GUIDELINES}
Based STRICTLY on the SASLT 2021 guidelines and criteria provided above, assess this patient's eligibility for HBV antiviral treatment.
You MUST respond with a valid JSON object in this exact format:
{{
  "eligible": true or false,
  "recommendations": "Comprehensive assessment with inline citations"
}}
IMPORTANT JSON FORMATTING:
- Return ONLY valid JSON without markdown code blocks.
- You MUST use "\\n" to indicate line breaks inside the "recommendations" string and format the content as clear bullet lists prefixed with "- ".
- Do NOT include literal newline characters. Use \\n for every new bullet or line.
- Use SINGLE \\n between lines. Do NOT use \\n\\n (double newlines) anywhere.

CRITICAL ELIGIBILITY HIERARCHY:
1.  **Check Special Populations FIRST (Pages 9-10):** "Eligible" means eligible for ANY antiviral intervention (treatment OR prophylaxis).
    * If patient is **HBsAg-positive** AND **Immunosuppressed** (Page 9): Set **"eligible": true"** (for prophylaxis).
    * If patient has **HBV-HIV coinfection** (Page 9): Set **"eligible": true"** (for ART).
    * If patient is **Pregnant** with **HBV DNA > 100,000 IU/mL** (Page 10): Set **"eligible": true"** (for prophylaxis).
    * If patient has **HBV-HCV coinfection** AND meets HBV treatment criteria (Page 9): Set **"eligible": true"**.
2.  **Check Standard Criteria SECOND (Page 6):**
    * If *not* eligible based on special populations, check standard criteria (HBV DNA, ALT, fibrosis, age, family history).
    * If any Page 6 criteria are met (e.g., Cirrhosis, or HBV DNA > 2,000 + ALT > ULN + moderate fibrosis, etc.): Set **"eligible": true"**.
3.  **If NO criteria from (1) or (2) are met:** Set **"eligible": false"**.
4.  The "eligible" flag MUST be consistent with the "Eligibility and Rationale" bullet. Do not contradict yourself.

STRUCTURE AND CONTENT OF "recommendations" (CONCISE & ORGANIZED):
- Use ONLY these sections in this exact order, each as a header followed by 1-3 concise bullets:
  1. "Eligibility and Rationale:" (1-2 bullets max, MUST state the primary reason for eligibility/ineligibility)
  2. "Treatment Recommendations:" (1-3 bullets: first-line drugs if eligible, or "Treatment not indicated" if not eligible)
  3. "Monitoring and Follow-up:" (1-2 bullets)
  4. "Special Considerations:" (0-2 bullets, ONLY if applicable and *not* the primary reason for eligibility)
  5. "References:" (1 line listing pages cited)
- OMIT "Additional Notes" and any other sections.
- Keep each bullet to ONE sentence (max 25 words per bullet).
- Total output: aim for 8-12 bullets maximum across all sections.

BULLETING AND CITATIONS RULES:
- Put citations at the end of each bullet using "[SASLT 2021, Page X]".
- Include evidence grade when available (e.g., "(Grade A)").
- Only cite pages 6–10 that actually contain the information.

STRICT ACCURACY AND CONSISTENCY RULES:
- **NO CONTRADICTIONS:** The "eligible" flag MUST match the rationale. Follow the CRITICAL ELIGIBILITY HIERARCHY.
- **Rationale First:** The Rationale MUST state the primary reason. If eligible due to immunosuppression, state that, even if Page 6 criteria are not met.
- **Use ONLY the provided SASLT 2021 content;** do NOT add external knowledge.
- **BREVITY:** Each bullet = 1 sentence, max 25 words. Total = 8-12 bullets max.

PAGE-TO-TOPIC MAPPING GUIDANCE (for correct citations):
- Page 6: Standard initiation of treatment criteria, management algorithm.
- Page 7: Monitoring of untreated patients, CHB treatment principles.
- Page 8: Treatment drugs/regimens (ETV, TDF, TAF), agents not recommended.
- Page 9: Special populations (HBV-HCV, HBV-HDV, HBV-HIV, Immunocompromised).
- Page 10: Pregnancy-related recommendations.

---
EXAMPLE OUTPUT (ELIGIBLE - STANDARD CRITERIA) - Use SINGLE \\n only:
{{
  "eligible": true,
  "recommendations": "Eligibility and Rationale:\\n- Eligible: HBV DNA > 2,000 IU/mL, ALT > ULN, moderate fibrosis (Grade A) [SASLT 2021, Page 6]\\nTreatment Recommendations:\\n- Start monotherapy with ETV, TDF, or TAF (Grade A) [SASLT 2021, Page 8]\\nMonitoring and Follow-up:\\n- Monitor treatment response per SASLT protocol [SASLT 2021, Page 7]\\nReferences:\\n- Pages 6, 7, 8: Treatment criteria, drugs, monitoring"
}}
---
EXAMPLE OUTPUT (NOT ELIGIBLE - STANDARD CRITERIA) - Use SINGLE \\n only:
{{
  "eligible": false,
  "recommendations": "Eligibility and Rationale:\\n- Not eligible: HBV DNA < 2,000 IU/mL, ALT ≤ ULN, no significant fibrosis [SASLT 2021, Page 6]\\nTreatment Recommendations:\\n- Treatment not indicated at this time [SASLT 2021, Page 6]\\nMonitoring and Follow-up:\\n- Monitor every 6-12 months (HBeAg-negative, HBV DNA < 2,000 IU/mL) (Grade B) [SASLT 2021, Page 7]\\nReferences:\\n- Pages 6, 7: Treatment criteria, monitoring protocols"
}}
---
EXAMPLE OUTPUT (ELIGIBLE - IMMUNOSUPPRESSION) - Use SINGLE \\n only:
{{
  "eligible": true,
  "recommendations": "Eligibility and Rationale:\\n- Eligible: HBsAg-positive patient requires prophylaxis for immunosuppressive therapy (Grade A) [SASLT 2021, Page 9]\\nTreatment Recommendations:\\n- Start antiviral prophylaxis (e.g., ETV, TDF, TAF) [SASLT 2021, Page 8, 9]\\nMonitoring and Follow-up:\\n- Continue prophylaxis for ≥6 months after immunosuppression (12 for anti-CD20) [SASLT 2021, Page 9]\\nReferences:\\n- Pages 8, 9: Prophylaxis criteria, drug options, monitoring"
}}
---
EXAMPLE OUTPUT (ELIGIBLE - HIV COINFECTION) - Use SINGLE \\n only:
{{
  "eligible": true,
  "recommendations": "Eligibility and Rationale:\\n- Eligible: Patient has HBV-HIV coinfection and should start ART (Grade A) [SASLT 2021, Page 9]\\nTreatment Recommendations:\\n- ART regimen must include TDF- or TAF-based therapy (Grade A) [SASLT 2021, Page 9]\\nMonitoring and Follow-up:\\n- Monitor patient closely after ART initiation for immune reconstitution [SASLT 2021, Page 9]\\nReferences:\\n- Page 9: HBV-HIV coinfection management, ART regimens"
}}
---
CRITICAL REQUIREMENTS:
1. Base assessment ONLY on SASLT 2021 guidelines provided.
2. Follow the CRITICAL ELIGIBILITY HIERARCHY to avoid contradictions.
3. Keep output SHORT: 8-12 bullets total, 1 sentence per bullet (max 25 words).
4. Use ONLY the 5 sections listed above.
5. Cite exact page at end of each bullet: [SASLT 2021, Page X].
6. Return ONLY valid JSON, no markdown, no extra text.
"""
        
        
        # Log the complete prompt being sent to LLM
        logger.info(f"\n{'='*80}")
        logger.info(f"LLM PROMPT")
        logger.info(f"{'='*80}")
        logger.info(f"\n{analysis_prompt}\n")
        logger.info(f"{'='*80}\n")
        
        # Get LLM response
        llm = get_llm()
        logger.info("Sending prompt to LLM...")
        response = llm.invoke(analysis_prompt)
        logger.info("LLM response received")
        
        # Extract JSON from response
        response_text = response.content if hasattr(response, 'content') else str(response)
        
        # Log LLM response
        logger.info(f"\n{'='*80}")
        logger.info(f"LLM RESPONSE")
        logger.info(f"{'='*80}")
        logger.info(f"\n{response_text}\n")
        logger.info(f"{'='*80}\n")
        
        # Try to parse JSON from response
        try:
            # Remove markdown code blocks if present
            if '```json' in response_text:
                json_start = response_text.find('```json') + 7
                json_end = response_text.find('```', json_start)
                response_text = response_text[json_start:json_end].strip()
            elif '```' in response_text:
                json_start = response_text.find('```') + 3
                json_end = response_text.find('```', json_start)
                response_text = response_text[json_start:json_end].strip()
            
            # Find JSON in response (handle cases where LLM adds extra text)
            json_start = response_text.find('{')
            json_end = response_text.rfind('}') + 1
            if json_start >= 0 and json_end > json_start:
                json_str = response_text[json_start:json_end]
                
                # Clean the JSON string to escape control characters within string values
                cleaned_json_str = clean_json_string(json_str)
                logger.debug(f"Cleaned JSON string (first 500 chars): {cleaned_json_str[:500]}")
                
                # Parse the cleaned JSON
                result = json.loads(cleaned_json_str)
                logger.info(f"✅ Successfully parsed JSON response")
            else:
                raise ValueError("No JSON found in response")
            
            # Validate and return result
            normalized_recs = normalize_recommendations(result.get("recommendations", ""))
            assessment_result = {
                "eligible": result.get("eligible", False),
                "recommendations": normalized_recs
            }
            
            # Log final assessment
            logger.info(f"\n{'='*80}")
            logger.info(f"FINAL ASSESSMENT")
            logger.info(f"{'='*80}")
            logger.info(f"Eligible: {assessment_result['eligible']}")
            logger.info(f"Recommendations length: {len(assessment_result['recommendations'])} characters")
            logger.info(f"{'='*80}\n")
            
            return assessment_result
            
        except (json.JSONDecodeError, ValueError) as e:
            logger.error(f"Failed to parse LLM response as JSON: {e}")
            logger.error(f"Response text: {response_text}")
            
            # Fallback: return error response
            return {
                "eligible": False,
                "recommendations": f"Error parsing assessment results. Please try again. Error details: {str(e)}"
            }
    
    except Exception as e:
        logger.error(f"Error in assess_hbv_eligibility: {str(e)}")
        raise