vikramvasudevan commited on
Commit
cf0fa8f
·
verified ·
1 Parent(s): 3bdd0bc

Upload folder using huggingface_hub

Browse files
Files changed (5) hide show
  1. graph.py +6 -100
  2. modules/db.py +15 -1
  3. modules/models.py +100 -0
  4. report_formatter.py +3 -3
  5. ui.py +2 -1
graph.py CHANGED
@@ -18,7 +18,7 @@ from common import get_db
18
  from config import SheamiConfig
19
  import logging
20
 
21
- from modules import db
22
  from pdf_helper import generate_pdf
23
 
24
  logging.basicConfig()
@@ -35,105 +35,6 @@ llm = ChatOpenAI(model=os.getenv("MODEL"), temperature=0.3)
35
 
36
  from typing import Optional, List
37
  from pydantic import BaseModel, Field
38
-
39
-
40
- class PatientInfo(BaseModel):
41
- name: Optional[str] = Field(None, description="Patient's full name")
42
- age: Optional[int] = Field(None, description="Patient's age in years")
43
- sex: Optional[str] = Field(None, description="Male/Female/Other")
44
- medical_record_number: Optional[str] = None
45
-
46
- class Config:
47
- extra = "forbid" # 🚨 ensures schema matches OpenAI’s strict rules
48
-
49
-
50
- class TestResultReferenceRange(BaseModel):
51
- min: Optional[float] = None
52
- max: Optional[float] = None
53
-
54
-
55
- class LabResult(BaseModel):
56
- test_name: str
57
- result_value: str
58
- test_unit: str
59
- test_reference_range: Optional[TestResultReferenceRange] = None
60
- test_date: Optional[str] = None
61
- inferred_range: Literal["low", "normal", "high"]
62
-
63
- class Config:
64
- extra = "forbid"
65
-
66
-
67
- class CompositeLabResult(BaseModel):
68
- section_name: str # e.g., "CUE - COMPLETE URINE ANALYSIS"
69
- sub_results: List[LabResult] # each individual parameter under the section
70
-
71
- class Config:
72
- extra = "forbid"
73
-
74
-
75
- class StandardizedReport(BaseModel):
76
- original_report_file_name: str
77
- patient_info: PatientInfo
78
- lab_results: List[
79
- Union[LabResult, CompositeLabResult]
80
- ] # ✅ supports both flat + grouped results
81
- diagnosis: List[str]
82
- recommendations: List[str]
83
-
84
- class Config:
85
- extra = "forbid"
86
-
87
-
88
- @dataclass
89
- class HealthReport:
90
- report_file_name: str
91
- report_contents: str
92
-
93
-
94
- @dataclass
95
- class SheamiMilestone:
96
- step_name: str
97
- status: str # e.g., "started", "in_progress", "completed", "failed"
98
- start_time: Optional[datetime] = None
99
- end_time: Optional[datetime] = None
100
-
101
- @property
102
- def time_taken(self) -> Optional[float]:
103
- """Return time taken in seconds if available."""
104
- if self.start_time and self.end_time:
105
- return (self.end_time - self.start_time).total_seconds()
106
- return None
107
-
108
- @property
109
- def status_icon(self) -> str:
110
- if self.status == "started":
111
- return "⏳"
112
- elif self.status == "completed":
113
- return "✅"
114
- else:
115
- return self.status
116
-
117
-
118
- class SheamiState(TypedDict):
119
- user_email: str
120
- patient_id: str
121
- run_id: str
122
- messages: list[str]
123
- thread_id: str
124
- uploaded_reports: List[HealthReport]
125
- standardized_reports: List[StandardizedReport]
126
- trends_json: dict
127
- interpreted_report: str
128
- current_index: int
129
- process_desc: str
130
- units_processed: int
131
- units_total: int
132
- overall_units_processed: int
133
- overall_units_total: int
134
- milestones: list[SheamiMilestone]
135
-
136
-
137
  import re
138
 
139
 
@@ -617,6 +518,11 @@ async def fn_interpreter_node(state: SheamiState):
617
 
618
  get_db().update_run_stats(run_id=state["run_id"], status="completed")
619
 
 
 
 
 
 
620
  return state
621
 
622
 
 
18
  from config import SheamiConfig
19
  import logging
20
 
21
+ from modules.models import SheamiMilestone, SheamiState, StandardizedReport, TestResultReferenceRange
22
  from pdf_helper import generate_pdf
23
 
24
  logging.basicConfig()
 
35
 
36
  from typing import Optional, List
37
  from pydantic import BaseModel, Field
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  import re
39
 
40
 
 
518
 
519
  get_db().update_run_stats(run_id=state["run_id"], status="completed")
520
 
521
+ ## add parsed reports
522
+ get_db().add_report_v2(
523
+ patient_id=state["patient_id"], reports=state["standardized_reports"]
524
+ )
525
+
526
  return state
527
 
528
 
modules/db.py CHANGED
@@ -5,6 +5,7 @@ from datetime import datetime, timezone
5
  from bson import ObjectId
6
  from dotenv import load_dotenv
7
 
 
8
 
9
  class SheamiDB:
10
  def __init__(self, uri: str, db_name: str = "sheami"):
@@ -68,7 +69,20 @@ class SheamiDB:
68
  # ---------------------------
69
  # REPORT FUNCTIONS
70
  # ---------------------------
71
- def add_report(self, patient_id: str, file_name: str, parsed_data: dict) -> str:
 
 
 
 
 
 
 
 
 
 
 
 
 
72
  report = {
73
  "patient_id": ObjectId(patient_id),
74
  "uploaded_at": datetime.now(timezone.utc),
 
5
  from bson import ObjectId
6
  from dotenv import load_dotenv
7
 
8
+ from modules.models import StandardizedReport
9
 
10
  class SheamiDB:
11
  def __init__(self, uri: str, db_name: str = "sheami"):
 
69
  # ---------------------------
70
  # REPORT FUNCTIONS
71
  # ---------------------------
72
+ def add_report_v2(self, patient_id: str, reports: list[StandardizedReport]) -> str:
73
+ inserted_ids = []
74
+ for parsed_data in reports:
75
+ report = {
76
+ "patient_id": ObjectId(patient_id),
77
+ "uploaded_at": datetime.now(timezone.utc),
78
+ "file_name": parsed_data.original_report_file_name,
79
+ "parsed_data_v2": parsed_data.model_dump(),
80
+ }
81
+ result = self.reports.insert_one(report)
82
+ inserted_ids.append(result.inserted_id)
83
+ return str(inserted_ids)
84
+
85
+ def add_report(self, patient_id: str, file_name: str, parsed_data: any) -> str:
86
  report = {
87
  "patient_id": ObjectId(patient_id),
88
  "uploaded_at": datetime.now(timezone.utc),
modules/models.py ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from dataclasses import dataclass
2
+ from datetime import datetime
3
+ from pydantic import BaseModel, Field
4
+ from typing import List, Literal, Optional, TypedDict, Union
5
+
6
+ class PatientInfo(BaseModel):
7
+ name: Optional[str] = Field(None, description="Patient's full name")
8
+ age: Optional[int] = Field(None, description="Patient's age in years")
9
+ sex: Optional[str] = Field(None, description="Male/Female/Other")
10
+ medical_record_number: Optional[str] = None
11
+
12
+ class Config:
13
+ extra = "forbid" # 🚨 ensures schema matches OpenAI’s strict rules
14
+
15
+
16
+ class TestResultReferenceRange(BaseModel):
17
+ min: Optional[float] = None
18
+ max: Optional[float] = None
19
+
20
+
21
+ class LabResult(BaseModel):
22
+ test_name: str
23
+ result_value: str
24
+ test_unit: str
25
+ test_reference_range: Optional[TestResultReferenceRange] = None
26
+ test_date: Optional[str] = None
27
+ inferred_range: Literal["low", "normal", "high"]
28
+
29
+ class Config:
30
+ extra = "forbid"
31
+
32
+
33
+ class CompositeLabResult(BaseModel):
34
+ section_name: str # e.g., "CUE - COMPLETE URINE ANALYSIS"
35
+ sub_results: List[LabResult] # each individual parameter under the section
36
+
37
+ class Config:
38
+ extra = "forbid"
39
+
40
+
41
+ class StandardizedReport(BaseModel):
42
+ original_report_file_name: str
43
+ patient_info: PatientInfo
44
+ lab_results: List[
45
+ Union[LabResult, CompositeLabResult]
46
+ ] # ✅ supports both flat + grouped results
47
+ diagnosis: List[str]
48
+ recommendations: List[str]
49
+
50
+ class Config:
51
+ extra = "forbid"
52
+
53
+
54
+ @dataclass
55
+ class HealthReport:
56
+ report_file_name: str
57
+ report_contents: str
58
+
59
+
60
+ @dataclass
61
+ class SheamiMilestone:
62
+ step_name: str
63
+ status: str # e.g., "started", "in_progress", "completed", "failed"
64
+ start_time: Optional[datetime] = None
65
+ end_time: Optional[datetime] = None
66
+
67
+ @property
68
+ def time_taken(self) -> Optional[float]:
69
+ """Return time taken in seconds if available."""
70
+ if self.start_time and self.end_time:
71
+ return (self.end_time - self.start_time).total_seconds()
72
+ return None
73
+
74
+ @property
75
+ def status_icon(self) -> str:
76
+ if self.status == "started":
77
+ return "⏳"
78
+ elif self.status == "completed":
79
+ return "✅"
80
+ else:
81
+ return self.status
82
+
83
+
84
+ class SheamiState(TypedDict):
85
+ user_email: str
86
+ patient_id: str
87
+ run_id: str
88
+ messages: list[str]
89
+ thread_id: str
90
+ uploaded_reports: List[HealthReport]
91
+ standardized_reports: List[StandardizedReport]
92
+ trends_json: dict
93
+ interpreted_report: str
94
+ current_index: int
95
+ process_desc: str
96
+ units_processed: int
97
+ units_total: int
98
+ overall_units_processed: int
99
+ overall_units_total: int
100
+ milestones: list[SheamiMilestone]
report_formatter.py CHANGED
@@ -3,11 +3,11 @@ import gradio as gr
3
  from typing import List, Optional
4
  from datetime import datetime
5
 
6
- from graph import (
7
- CompositeLabResult,
8
- LabResult,
9
  StandardizedReport,
10
  TestResultReferenceRange,
 
 
11
  )
12
 
13
 
 
3
  from typing import List, Optional
4
  from datetime import datetime
5
 
6
+ from modules.models import (
 
 
7
  StandardizedReport,
8
  TestResultReferenceRange,
9
+ CompositeLabResult,
10
+ LabResult,
11
  )
12
 
13
 
ui.py CHANGED
@@ -6,7 +6,8 @@ import os
6
  import pandas as pd
7
  from tqdm.auto import tqdm
8
  from config import SheamiConfig
9
- from graph import SheamiMilestone, create_graph, SheamiState, HealthReport
 
10
  from pdf_reader import read_pdf
11
  from gradio_modal import Modal
12
  from report_formatter import render_patient_state
 
6
  import pandas as pd
7
  from tqdm.auto import tqdm
8
  from config import SheamiConfig
9
+ from graph import create_graph
10
+ from modules.models import HealthReport, SheamiMilestone, SheamiState
11
  from pdf_reader import read_pdf
12
  from gradio_modal import Modal
13
  from report_formatter import render_patient_state