Compare commits
2 Commits
ccfdfb2c20
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b83f466271 | ||
|
|
72a4e8f3b1 |
File diff suppressed because one or more lines are too long
@@ -1,25 +0,0 @@
|
||||
<IfModule mod_authz_core.c>
|
||||
<FilesMatch ".*">
|
||||
Require all denied
|
||||
</FilesMatch>
|
||||
<FilesMatch "\.log$">
|
||||
Require all granted
|
||||
</FilesMatch>
|
||||
</IfModule>
|
||||
<IfModule !mod_authz_core.c>
|
||||
Order allow,deny
|
||||
Deny from all
|
||||
<FilesMatch "\.log$">
|
||||
Order allow,deny
|
||||
Allow from all
|
||||
</FilesMatch>
|
||||
</IfModule>
|
||||
<IfModule mod_mime.c>
|
||||
AddType text/plain .log
|
||||
</IfModule>
|
||||
<IfModule mod_dir.c>
|
||||
DirectoryIndex index.php
|
||||
</IfModule>
|
||||
<IfModule mod_autoindex.c>
|
||||
Options -Indexes
|
||||
</IfModule>
|
||||
@@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<system.webServer>
|
||||
<security>
|
||||
<authorization>
|
||||
<deny users="*" />
|
||||
</authorization>
|
||||
</security>
|
||||
<requestFiltering>
|
||||
<fileExtensions allowUnlisted="false">
|
||||
<add fileExtension=".log" allowed="true" />
|
||||
</fileExtensions>
|
||||
</requestFiltering>
|
||||
<staticContent>
|
||||
<mimeMap fileExtension=".log" mimeType="text/plain" />
|
||||
</staticContent>
|
||||
<defaultDocument>
|
||||
<files>
|
||||
<add value="index.php" />
|
||||
</files>
|
||||
</defaultDocument>
|
||||
<directoryBrowse enabled="false" />
|
||||
</system.webServer>
|
||||
</configuration>
|
||||
@@ -473,15 +473,24 @@ async function semanticSearch() {
|
||||
const textAttr = (i.text_content || '').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
|
||||
const startTime = i.start_time || (i.start_frame && i.fps ? i.start_frame / i.fps : 0);
|
||||
const endTime = i.end_time || (i.end_frame && i.fps ? i.end_frame / i.fps : startTime + 10);
|
||||
const thumbFrame = Math.round(startTime * 24);
|
||||
return `<div class="chunk-item clickable"
|
||||
data-file-uuid="${i.file_uuid}"
|
||||
data-start-time="${startTime}"
|
||||
data-end-time="${endTime}"
|
||||
data-text="${textAttr}">
|
||||
<div style="display:flex;gap:10px;">
|
||||
<img class="search-thumb" loading="lazy"
|
||||
data-src="${API_BASE}/file/${i.file_uuid}/thumbnail?api_key=${API_KEY}&frame=${thumbFrame}"
|
||||
style="width:120px;height:68px;object-fit:cover;border-radius:4px;flex-shrink:0;background:#e2e8f0;"
|
||||
alt="">
|
||||
<div style="flex:1;">
|
||||
<div style="font-weight:600;color:#1e40af;">${i.name} (${i.source || 'unknown'})</div>
|
||||
<div class="chunk-time">${i.file_uuid} | ${startTime.toFixed(1)}s - ${endTime.toFixed(1)}s</div>
|
||||
<div style="margin-top: 4px;">${i.text_content || '無內容'}</div>
|
||||
<button class="play-btn">▶ 播放片段</button>
|
||||
<div class="chunk-time">${startTime.toFixed(1)}s - ${endTime.toFixed(1)}s${i.chunk_id ? ` | ${i.chunk_id}` : ''}</div>
|
||||
<div style="margin-top:4px;font-size:13px;color:#555;">${i.text_content || ''}</div>
|
||||
<button class="play-btn" style="margin-top:6px;">▶ 播放片段</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}).join('');
|
||||
resultEl.innerHTML = `<p style="padding: 0.5rem; background: #d1fae5; border-radius: 4px; margin-bottom: 0.5rem;">找到 ${data.total || 0} 個身份相關片段</p>${resultsHtml || '<p>沒有結果</p>'}`;
|
||||
@@ -498,23 +507,72 @@ async function semanticSearch() {
|
||||
const textAttr = (r.text || '').replace(/"/g, '"').replace(/</g, '<').replace(/>/g, '>');
|
||||
const startTime = r.start_time || (r.start_frame && r.fps ? r.start_frame / r.fps : 0);
|
||||
const endTime = r.end_time || (r.end_frame && r.fps ? r.end_frame / r.fps : startTime + 10);
|
||||
const thumbFrame = Math.round(startTime * 24);
|
||||
return `<div class="chunk-item clickable"
|
||||
data-file-uuid="${r.file_uuid}"
|
||||
data-start-time="${startTime}"
|
||||
data-end-time="${endTime}"
|
||||
data-text="${textAttr}">
|
||||
<div class="chunk-time">${r.file_uuid} | ${startTime.toFixed(1)}s - ${endTime.toFixed(1)}s</div>
|
||||
<div style="margin-top: 4px;">${r.text || '無內容'}</div>
|
||||
<div style="display:flex;gap:10px;">
|
||||
<img class="search-thumb" loading="lazy"
|
||||
data-src="${API_BASE}/file/${r.file_uuid}/thumbnail?api_key=${API_KEY}&frame=${thumbFrame}"
|
||||
style="width:120px;height:68px;object-fit:cover;border-radius:4px;flex-shrink:0;background:#e2e8f0;"
|
||||
alt="">
|
||||
<div style="flex:1;">
|
||||
<div class="chunk-time">${startTime.toFixed(1)}s - ${endTime.toFixed(1)}s${r.chunk_id ? ` | ${r.chunk_id}` : ''}</div>
|
||||
<div style="margin-top:4px;font-size:13px;color:#555;">${r.text || ''}</div>
|
||||
<div class="badge-status completed" style="margin-top:4px;">相似度: ${(r.score * 100).toFixed(1)}%</div>
|
||||
<button class="play-btn">▶ 播放片段</button>
|
||||
<button class="play-btn" style="margin-top:6px;">▶ 播放片段</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
}).join('');
|
||||
resultEl.innerHTML = `<p style="padding: 0.5rem; background: #d1fae5; border-radius: 4px; margin-bottom: 0.5rem;">找到 ${data.total || 0} 個片段</p>${resultsHtml || '<p>沒有結果</p>'}`;
|
||||
}
|
||||
loadSearchThumbnails();
|
||||
} catch (e) {
|
||||
resultEl.innerHTML = '<p style="color:#ef4444; padding: 1rem;">錯誤: ' + e.message + '</p>';
|
||||
}
|
||||
}
|
||||
|
||||
function loadSearchThumbnails(){
|
||||
const imgs = Array.from(document.querySelectorAll('img.search-thumb[data-src]'));
|
||||
const MAX = 4;
|
||||
let queue = [];
|
||||
let inflight = 0;
|
||||
|
||||
function next(){
|
||||
while (inflight < MAX && queue.length) {
|
||||
const img = queue.shift();
|
||||
inflight++;
|
||||
img.onload = function(){ inflight--; next(); };
|
||||
img.onerror = function(){ inflight--; next(); };
|
||||
img.src = img.dataset.src;
|
||||
}
|
||||
}
|
||||
|
||||
if ('IntersectionObserver' in window) {
|
||||
const obs = new IntersectionObserver(function(entries){
|
||||
entries.forEach(function(e){
|
||||
if (!e.isIntersecting) return;
|
||||
var img = e.target;
|
||||
if (img.dataset.loaded) return;
|
||||
img.dataset.loaded = '1';
|
||||
queue.push(img);
|
||||
obs.unobserve(img);
|
||||
next();
|
||||
});
|
||||
}, { rootMargin: '200px 0px' });
|
||||
imgs.forEach(function(img){ obs.observe(img); });
|
||||
} else {
|
||||
imgs.forEach(function(img){
|
||||
if (img.dataset.loaded) return;
|
||||
img.dataset.loaded = '1';
|
||||
queue.push(img);
|
||||
});
|
||||
next();
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<?php get_footer(); ?>
|
||||
|
||||
Reference in New Issue
Block a user