Spaces:
Sleeping
Sleeping
Said Lfagrouche
commited on
Commit
·
c13c6ef
1
Parent(s):
ed78072
Fix model artifacts copying in Dockerfile and add fallback functionality for missing models
Browse files- Dockerfile +3 -0
- api_mental_health.py +99 -43
Dockerfile
CHANGED
@@ -31,6 +31,9 @@ COPY .env.example .env
|
|
31 |
COPY api_mental_health.py .
|
32 |
COPY run_api.sh .
|
33 |
|
|
|
|
|
|
|
34 |
# Make the script executable
|
35 |
RUN chmod +x run_api.sh
|
36 |
|
|
|
31 |
COPY api_mental_health.py .
|
32 |
COPY run_api.sh .
|
33 |
|
34 |
+
# Copy model artifacts directory
|
35 |
+
COPY mental_health_model_artifacts/ mental_health_model_artifacts/
|
36 |
+
|
37 |
# Make the script executable
|
38 |
RUN chmod +x run_api.sh
|
39 |
|
api_mental_health.py
CHANGED
@@ -81,20 +81,23 @@ async def startup_event():
|
|
81 |
|
82 |
# Check environment variables
|
83 |
if not os.environ.get("OPENAI_API_KEY"):
|
84 |
-
logger.
|
85 |
-
raise HTTPException(status_code=500, detail="OPENAI_API_KEY not set in .env file")
|
86 |
if not os.environ.get("LANGCHAIN_API_KEY"):
|
87 |
-
logger.
|
88 |
-
raise HTTPException(status_code=500, detail="LANGCHAIN_API_KEY not set in .env file")
|
89 |
os.environ["LANGCHAIN_TRACING_V2"] = "true"
|
90 |
os.environ["LANGCHAIN_PROJECT"] = "MentalHealthCounselorPOC"
|
91 |
|
92 |
-
# Initialize LangSmith client
|
93 |
-
|
94 |
-
|
|
|
|
|
|
|
|
|
95 |
|
96 |
-
#
|
97 |
logger.info("Loading model artifacts")
|
|
|
98 |
try:
|
99 |
response_clf = joblib.load(f"{output_dir}/response_type_classifier.pkl")
|
100 |
crisis_clf = joblib.load(f"{output_dir}/crisis_classifier.pkl")
|
@@ -111,47 +114,89 @@ async def startup_event():
|
|
111 |
# Note: Placeholder is untrained; retrain for accurate results
|
112 |
|
113 |
except FileNotFoundError as e:
|
114 |
-
logger.
|
115 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
116 |
|
117 |
-
# Initialize ChromaDB
|
118 |
chroma_db_path = f"{output_dir}/chroma_db"
|
119 |
if not os.path.exists(chroma_db_path):
|
120 |
-
logger.
|
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 |
-
# Initialize OpenAI client and LLM
|
147 |
logger.info("Initializing OpenAI client and LLM")
|
148 |
global openai_client, llm
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
155 |
|
156 |
# Pydantic model for request
|
157 |
class PatientContext(BaseModel):
|
@@ -266,6 +311,16 @@ def engineer_features(context, response=""):
|
|
266 |
# Prediction function
|
267 |
@traceable(run_type="chain", name="Predict Response Type")
|
268 |
def predict_response_type(context):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
269 |
features, feature_cols = engineer_features(context)
|
270 |
selected_features = selector.transform(features[feature_cols])
|
271 |
pred_encoded = response_clf.predict(selected_features)[0]
|
@@ -285,7 +340,8 @@ def predict_response_type(context):
|
|
285 |
"response_type": pred_label,
|
286 |
"crisis_flag": crisis_flag,
|
287 |
"confidence": confidence,
|
288 |
-
"features": features.to_dict()
|
|
|
289 |
}
|
290 |
|
291 |
# RAG suggestion function
|
|
|
81 |
|
82 |
# Check environment variables
|
83 |
if not os.environ.get("OPENAI_API_KEY"):
|
84 |
+
logger.warning("OPENAI_API_KEY not set in .env file. Some functionality will be limited.")
|
|
|
85 |
if not os.environ.get("LANGCHAIN_API_KEY"):
|
86 |
+
logger.warning("LANGCHAIN_API_KEY not set in .env file. Some functionality will be limited.")
|
|
|
87 |
os.environ["LANGCHAIN_TRACING_V2"] = "true"
|
88 |
os.environ["LANGCHAIN_PROJECT"] = "MentalHealthCounselorPOC"
|
89 |
|
90 |
+
# Initialize LangSmith client if API key is available
|
91 |
+
try:
|
92 |
+
logger.info("Initializing LangSmith client")
|
93 |
+
langsmith_client = Client()
|
94 |
+
except Exception as e:
|
95 |
+
logger.warning(f"Failed to initialize LangSmith client: {e}")
|
96 |
+
langsmith_client = None
|
97 |
|
98 |
+
# Try to load saved components, continue with limited functionality if not available
|
99 |
logger.info("Loading model artifacts")
|
100 |
+
models_available = True
|
101 |
try:
|
102 |
response_clf = joblib.load(f"{output_dir}/response_type_classifier.pkl")
|
103 |
crisis_clf = joblib.load(f"{output_dir}/crisis_classifier.pkl")
|
|
|
114 |
# Note: Placeholder is untrained; retrain for accurate results
|
115 |
|
116 |
except FileNotFoundError as e:
|
117 |
+
logger.warning(f"Missing model artifact: {e}. Running with limited functionality.")
|
118 |
+
models_available = False
|
119 |
+
# Set placeholder values for models to avoid errors
|
120 |
+
from sklearn.ensemble import RandomForestClassifier
|
121 |
+
from sklearn.feature_extraction.text import TfidfVectorizer
|
122 |
+
from sklearn.feature_selection import SelectKBest
|
123 |
+
from sklearn.preprocessing import LabelEncoder
|
124 |
+
from sklearn.decomposition import LatentDirichletAllocation
|
125 |
+
|
126 |
+
response_clf = RandomForestClassifier()
|
127 |
+
crisis_clf = RandomForestClassifier()
|
128 |
+
vectorizer = TfidfVectorizer()
|
129 |
+
le = LabelEncoder()
|
130 |
+
selector = SelectKBest()
|
131 |
+
lda = LatentDirichletAllocation(n_components=10)
|
132 |
|
133 |
+
# Initialize ChromaDB if possible
|
134 |
chroma_db_path = f"{output_dir}/chroma_db"
|
135 |
if not os.path.exists(chroma_db_path):
|
136 |
+
logger.warning(f"ChromaDB not found at {chroma_db_path}. Vector search will be unavailable.")
|
137 |
+
vector_store = None
|
138 |
+
else:
|
139 |
+
try:
|
140 |
+
logger.info("Initializing ChromaDB")
|
141 |
+
if os.environ.get("OPENAI_API_KEY"):
|
142 |
+
chroma_client = chromadb.PersistentClient(
|
143 |
+
path=chroma_db_path,
|
144 |
+
settings=Settings(anonymized_telemetry=False)
|
145 |
+
)
|
146 |
|
147 |
+
embeddings = OpenAIEmbeddings(
|
148 |
+
model="text-embedding-ada-002",
|
149 |
+
api_key=os.environ["OPENAI_API_KEY"],
|
150 |
+
disallowed_special=(),
|
151 |
+
chunk_size=1000
|
152 |
+
)
|
153 |
+
global vector_store
|
154 |
+
try:
|
155 |
+
vector_store = Chroma(
|
156 |
+
client=chroma_client,
|
157 |
+
collection_name="mental_health_conversations",
|
158 |
+
embedding_function=embeddings
|
159 |
+
)
|
160 |
+
except Exception as chroma_error:
|
161 |
+
logger.warning(f"Error initializing Chroma collection: {chroma_error}")
|
162 |
+
vector_store = None
|
163 |
+
else:
|
164 |
+
logger.warning("Skipping ChromaDB initialization as OPENAI_API_KEY is not set")
|
165 |
+
vector_store = None
|
166 |
+
except Exception as e:
|
167 |
+
logger.warning(f"Error initializing ChromaDB: {e}")
|
168 |
+
vector_store = None
|
169 |
|
170 |
+
# Initialize OpenAI client and LLM if API key is available
|
171 |
logger.info("Initializing OpenAI client and LLM")
|
172 |
global openai_client, llm
|
173 |
+
if os.environ.get("OPENAI_API_KEY"):
|
174 |
+
try:
|
175 |
+
openai_client = OpenAI(api_key=os.environ["OPENAI_API_KEY"])
|
176 |
+
llm = ChatOpenAI(
|
177 |
+
model="gpt-4o-mini",
|
178 |
+
temperature=0.7,
|
179 |
+
api_key=os.environ["OPENAI_API_KEY"]
|
180 |
+
)
|
181 |
+
except Exception as e:
|
182 |
+
logger.warning(f"Error initializing OpenAI client: {e}")
|
183 |
+
openai_client = None
|
184 |
+
llm = None
|
185 |
+
else:
|
186 |
+
logger.warning("OpenAI client not initialized as OPENAI_API_KEY is not set")
|
187 |
+
openai_client = None
|
188 |
+
llm = None
|
189 |
+
|
190 |
+
# Add route to check model availability
|
191 |
+
@app.get("/model-status")
|
192 |
+
async def model_status():
|
193 |
+
return {
|
194 |
+
"models_available": models_available,
|
195 |
+
"vector_store_available": vector_store is not None,
|
196 |
+
"llm_available": llm is not None,
|
197 |
+
"openai_api_key_set": os.environ.get("OPENAI_API_KEY") is not None,
|
198 |
+
"langchain_api_key_set": os.environ.get("LANGCHAIN_API_KEY") is not None
|
199 |
+
}
|
200 |
|
201 |
# Pydantic model for request
|
202 |
class PatientContext(BaseModel):
|
|
|
311 |
# Prediction function
|
312 |
@traceable(run_type="chain", name="Predict Response Type")
|
313 |
def predict_response_type(context):
|
314 |
+
if response_clf is None or vectorizer is None or le is None or selector is None or lda is None:
|
315 |
+
logger.warning("Models not available, returning dummy prediction")
|
316 |
+
return {
|
317 |
+
"response_type": "Empathetic Listening",
|
318 |
+
"crisis_flag": False,
|
319 |
+
"confidence": 0.5,
|
320 |
+
"features": {},
|
321 |
+
"models_available": False
|
322 |
+
}
|
323 |
+
|
324 |
features, feature_cols = engineer_features(context)
|
325 |
selected_features = selector.transform(features[feature_cols])
|
326 |
pred_encoded = response_clf.predict(selected_features)[0]
|
|
|
340 |
"response_type": pred_label,
|
341 |
"crisis_flag": crisis_flag,
|
342 |
"confidence": confidence,
|
343 |
+
"features": features.to_dict(),
|
344 |
+
"models_available": True
|
345 |
}
|
346 |
|
347 |
# RAG suggestion function
|