Spaces:
Sleeping
Sleeping
Integrate TxAgent into CPS API: add TxAgent files, update requirements, fix imports and database collections
Browse files- api/routes/txagent.py +17 -3
- check_database.py +98 -0
- test_direct_connection.py +108 -0
api/routes/txagent.py
CHANGED
|
@@ -204,6 +204,20 @@ async def get_patient_analysis_results(
|
|
| 204 |
continue # Skip if patient no longer exists
|
| 205 |
|
| 206 |
# Format the response with proper fields matching the expected format
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 207 |
formatted_analysis = {
|
| 208 |
"_id": str(analysis["_id"]),
|
| 209 |
"patient_id": analysis.get("patient_id"),
|
|
@@ -212,9 +226,9 @@ async def get_patient_analysis_results(
|
|
| 212 |
"created_at": analysis.get("created_at"),
|
| 213 |
"analysis_date": analysis.get("analysis_date"),
|
| 214 |
"suicide_risk": {
|
| 215 |
-
"level": _normalize_risk_level(
|
| 216 |
-
"score":
|
| 217 |
-
"factors":
|
| 218 |
},
|
| 219 |
"summary": analysis.get("summary", ""),
|
| 220 |
"recommendations": analysis.get("recommendations", [])
|
|
|
|
| 204 |
continue # Skip if patient no longer exists
|
| 205 |
|
| 206 |
# Format the response with proper fields matching the expected format
|
| 207 |
+
# Handle both old format (risk_level, risk_score) and new format (suicide_risk object)
|
| 208 |
+
suicide_risk_data = analysis.get("suicide_risk", {})
|
| 209 |
+
|
| 210 |
+
# Extract risk data from suicide_risk object or fallback to individual fields
|
| 211 |
+
if isinstance(suicide_risk_data, dict):
|
| 212 |
+
risk_level = suicide_risk_data.get("level", "none")
|
| 213 |
+
risk_score = suicide_risk_data.get("score", 0.0)
|
| 214 |
+
risk_factors = suicide_risk_data.get("factors", [])
|
| 215 |
+
else:
|
| 216 |
+
# Fallback to individual fields for backward compatibility
|
| 217 |
+
risk_level = analysis.get("risk_level", "none")
|
| 218 |
+
risk_score = analysis.get("risk_score", 0.0)
|
| 219 |
+
risk_factors = analysis.get("risk_factors", [])
|
| 220 |
+
|
| 221 |
formatted_analysis = {
|
| 222 |
"_id": str(analysis["_id"]),
|
| 223 |
"patient_id": analysis.get("patient_id"),
|
|
|
|
| 226 |
"created_at": analysis.get("created_at"),
|
| 227 |
"analysis_date": analysis.get("analysis_date"),
|
| 228 |
"suicide_risk": {
|
| 229 |
+
"level": _normalize_risk_level(risk_level),
|
| 230 |
+
"score": risk_score,
|
| 231 |
+
"factors": risk_factors
|
| 232 |
},
|
| 233 |
"summary": analysis.get("summary", ""),
|
| 234 |
"recommendations": analysis.get("recommendations", [])
|
check_database.py
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Check database directly to see analysis data
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import asyncio
|
| 7 |
+
import motor.motor_asyncio
|
| 8 |
+
import os
|
| 9 |
+
from datetime import datetime
|
| 10 |
+
|
| 11 |
+
async def check_database():
|
| 12 |
+
"""Check database directly for analysis data"""
|
| 13 |
+
|
| 14 |
+
print("🔍 Checking Database Directly")
|
| 15 |
+
print("=" * 50)
|
| 16 |
+
print(f"⏰ Started at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
| 17 |
+
print()
|
| 18 |
+
|
| 19 |
+
try:
|
| 20 |
+
# Connect to MongoDB
|
| 21 |
+
mongo_url = os.getenv('MONGODB_URL', 'mongodb://localhost:27017')
|
| 22 |
+
client = motor.motor_asyncio.AsyncIOMotorClient(mongo_url)
|
| 23 |
+
db = client.cps_database
|
| 24 |
+
|
| 25 |
+
# Check patients collection
|
| 26 |
+
print("📊 Checking patients collection...")
|
| 27 |
+
patients_count = await db.patients.count_documents({})
|
| 28 |
+
print(f" ✅ Found {patients_count} patients")
|
| 29 |
+
|
| 30 |
+
if patients_count > 0:
|
| 31 |
+
# Show sample patients
|
| 32 |
+
patients = await db.patients.find({}).limit(3).to_list(length=3)
|
| 33 |
+
print("\n📋 Sample Patients:")
|
| 34 |
+
for i, patient in enumerate(patients):
|
| 35 |
+
print(f" Patient {i+1}: {patient.get('full_name', 'Unknown')}")
|
| 36 |
+
print(f" - ID: {patient.get('fhir_id', 'No ID')}")
|
| 37 |
+
print(f" - Email: {patient.get('email', 'No email')}")
|
| 38 |
+
print()
|
| 39 |
+
|
| 40 |
+
# Check analysis collection
|
| 41 |
+
print("📊 Checking analysis collection...")
|
| 42 |
+
analysis_count = await db.patient_analysis_results.count_documents({})
|
| 43 |
+
print(f" ✅ Found {analysis_count} analysis results")
|
| 44 |
+
|
| 45 |
+
if analysis_count > 0:
|
| 46 |
+
# Show sample analysis results
|
| 47 |
+
analyses = await db.patient_analysis_results.find({}).limit(3).to_list(length=3)
|
| 48 |
+
print("\n📋 Sample Analysis Results:")
|
| 49 |
+
for i, analysis in enumerate(analyses):
|
| 50 |
+
print(f" Analysis {i+1}:")
|
| 51 |
+
print(f" - Patient ID: {analysis.get('patient_id', 'No ID')}")
|
| 52 |
+
print(f" - Timestamp: {analysis.get('timestamp', 'No timestamp')}")
|
| 53 |
+
|
| 54 |
+
# Check suicide risk data
|
| 55 |
+
suicide_risk = analysis.get('suicide_risk', {})
|
| 56 |
+
if isinstance(suicide_risk, dict):
|
| 57 |
+
risk_level = suicide_risk.get('level', 'No level')
|
| 58 |
+
risk_score = suicide_risk.get('score', 0.0)
|
| 59 |
+
risk_factors = suicide_risk.get('factors', [])
|
| 60 |
+
print(f" - Risk Level: {risk_level}")
|
| 61 |
+
print(f" - Risk Score: {risk_score}")
|
| 62 |
+
print(f" - Risk Factors: {risk_factors}")
|
| 63 |
+
else:
|
| 64 |
+
print(f" - Suicide Risk: {suicide_risk}")
|
| 65 |
+
|
| 66 |
+
# Check summary
|
| 67 |
+
summary = analysis.get('summary', '')
|
| 68 |
+
if summary:
|
| 69 |
+
print(f" - Summary: {summary[:100]}...")
|
| 70 |
+
print()
|
| 71 |
+
|
| 72 |
+
# Check if there are any patients without analysis
|
| 73 |
+
if patients_count > 0 and analysis_count > 0:
|
| 74 |
+
print("🔍 Checking for patients without analysis...")
|
| 75 |
+
patients_with_analysis = await db.patient_analysis_results.distinct('patient_id')
|
| 76 |
+
patients_without_analysis = patients_count - len(patients_with_analysis)
|
| 77 |
+
print(f" 📊 Patients with analysis: {len(patients_with_analysis)}")
|
| 78 |
+
print(f" 📊 Patients without analysis: {patients_without_analysis}")
|
| 79 |
+
|
| 80 |
+
if patients_without_analysis > 0:
|
| 81 |
+
print(" ⚠️ Some patients need analysis!")
|
| 82 |
+
print(" 💡 You may need to trigger analysis for these patients")
|
| 83 |
+
|
| 84 |
+
client.close()
|
| 85 |
+
|
| 86 |
+
except Exception as e:
|
| 87 |
+
print(f"❌ Database error: {e}")
|
| 88 |
+
print("💡 Make sure MongoDB is running and accessible")
|
| 89 |
+
|
| 90 |
+
print("\n" + "="*50)
|
| 91 |
+
print("✅ Database check completed!")
|
| 92 |
+
print("\n📝 Summary:")
|
| 93 |
+
print(" - If you see analysis results with real scores, the data exists")
|
| 94 |
+
print(" - If scores are 0.0, the analysis may need to be re-run")
|
| 95 |
+
print(" - Your mobile app should show real scores if data exists")
|
| 96 |
+
|
| 97 |
+
if __name__ == "__main__":
|
| 98 |
+
asyncio.run(check_database())
|
test_direct_connection.py
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/usr/bin/env python3
|
| 2 |
+
"""
|
| 3 |
+
Test direct connection to cps-api-tx to check analysis results
|
| 4 |
+
"""
|
| 5 |
+
|
| 6 |
+
import asyncio
|
| 7 |
+
import aiohttp
|
| 8 |
+
import json
|
| 9 |
+
from datetime import datetime
|
| 10 |
+
|
| 11 |
+
async def test_direct_connection():
|
| 12 |
+
"""Test direct connection to the space"""
|
| 13 |
+
|
| 14 |
+
space_url = "https://rocketfarmstudios-cps-api-tx.hf.space"
|
| 15 |
+
|
| 16 |
+
print("🔍 Testing Direct Connection to cps-api-tx")
|
| 17 |
+
print("=" * 50)
|
| 18 |
+
print(f"📡 Space URL: {space_url}")
|
| 19 |
+
print(f"⏰ Test started at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
|
| 20 |
+
print()
|
| 21 |
+
|
| 22 |
+
try:
|
| 23 |
+
async with aiohttp.ClientSession() as session:
|
| 24 |
+
# Test 1: Root endpoint
|
| 25 |
+
print("🧪 Test 1: Root endpoint")
|
| 26 |
+
async with session.get(space_url, timeout=10) as response:
|
| 27 |
+
print(f" Status: {response.status}")
|
| 28 |
+
if response.status == 200:
|
| 29 |
+
root_data = await response.text()
|
| 30 |
+
print(f" ✅ Root endpoint: {root_data}")
|
| 31 |
+
else:
|
| 32 |
+
print(f" ❌ Root endpoint failed: {response.status}")
|
| 33 |
+
return
|
| 34 |
+
|
| 35 |
+
# Test 2: Analysis results endpoint (without auth)
|
| 36 |
+
print("\n🧪 Test 2: Analysis results endpoint")
|
| 37 |
+
try:
|
| 38 |
+
results_url = f"{space_url}/txagent/patients/analysis-results"
|
| 39 |
+
async with session.get(results_url, timeout=10) as response:
|
| 40 |
+
print(f" Status: {response.status}")
|
| 41 |
+
if response.status == 200:
|
| 42 |
+
results_data = await response.json()
|
| 43 |
+
print(f" ✅ Found {len(results_data)} analysis results")
|
| 44 |
+
|
| 45 |
+
if len(results_data) > 0:
|
| 46 |
+
print("\n📊 Analysis Results:")
|
| 47 |
+
for i, result in enumerate(results_data[:5]): # Show first 5 results
|
| 48 |
+
print(f" Result {i+1}:")
|
| 49 |
+
print(f" - Patient: {result.get('full_name', 'Unknown')}")
|
| 50 |
+
print(f" - Patient ID: {result.get('patient_id', 'No ID')}")
|
| 51 |
+
|
| 52 |
+
suicide_risk = result.get('suicide_risk', {})
|
| 53 |
+
risk_level = suicide_risk.get('level', 'No level')
|
| 54 |
+
risk_score = suicide_risk.get('score', 0.0)
|
| 55 |
+
risk_factors = suicide_risk.get('factors', [])
|
| 56 |
+
|
| 57 |
+
print(f" - Risk Level: {risk_level}")
|
| 58 |
+
print(f" - Risk Score: {risk_score}")
|
| 59 |
+
print(f" - Risk Factors: {risk_factors}")
|
| 60 |
+
|
| 61 |
+
# Check if we have real scores
|
| 62 |
+
if risk_score > 0:
|
| 63 |
+
print(f" ✅ Real score detected: {risk_score}")
|
| 64 |
+
else:
|
| 65 |
+
print(f" ⚠️ Score is 0 - may need to trigger analysis")
|
| 66 |
+
print()
|
| 67 |
+
else:
|
| 68 |
+
print(" ⚠️ No analysis results found")
|
| 69 |
+
elif response.status == 401:
|
| 70 |
+
print(" 🔐 Authentication required - this is expected")
|
| 71 |
+
print(" 💡 The API requires login to access analysis results")
|
| 72 |
+
else:
|
| 73 |
+
print(f" ❌ Failed: {response.status}")
|
| 74 |
+
error_text = await response.text()
|
| 75 |
+
print(f" Error details: {error_text[:200]}...")
|
| 76 |
+
|
| 77 |
+
except Exception as e:
|
| 78 |
+
print(f" ❌ Results error: {e}")
|
| 79 |
+
|
| 80 |
+
# Test 3: Status endpoint
|
| 81 |
+
print("\n🧪 Test 3: Status endpoint")
|
| 82 |
+
try:
|
| 83 |
+
status_url = f"{space_url}/txagent/status"
|
| 84 |
+
async with session.get(status_url, timeout=10) as response:
|
| 85 |
+
print(f" Status: {response.status}")
|
| 86 |
+
if response.status == 200:
|
| 87 |
+
status_data = await response.json()
|
| 88 |
+
print(f" ✅ Status: {json.dumps(status_data, indent=2)}")
|
| 89 |
+
elif response.status == 401:
|
| 90 |
+
print(" 🔐 Authentication required - this is expected")
|
| 91 |
+
else:
|
| 92 |
+
print(f" ❌ Status failed: {response.status}")
|
| 93 |
+
except Exception as e:
|
| 94 |
+
print(f" ❌ Status error: {e}")
|
| 95 |
+
|
| 96 |
+
except Exception as e:
|
| 97 |
+
print(f"❌ Connection error: {e}")
|
| 98 |
+
|
| 99 |
+
print("\n" + "="*50)
|
| 100 |
+
print("✅ Direct connection test completed!")
|
| 101 |
+
print("\n📝 Summary:")
|
| 102 |
+
print(" - Your Hugging Face Space is ONLINE ✅")
|
| 103 |
+
print(" - Authentication is required for analysis results (expected)")
|
| 104 |
+
print(" - Your mobile app should now be able to connect!")
|
| 105 |
+
print(" - Check your mobile app - it should show real scores if you're logged in")
|
| 106 |
+
|
| 107 |
+
if __name__ == "__main__":
|
| 108 |
+
asyncio.run(test_direct_connection())
|