Jose Salazar Claude Opus 5 commited on
Commit
fbec6dd
·
1 Parent(s): e6acd07

README al día con el estado real del código

Browse files

ARCHITECTURE_REVIEW §4.3. Cinco afirmaciones habían quedado FALSAS, no sólo
desactualizadas, y una documentación de seguridad que promete de más es peor que
no tenerla:

- «Con MORPHOS_MYSQL_DSN definido se usa MySQL/MariaDB»: esas variables no las
leía nadie y se eliminaron. Quien las configurara seguiría en SQLite.
- «/api/interpret y /api/papers exigen sesión»: papers NO la exige, y es
deliberado. Ahora se dice eso, y por qué.
- «Sexo: felinos machos tienen mayor tolerancia a creatinina»: ese ajuste se
retiró por falta de respaldo en el corpus —toleraba un 15 % más justo en la
población con más ERC—.
- «Raza: Shiba/Akita (RBC)»: es VCM. Subir la serie roja generaba falsas anemias;
lo documentado es microcitosis fisiológica SIN anemia.
- «SQLite en instance/morphos.db»: ahora prefiere el volumen persistente si lo
hay, y avisa cuando cae a almacenamiento efímero.

PRIVACIDAD, dicha con precisión. «Sin exponer la data sensible a los LLM» era
falso para la ruta por defecto y, a la vez, se quedaba corto: el esquema de la
petición admite SÓLO especie, raza, edad y sexo, así que no hay campo donde
quepan el nombre del animal o el propietario —no es una política, es una
imposibilidad estructural—. Las imágenes son campos de microscopio sin
identificadores y el PDF nunca se sube. El único texto libre es «signos
clínicos», que hoy viaja tal cual; se dice así, en presente, y el filtro por
vocabulario clínico previsto queda en Mejoras futuras, que es donde va lo que
todavía no existe.

PUERTA DE CI, sin adornos: se nombran los dos workflows y se dice que las evals
corren con --simular, así que hoy comprueban el medidor y no el modelo real.

Se añaden a Seguridad las cinco defensas nuevas (alta cerrada por allowlist,
aislamiento por clínica, sesiones revocables, suelo de seguridad recalculado en
servidor, rate limiting consciente del proxy) y se actualizan las estructuras de
data/, backend/ y frontend/.

Sin tocar Objetivo, Retos ni Mejoras futuras salvo la línea añadida.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

Files changed (1) hide show
  1. README.md +74 -14
README.md CHANGED
@@ -22,7 +22,21 @@ pinned: false
22
  Morphos es una aplicación web de apoyo al diagnóstico veterinario. Detecta patrones clínicos en tiempo real a partir de valores de laboratorio con un motor propio que corre entero en el navegador, y permite interpretarlos con un modelo de IA especializado en medicina (medGemma multimodal de Google DeepMind, auto-alojado) o con Claude. Incluye búsqueda de artículos científicos en PubMed relacionados con los diagnósticos diferenciales del paciente.
23
 
24
  Está orientada a caninos y felinos, con ajuste automático de rangos de referencia por especie, edad, raza y sexo.
25
- Ataca una necesidad real del sector veterinario que actualmente no dispone de herramientas de este tipo que sean gratuitas y de fácil uso y que permitan obtener información complementaria relevante sobre sus pacientes en muy poco tiempo y sin exponer la data sensible a los LLM.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
 
27
  Funcionalidades principales:
28
 
@@ -69,19 +83,23 @@ Conceptos aplicados:
69
 
70
  ```text
71
  /frontend
72
- src/analisis.ts → motor de detección de patrones clínicos (única fuente de verdad)
73
  src/main.ts → orquestación general, eventos y renderizado
74
  src/ia.ts → cliente tipado de /api/interpret y render de la salida estructurada
75
  src/ui.ts → navegación por tabs, gestos, sincronización móvil
76
  src/auth.ts → modal de autenticación y validación en tiempo real
77
  src/papers.ts → búsqueda y paginación de literatura científica
78
  src/pdf-parser.ts→ extracción de valores desde PDF en el navegador
79
- tests/ suite de regresión del motor (Vitest)
 
 
 
80
 
81
  /backend
82
  app/main.py → app FastAPI, CORS, cabeceras, montaje de estáticos
83
  app/config.py → configuración por variables de entorno (sin secretos por defecto)
84
  app/schemas.py → esquemas Pydantic: petición y salida clínica validada
 
85
  app/ai/ → rutas de modelo (hf_space, medgemma/Ollama, claude), prompt y citas
86
  app/rag/ → ingesta e índice LanceDB + recuperación híbrida con reranking
87
  app/routers/ → interpret, auth, papers, lab
@@ -101,14 +119,19 @@ Conceptos aplicados:
101
 
102
  /data
103
  valores_referencia.json → rangos de referencia por especie y analito
 
 
104
  alteraciones.json → descripciones clínicas de los patrones
 
 
105
 
106
  /assets
107
  /fonts → Inter y JetBrains Mono (carga local)
108
  /icons → iconos SVG de la interfaz
109
  /lib/pdfjs → librería PDF.js en local
110
 
111
- /instance → BD de usuarios e índice RAG, FUERA de la raíz servida (gitignored)
 
112
  index.html → SPA principal (carga el bundle de frontend/)
113
  Dockerfile → imagen de despliegue (frontend + backend + índice RAG horneado)
114
  ```
@@ -170,8 +193,15 @@ ni al repositorio; en HF Spaces se usan los *Secrets* del Space en su lugar.
170
 
171
  ### 3. Base de datos
172
 
173
- Se crea sola al arrancar: SQLite en `instance/morphos.db`, fuera de la raiz servida. Con
174
- `MORPHOS_MYSQL_DSN` definido se usa MySQL/MariaDB en su lugar.
 
 
 
 
 
 
 
175
 
176
  ### 4. Iniciar la aplicacion
177
 
@@ -237,14 +267,29 @@ El mismo Ollama sirve ademas de **juez gratuito** para las evals (ver `evals/REA
237
 
238
  ## Motor de deteccion de patrones
239
 
240
- `frontend/src/analisis.ts` compara cada valor ingresado contra los rangos de referencia del JSON, ajustados dinamicamente segun:
 
241
 
242
  * **Especie**: canino / felino
243
- * **Edad**: cachorro, adulto, senior, geriatrico
244
- * **Raza**: galgo/whippet (RBC y plaquetas), Shiba/Akita (RBC)
245
- * **Sexo**: felinos machos tienen mayor tolerancia a creatinina
246
-
247
- La gravedad se calcula como la desviacion relativa al ancho del rango de referencia. Con los hallazgos se identifican mas de 50 patrones clinicos (anemias, hepatopatias, nefropatia, alteraciones endocrinas, electrolitos, entre otros).
 
 
 
 
 
 
 
 
 
 
 
 
 
 
248
 
249
  El motor está congelado por una suite de regresión (`frontend/tests`, Vitest) que se ejecuta
250
  con `make frontend-test`. Es la red que permite tocar el resto del stack sin cambiar
@@ -276,7 +321,8 @@ validación veterinaria firmada. Detalle en `evals/README.md`.
276
  * Sesiones firmadas con cookie `HttpOnly` / `SameSite` / `Secure`, y CSRF de doble token
277
  * Contraseñas hasheadas con **scrypt** y comparación en tiempo constante
278
  * Consultas parametrizadas (sin interpolacion directa)
279
- * `/api/interpret` y `/api/papers` exigen sesión: no hay acceso anónimo al modelo
 
280
  * Rate limiting por IP **y por usuario** (la cuota de GPU es compartida entre veterinarios)
281
  * CORS restringido a orígenes conocidos, nunca `*`
282
  * Cabeceras de seguridad: CSP estricta, HSTS en producción, `nosniff`, `frame-ancestors none`
@@ -284,6 +330,18 @@ validación veterinaria firmada. Detalle en `evals/README.md`.
284
  * BD de usuarios e índice RAG **fuera de la raíz servida** (`instance/`), no descargables
285
  * Validación en servidor de las imágenes de citología (número, tipo MIME y tamaño)
286
  * Texto del modelo y de APIs externas insertado con escapado, sin `eval` ni `document.write`
 
 
 
 
 
 
 
 
 
 
 
 
287
 
288
  ---
289
 
@@ -293,7 +351,7 @@ validación veterinaria firmada. Detalle en `evals/README.md`.
293
  * CSS personalizado: variables, fuentes fluidas, grid, flexbox, media queries, temas claro/oscuro
294
  * JavaScript/TypeScript: ES Modules, `fetch`, `async/await`, eventos, DOM API, tipos estrictos
295
  * Python: FastAPI, Pydantic, `async`/`await`, gestión de dependencias con uv
296
- * Bases de datos: creacion de tablas, consultas con parametros, indices unicos (SQLite o MariaDB)
297
 
298
  ---
299
 
@@ -303,6 +361,8 @@ validación veterinaria firmada. Detalle en `evals/README.md`.
303
  * Desarrollo de extensión de navegador para captar datos del DOM de PIMS y obtener los datos de los analisis de los pacientes con intervención mínima del usuario
304
  * Desarrollo de mobile app dedicada
305
  * Integración con PIMS más utilizados en veterinaria
 
 
306
  * Rankeo de papers basado en confiabilidad y relevancia
307
  * Creación de Dataset específico para citologías de animales
308
  * Hosting del modelo en VPS serverless para finetuning y menor latencia
 
22
  Morphos es una aplicación web de apoyo al diagnóstico veterinario. Detecta patrones clínicos en tiempo real a partir de valores de laboratorio con un motor propio que corre entero en el navegador, y permite interpretarlos con un modelo de IA especializado en medicina (medGemma multimodal de Google DeepMind, auto-alojado) o con Claude. Incluye búsqueda de artículos científicos en PubMed relacionados con los diagnósticos diferenciales del paciente.
23
 
24
  Está orientada a caninos y felinos, con ajuste automático de rangos de referencia por especie, edad, raza y sexo.
25
+ Ataca una necesidad real del sector veterinario, que hoy no dispone de herramientas de este tipo
26
+ gratuitas, de uso sencillo y capaces de dar información complementaria relevante en muy poco tiempo.
27
+
28
+ **Qué sale del navegador y qué no.** El esquema de la petición (`PacienteEntrada`) admite
29
+ únicamente **especie, raza, edad y sexo**: no existe ningún campo para el nombre del animal ni
30
+ para datos del propietario, así que no es una política sino una imposibilidad estructural. A eso
31
+ se suman los valores de laboratorio y, si las hay, imágenes de citología o microscopía: campos de
32
+ microscopio, sin identificadores. El PDF original **nunca se sube**: se parsea entero en el
33
+ navegador.
34
+
35
+ El único campo de texto libre es «signos clínicos». Hoy viaja tal cual —el servidor lo inspecciona
36
+ para la guarda de alcance, pero no lo filtra—, así que es el único sitio donde alguien podría
37
+ teclear algo identificativo. Está previsto acotarlo a vocabulario clínico (ver *Mejoras futuras*).
38
+
39
+ Con la ruta auto-alojada (Ollama en la clínica) no sale nada en absoluto: ver más abajo.
40
 
41
  Funcionalidades principales:
42
 
 
83
 
84
  ```text
85
  /frontend
86
+ src/analisis.ts → motor de detección de patrones clínicos (tiempo real, en el navegador)
87
  src/main.ts → orquestación general, eventos y renderizado
88
  src/ia.ts → cliente tipado de /api/interpret y render de la salida estructurada
89
  src/ui.ts → navegación por tabs, gestos, sincronización móvil
90
  src/auth.ts → modal de autenticación y validación en tiempo real
91
  src/papers.ts → búsqueda y paginación de literatura científica
92
  src/pdf-parser.ts→ extracción de valores desde PDF en el navegador
93
+ src/lab-import.tsimportación desde analizadores (cola de muestras y emparejado)
94
+ src/panel-vacio.ts→ estado vacío de los paneles de exámenes (escritorio)
95
+ src/form-inject.ts→ base común de los importadores (PDF y analizador)
96
+ tests/ → suite de regresión del motor y del parser de PDF (Vitest)
97
 
98
  /backend
99
  app/main.py → app FastAPI, CORS, cabeceras, montaje de estáticos
100
  app/config.py → configuración por variables de entorno (sin secretos por defecto)
101
  app/schemas.py → esquemas Pydantic: petición y salida clínica validada
102
+ app/motor/ → suelo de seguridad recalculado en servidor (rangos y gravedad)
103
  app/ai/ → rutas de modelo (hf_space, medgemma/Ollama, claude), prompt y citas
104
  app/rag/ → ingesta e índice LanceDB + recuperación híbrida con reranking
105
  app/routers/ → interpret, auth, papers, lab
 
119
 
120
  /data
121
  valores_referencia.json → rangos de referencia por especie y analito
122
+ ajustes_clinicos.json → umbrales de gravedad, cortes clínicos, ajustes por edad/raza e IRIS
123
+ (única fuente de verdad: la leen los DOS motores)
124
  alteraciones.json → descripciones clínicas de los patrones
125
+ lab_mapeos/ → códigos de prueba → analito canónico, por fabricante
126
+ rag_alcance.json → qué páginas del corpus entran y con qué especie
127
 
128
  /assets
129
  /fonts → Inter y JetBrains Mono (carga local)
130
  /icons → iconos SVG de la interfaz
131
  /lib/pdfjs → librería PDF.js en local
132
 
133
+ /instance → índice RAG y BD de usuarios si no hay volumen persistente; FUERA de la
134
+ raíz servida (gitignored)
135
  index.html → SPA principal (carga el bundle de frontend/)
136
  Dockerfile → imagen de despliegue (frontend + backend + índice RAG horneado)
137
  ```
 
193
 
194
  ### 3. Base de datos
195
 
196
+ Se crea sola al arrancar y el esquema se migra solo (`PRAGMA user_version`; ver `_MIGRACIONES`
197
+ en `backend/app/db.py`). Es SQLite, siempre fuera de la raiz servida:
198
+
199
+ * Si hay un **volumen persistente** montado en `/data`, la BD vive ahí y sobrevive a los reinicios.
200
+ * Si no, cae a `instance/morphos.db`, que en HF Spaces es **efímero**: cada reinicio borra
201
+ cuentas, contraseñas e historial de intentos. Se avisa por log al arrancar.
202
+
203
+ Se puede forzar la ruta con `MORPHOS_DB_PATH`. **No hay soporte de MySQL/MariaDB**: existieron
204
+ variables `MORPHOS_MYSQL_*` que ningún código leía y se eliminaron.
205
 
206
  ### 4. Iniciar la aplicacion
207
 
 
267
 
268
  ## Motor de deteccion de patrones
269
 
270
+ `frontend/src/analisis.ts` compara cada valor ingresado contra los rangos de referencia del JSON,
271
+ ajustados dinamicamente segun:
272
 
273
  * **Especie**: canino / felino
274
+ * **Edad**: cachorro, adulto, senior, geriatrico (p. ej. el fosforo del cachorro, sin el cual todo
275
+ animal en crecimiento sale hiperfosforemico)
276
+ * **Raza**: lebreles —galgo, greyhound, whippet, saluki…— en serie roja, plaquetas, creatinina y
277
+ T4 (sin ese ajuste, ~90 % de los galgos sanos salen hipotiroideos); razas asiaticas (shiba,
278
+ akita, chow, shar pei) en **VCM**, que es microcitosis fisiologica **sin** anemia; Maine Coon y
279
+ Birman en felinos
280
+ * **Sexo**: sin ajustes. El que habia —mas tolerancia a creatinina en el gato macho— se **retiro**
281
+ por no tener respaldo en el corpus: toleraba un 15 % mas justo en la poblacion con mas ERC
282
+
283
+ La gravedad se mide como desviacion relativa al ancho del rango, **salvo** donde esa regla no sabe
284
+ expresar la clinica: hematocrito y plaquetas por lo bajo, y creatinina, SDMA y UP/C por lo alto,
285
+ tienen cortes explicitos (con rango 24-45, un gato necesitaria un hematocrito negativo para llegar
286
+ a «grave»). Con los hallazgos se identifican mas de 50 patrones clinicos (anemias, hepatopatias,
287
+ nefropatia, alteraciones endocrinas, electrolitos, entre otros) y el estadiaje IRIS de ERC.
288
+
289
+ **Las reglas clinicas son datos, no codigo.** Umbrales, cortes, limites de edad, factores por raza
290
+ y cortes IRIS viven en `data/ajustes_clinicos.json`, con su procedencia bibliografica, y los leen
291
+ por igual el motor del navegador y el del servidor. Un veterinario puede revisarlos y ajustarlos
292
+ sin desarrollador ni build.
293
 
294
  El motor está congelado por una suite de regresión (`frontend/tests`, Vitest) que se ejecuta
295
  con `make frontend-test`. Es la red que permite tocar el resto del stack sin cambiar
 
321
  * Sesiones firmadas con cookie `HttpOnly` / `SameSite` / `Secure`, y CSRF de doble token
322
  * Contraseñas hasheadas con **scrypt** y comparación en tiempo constante
323
  * Consultas parametrizadas (sin interpolacion directa)
324
+ * `/api/interpret` exige sesión: no hay acceso anónimo al modelo. `/api/papers` **no** la exige
325
+ a propósito (búsqueda en PubMed, ni sensible ni cara); lo acota el rate limiting
326
  * Rate limiting por IP **y por usuario** (la cuota de GPU es compartida entre veterinarios)
327
  * CORS restringido a orígenes conocidos, nunca `*`
328
  * Cabeceras de seguridad: CSP estricta, HSTS en producción, `nosniff`, `frame-ancestors none`
 
330
  * BD de usuarios e índice RAG **fuera de la raíz servida** (`instance/`), no descargables
331
  * Validación en servidor de las imágenes de citología (número, tipo MIME y tamaño)
332
  * Texto del modelo y de APIs externas insertado con escapado, sin `eval` ni `document.write`
333
+ * **Alta de cuentas cerrada** por lista blanca de emails (`MORPHOS_REGISTRO_ALLOWLIST`): una
334
+ cuenta alcanza el modelo, así que el alta abierta era una autorización de gasto para cualquiera
335
+ * **Resultados de analizador aislados por clínica**: el tenant lo pone el servidor —de la API key
336
+ del dispositivo al ingerir, de la cookie firmada al leer—, nunca el cuerpo de la petición. Una
337
+ muestra de otra clínica responde 404, no 403
338
+ * **Sesiones revocables**: el logout invalida el token de verdad (no sólo borra la cookie) y
339
+ `/api/auth/logout-todas` cierra la sesión en todos los dispositivos
340
+ * **El suelo de seguridad se recalcula en el servidor**: los hallazgos y su gravedad se derivan de
341
+ los valores crudos (`app/motor/gravedad.py`), así que omitir o falsear el veredicto del cliente
342
+ ya no relaja la derivación obligatoria. Lo que afirma el navegador sólo puede endurecerla
343
+ * Rate limiting consciente del proxy inverso (`MORPHOS_PROXY_SALTOS_CONFIABLES`): detrás de un
344
+ proxy, `request.client.host` es el proxy y los límites «por IP» serían en realidad globales
345
 
346
  ---
347
 
 
351
  * CSS personalizado: variables, fuentes fluidas, grid, flexbox, media queries, temas claro/oscuro
352
  * JavaScript/TypeScript: ES Modules, `fetch`, `async/await`, eventos, DOM API, tipos estrictos
353
  * Python: FastAPI, Pydantic, `async`/`await`, gestión de dependencias con uv
354
+ * Bases de datos: creacion de tablas, consultas con parametros, indices unicos y migraciones versionadas (SQLite)
355
 
356
  ---
357
 
 
361
  * Desarrollo de extensión de navegador para captar datos del DOM de PIMS y obtener los datos de los analisis de los pacientes con intervención mínima del usuario
362
  * Desarrollo de mobile app dedicada
363
  * Integración con PIMS más utilizados en veterinaria
364
+ * Filtrado del campo «signos clínicos» contra una lista de términos clínicos permitidos, para que
365
+ ni datos identificativos ni texto arbitrario lleguen al modelo
366
  * Rankeo de papers basado en confiabilidad y relevancia
367
  * Creación de Dataset específico para citologías de animales
368
  * Hosting del modelo en VPS serverless para finetuning y menor latencia