Spaces:
Sleeping
Sleeping
feat (ner/anatomy): presenting in the image
Browse files- app/static/anatomic-parts.svg +97 -0
- app/static/browser/index.html +102 -1
app/static/anatomic-parts.svg
ADDED
|
|
app/static/browser/index.html
CHANGED
|
@@ -421,6 +421,16 @@
|
|
| 421 |
.tab-content.active {
|
| 422 |
display: block;
|
| 423 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 424 |
</style>
|
| 425 |
</head>
|
| 426 |
<body>
|
|
@@ -499,6 +509,19 @@
|
|
| 499 |
</div>
|
| 500 |
|
| 501 |
<div id="anatomy" class="tab-content">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 502 |
<div class="result-section">
|
| 503 |
<h2>🫀 Highlighted Text - Anatomy Entities</h2>
|
| 504 |
<div class="legend">
|
|
@@ -897,6 +920,82 @@
|
|
| 897 |
if (prolog) {
|
| 898 |
document.getElementById('prologFactsAnatomy').textContent = prolog || 'No anatomy entities found.';
|
| 899 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 900 |
}
|
| 901 |
|
| 902 |
function displayPOSResults(originalText, posTags, prolog) {
|
|
@@ -932,7 +1031,9 @@
|
|
| 932 |
posList.appendChild(item);
|
| 933 |
});
|
| 934 |
|
| 935 |
-
|
|
|
|
|
|
|
| 936 |
}
|
| 937 |
|
| 938 |
function switchToTab(tabName) {
|
|
|
|
| 421 |
.tab-content.active {
|
| 422 |
display: block;
|
| 423 |
}
|
| 424 |
+
|
| 425 |
+
/* Pulse animation for highlighted anatomy parts */
|
| 426 |
+
@keyframes pulse {
|
| 427 |
+
0%, 100% {
|
| 428 |
+
opacity: 0.7;
|
| 429 |
+
}
|
| 430 |
+
50% {
|
| 431 |
+
opacity: 1;
|
| 432 |
+
}
|
| 433 |
+
}
|
| 434 |
</style>
|
| 435 |
</head>
|
| 436 |
<body>
|
|
|
|
| 509 |
</div>
|
| 510 |
|
| 511 |
<div id="anatomy" class="tab-content">
|
| 512 |
+
<div class="result-section">
|
| 513 |
+
<h2>🫀 Anatomical Visualization</h2>
|
| 514 |
+
<div id="anatomyVisualization" style="text-align: center; padding: 20px; background: white; border-radius: 8px; min-height: 400px;">
|
| 515 |
+
<object id="anatomySvg" data="/app/static/anatomic-parts.svg" type="image/svg+xml"
|
| 516 |
+
style="max-width: 512px; height: auto; display: none;">
|
| 517 |
+
Your browser does not support SVG
|
| 518 |
+
</object>
|
| 519 |
+
<p id="anatomyPlaceholder" style="color: #999; padding: 50px;">
|
| 520 |
+
Anatomical parts will be highlighted here after analysis
|
| 521 |
+
</p>
|
| 522 |
+
</div>
|
| 523 |
+
</div>
|
| 524 |
+
|
| 525 |
<div class="result-section">
|
| 526 |
<h2>🫀 Highlighted Text - Anatomy Entities</h2>
|
| 527 |
<div class="legend">
|
|
|
|
| 920 |
if (prolog) {
|
| 921 |
document.getElementById('prologFactsAnatomy').textContent = prolog || 'No anatomy entities found.';
|
| 922 |
}
|
| 923 |
+
|
| 924 |
+
// Highlight anatomy parts in SVG
|
| 925 |
+
highlightAnatomyParts(entities);
|
| 926 |
+
}
|
| 927 |
+
|
| 928 |
+
/**
|
| 929 |
+
* Highlights anatomical parts in the SVG visualization
|
| 930 |
+
* @param {Array} entities - Array of anatomy entities from NER
|
| 931 |
+
*/
|
| 932 |
+
function highlightAnatomyParts(entities) {
|
| 933 |
+
const svgObject = document.getElementById('anatomySvg');
|
| 934 |
+
const placeholder = document.getElementById('anatomyPlaceholder');
|
| 935 |
+
|
| 936 |
+
if (!entities || entities.length === 0) {
|
| 937 |
+
svgObject.style.display = 'none';
|
| 938 |
+
placeholder.style.display = 'block';
|
| 939 |
+
placeholder.textContent = 'No anatomical parts detected in the text';
|
| 940 |
+
return;
|
| 941 |
+
}
|
| 942 |
+
|
| 943 |
+
// Show SVG and hide placeholder
|
| 944 |
+
svgObject.style.display = 'block';
|
| 945 |
+
placeholder.style.display = 'none';
|
| 946 |
+
|
| 947 |
+
// Wait for SVG to load
|
| 948 |
+
svgObject.addEventListener('load', function() {
|
| 949 |
+
const svgDoc = svgObject.contentDocument;
|
| 950 |
+
if (!svgDoc) {
|
| 951 |
+
console.error('Could not access SVG document');
|
| 952 |
+
return;
|
| 953 |
+
}
|
| 954 |
+
|
| 955 |
+
// Reset all polygons to hidden first
|
| 956 |
+
const allPolygons = svgDoc.querySelectorAll('polygon');
|
| 957 |
+
allPolygons.forEach(polygon => {
|
| 958 |
+
polygon.setAttribute('display', 'none');
|
| 959 |
+
});
|
| 960 |
+
|
| 961 |
+
// Highlight detected anatomy parts
|
| 962 |
+
entities.forEach(entity => {
|
| 963 |
+
showAnatomyPart(svgDoc, entity.word);
|
| 964 |
+
});
|
| 965 |
+
});
|
| 966 |
+
|
| 967 |
+
// If already loaded, trigger immediately
|
| 968 |
+
if (svgObject.contentDocument) {
|
| 969 |
+
svgObject.dispatchEvent(new Event('load'));
|
| 970 |
+
}
|
| 971 |
+
}
|
| 972 |
+
|
| 973 |
+
/**
|
| 974 |
+
* Shows a specific anatomical part in the SVG
|
| 975 |
+
* @param {Document} svgDoc - The SVG document
|
| 976 |
+
* @param {string} bodyPart - The name of the body part (e.g., "left ventricle")
|
| 977 |
+
*/
|
| 978 |
+
function showAnatomyPart(svgDoc, bodyPart) {
|
| 979 |
+
if (!svgDoc || !bodyPart) return;
|
| 980 |
+
|
| 981 |
+
// Normalize the body part name: lowercase and replace spaces with hyphens
|
| 982 |
+
const normalizedName = bodyPart.toLowerCase().trim().replace(/\s+/g, '-');
|
| 983 |
+
|
| 984 |
+
// Try to find the element by ID
|
| 985 |
+
const element = svgDoc.getElementById(normalizedName);
|
| 986 |
+
|
| 987 |
+
if (element) {
|
| 988 |
+
// Remove display="none" to show the element
|
| 989 |
+
element.removeAttribute('display');
|
| 990 |
+
element.setAttribute('display', 'inline');
|
| 991 |
+
|
| 992 |
+
// Optional: Add a pulsing animation effect
|
| 993 |
+
element.style.animation = 'pulse 2s ease-in-out infinite';
|
| 994 |
+
|
| 995 |
+
console.log(`Highlighted anatomy part: ${normalizedName}`);
|
| 996 |
+
} else {
|
| 997 |
+
console.warn(`Anatomy part not found in SVG: ${normalizedName}`);
|
| 998 |
+
}
|
| 999 |
}
|
| 1000 |
|
| 1001 |
function displayPOSResults(originalText, posTags, prolog) {
|
|
|
|
| 1031 |
posList.appendChild(item);
|
| 1032 |
});
|
| 1033 |
|
| 1034 |
+
if (prolog) {
|
| 1035 |
+
document.getElementById('prologFactsPOS').textContent = prolog || 'No POS tags found.';
|
| 1036 |
+
}
|
| 1037 |
}
|
| 1038 |
|
| 1039 |
function switchToTab(tabName) {
|