sam_kraken / templates /image.html
johnlockejrr's picture
Upload 16 files
d0681c4 verified
<div class="visualization-container">
<div class="image-container">
<svg width="{{ width }}" height="{{ height }}" viewBox="0 0 {{ width }} {{ height }}">
<image href="data:image/png;base64,{{ image_base64 }}" width="{{ width }}" height="{{ height }}"/>
{% for line in lines %}
<a class="textline line{{loop.index}}" onmouseover="document.querySelectorAll('.line{{loop.index}}').forEach(element => {element.classList.add('highlighted')});" onmouseout="document.querySelectorAll('*').forEach(element => {element.classList.remove('highlighted')});">
<path class="line-boundary" d="M {{ line.boundary|join(' L ') }} Z" fill="rgba(0, 128, 255, 0.2)" stroke="none"/>
<path class="line-baseline" d="M {{ line.baseline|join(' L ') }}" stroke="red" stroke-width="1" fill="none"/>
</a>
{% endfor %}
</svg>
</div>
<div class="transcription-container">
{% for line in lines %}
<span class="textline line{{loop.index}}" onmouseover="document.querySelectorAll('.line{{loop.index}}').forEach(element => {element.classList.add('highlighted')});" onmouseout="document.querySelectorAll('*').forEach(element => {element.classList.remove('highlighted')});">
<span class="line-number">{{ loop.index }}:</span>
<span class="line-text">{{ line.text }}</span>
{% if line.confidence %}
<span class="line-confidence">({{ "%.2f"|format(line.confidence) }})</span>
{% endif %}
</span>
<br>
{% endfor %}
</div>
</div>
<style>
.visualization-container {
display: flex;
gap: 20px;
max-height: 1000px;
}
.image-container {
flex: 2;
overflow: auto;
border: 1px solid #ddd;
border-radius: 4px;
}
.image-container svg {
display: block;
width: 100%;
height: auto;
max-width: 100%;
}
.transcription-container {
flex: 1;
overflow-y: auto;
padding: 10px;
border: 1px solid #ddd;
border-radius: 4px;
}
/* Synchronize scrolling between containers */
.image-container, .transcription-container {
scroll-behavior: smooth;
}
.image-container::-webkit-scrollbar, .transcription-container::-webkit-scrollbar {
width: 8px;
}
.image-container::-webkit-scrollbar-track, .transcription-container::-webkit-scrollbar-track {
background: #f1f1f1;
}
.image-container::-webkit-scrollbar-thumb, .transcription-container::-webkit-scrollbar-thumb {
background: #888;
border-radius: 4px;
}
.image-container::-webkit-scrollbar-thumb:hover, .transcription-container::-webkit-scrollbar-thumb:hover {
background: #555;
}
.textline {
padding: 5px;
cursor: pointer;
display: inline-block;
unicode-bidi: bidi-override;
}
.textline:hover,
.textline.highlighted {
background-color: rgba(0, 128, 255, 0.1);
}
.textline:hover .line-boundary,
.textline.highlighted .line-boundary {
fill: rgba(0, 255, 255, 0.3);
}
.textline:hover .line-baseline,
.textline.highlighted .line-baseline {
stroke: yellow;
}
.line-number {
color: #666;
margin-right: 5px;
}
.line-confidence {
color: #888;
font-size: 0.9em;
margin-left: 5px;
}
/* RTL text support */
.textline[dir="rtl"] {
text-align: right;
}
.textline[dir="ltr"] {
text-align: left;
}
</style>
<script>
// Synchronize scrolling between containers
const imageContainer = document.querySelector('.image-container');
const textContainer = document.querySelector('.transcription-container');
function syncScroll(source, target) {
const ratio = target.scrollHeight / source.scrollHeight;
target.scrollTop = source.scrollTop * ratio;
}
imageContainer.addEventListener('scroll', () => syncScroll(imageContainer, textContainer));
textContainer.addEventListener('scroll', () => syncScroll(textContainer, imageContainer));
// Function to detect text direction
function detectTextDirection(text) {
const rtlChars = /[֑-߿‏‫‮יִ-﷽ﹰ-ﻼ]/;
return rtlChars.test(text) ? 'rtl' : 'ltr';
}
// Add direction attribute to text lines
function updateTextDirections() {
document.querySelectorAll('.textline').forEach(line => {
const text = line.textContent;
line.setAttribute('dir', detectTextDirection(text));
});
}
// Update text directions when visualization changes
const observer = new MutationObserver(updateTextDirections);
observer.observe(document.body, { childList: true, subtree: true });
</script>