Spaces:
Sleeping
Sleeping
File size: 6,428 Bytes
acaf471 | 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 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 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 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | from fastapi import FastAPI, File, UploadFile
from fastapi.middleware.cors import CORSMiddleware
from fastapi.staticfiles import StaticFiles
import os
from services.whisper_service import transcribeAudio
from services.llm_service import analyzePainDescription
from services.conversation_service import generateFollowUpQuestions
from services.neuro_symbolic_service import analyze_pain_neuro_symbolic, get_system_info
# Smart embedding service selection
EMBEDDING_MODEL = os.getenv("EMBEDDING_MODEL", "biolord") # Options: "biolord", "openai"
if EMBEDDING_MODEL == "biolord":
print(f"[Main] Using BioLORD-2023-M embeddings (medical specialist)")
from services.semantic_distance_service_biolord import precompute_dictionary_embeddings
else:
print(f"[Main] Using OpenAI embeddings (general purpose)")
from services.semantic_distance_service_v2 import precompute_dictionary_embeddings
from pydantic import BaseModel
from typing import List, Dict
class ConversationRequest(BaseModel):
history: List[Dict]
app = FastAPI(
title = "Pain Report Platform",
version = "0.2.0" # Updated to v0.2.0 with BioLORD support
)
app.add_middleware(
CORSMiddleware,
allow_origins=["*"],
allow_credentials=True,
allow_methods=["*"],
allow_headers=["*"],
)
app.mount("/images", StaticFiles(directory="images"), name="images")
@app.get("/")
async def root():
return {
"message": "This is pain report platform backend API.",
"status": "running"
}
@app.get("/health")
async def healthCheck():
return {
"status": "healthy",
"message": "The API is healthy and running",
"version": "0.1.3"
}
@app.post("/api/analyze-audio")
async def analyze_audio(file: UploadFile = File(...)):
#check file
if not file.content_type.startswith("audio/"):
return {"error": "Invalid file type.",
"message": "Please upload an audio file."}
#read file
audioBytes = await file.read()
try:
transcription = transcribeAudio(audioBytes, language=None)
analysis = analyzePainDescription(transcription["text"])
return {
"status": "success",
"message": "Audio file received",
"size": len(audioBytes),
"filename": file.filename,
"trancription": transcription["text"],
"language": transcription["language"],
"analysis": analysis
}
except Exception as e:
return {
"status": "error",
"message": str(e)
}
@app.post("/api/follow-up")
async def getFollowUpQuestion(request: ConversationRequest):
try:
followUp = generateFollowUpQuestions(request.history)
return {
"status": "success",
"followup": followUp
}
except Exception as e:
return {
"status": "error",
"message": str(e)
}
@app.post("/api/analyze-text-neuro-symbolic")
async def analyzeTextNeuroSymbolic(request: dict):
"""
Analyze text pain description using neuro-symbolic architecture.
This is the new upgraded analysis endpoint that uses:
- LLM for narrow-scope entity extraction only
- Ontology mapping for multilingual medical terminology
- Rule-based engine for deterministic clinical recommendations
Returns structured pain data with complete explainability and reasoning chain.
"""
try:
patient_text = request.get("text", "")
if not patient_text:
return {
"status": "error",
"message": "No text provided"
}
# Execute neuro-symbolic pipeline
analysis = analyze_pain_neuro_symbolic(patient_text)
return analysis
except Exception as e:
return {
"status": "error",
"message": str(e)
}
@app.post("/api/analyze-audio-neuro-symbolic")
async def analyzeAudioNeuroSymbolic(file: UploadFile = File(...)):
"""
Analyze audio pain description using neuro-symbolic architecture.
Combines:
1. Whisper transcription (audio → text)
2. Neuro-symbolic analysis (text → structured clinical data)
Returns complete explainable report with reasoning chain.
"""
if not file.content_type.startswith("audio/"):
return {
"error": "Invalid file type.",
"message": "Please upload an audio file."
}
audioBytes = await file.read()
try:
# Step 1: Transcribe audio
transcription_result = transcribeAudio(audioBytes, language=None)
original_transcription = transcription_result["text"]
# Step 2: Neuro-symbolic analysis (includes normalization + ontology mapping)
analysis = analyze_pain_neuro_symbolic(original_transcription)
# Merge transcription info with analysis results
# The analysis already contains transcription normalization in analysis["transcription"]
return {
"status": "success",
"message": "Audio analyzed successfully using neuro-symbolic architecture",
"size": len(audioBytes),
"filename": file.filename,
"whisper_language": transcription_result["language"],
**analysis # Spread analysis results (includes transcription, structured_data, etc.)
}
except Exception as e:
return {
"status": "error",
"message": str(e)
}
@app.get("/api/system-info")
async def getSystemInfo():
"""
Get information about the neuro-symbolic pain assessment system.
Returns system configuration, capabilities, and limitations.
Useful for documentation and debugging.
"""
try:
info = get_system_info()
return {
"status": "success",
"system_info": info
}
except Exception as e:
return {
"status": "error",
"message": str(e)
}
@app.on_event("startup")
async def startup_event():
print("[Startup] Precomputing dictionary embeddings...")
precompute_dictionary_embeddings()
print("[Startup] System ready!")
if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=8000)
|