Arjun Moorthy commited on
Commit
da47961
·
1 Parent(s): cefbc35

Clean up repository and fix file locations

Browse files
Files changed (3) hide show
  1. Oncolife/requirements.txt +0 -20
  2. README.md +1 -1
  3. app.py +0 -259
Oncolife/requirements.txt DELETED
@@ -1,20 +0,0 @@
1
- # Medical Chatbot HF Space Requirements
2
-
3
- # Web framework
4
- gradio>=4.44.0
5
-
6
- # Machine learning libraries - specific versions for compatibility
7
- torch>=2.1.0,<3.0.0
8
- transformers>=4.35.0,<5.0.0
9
- accelerate>=0.24.0
10
-
11
- # HF Spaces GPU support
12
- spaces>=0.1.0
13
-
14
- # Basic utilities
15
- numpy>=1.21.0,<2.0.0
16
- requests>=2.28.0
17
-
18
- # Additional dependencies for better device handling
19
- safetensors>=0.4.0
20
- tokenizers>=0.15.0
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
README.md CHANGED
@@ -6,7 +6,7 @@ colorTo: green
6
  sdk: gradio
7
  sdk_version: 4.44.0
8
  app_file: Oncolife/app.py
9
- requirements_file: Oncolife/requirements.txt
10
  pinned: false
11
  ---
12
 
 
6
  sdk: gradio
7
  sdk_version: 4.44.0
8
  app_file: Oncolife/app.py
9
+ requirements_file: requirements.txt
10
  pinned: false
11
  ---
12
 
app.py DELETED
@@ -1,259 +0,0 @@
1
- #!/usr/bin/env python3
2
- """
3
- OncoLife Symptom & Triage Assistant
4
- A medical chatbot that performs both symptom assessment and clinical triage for chemotherapy patients.
5
- Updated: Using BioMistral-7B base model for medical conversations.
6
- REBUILD: Simplified to use only base model, no adapters.
7
- """
8
-
9
- import gradio as gr
10
- import os
11
- import json
12
- from transformers import AutoTokenizer, MistralForCausalLM
13
- import torch
14
- from spaces import GPU
15
-
16
- # Force GPU detection for HF Spaces
17
- @GPU
18
- def force_gpu_detection():
19
- """Force GPU detection for Hugging Face Spaces"""
20
- return torch.cuda.is_available()
21
-
22
- class OncoLifeAssistant:
23
- def __init__(self):
24
- # BioMistral base model configuration
25
- BASE = "BioMistral/BioMistral-7B"
26
-
27
- print("🔄 Initializing OncoLife Symptom & Triage Assistant")
28
- print(f"📦 Loading base model: {BASE}")
29
-
30
- # Force GPU detection first
31
- try:
32
- gpu_available = force_gpu_detection()
33
- print(f"🖥️ GPU Detection: {gpu_available}")
34
- except Exception as e:
35
- print(f"⚠️ GPU detection error: {e}")
36
- gpu_available = torch.cuda.is_available()
37
-
38
- self._load_model(BASE, gpu_available)
39
-
40
- # Initialize conversation state
41
- self.conversation_state = {
42
- "symptoms": [],
43
- "asked_ids": [],
44
- "answers": {},
45
- "current_symptom": None,
46
- "conversation_phase": "initial" # initial, symptom_assessment, triage, summary
47
- }
48
-
49
- def _load_model(self, model_id, gpu_available):
50
- """Load the BioMistral base model"""
51
- try:
52
- print("🔄 Loading BioMistral base model...")
53
-
54
- # Determine device strategy
55
- if gpu_available and torch.cuda.is_available():
56
- device = "cuda"
57
- dtype = torch.float16
58
- print("🖥️ Loading BioMistral model on GPU...")
59
- else:
60
- device = "cpu"
61
- dtype = torch.float32
62
- print("💻 Loading BioMistral model on CPU...")
63
-
64
- # Load tokenizer
65
- print(f"📝 Loading tokenizer: {model_id}")
66
- self.tokenizer = AutoTokenizer.from_pretrained(
67
- model_id,
68
- trust_remote_code=True
69
- )
70
-
71
- # Load the model
72
- print(f"📦 Loading model: {model_id}")
73
- self.model = MistralForCausalLM.from_pretrained(
74
- model_id,
75
- trust_remote_code=True,
76
- device_map="auto",
77
- torch_dtype=dtype,
78
- low_cpu_mem_usage=True
79
- )
80
-
81
- # Add pad token if not present
82
- if self.tokenizer.pad_token is None:
83
- self.tokenizer.pad_token = self.tokenizer.eos_token
84
-
85
- print(f"✅ BioMistral base model loaded successfully on {device.upper()}!")
86
-
87
- except Exception as e:
88
- print(f"❌ Error loading BioMistral model: {e}")
89
- self.model = None
90
- self.tokenizer = None
91
-
92
- def generate_oncolife_response(self, user_input, conversation_history):
93
- """Generate response using OncoLife Symptom & Triage Assistant protocol"""
94
- try:
95
- if self.model is None or self.tokenizer is None:
96
- return """❌ **Model Loading Error**
97
-
98
- The OncoLife assistant model failed to load. This could be due to:
99
- 1. Model not available
100
- 2. Memory constraints
101
- 3. Network issues
102
-
103
- Please check the Space logs for details."""
104
-
105
- print(f"🔄 Generating OncoLife response for: {user_input}")
106
-
107
- # Create OncoLife-specific prompt
108
- system_prompt = """You are the OncoLife Symptom & Triage Assistant, a medical chatbot that performs both symptom assessment and clinical triage for chemotherapy patients. Your task is to guide users through structured symptom reporting and decide whether any responses require escalation to their care team.
109
-
110
- Follow this workflow:
111
- 1. Ask for symptoms if none provided
112
- 2. For each symptom, ask severity rating (mild/moderate/severe)
113
- 3. Check for red flags and immediate escalation needs
114
- 4. Grade severity using CTCAE or UKONS criteria
115
- 5. Ask targeted questions based on utility scoring
116
- 6. Provide structured summary with triage recommendations
117
-
118
- Safety protocols:
119
- - Never provide medical advice or treatment recommendations
120
- - Always redirect to oncology team for medical decisions
121
- - Escalate immediately for dangerous symptoms
122
- - Add legal disclaimer at session end
123
-
124
- Current conversation state: {conversation_state}"""
125
-
126
- # Format conversation history
127
- history_text = ""
128
- if conversation_history:
129
- for entry in conversation_history:
130
- history_text += f"User: {entry['user']}\nAssistant: {entry['assistant']}\n\n"
131
-
132
- # Create full prompt
133
- prompt = f"{system_prompt}\n\nConversation History:\n{history_text}\nUser: {user_input}\nAssistant:"
134
-
135
- # Tokenize
136
- inputs = self.tokenizer(prompt, return_tensors="pt", padding=True)
137
-
138
- # Get the device the model is actually on
139
- model_device = next(self.model.parameters()).device
140
- print(f"🔧 Model device: {model_device}")
141
-
142
- # Move inputs to the same device as the model
143
- for key in inputs:
144
- if isinstance(inputs[key], torch.Tensor):
145
- inputs[key] = inputs[key].to(model_device)
146
- print(f"📦 Moved {key} to {model_device}")
147
-
148
- # Ensure model is in eval mode
149
- self.model.eval()
150
-
151
- # Generate with proper device handling
152
- with torch.no_grad():
153
- try:
154
- outputs = self.model.generate(
155
- **inputs,
156
- max_new_tokens=512, # Longer responses for detailed medical assessment
157
- temperature=0.7,
158
- do_sample=True,
159
- top_p=0.9,
160
- pad_token_id=self.tokenizer.eos_token_id,
161
- eos_token_id=self.tokenizer.eos_token_id
162
- )
163
- except RuntimeError as e:
164
- if "device" in str(e).lower():
165
- print("🔄 Device error detected, trying CPU fallback...")
166
- # Move everything to CPU and try again
167
- self.model = self.model.to("cpu")
168
- for key in inputs:
169
- if isinstance(inputs[key], torch.Tensor):
170
- inputs[key] = inputs[key].to("cpu")
171
-
172
- outputs = self.model.generate(
173
- **inputs,
174
- max_new_tokens=512,
175
- temperature=0.7,
176
- do_sample=True,
177
- top_p=0.9,
178
- pad_token_id=self.tokenizer.eos_token_id,
179
- eos_token_id=self.tokenizer.eos_token_id
180
- )
181
- else:
182
- raise e
183
-
184
- # Decode response
185
- response = self.tokenizer.decode(outputs[0], skip_special_tokens=True)
186
-
187
- # Extract just the assistant's response
188
- if "Assistant:" in response:
189
- answer = response.split("Assistant:")[-1].strip()
190
- else:
191
- answer = response.strip()
192
-
193
- # Add legal disclaimer if this appears to be end of session
194
- if any(keyword in user_input.lower() for keyword in ['done', 'finished', 'complete', 'summary']):
195
- answer += "\n\n" + self._get_legal_disclaimer()
196
-
197
- print("✅ OncoLife response generated successfully")
198
- return answer
199
-
200
- except Exception as e:
201
- print(f"❌ Error generating OncoLife response: {e}")
202
- return f"""❌ **Generation Error**
203
-
204
- Error: {str(e)}
205
-
206
- This could be due to:
207
- 1. Model compatibility issues
208
- 2. Memory constraints
209
- 3. Input format problems
210
-
211
- Please try a simpler question or check the logs for more details."""
212
-
213
- def _get_legal_disclaimer(self):
214
- """Return the legal disclaimer as specified in the instructions"""
215
- return """**Legal Disclaimer:**
216
-
217
- Patient verbalizes agreement with plan of care and understanding of the information we have gone over today and has no further comments, questions or concerns at this time. Will follow up with Doctor or ONN if symptoms worsen, do not improve, or any other symptoms develop. Agrees to seek emergency care if pt believes is needed, including for increased dizziness, depression, or any thoughts of SI.
218
-
219
- **Important:** I cannot provide medical advice or treatment recommendations. Please call your oncology team to confirm what's appropriate for your specific situation."""
220
-
221
- def chat(self, message, history):
222
- """Main chat interface for OncoLife Assistant"""
223
- if not message.strip():
224
- return "Please describe your symptoms or concerns."
225
-
226
- # Convert history to the format expected by generate_oncolife_response
227
- conversation_history = []
228
- for user_msg, assistant_msg in history:
229
- conversation_history.append({
230
- "user": user_msg,
231
- "assistant": assistant_msg
232
- })
233
-
234
- # Generate response using OncoLife protocol
235
- response = self.generate_oncolife_response(message, conversation_history)
236
-
237
- return response
238
-
239
- # Create interface
240
- assistant = OncoLifeAssistant()
241
- interface = gr.ChatInterface(
242
- fn=assistant.chat,
243
- title="🏥 OncoLife Symptom & Triage Assistant",
244
- description="I'm here to help assess your symptoms and determine if you need to contact your care team. Please describe your symptoms or concerns.",
245
- examples=[
246
- ["I'm feeling nauseous and tired"],
247
- ["I have a fever of 101"],
248
- ["My neuropathy is getting worse"],
249
- ["I'm having trouble eating"],
250
- ["I feel dizzy and lightheaded"]
251
- ],
252
- theme=gr.themes.Soft()
253
- )
254
-
255
- if __name__ == "__main__":
256
- print("=" * 60)
257
- print("OncoLife Symptom & Triage Assistant")
258
- print("=" * 60)
259
- interface.launch(server_name="0.0.0.0", server_port=7860)