@ -1039,15 +1039,7 @@ HTML = """<!doctype html>
. netron - state { min - width : 0 ; color : #8e99a6; font-size: 12px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
. netron - panel { min - height : 420 px ; margin - top : 8 px ; overflow : hidden ; border : 1 px solid #2b3037; background: #fff; }
. netron - frame { display : block ; width : 100 % ; height : min ( 68 vh , 720 px ) ; border : 0 ; background : #fff; }
. netron - tab { height : 100 % ; min - height : 0 ; overflow : auto ; padding : 10 px ; }
. netron - page - panel { width : min ( 1400 px , 100 % ) ! important ; min - height : 100 % ; margin : 0 auto ; border : 1 px solid var ( - - ui - border ) ; background : var ( - - ui - surface ) ; }
. netron - page - section { min - height : 100 % ; padding : 16 px ; border : 0 ; }
. netron - page - head { display : flex ; align - items : end ; justify - content : space - between ; gap : 16 px ; flex - wrap : wrap ; }
. netron - page - head h2 { margin : 0 ; }
. netron - model - field { min - width : min ( 420 px , 100 % ) ; display : grid ; gap : 4 px ; color : var ( - - ui - muted ) ; font - size : 12 px ; }
. netron - model - field select { min - width : 0 ; height : 34 px ; border : 1 px solid var ( - - ui - border ) ; border - radius : var ( - - ui - radius ) ; background : var ( - - ui - input ) ; color : var ( - - ui - text ) ; padding : 0 10 px ; font : inherit ; }
. netron - page - section . netron - panel { min - height : calc ( 100 vh - 230 px ) ; }
. netron - page - section . netron - frame { height : min ( 74 vh , 860 px ) ; }
. network - model - netron { grid - column : 1 / - 1 ; padding - top : 10 px ; border - top : 1 px solid var ( - - ui - border ) ; }
. theme - select { width : 112 px ; height : 28 px ; border : 1 px solid #2b3037; background: #101317; color: #dce3ea; padding: 0 5px; font: 11px Segoe UI, Arial, sans-serif; }
. control - form { display : grid ; grid - template - columns : 1 fr 1 fr ; align - items : start ; }
. settings - group { min - width : 0 ; margin : 0 ; padding : 10 px ; border : 0 ; border - bottom : 1 px solid #2b3037; display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
@ -1221,7 +1213,7 @@ HTML = """<!doctype html>
. theme - select , . accent - select , . accent - custom { border - radius : 8 px ; transition : border - color .2 s ease , box - shadow .2 s ease , transform .2 s ease ; }
. theme - select : hover , . accent - select : hover , . accent - custom : hover { border - color : var ( - - ui - accent ) ! important ; transform : translateY ( - 1 px ) ; }
main { height : calc ( 100 vh - 52 px ) ; }
. stream - tab , . archive - tab , . settings - tab , . model - tab , . netron - tab { padding : 10 px ; }
. stream - tab , . archive - tab , . settings - tab , . model - tab { padding : 10 px ; }
. stage , . settings - panel , . model - panel , . archive - panel , . log - drawer , . player - box , . netron - panel { border - radius : var ( - - ui - radius ) ; box - shadow : var ( - - ui - shadow ) ; }
. stage { isolation : isolate ; }
. stage : : after { content : " " ; position : absolute ; inset : 0 ; pointer - events : none ; border - radius : inherit ; box - shadow : inset 0 0 0 1 px color - mix ( in srgb , var ( - - ui - accent ) 8 % , transparent ) ; }
@ -1507,15 +1499,8 @@ HTML = """<!doctype html>
. network - block . settings - group input : not ( [ type = " checkbox " ] ) : not ( [ type = " file " ] ) , . network - block . settings - group select , . network - block . settings - group button { min - height : calc ( 28 px * var ( - - block - scale ) ) ; height : calc ( 28 px * var ( - - block - scale ) ) ; padding - left : calc ( 7 px * var ( - - block - scale ) ) ; padding - right : calc ( 7 px * var ( - - block - scale ) ) ; font - size : clamp ( 8 px , calc ( 12 px * var ( - - block - scale ) ) , 26 px ) ; }
. network - block . settings - group . network - summary { margin - bottom : calc ( 8 px * var ( - - block - scale ) ) ; padding - bottom : calc ( 8 px * var ( - - block - scale ) ) ; font - size : clamp ( 9 px , calc ( 12 px * var ( - - block - scale ) ) , 24 px ) ; }
. network - block . model - actions { padding - top : 3 px ; }
. network - visual - card { padding : calc ( 14 px * var ( - - block - scale ) ) ; }
. network - visual - card . network - summary { margin - bottom : calc ( 8 px * var ( - - block - scale ) ) ; padding - bottom : calc ( 8 px * var ( - - block - scale ) ) ; font - size : clamp ( 9 px , calc ( 12 px * var ( - - block - scale ) ) , 24 px ) ; }
. network - visual - card . netron - toolbar { gap : calc ( 8 px * var ( - - block - scale ) ) ; margin - top : calc ( 10 px * var ( - - block - scale ) ) ; }
. network - visual - card . netron - toolbar . command { height : calc ( 32 px * var ( - - block - scale ) ) ; padding - left : calc ( 12 px * var ( - - block - scale ) ) ; padding - right : calc ( 12 px * var ( - - block - scale ) ) ; font - size : clamp ( 9 px , calc ( 13 px * var ( - - block - scale ) ) , 24 px ) ; }
. network - visual - card . netron - state { font - size : clamp ( 8 px , calc ( 12 px * var ( - - block - scale ) ) , 22 px ) ; }
. network - visual - card . netron - panel { min - height : max ( 180 px , calc ( 420 px * var ( - - block - scale ) ) ) ; margin - top : calc ( 8 px * var ( - - block - scale ) ) ; }
. network - visual - card . netron - frame { height : min ( 68 vh , calc ( 720 px * var ( - - block - scale ) ) ) ; }
body [ data - card - style = " flat " ] . network - block , body [ data - card - style = " flat " ] . network - visual - card { box - shadow : none ; border - radius : 8 px ! important ; }
body [ data - card - style = " neon " ] . network - block , body [ data - card - style = " neon " ] . network - visual - card { border - color : color - mix ( in srgb , var ( - - ui - accent ) 48 % , var ( - - ui - border ) ) ! important ; box - shadow : 0 0 0 1 px color - mix ( in srgb , var ( - - ui - accent ) 12 % , transparent ) , 0 10 px 24 px color - mix ( in srgb , var ( - - ui - accent ) 10 % , transparent ) ; }
body [ data - card - style = " flat " ] . network - block { box - shadow : none ; border - radius : 8 px ! important ; }
body [ data - card - style = " neon " ] . network - block { border - color : color - mix ( in srgb , var ( - - ui - accent ) 48 % , var ( - - ui - border ) ) ! important ; box - shadow : 0 0 0 1 px color - mix ( in srgb , var ( - - ui - accent ) 12 % , transparent ) , 0 10 px 24 px color - mix ( in srgb , var ( - - ui - accent ) 10 % , transparent ) ; }
@keyframes appearance - in { from { opacity : 0 ; transform : translateY ( - 5 px ) scale ( .98 ) ; } to { opacity : 1 ; transform : none ; } }
@keyframes preview - float { 0 % , 100 % { transform : translateY ( 0 ) ; } 50 % { transform : translateY ( - 2 px ) ; } }
@keyframes preview - sheen { 0 % , 55 % { transform : translateX ( 0 ) skewX ( - 18 deg ) ; opacity : 0 ; } 70 % { opacity : 1 ; } 100 % { transform : translateX ( 430 % ) skewX ( - 18 deg ) ; opacity : 0 ; } }
@ -1531,7 +1516,6 @@ HTML = """<!doctype html>
. network - workspace . has - structure > . network - restore - panel { border - right : 0 ; border - bottom : 1 px solid var ( - - ui - border ) ; max - height : 42 vh ; }
. network - canvas { min - height : 900 px ; padding : 10 px ; }
. network - block { min - width : 220 px ; max - width : calc ( 100 % - 8 px ) ; }
. network - visual - card { padding : 10 px ; }
}
@media ( max - width : 420 px ) { . appearance - options { grid - template - columns : repeat ( 2 , minmax ( 0 , 1 fr ) ) ; } }
< / style >
@ -1546,7 +1530,6 @@ HTML = """<!doctype html>
< button class = " tab " type = " button " data - tab = " archive " > Архив < / button >
< button class = " tab " type = " button " data - tab = " settings " > Настройки < / button >
< button class = " tab " type = " button " data - tab = " model " > Сеть < / button >
< button class = " tab " type = " button " data - tab = " netron " > Netron < / button >
< / nav >
< div class = " appearance-module " >
< button id = " appearanceToggle " class = " appearance-trigger " type = " button " aria - expanded = " false " aria - controls = " appearancePanel " >
@ -1869,6 +1852,16 @@ HTML = """<!doctype html>
< span id = " modelState " class = " model-state " > модель не выбрана < / span >
< / div >
< label class = " model-wide " > Путь < input id = " modelPath " type = " text " readonly > < / label >
< div class = " netron-section network-model-netron " >
< div class = " network-summary " > Визуализация сети < / div >
< div class = " netron-toolbar " >
< button id = " modelNetron " class = " command primary " type = " button " > Показать в Netron < / button >
< span id = " netronState " class = " netron-state " > граф Netron не загружен < / span >
< / div >
< div id = " netronPanel " class = " netron-panel " hidden >
< iframe id = " netronFrame " class = " netron-frame " title = " Визуализация архитектуры сети в Netron " loading = " lazy " sandbox = " allow-scripts allow-same-origin " > < / iframe >
< / div >
< / div >
< / section >
< section class = " model-group settings-group network-block " data - section = " model-params " >
< div class = " network-summary " > Параметры до инференса < / div >
@ -1890,28 +1883,6 @@ HTML = """<!doctype html>
< / div >
< / section >
< / div >
< div id = " netronTab " class = " tab-page netron-tab " hidden >
< section class = " model-panel netron-page-panel " >
< div class = " netron-section netron-page-section " >
< div class = " netron-page-head " >
< div >
< h2 > Netron < / h2 >
< span class = " netron-state " > Архитектура модели до инференса < / span >
< / div >
< label class = " netron-model-field " > Модель
< select id = " netronModelSelect " > < option value = " " > загрузка списка . . . < / option > < / select >
< / label >
< / div >
< div class = " netron-toolbar " >
< button id = " modelNetron " class = " command primary " type = " button " > Показать в Netron < / button >
< span id = " netronState " class = " netron-state " > граф Netron не загружен < / span >
< / div >
< div id = " netronPanel " class = " netron-panel " hidden >
< iframe id = " netronFrame " class = " netron-frame " title = " Визуализация архитектуры сети в Netron " loading = " lazy " sandbox = " allow-scripts allow-same-origin " > < / iframe >
< / div >
< / div >
< / section >
< / div >
< div id = " archiveTab " class = " tab-page archive-tab " hidden >
< section class = " archive-panel " >
< h2 > & #1040;рхив</h2>
@ -3696,23 +3667,20 @@ HTML = """<!doctype html>
}
async function loadModels ( ) {
const data = await fetch ( ' /api/models ' , { cache : ' no-store ' } ) . then ( r = > r . json ( ) ) ;
const select s = [ $ ( ' modelSelect ' ) , $ ( ' netronModelSelect ' ) ] . filter ( Boolean ) ;
select s. forEach ( select = > { select . innerHTML = ' ' ; } ) ;
for ( const model of data . models | | [ ] ) selects . forEach ( select = > {
const select = $ ( ' modelSelect ' ) ;
select . innerHTML = ' ' ;
for ( const model of data . models | | [ ] ) {
const option = document . createElement ( ' option ' ) ;
option . value = model . path ;
option . textContent = ` $ { model . name } · $ { mb ( model . size ) } ` ;
select . appendChild ( option ) ;
} ) ;
}
const selected = data . selected | | data . default | | ' ' ;
selects . forEach ( select = > {
if ( ! select . options . length ) select . innerHTML = ' <option value= " " >модели .pt не найдены</option> ' ;
else if ( selected ) select . value = selected ;
} ) ;
const modelSelect = $ ( ' modelSelect ' ) ;
if ( modelSelect ? . value ) {
setValue ( ' modelPath ' , modelSelect . value ) ;
setText ( ' modelState ' , ` $ { modelSelect . selectedOptions [ 0 ] ? . textContent | | ' модель выбрана ' } ` ) ;
if ( select . value ) {
setValue ( ' modelPath ' , select . value ) ;
setText ( ' modelState ' , ` $ { select . selectedOptions [ 0 ] ? . textContent | | ' модель выбрана ' } ` ) ;
}
}
function resetNetron ( ) {
@ -3721,7 +3689,7 @@ HTML = """<!doctype html>
setText ( ' netronState ' , ' граф Netron не загружен ' ) ;
}
async function openNetron ( ) {
const path = $ ( ' netronModelSelect' ) ? . value | | $ ( ' modelSelect' ) . value | | $ ( ' modelPath ' ) . value ;
const path = $ ( ' modelSelect' ) . value | | $ ( ' modelPath ' ) . value ;
if ( ! path ) throw new Error ( ' выберите файл модели .pt ' ) ;
setText ( ' netronState ' , ' запуск Netron... ' ) ;
const response = await fetch ( ' /api/model/netron?path= ' + enc ( path ) , { cache : ' no-store ' } ) ;
@ -4100,13 +4068,12 @@ HTML = """<!doctype html>
$ ( ' playerOverlay ' ) . hidden = true ;
}
function switchTab ( name , updateHash = true ) {
if ( ! [ ' stream ' , ' archive ' , ' settings ' , ' model ' , ' netron ' ]. includes ( name ) ) name = ' stream ' ;
if ( ! [ ' stream ' , ' archive ' , ' settings ' , ' model ' ]. includes ( name ) ) name = ' stream ' ;
document . querySelectorAll ( ' .tab ' ) . forEach ( btn = > btn . classList . toggle ( ' active ' , btn . dataset . tab == = name ) ) ;
$ ( ' streamTab ' ) . hidden = name != = ' stream ' ;
$ ( ' archiveTab ' ) . hidden = name != = ' archive ' ;
$ ( ' settingsTab ' ) . hidden = name != = ' settings ' ;
$ ( ' modelTab ' ) . hidden = name != = ' model ' ;
$ ( ' netronTab ' ) . hidden = name != = ' netron ' ;
if ( name == = ' settings ' & & typeof applyStoredConfigLayout == = ' function ' ) requestAnimationFrame ( applyStoredConfigLayout ) ;
if ( name == = ' model ' & & typeof applyNetworkLayout == = ' function ' ) requestAnimationFrame ( applyNetworkLayout ) ;
if ( name == = ' archive ' ) loadArchive ( ) ;
@ -4343,14 +4310,6 @@ HTML = """<!doctype html>
$ ( ' decorIntensity ' ) . addEventListener ( ' input ' , e = > applyAppearanceSetting ( ' decor ' , e . target . value ) ) ;
document . querySelectorAll ( ' [data-setting] ' ) . forEach ( button = > button . addEventListener ( ' click ' , ( ) = > applyAppearanceSetting ( button . dataset . setting , button . dataset . value ) ) ) ;
$ ( ' modelSelect ' ) . addEventListener ( ' change ' , e = > {
setValue ( ' modelPath ' , e . target . value ) ;
setValue ( ' netronModelSelect ' , e . target . value ) ;
setText ( ' modelState ' , e . target . selectedOptions [ 0 ] ? . textContent | | ' модель выбрана ' ) ;
resetNetron ( ) ;
controlDirty = true ;
} ) ;
$ ( ' netronModelSelect ' ) . addEventListener ( ' change ' , e = > {
setValue ( ' modelSelect ' , e . target . value ) ;
setValue ( ' modelPath ' , e . target . value ) ;
setText ( ' modelState ' , e . target . selectedOptions [ 0 ] ? . textContent | | ' модель выбрана ' ) ;
resetNetron ( ) ;