Update app.py
Browse files
app.py
CHANGED
|
@@ -43,7 +43,7 @@ THREAD_POOL = ThreadPoolExecutor(max_workers=16)
|
|
| 43 |
@asynccontextmanager
|
| 44 |
async def lifespan(app: FastAPI):
|
| 45 |
task = asyncio.create_task(periodic_cleanup())
|
| 46 |
-
log.info("DubFlow v2.5.
|
| 47 |
yield
|
| 48 |
task.cancel()
|
| 49 |
THREAD_POOL.shutdown(wait=False)
|
|
@@ -51,7 +51,7 @@ async def lifespan(app: FastAPI):
|
|
| 51 |
|
| 52 |
app = FastAPI(
|
| 53 |
title="DubFlow API",
|
| 54 |
-
version="2.5.
|
| 55 |
description="Video dubbing pipeline β MP4 β SRT β Translate β TTS β Dubbed MP4",
|
| 56 |
lifespan=lifespan,
|
| 57 |
)
|
|
@@ -1697,7 +1697,7 @@ async def voices():
|
|
| 1697 |
|
| 1698 |
@app.get("/health", tags=["Meta"])
|
| 1699 |
async def health():
|
| 1700 |
-
return {"status":"ok", "version": "2.5.
|
| 1701 |
"jobs_active": sum(1 for j in JOBS.values() if not j["done"]),
|
| 1702 |
"jobs_total": len(JOBS),
|
| 1703 |
"max_upload_mb": MAX_UPLOAD_MB}
|
|
@@ -1750,9 +1750,10 @@ body{background:radial-gradient(900px 600px at 10% -10%,rgba(139,92,246,.18),tra
|
|
| 1750 |
.label{letter-spacing:.12em;text-transform:uppercase;font-size:11px;color:#94a3b8;}
|
| 1751 |
input,select{background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.1);}
|
| 1752 |
input:focus,select:focus{border-color:#a78bfa;box-shadow:0 0 0 3px rgba(167,139,250,.15);outline:none;}
|
| 1753 |
-
.step-row{display:flex;align-items:
|
|
|
|
| 1754 |
.step-row.active{background:rgba(139,92,246,.08);border-color:rgba(139,92,246,.3);}
|
| 1755 |
-
.step-num{width:28px;height:28px;border-radius:999px;display:flex;align-items:center;justify-content:center;font-weight:600;font-size:12px;background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.1);color:#94a3b8;flex-shrink:0;transition:.3s;}
|
| 1756 |
.step-num.active{background:linear-gradient(90deg,#8b5cf6,#3b82f6);border-color:transparent;color:white;animation:pulse 2s infinite;}
|
| 1757 |
.step-num.done{background:#10b981;border-color:transparent;color:white;}
|
| 1758 |
@keyframes pulse{0%,100%{box-shadow:0 0 0 0 rgba(139,92,246,.5)}50%{box-shadow:0 0 0 8px rgba(139,92,246,0)}}
|
|
@@ -1760,6 +1761,9 @@ input:focus,select:focus{border-color:#a78bfa;box-shadow:0 0 0 3px rgba(167,139,
|
|
| 1760 |
.toast.err{background:rgba(239,68,68,.95);} .toast.ok{background:rgba(16,185,129,.95);} .toast.info{background:rgba(59,130,246,.95);}
|
| 1761 |
@keyframes slideIn{from{transform:translateX(100%);opacity:0}to{transform:translateX(0);opacity:1}}
|
| 1762 |
.hint{font-size:11px;color:#64748b;margin-top:4px;}
|
|
|
|
|
|
|
|
|
|
| 1763 |
.speed{font-size:10px;color:#10b981;font-family:'JetBrains Mono',monospace;}
|
| 1764 |
.heartbeat{display:inline-block;width:6px;height:6px;border-radius:50%;background:#10b981;margin-left:6px;animation:beat 1s infinite;}
|
| 1765 |
@keyframes beat{0%,100%{opacity:.3}50%{opacity:1;box-shadow:0 0 8px #10b981}}
|
|
@@ -1767,7 +1771,7 @@ input:focus,select:focus{border-color:#a78bfa;box-shadow:0 0 0 3px rgba(167,139,
|
|
| 1767 |
|
| 1768 |
<div class="max-w-5xl mx-auto pt-10 px-6 pb-20">
|
| 1769 |
<header class="mb-8">
|
| 1770 |
-
<p class="label mb-2">Engine v2.5.
|
| 1771 |
<h1 class="text-4xl md:text-5xl font-semibold tracking-tight">DubFlow <span class="text-slate-400 font-light">Web</span></h1>
|
| 1772 |
<p class="text-slate-400 mt-2 text-sm">Pipeline: upload Β· estrazione Β· traduzione Β· TTS Β· dub</p>
|
| 1773 |
</header>
|
|
@@ -1845,38 +1849,46 @@ input:focus,select:focus{border-color:#a78bfa;box-shadow:0 0 0 3px rgba(167,139,
|
|
| 1845 |
<div class="step-row" id="row0">
|
| 1846 |
<div class="step-num" id="num0">β</div>
|
| 1847 |
<div class="flex-1 min-w-0">
|
| 1848 |
-
<div class="flex justify-between"><p class="text-sm font-medium">Upload</p><span id="
|
| 1849 |
<div class="bar-track mt-1.5"><div id="s0bar" class="bar-fill upload"></div></div>
|
|
|
|
| 1850 |
</div>
|
| 1851 |
-
<span id="s0pct" class="code text-slate-500">β</span>
|
| 1852 |
</div>
|
| 1853 |
|
| 1854 |
<div class="step-row" id="row1">
|
| 1855 |
<div class="step-num" id="num1">1</div>
|
| 1856 |
-
<div class="flex-1 min-w-0">
|
| 1857 |
-
<div class="
|
| 1858 |
-
<
|
|
|
|
|
|
|
| 1859 |
</div>
|
| 1860 |
|
| 1861 |
<div class="step-row" id="row2">
|
| 1862 |
<div class="step-num" id="num2">2</div>
|
| 1863 |
-
<div class="flex-1 min-w-0">
|
| 1864 |
-
<div class="
|
| 1865 |
-
<
|
|
|
|
|
|
|
| 1866 |
</div>
|
| 1867 |
|
| 1868 |
<div class="step-row" id="row3">
|
| 1869 |
<div class="step-num" id="num3">3</div>
|
| 1870 |
-
<div class="flex-1 min-w-0">
|
| 1871 |
-
<div class="
|
| 1872 |
-
<
|
|
|
|
|
|
|
| 1873 |
</div>
|
| 1874 |
|
| 1875 |
<div class="step-row" id="row4">
|
| 1876 |
<div class="step-num" id="num4">4</div>
|
| 1877 |
-
<div class="flex-1 min-w-0">
|
| 1878 |
-
<div class="
|
| 1879 |
-
<
|
|
|
|
|
|
|
| 1880 |
</div>
|
| 1881 |
</div>
|
| 1882 |
|
|
@@ -1996,8 +2008,14 @@ function resetUI(){
|
|
| 1996 |
setStep(i,'idle');
|
| 1997 |
targetBars['s'+i]=0;
|
| 1998 |
currentBars['s'+i]=0;
|
| 1999 |
-
|
| 2000 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2001 |
}
|
| 2002 |
targetBars['global']=0;
|
| 2003 |
currentBars['global']=0;
|
|
@@ -2006,7 +2024,6 @@ function resetUI(){
|
|
| 2006 |
$('globalStage').textContent='Avvio';
|
| 2007 |
$('result').classList.add('hidden');
|
| 2008 |
$('msg').textContent='';
|
| 2009 |
-
$('upSpeed').textContent='';
|
| 2010 |
$('hb').style.display='none';
|
| 2011 |
}
|
| 2012 |
|
|
@@ -2032,24 +2049,43 @@ function track(jid){
|
|
| 2032 |
$('msg').textContent=d.message||'';
|
| 2033 |
const curStep = d.step !== undefined ? d.step : 0;
|
| 2034 |
const curStepProg = d.step_progress || 0;
|
|
|
|
|
|
|
| 2035 |
for(let i=0;i<=4;i++){
|
|
|
|
|
|
|
|
|
|
| 2036 |
if(curStep > i){
|
| 2037 |
// Step giΓ superato β DONE al 100%
|
| 2038 |
setStep(i, 'done');
|
| 2039 |
targetBars['s'+i] = 100;
|
| 2040 |
-
// Snap immediato per evitare lag visivo
|
| 2041 |
currentBars['s'+i] = 100;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2042 |
}
|
| 2043 |
else if(curStep === i){
|
| 2044 |
-
// Step corrente β ACTIVE con
|
| 2045 |
setStep(i, 'active');
|
| 2046 |
targetBars['s'+i] = curStepProg;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2047 |
}
|
| 2048 |
else {
|
| 2049 |
// Step futuro β IDLE
|
| 2050 |
setStep(i, 'idle');
|
| 2051 |
targetBars['s'+i] = 0;
|
| 2052 |
currentBars['s'+i] = 0;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2053 |
}
|
| 2054 |
}
|
| 2055 |
if(d.done && d.result){
|
|
@@ -2057,8 +2093,14 @@ function track(jid){
|
|
| 2057 |
setStep(i,'done');
|
| 2058 |
targetBars['s'+i]=100;
|
| 2059 |
currentBars['s'+i]=100;
|
| 2060 |
-
|
| 2061 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2062 |
}
|
| 2063 |
targetBars['global']=100;
|
| 2064 |
currentBars['global']=100;
|
|
@@ -2116,12 +2158,15 @@ function uploadFile(jid, file){
|
|
| 2116 |
const eta=e.loaded>0 ? (e.total-e.loaded)/(e.loaded/elapsed) : 0;
|
| 2117 |
const mb=(e.loaded/1048576).toFixed(2);
|
| 2118 |
const tot=(e.total/1048576).toFixed(2);
|
| 2119 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2120 |
};
|
| 2121 |
xhr.upload.onload=()=>{
|
| 2122 |
-
|
| 2123 |
-
|
| 2124 |
-
// perchΓ© il server deve ancora ricevere/validare il file
|
| 2125 |
};
|
| 2126 |
xhr.onload=()=>{
|
| 2127 |
currentXHR=null;
|
|
|
|
| 43 |
@asynccontextmanager
|
| 44 |
async def lifespan(app: FastAPI):
|
| 45 |
task = asyncio.create_task(periodic_cleanup())
|
| 46 |
+
log.info("DubFlow v2.5.3 started")
|
| 47 |
yield
|
| 48 |
task.cancel()
|
| 49 |
THREAD_POOL.shutdown(wait=False)
|
|
|
|
| 51 |
|
| 52 |
app = FastAPI(
|
| 53 |
title="DubFlow API",
|
| 54 |
+
version="2.5.3",
|
| 55 |
description="Video dubbing pipeline β MP4 β SRT β Translate β TTS β Dubbed MP4",
|
| 56 |
lifespan=lifespan,
|
| 57 |
)
|
|
|
|
| 1697 |
|
| 1698 |
@app.get("/health", tags=["Meta"])
|
| 1699 |
async def health():
|
| 1700 |
+
return {"status":"ok", "version": "2.5.3",
|
| 1701 |
"jobs_active": sum(1 for j in JOBS.values() if not j["done"]),
|
| 1702 |
"jobs_total": len(JOBS),
|
| 1703 |
"max_upload_mb": MAX_UPLOAD_MB}
|
|
|
|
| 1750 |
.label{letter-spacing:.12em;text-transform:uppercase;font-size:11px;color:#94a3b8;}
|
| 1751 |
input,select{background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.1);}
|
| 1752 |
input:focus,select:focus{border-color:#a78bfa;box-shadow:0 0 0 3px rgba(167,139,250,.15);outline:none;}
|
| 1753 |
+
.step-row{display:flex;align-items:flex-start;gap:10px;padding:12px;border-radius:10px;background:rgba(255,255,255,.02);border:1px solid rgba(255,255,255,.05);transition:background .3s, border-color .3s;}
|
| 1754 |
+
.step-row.done-row{background:rgba(16,185,129,.04);border-color:rgba(16,185,129,.15);}
|
| 1755 |
.step-row.active{background:rgba(139,92,246,.08);border-color:rgba(139,92,246,.3);}
|
| 1756 |
+
.step-num{width:28px;height:28px;border-radius:999px;display:flex;align-items:center;justify-content:center;font-weight:600;font-size:12px;background:rgba(255,255,255,.05);border:1px solid rgba(255,255,255,.1);color:#94a3b8;flex-shrink:0;transition:.3s;margin-top:1px;}
|
| 1757 |
.step-num.active{background:linear-gradient(90deg,#8b5cf6,#3b82f6);border-color:transparent;color:white;animation:pulse 2s infinite;}
|
| 1758 |
.step-num.done{background:#10b981;border-color:transparent;color:white;}
|
| 1759 |
@keyframes pulse{0%,100%{box-shadow:0 0 0 0 rgba(139,92,246,.5)}50%{box-shadow:0 0 0 8px rgba(139,92,246,0)}}
|
|
|
|
| 1761 |
.toast.err{background:rgba(239,68,68,.95);} .toast.ok{background:rgba(16,185,129,.95);} .toast.info{background:rgba(59,130,246,.95);}
|
| 1762 |
@keyframes slideIn{from{transform:translateX(100%);opacity:0}to{transform:translateX(0);opacity:1}}
|
| 1763 |
.hint{font-size:11px;color:#64748b;margin-top:4px;}
|
| 1764 |
+
.step-msg{font-size:10.5px;color:#94a3b8;margin-top:6px;font-family:'JetBrains Mono',monospace;line-height:1.3;min-height:13px;letter-spacing:.01em;}
|
| 1765 |
+
.step-row.active .step-msg{color:#c4b5fd;}
|
| 1766 |
+
.step-row.done-row .step-msg{color:#6ee7b7;}
|
| 1767 |
.speed{font-size:10px;color:#10b981;font-family:'JetBrains Mono',monospace;}
|
| 1768 |
.heartbeat{display:inline-block;width:6px;height:6px;border-radius:50%;background:#10b981;margin-left:6px;animation:beat 1s infinite;}
|
| 1769 |
@keyframes beat{0%,100%{opacity:.3}50%{opacity:1;box-shadow:0 0 8px #10b981}}
|
|
|
|
| 1771 |
|
| 1772 |
<div class="max-w-5xl mx-auto pt-10 px-6 pb-20">
|
| 1773 |
<header class="mb-8">
|
| 1774 |
+
<p class="label mb-2">Engine v2.5.3 β Real-time + REST API</p>
|
| 1775 |
<h1 class="text-4xl md:text-5xl font-semibold tracking-tight">DubFlow <span class="text-slate-400 font-light">Web</span></h1>
|
| 1776 |
<p class="text-slate-400 mt-2 text-sm">Pipeline: upload Β· estrazione Β· traduzione Β· TTS Β· dub</p>
|
| 1777 |
</header>
|
|
|
|
| 1849 |
<div class="step-row" id="row0">
|
| 1850 |
<div class="step-num" id="num0">β</div>
|
| 1851 |
<div class="flex-1 min-w-0">
|
| 1852 |
+
<div class="flex justify-between items-center"><p class="text-sm font-medium">Upload</p><span id="s0pct" class="code text-violet-300">β</span></div>
|
| 1853 |
<div class="bar-track mt-1.5"><div id="s0bar" class="bar-fill upload"></div></div>
|
| 1854 |
+
<p id="s0msg" class="step-msg">β</p>
|
| 1855 |
</div>
|
|
|
|
| 1856 |
</div>
|
| 1857 |
|
| 1858 |
<div class="step-row" id="row1">
|
| 1859 |
<div class="step-num" id="num1">1</div>
|
| 1860 |
+
<div class="flex-1 min-w-0">
|
| 1861 |
+
<div class="flex justify-between items-center"><p class="text-sm font-medium">Extract SRT</p><span id="s1pct" class="code text-violet-300">β</span></div>
|
| 1862 |
+
<div class="bar-track mt-1.5"><div id="s1bar" class="bar-fill step"></div></div>
|
| 1863 |
+
<p id="s1msg" class="step-msg">β</p>
|
| 1864 |
+
</div>
|
| 1865 |
</div>
|
| 1866 |
|
| 1867 |
<div class="step-row" id="row2">
|
| 1868 |
<div class="step-num" id="num2">2</div>
|
| 1869 |
+
<div class="flex-1 min-w-0">
|
| 1870 |
+
<div class="flex justify-between items-center"><p class="text-sm font-medium">Translate</p><span id="s2pct" class="code text-violet-300">β</span></div>
|
| 1871 |
+
<div class="bar-track mt-1.5"><div id="s2bar" class="bar-fill step"></div></div>
|
| 1872 |
+
<p id="s2msg" class="step-msg">β</p>
|
| 1873 |
+
</div>
|
| 1874 |
</div>
|
| 1875 |
|
| 1876 |
<div class="step-row" id="row3">
|
| 1877 |
<div class="step-num" id="num3">3</div>
|
| 1878 |
+
<div class="flex-1 min-w-0">
|
| 1879 |
+
<div class="flex justify-between items-center"><p class="text-sm font-medium">Synced TTS</p><span id="s3pct" class="code text-violet-300">β</span></div>
|
| 1880 |
+
<div class="bar-track mt-1.5"><div id="s3bar" class="bar-fill step"></div></div>
|
| 1881 |
+
<p id="s3msg" class="step-msg">β</p>
|
| 1882 |
+
</div>
|
| 1883 |
</div>
|
| 1884 |
|
| 1885 |
<div class="step-row" id="row4">
|
| 1886 |
<div class="step-num" id="num4">4</div>
|
| 1887 |
+
<div class="flex-1 min-w-0">
|
| 1888 |
+
<div class="flex justify-between items-center"><p class="text-sm font-medium">Dub Video</p><span id="s4pct" class="code text-violet-300">β</span></div>
|
| 1889 |
+
<div class="bar-track mt-1.5"><div id="s4bar" class="bar-fill step"></div></div>
|
| 1890 |
+
<p id="s4msg" class="step-msg">β</p>
|
| 1891 |
+
</div>
|
| 1892 |
</div>
|
| 1893 |
</div>
|
| 1894 |
|
|
|
|
| 2008 |
setStep(i,'idle');
|
| 2009 |
targetBars['s'+i]=0;
|
| 2010 |
currentBars['s'+i]=0;
|
| 2011 |
+
const bar=document.getElementById('s'+i+'bar');
|
| 2012 |
+
const pct=document.getElementById('s'+i+'pct');
|
| 2013 |
+
const msg=document.getElementById('s'+i+'msg');
|
| 2014 |
+
const row=document.getElementById('row'+i);
|
| 2015 |
+
if(bar) bar.style.width='0%';
|
| 2016 |
+
if(pct) pct.textContent='β';
|
| 2017 |
+
if(msg){msg.textContent='β'; delete msg.dataset.locked;}
|
| 2018 |
+
if(row) row.classList.remove('active', 'done-row');
|
| 2019 |
}
|
| 2020 |
targetBars['global']=0;
|
| 2021 |
currentBars['global']=0;
|
|
|
|
| 2024 |
$('globalStage').textContent='Avvio';
|
| 2025 |
$('result').classList.add('hidden');
|
| 2026 |
$('msg').textContent='';
|
|
|
|
| 2027 |
$('hb').style.display='none';
|
| 2028 |
}
|
| 2029 |
|
|
|
|
| 2049 |
$('msg').textContent=d.message||'';
|
| 2050 |
const curStep = d.step !== undefined ? d.step : 0;
|
| 2051 |
const curStepProg = d.step_progress || 0;
|
| 2052 |
+
const curMsg = d.message || '';
|
| 2053 |
+
|
| 2054 |
for(let i=0;i<=4;i++){
|
| 2055 |
+
const msgEl = document.getElementById('s'+i+'msg');
|
| 2056 |
+
const rowEl = document.getElementById('row'+i);
|
| 2057 |
+
|
| 2058 |
if(curStep > i){
|
| 2059 |
// Step giΓ superato β DONE al 100%
|
| 2060 |
setStep(i, 'done');
|
| 2061 |
targetBars['s'+i] = 100;
|
|
|
|
| 2062 |
currentBars['s'+i] = 100;
|
| 2063 |
+
if(rowEl){rowEl.classList.add('done-row'); rowEl.classList.remove('active');}
|
| 2064 |
+
if(msgEl && !msgEl.dataset.locked){
|
| 2065 |
+
msgEl.textContent = 'β completato';
|
| 2066 |
+
msgEl.dataset.locked = '1';
|
| 2067 |
+
}
|
| 2068 |
}
|
| 2069 |
else if(curStep === i){
|
| 2070 |
+
// Step corrente β ACTIVE con messaggio LIVE
|
| 2071 |
setStep(i, 'active');
|
| 2072 |
targetBars['s'+i] = curStepProg;
|
| 2073 |
+
if(rowEl){rowEl.classList.add('active'); rowEl.classList.remove('done-row');}
|
| 2074 |
+
if(msgEl){
|
| 2075 |
+
msgEl.textContent = curMsg || '...';
|
| 2076 |
+
delete msgEl.dataset.locked;
|
| 2077 |
+
}
|
| 2078 |
}
|
| 2079 |
else {
|
| 2080 |
// Step futuro β IDLE
|
| 2081 |
setStep(i, 'idle');
|
| 2082 |
targetBars['s'+i] = 0;
|
| 2083 |
currentBars['s'+i] = 0;
|
| 2084 |
+
if(rowEl){rowEl.classList.remove('active', 'done-row');}
|
| 2085 |
+
if(msgEl){
|
| 2086 |
+
msgEl.textContent = 'β';
|
| 2087 |
+
delete msgEl.dataset.locked;
|
| 2088 |
+
}
|
| 2089 |
}
|
| 2090 |
}
|
| 2091 |
if(d.done && d.result){
|
|
|
|
| 2093 |
setStep(i,'done');
|
| 2094 |
targetBars['s'+i]=100;
|
| 2095 |
currentBars['s'+i]=100;
|
| 2096 |
+
const bar=document.getElementById('s'+i+'bar');
|
| 2097 |
+
const pct=document.getElementById('s'+i+'pct');
|
| 2098 |
+
const msg=document.getElementById('s'+i+'msg');
|
| 2099 |
+
const row=document.getElementById('row'+i);
|
| 2100 |
+
if(bar) bar.style.width='100%';
|
| 2101 |
+
if(pct) pct.textContent='100.00%';
|
| 2102 |
+
if(msg) msg.textContent='β completato';
|
| 2103 |
+
if(row){row.classList.add('done-row'); row.classList.remove('active');}
|
| 2104 |
}
|
| 2105 |
targetBars['global']=100;
|
| 2106 |
currentBars['global']=100;
|
|
|
|
| 2158 |
const eta=e.loaded>0 ? (e.total-e.loaded)/(e.loaded/elapsed) : 0;
|
| 2159 |
const mb=(e.loaded/1048576).toFixed(2);
|
| 2160 |
const tot=(e.total/1048576).toFixed(2);
|
| 2161 |
+
const msg = `${mb}/${tot} MB Β· ${speed.toFixed(2)} MB/s Β· ETA ${eta.toFixed(1)}s`;
|
| 2162 |
+
const s0msg = document.getElementById('s0msg');
|
| 2163 |
+
if(s0msg){s0msg.textContent = msg; delete s0msg.dataset.locked;}
|
| 2164 |
+
const rowEl = document.getElementById('row0');
|
| 2165 |
+
if(rowEl) rowEl.classList.add('active');
|
| 2166 |
};
|
| 2167 |
xhr.upload.onload=()=>{
|
| 2168 |
+
const s0msg = document.getElementById('s0msg');
|
| 2169 |
+
if(s0msg) s0msg.textContent = 'upload completato, attesa serverβ¦';
|
|
|
|
| 2170 |
};
|
| 2171 |
xhr.onload=()=>{
|
| 2172 |
currentXHR=null;
|