File size: 2,690 Bytes
2c2fc49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# utils/report.py

from __future__ import annotations
from typing import Dict, Any, Optional
import base64
from io import BytesIO
from PIL import Image

from utils.analysis import (
    compute_differential_percentages,
    generate_report_from_ai,
)


# -------------------------------------------------
# OPTIONAL IMAGE ENCODING (for API responses)
# -------------------------------------------------
def pil_to_base64(img: Image.Image, format="PNG") -> str:
    """
    Convert a PIL image to Base64 (useful for overlay images in API mode).
    """
    buffer = BytesIO()
    img.save(buffer, format=format)
    return base64.b64encode(buffer.getvalue()).decode()


# -------------------------------------------------
# STRUCTURED API RESPONSE GENERATION
# -------------------------------------------------
def build_api_response(
    ai_result: Dict[str, Any],
    age_group: str,
    gender: Optional[str],
    reference_csv: str,
    overlay_image: Optional[Image.Image] = None,
) -> Dict[str, Any]:
    """
    Build a clean JSON response combining:
      - coarse counts (RBC/WBC/Platelets)
      - WBC subtype counts
      - WBC subtype percentages
      - generated plain-text report
      - optional overlay image (Base64)
    """

    coarse = ai_result.get("coarse_counts", {})
    subtypes = ai_result.get("wbc_subtypes", {})

    pct = compute_differential_percentages(subtypes)

    # Generate full text report (human readable)
    text_report = generate_report_from_ai(
        ai_result=ai_result,
        age_group=age_group,
        gender=gender,
        csv_path=reference_csv,
    )

    # Build JSON response
    response = {
        "patient_id": ai_result.get("patient_id"),
        "timestamp": ai_result.get("timestamp"),
        "fovs_analyzed": ai_result.get("fovs_analyzed"),
        "coarse_counts": coarse,
        "wbc_subtypes": subtypes,
        "wbc_percentages": pct,
        "report_text": text_report,
        "calibration": ai_result.get("calibration", {}),
    }

    # Add overlay image only if provided
    if overlay_image is not None:
        response["overlay_image"] = pil_to_base64(overlay_image)

    return response


# -------------------------------------------------
# SIMPLE TEXT-ONLY REPORT (UI mode)
# -------------------------------------------------
def build_text_report(
    ai_result: Dict[str, Any],
    age_group: str,
    gender: Optional[str],
    reference_csv: str,
) -> str:
    """
    Helper to get only the text report.
    Useful for Gradio or CLI mode.
    """
    return generate_report_from_ai(
        ai_result=ai_result,
        age_group=age_group,
        gender=gender,
        csv_path=reference_csv,
    )