2026-05-13 19:57:34 +09:00
( function ( ) { const e = document . createElement ( "link" ) . relList ; if ( e && e . supports && e . supports ( "modulepreload" ) ) return ; for ( const n of document . querySelectorAll ( 'link[rel="modulepreload"]' ) ) a ( n ) ; new MutationObserver ( n => { for ( const i of n ) if ( i . type === "childList" ) for ( const s of i . addedNodes ) s . tagName === "LINK" && s . rel === "modulepreload" && a ( s ) } ) . observe ( document , { childList : ! 0 , subtree : ! 0 } ) ; function r ( n ) { const i = { } ; return n . integrity && ( i . integrity = n . integrity ) , n . referrerPolicy && ( i . referrerPolicy = n . referrerPolicy ) , n . crossOrigin === "use-credentials" ? i . credentials = "include" : n . crossOrigin === "anonymous" ? i . credentials = "omit" : i . credentials = "same-origin" , i } function a ( n ) { if ( n . ep ) return ; n . ep = ! 0 ; const i = r ( n ) ; fetch ( n . href , i ) } } ) ( ) ; const od = "ocp.lang" , ld = [ "ko" , "en" ] , ud = "ko" , Sl = { ko : { "app.title" : "RPG Onta" , "app.subtitle" : "프로젝트 크롤, 온톨로지 매핑, 클레임 리뷰, 추천 태그" , "header.refresh" : "새로고침" , "header.lang.ko" : "한" , "header.lang.en" : "EN" , "sidebar.projects" : "프로젝트" , "sidebar.config_path" : "설정 파일 경로" , "sidebar.create_project" : "프로젝트 생성" , "sidebar.reset_project" : "현재 프로젝트 데이터 리셋" , "sidebar.crawl" : "크롤" , "sidebar.source" : "소스" , "sidebar.url_or_seed" : "URL / 시드 URL" , "sidebar.analyzer" : "분석기" , "sidebar.model" : "모델" , "sidebar.base_url" : "Base URL" , "sidebar.test_analyzer" : "분석기 테스트" , "sidebar.discover" : "링크 탐색" , "sidebar.crawl_url" : "URL 크롤" , "sidebar.max_depth" : "최대 깊이" , "sidebar.max_pages" : "최대 페이지" , "sidebar.same_domain" : "같은 도메인만" , "sidebar.respect_robots" : "robots.txt 준수" , "sidebar.crawl_site" : "시드부터 사이트 크롤" , "sidebar.stop_crawl" : "현재 크롤 중지" , "tabs.overview" : "개요" , "tabs.graph" : "그래프" , "tabs.ontology" : "온톨로지" , "tabs.entities" : "엔티티" , "tabs.claims" : "클레임" , "tabs.debug" : "디버그" , "tabs.research" : "리서치" , "tabs.tags" : "태그" , "tabs.recommend" : "추천" , "graph.search_placeholder" : "엔티티명 검색..." , "graph.entity_type_all" : "전체 타입" , "graph.predicate_all" : "전체 관계" , "graph.min_confidence" : "최소 신뢰도" , "graph.layout" : "레이아웃" , "graph.layout.cose" : "Force" , "graph.layout.circle" : "원형" , "graph.layout.concentric" : "동심원" , "graph.layout.grid" : "그리드" , "graph.layout.breadthfirst" : "트리" , "graph.reload" : "그래프 새로고침" , "graph.fit" : "맞춤" , "graph.empty" : "아직 데이터가 없습니다. 크롤이 클레임을 만들면 그래프에 노드가 나타납니다." , "graph.stats.nodes" : "노드" , "graph.stats.edges" : "엣지" , "graph.stats.shown" : "표시" , "overview.project" : "프로젝트" , "overview.domain" : "도메인" , "overview.sources" : "소스" , "overview.entities" : "엔티티" , "overview.sources_heading" : "소스" , "pipeline.heading" : "파이프라인" , "pipeline.refresh" : "새로고침" , "pipeline.stage.crawled" : "크롤됨" , "pipeline.stage.extracted" : "추출됨" , "pipeline.stage.claims" : "클레임" , "pipeline.stage.validated" : "승인됨" , "pipeline.stage.graph" : "그래프 트리플" , "pipeline.retained" : "유지율" , "pipeline.entity_types_heading" : "엔티티 타입 분포" , "pipeline.recent_pages" : "최근 페이지" , "pipeline.recent_claims" : "최근 클레임" , "pipeline.empty.pages" : "아직 크롤된 페이지가 없습니다." , "pipeline.empty.claims" : "아직 생성된 클레임이 없습니다." , "search.placeholder" : "엔티티 · 클레임 · 페이지 검색..." , "search.aria_label" : "전역 검색" , "search.group.entities" : "엔티티" , "search.group.claims" : "클레임" , "search.group.pages" : "페이지" , "search.group.predicates" : "술어" , "search.empty" : "결과 없음" , "search.hint" : "최소 1글자 이상 입력하세요" , "table.name" : "이름" , "table.type" : "타입" , "table.trust" : "신뢰도" , "table.robots" : "robots" , "table.rate" : "속도제한" , "table.domain" : "도메인" , "table.status" : "상태" , "table.confidence" : "신뢰도" , "table.relation" : "관계" , "table.subject" : "주체" , "table.object" : "객체" , "table.support" : "근거 수" , "table.predicate" : "술어" , "table.tag" : "태그" , "table.brand" : "브랜드" , "table.product" : "상품" , "table.count" : "수" , "table.no_data" : " 데이터 <EFBFBD> <EFBFBD>
2026-05-12 19:40:31 +09:00
< header class = "topbar" >
< div class = "topbar-brand" >
< h1 data - i18n = "app.title" > < / h 1 >
< p data - i18n = "app.subtitle" > < / p >
< / d i v >
< div class = "topbar-actions" >
< div class = "global-search" >
< svg viewBox = "0 0 24 24" width = "14" height = "14" class = "global-search-icon" aria - hidden = "true" >
< path fill = "none" stroke = "currentColor" stroke - width = "2" stroke - linecap = "round" stroke - linejoin = "round"
d = "M11 19a8 8 0 1 1 0-16 8 8 0 0 1 0 16Zm10 2-4.35-4.35" / >
< / s v g >
< input id = "globalSearchInput" type = "search" autocomplete = "off"
data - i18n - placeholder = "search.placeholder" data - i18n - aria - label = "search.aria_label" / >
< div id = "globalSearchPanel" class = "global-search-panel" hidden > < / d i v >
< / d i v >
< div class = "lang-toggle" role = "group" aria - label = "Language" >
< button class = "lang-btn" data - lang = "ko" data - i18n = "header.lang.ko" > < / b u t t o n >
< button class = "lang-btn" data - lang = "en" data - i18n = "header.lang.en" > < / b u t t o n >
< / d i v >
< button id = "refreshBtn" class = "icon-button" data - i18n - title = "header.refresh" data - i18n - aria - label = "header.refresh" >
< svg viewBox = "0 0 24 24" aria - hidden = "true" width = "18" height = "18" >
< path fill = "none" stroke = "currentColor" stroke - width = "2" stroke - linecap = "round" stroke - linejoin = "round"
d = "M3 12a9 9 0 0 1 15.5-6.3L21 8M21 3v5h-5M21 12a9 9 0 0 1-15.5 6.3L3 16M3 21v-5h5" / >
< / s v g >
< / b u t t o n >
< / d i v >
< / h e a d e r >
< main class = "layout" >
< aside id = "sidebarHost" class = "sidebar" > < / a s i d e >
< section id = "workspaceHost" class = "workspace" > < / s e c t i o n >
< aside id = "inspectorHost" class = "inspector" > < / a s i d e >
< / m a i n >
< div id = "toast" role = "status" aria - live = "polite" > < / d i v >
2026-05-13 19:57:34 +09:00
` ,document.documentElement.setAttribute("lang",kl()),xt(t);const e=t.querySelectorAll(".lang-btn"),r=()=>{const a=kl();e.forEach(n=>{n.classList.toggle("active",n.dataset.lang===a)})};return e.forEach(a=>{a.addEventListener("click",()=>Dv(a.dataset.lang))}),r(),fr(r),{sidebarHost:document.getElementById("sidebarHost"),workspaceHost:document.getElementById("workspaceHost"),inspectorHost:document.getElementById("inspectorHost")}}async function Fe(t,e={}){const r=await fetch(t,{headers:{"Content-Type":"application/json"},...e});if(!r.ok){let a= ` $ { r . status } $ { r . statusText } ` ;try{const n=await r.json();a=n.detail||n.error||a}catch{}throw new Error(a)}return r.json()}const ue={projects:[],selectedProject:null,projectDetail:null,ontology:null,siteCrawlPoll:null,siteCrawlPageCount:0,siteCrawlPollErrorCount:0,activeSiteCrawlJobId:null,latestActivity:null,selection:null},F=t=>document.getElementById(t);function Di(t){return String(t||"").split(",").map(e=>e.trim()).filter(Boolean)}function z(t){return String(t??"").replaceAll("&","&").replaceAll("<","<").replaceAll(">",">").replaceAll('"',""").replaceAll("'","'")}function Pl(t){return ` < span class = "chip" > $ { z ( t ) } < / s p a n > ` } f u n c t i o n M t ( t , e ) { r e t u r n e . l e n g t h ? `
2026-05-12 19:40:31 +09:00
< table >
< thead > < tr > $ { t . map ( r => ` <th> ${ z ( r ) } </th> ` ) . join ( "" ) } < / t r > < / t h e a d >
< tbody > $ { e . map ( r => ` <tr> ${ r . map ( a => ` <td> ${ String ( a ? ? "" ) } </td> ` ) . join ( "" ) } </tr> ` ) . join ( "" ) } < / t b o d y >
< / t a b l e >
2026-05-13 19:57:34 +09:00
` : ` < table > < tbody > < tr > < td > $ { z ( V ( "table.no_data" ) ) } < / t d > < / t r > < / t b o d y > < / t a b l e > ` } l e t R i = n u l l ; f u n c t i o n A e ( t ) { c o n s t e = d o c u m e n t . g e t E l e m e n t B y I d ( " t o a s t " ) ; e & & ( e . t e x t C o n t e n t = t , e . c l a s s L i s t . a d d ( " s h o w " ) , R i & & w i n d o w . c l e a r T i m e o u t ( R i ) , R i = w i n d o w . s e t T i m e o u t ( ( ) = > e . c l a s s L i s t . r e m o v e ( " s h o w " ) , 2 4 0 0 ) ) } f u n c t i o n A v ( t , { o n P r o j e c t C h a n g e d : e , o n C r a w l U p d a t e : r , r e f r e s h A l l : a } ) { t . i n n e r H T M L = L v ( ) , x t ( t ) , F ( " c r e a t e P r o j e c t B t n " ) . a d d E v e n t L i s t e n e r ( " c l i c k " , ( ) = > _ v ( e ) ) , F ( " i n i t P r o j e c t B t n " ) . a d d E v e n t L i s t e n e r ( " c l i c k " , ( ) = > I v ( e ) ) , F ( " d i s c o v e r B t n " ) . a d d E v e n t L i s t e n e r ( " c l i c k " , F v ) , F ( " c r a w l B t n " ) . a d d E v e n t L i s t e n e r ( " c l i c k " , ( ) = > O v ( a ) ) , F ( " s i t e C r a w l B t n " ) . a d d E v e n t L i s t e n e r ( " c l i c k " , ( ) = > N v ( r , a ) ) , F ( " s t o p S i t e C r a w l B t n " ) . a d d E v e n t L i s t e n e r ( " c l i c k " , z v ) , F ( " e x t r a c t o r P r o v i d e r " ) . a d d E v e n t L i s t e n e r ( " c h a n g e " , B l ) , F ( " t e s t E x t r a c t o r B t n " ) . a d d E v e n t L i s t e n e r ( " c l i c k " , ( ) = > d d ( { a n n o u n c e : ! 0 } ) ) , B l ( ) , V v ( ) , f r ( ( ) = > { x t ( t ) , G o ( ) , s i ( c d ) } ) } f u n c t i o n L v ( ) { r e t u r n `
2026-05-12 19:40:31 +09:00
< section class = "panel" >
< div class = "panel-head" > < h2 data - i18n = "sidebar.projects" > < / h 2 > < / d i v >
< div class = "field-row" >
< input id = "configPath" value = "configs/perfume_subscription.yaml" data - i18n - aria - label = "sidebar.config_path" / >
< button id = "createProjectBtn" data - i18n - title = "sidebar.create_project" > + < / b u t t o n >
< / d i v >
< button id = "initProjectBtn" class = "full" data - i18n = "sidebar.reset_project" > < / b u t t o n >
< div id = "projectList" class = "list" > < / d i v >
< / s e c t i o n >
< section class = "panel" >
< div class = "panel-head" > < h2 data - i18n = "sidebar.crawl" > < / h 2 > < / d i v >
< label >
< span data - i18n = "sidebar.source" > < / s p a n >
< select id = "sourceSelect" > < / s e l e c t >
< / l a b e l >
< label >
< span data - i18n = "sidebar.url_or_seed" > < / s p a n >
< input id = "crawlUrl" value = "tests/fixtures/sample_perfume.html" / >
< / l a b e l >
< label >
< span data - i18n = "sidebar.analyzer" > < / s p a n >
< select id = "extractorProvider" >
< option value = "rule_based" data - i18n = "extractor.rule_based" > < / o p t i o n >
< option value = "openai" data - i18n = "extractor.openai" > < / o p t i o n >
< option value = "ollama" data - i18n = "extractor.ollama" > < / o p t i o n >
< option value = "lm_studio" selected data - i18n = "extractor.lm_studio" > < / o p t i o n >
< / s e l e c t >
< / l a b e l >
< div class = "extractor-options" id = "extractorOptions" >
< label >
< span data - i18n = "sidebar.model" > < / s p a n >
< input id = "extractorModel" placeholder = "local or API model" / >
< / l a b e l >
< label >
< span data - i18n = "sidebar.base_url" > < / s p a n >
< input id = "extractorBaseUrl" value = "http://localhost:1234/v1" placeholder = "optional provider endpoint" / >
< / l a b e l >
< button id = "testExtractorBtn" data - i18n = "sidebar.test_analyzer" > < / b u t t o n >
< / d i v >
< div class = "button-grid" >
< button id = "discoverBtn" data - i18n = "sidebar.discover" > < / b u t t o n >
< button id = "crawlBtn" class = "primary" data - i18n = "sidebar.crawl_url" > < / b u t t o n >
< / d i v >
< div class = "site-controls" >
< label >
< span data - i18n = "sidebar.max_depth" > < / s p a n >
< input id = "siteMaxDepth" type = "number" min = "0" max = "5" value = "2" / >
< / l a b e l >
< label >
< span data - i18n = "sidebar.max_pages" > < / s p a n >
< input id = "siteMaxPages" type = "number" min = "1" max = "500" value = "25" / >
< / l a b e l >
< label class = "check-row" >
< input id = "sameDomainOnly" type = "checkbox" checked / >
< span data - i18n = "sidebar.same_domain" > < / s p a n >
< / l a b e l >
2026-05-13 19:57:34 +09:00
< label class = "check-row" >
< input id = "respectRobotsTxt" type = "checkbox" / >
< span data - i18n = "sidebar.respect_robots" > < / s p a n >
< / l a b e l >
2026-05-12 19:40:31 +09:00
< / d i v >
< button id = "siteCrawlBtn" class = "primary full" data - i18n = "sidebar.crawl_site" > < / b u t t o n >
< button id = "stopSiteCrawlBtn" class = "full" disabled data - i18n = "sidebar.stop_crawl" > < / b u t t o n >
< div id = "crawlResult" class = "mini-log" > < / d i v >
< div id = "discoveredLinks" class = "discovered-links" > < / d i v >
< / s e c t i o n >
2026-05-13 19:57:34 +09:00
` }function Ho(){return{config_path:F("configPath").value.trim(),source_name:F("sourceSelect").value,url:F("crawlUrl").value.trim(),extractor_provider:F("extractorProvider").value,extractor_model:F("extractorModel").value.trim()||null,extractor_base_url:F("extractorBaseUrl").value.trim()||null,check_robots_txt:F("respectRobotsTxt")?.checked??!1}}function Go(){const t=F("projectList");t&&(t.innerHTML="",ue.projects.forEach(e=>{const r=document.createElement("button");r.className= ` project - item $ { ue . selectedProject === e . name ? "active" : "" } ` ,r.innerHTML= ` < strong > $ { z ( e . name ) } < / s t r o n g > < s p a n > $ { z ( e . d o m a i n ) } < / s p a n > ` , r . a d d E v e n t L i s t e n e r ( " c l i c k " , ( ) = > { c o n s t a = n e w C u s t o m E v e n t ( " p r o j e c t : s e l e c t " , { d e t a i l : e . n a m e } ) ; w i n d o w . d i s p a t c h E v e n t ( a ) } ) , t . a p p e n d C h i l d ( r ) } ) ) } f u n c t i o n M v ( t ) { c o n s t e = F ( " s o u r c e S e l e c t " ) ; e & & ( e . i n n e r H T M L = " " , ( t ? . s o u r c e s ? ? [ ] ) . f o r E a c h ( r = > { c o n s t a = d o c u m e n t . c r e a t e E l e m e n t ( " o p t i o n " ) ; a . v a l u e = r . n a m e , a . t e x t C o n t e n t = ` $ { r . n a m e } ( $ { r . t y p e } ) ` , e . a p p e n d C h i l d ( a ) } ) ) } a s y n c f u n c t i o n _ v ( t ) { c o n s t e = F ( " c o n f i g P a t h " ) . v a l u e . t r i m ( ) ; i f ( e ) t r y { c o n s t r = a w a i t F e ( " / p r o j e c t s " , { m e t h o d : " P O S T " , b o d y : J S O N . s t r i n g i f y ( { c o n f i g _ p a t h : e } ) } ) ; A e ( ` $ { V ( " t o a s t . p r o j e c t _ c r e a t e d " ) } : $ { r . n a m e } ` ) , u e . s e l e c t e d P r o j e c t = r . n a m e , a w a i t t ? . ( ) } c a t c h ( r ) { A e ( r . m e s s a g e ) } } a s y n c f u n c t i o n I v ( t ) { c o n s t e = F ( " c o n f i g P a t h " ) . v a l u e . t r i m ( ) ; i f ( ! e ) { A e ( V ( " t o a s t . c o n f i g _ p a t h _ r e q u i r e d " ) ) ; r e t u r n } i f ( w i n d o w . c o n f i r m ( V ( " t o a s t . r e s e t _ c o n f i r m " ) ) ) t r y { c o n s t r = a w a i t F e ( " / p r o j e c t s / r e s e t " , { m e t h o d : " P O S T " , b o d y : J S O N . s t r i n g i f y ( { c o n f i g _ p a t h : e , p r o j e c t _ n a m e : u e . s e l e c t e d P r o j e c t } ) } ) ; i f ( u e . s e l e c t e d P r o j e c t = r . n a m e , a w a i t t ? . ( ) , r . r e s e t ) { c o n s t a = r . d e l e t e d ? . c l a i m s ? ? 0 , n = r . d e l e t e d ? . e n t i t i e s ? ? 0 , i = r . d e l e t e d ? . p a g e s ? ? 0 ; F ( " c r a w l R e s u l t " ) . t e x t C o n t e n t = ` $ { V ( " t o a s t . r e s e t _ d o n e " ) } : p a g e s $ { i } , e n t i t i e s $ { n } , c l a i m s $ { a } ` , A e ( ` $ { V ( " t o a s t . r e s e t _ d o n e " ) } : $ { r . n a m e } ` ) } e l s e F ( " c r a w l R e s u l t " ) . t e x t C o n t e n t = ` $ { V ( " t o a s t . p r o j e c t _ c r e a t e d " ) } : $ { r . n a m e } ` , A e ( ` $ { V ( " t o a s t . p r o j e c t _ c r e a t e d " ) } : $ { r . n a m e } ` ) } c a t c h ( r ) { A e ( r . m e s s a g e ) } } a s y n c f u n c t i o n O v ( t ) { i f ( u e . s e l e c t e d P r o j e c t ) { F ( " c r a w l R e s u l t " ) . t e x t C o n t e n t = V ( " s t a t u s . c r a w l i n g _ u r l " ) ; t r y { c o n s t e = a w a i t F e ( " / c r a w l " , { m e t h o d : " P O S T " , b o d y : J S O N . s t r i n g i f y ( H o ( ) ) } ) ; F ( " c r a w l R e s u l t " ) . t e x t C o n t e n t = ` U R L d o n e : p a g e $ { e . p a g e _ i d } , $ { e . c r a w l _ s t a t u s } / $ { e . e x t r a c t i o n _ s t a t u s } , $ { e . p a g e _ t y p e } , r a w $ { e . r a w _ t e x t _ l e n g t h } , c l e a n $ { e . c l e a n _ t e x t _ l e n g t h } , c l a i m s $ { e . c l a i m _ c o u n t } , e n t i t i e s $ { e . e n t i t y _ c o u n t } ` , u e . l a t e s t A c t i v i t y = { k i n d : " u r l _ c r a w l " , r e s u l t : e } , A e ( V ( " t o a s t . u r l _ c r a w l _ c o m p l e t e d " ) ) , a w a i t t ? . ( ) } c a t c h ( e ) { F ( " c r a w l R e s u l t " ) . t e x t C o n t e n t = ` $ { V ( " t o a s t . c r a w l _ f a i l e d " ) } : $ { e . m e s s a g e } ` , A e ( V ( " t o a s t . c r a w l _ f a i l e d " ) ) } } } l e t c d = n u l l ; a s y n c f u n c t i o n N v ( t , e ) { i f ( u e . s e l e c t e d P r o j e c t ) { f o ( ) , u e . s i t e C r a w l P a g e C o u n t = 0 , u e . s i t e C r a w l P o l l E r r o r C o u n t = 0 , F ( " c r a w l R e s u l t " ) . t e x t C o n t e n t = V ( " s t a t u s . s t a r t i n g _ s i t e _ c r a w l " ) , F ( " d i s c o v e r e d L i n k s " ) . i n n e r H T M L = " " ; t r y { c o n s t r = a w a i t F e ( " / c r a w l - s i t e " , { m e t h o d : " P O S T " , b o d y : J S O N . s t r i n g i f y ( { . . . H o ( ) , m a x _ d e p t h : N u m b e r ( F ( " s i t e M a x D e p t h " ) . v a l u e | | 0 ) , m a x _ p a g e s : N u m b e r ( F ( " s i t e M a x P a g e s " ) . v a l u e | | 1 ) , s a m e _ d o m a i n _ o n l y : F ( " s a m e D o m a i n O n l y " ) . c h e c k e d , a n a l y z e _ p a g e _ t y p e s : [ " P r o d u c t P a g e " , " B r a n d S t o r y P a g e " , " R e v i e w P a g e " ] } ) } ) ; F ( " c r a w l R e s u l t " ) . t e x t C o n t e n t = ` S i t e c r a w l q u e u e d : j o b $ { r . j o b _ i d } ` , u e . a c t i v e S i t e C r a w l J o b I d = r . j o b _ i d , F ( " s t o p S i t e C r a w l B t n " ) . d i s a b l e d = ! 1 , s i ( r ) , v o ( r . j o b _ i d , t , e ) , A e ( V ( " t o a s t . s i t e _ c r a w l _ s t a r t e d " ) ) } c a t c h ( r ) { F ( " c r a w l R e s u l t " ) . t e x t C o n t e n t = ` $ { V ( " t o a s t . s i t e _ c r a w l _ f a i l e d " ) } : $ { r . m e s s a g e } ` , A e ( V ( " t o a s t . s i t e _ c r a w l _ f a i l e d " ) ) } } } a s y n c f u n c t i o n z v ( ) { c o n s t t = u e . a c t i v e S i t e C r a w l J o b I d ; i f ( t ) { F ( " s t o p S i t e C r a w l B t n " ) . d i s a b l e d = ! 0 , F ( " c r a w l R e s u l t " ) . t e x t C o n t e n t = ` $ { V ( " s t a t u s . s t o p p i n g _ c r a w l " ) } : j o b $ { t } ` ; t r y { c o n s t e = a w a i t F e ( ` / c r a w l - s i t e / j o b s / $ { t } / c a n c e l ` , { m e t h o d : " P O S T " } ) ; s i ( e ) , A e ( V ( " t o a s t . s t o p _ r e q u e s t e d " ) ) } c a t c h ( e ) { F ( " s t o p S i t e C r a w l B t n " ) . d i s a b l e d = ! 1 , F ( " c r a w l R e s u l t " ) . t e x t C o n t e n t = ` $ { V ( " t o a s t . s t o p _ f a i l e d " ) } : $ { e . m e s s a g e } ` , A e ( V ( " t o a s t . s t o p _ f a i l e d " ) ) } } } f u n c t i o n f o ( ) { u e . s i t e C r a w l P o l l & & ( w i n d o w . c l e a r T i m e o u t ( u e . s i t e C r a w l P o l l ) , u e . s i t e C r a w l P o l l = n u l l ) } a s y n c f u n c t i o n v o ( t , e , r ) { l e t a ; t r y { a = a w a i t F e ( ` / c r a w l - s i t e / j o b s / $ { t } ` ) } c a t c h ( s ) { c o n s t o = u e . s i t e C r a w l P o l l E r r o r C o u n t = ( u e . s i t e C r a w l P o l l E r r o r C o u n t ? ? 0 ) + 1 ; i f ( F ( " c r a w l R e s u l t " ) . t e x t C o n t e n t = ` S i t e c r a w l s t a t u s c h e c k f a i l e d ( r e t r y $ { o } ) : $ { s . m e s s a g e } ` , o > = 5 ) { f o ( ) , A e ( V ( " t o a s t . s i t e _ c r a w l _ f a i l e d " ) )
2026-05-12 19:40:31 +09:00
< button class = "discovered-link" data - discovered - url = "${z(t.url)}" >
< strong > $ { z ( t . status ) } · $ { z ( t . page _type ) } · depth $ { t . depth } < / s t r o n g >
< span > $ { z ( t . url ) } < / s p a n >
< span > $ { z ( e ) } $ { z ( r ) } < / s p a n >
< span > claims $ { t . claim _count } , entities $ { t . entity _count } , links $ { t . discovered _count } $ { t . error ? ` , error: ${ z ( t . error ) } ` : "" } < / s p a n >
< / b u t t o n >
2026-05-13 19:57:34 +09:00
` }async function Fv(){F("crawlResult").textContent=V("status.discovering"),F("discoveredLinks").innerHTML="";try{const t=await Fe("/discover",{method:"POST",body:JSON.stringify({config_path:F("configPath").value.trim(),source_name:F("sourceSelect").value,url:F("crawlUrl").value.trim(),limit:30,check_robots_txt:F("respectRobotsTxt")?.checked??!1})});if(!t.ok){F("crawlResult").textContent=t.error??V("toast.discovery_failed");return}F("crawlResult").textContent= ` Discovered $ { t . links . length } links ` ,F("discoveredLinks").innerHTML=t.links.map(qv).join(""),document.querySelectorAll("[data-discovered-url]").forEach(e=>{e.addEventListener("click",()=>{F("crawlUrl").value=e.dataset.discoveredUrl,Ae(V("toast.url_copied"))})})}catch(t){F("crawlResult").textContent= ` $ { V ( "toast.discovery_failed" ) } : $ { t . message } ` ,Ae(V("toast.discovery_failed"))}}function qv(t){return `
2026-05-12 19:40:31 +09:00
< button class = "discovered-link" data - discovered - url = "${z(t.url)}" >
< strong > $ { z ( t . label ) } < / s t r o n g >
< span > $ { z ( t . kind ) } · $ { z ( t . url ) } < / s p a n >
< / b u t t o n >
2026-05-13 19:57:34 +09:00
` }function Bl(){const t=F("extractorProvider").value;F("extractorOptions").classList.toggle("active",t!=="rule_based"),t==="ollama"&&!F("extractorBaseUrl").value.trim()?F("extractorBaseUrl").placeholder="http://localhost:11434/api/chat":t==="lm_studio"&&!F("extractorBaseUrl").value.trim()?(F("extractorBaseUrl").value="http://localhost:1234/v1",F("extractorBaseUrl").placeholder="http://localhost:1234/v1"):F("extractorBaseUrl").placeholder="optional provider endpoint"}async function dd({announce:t=!0}={}){const e=F("extractorProvider").value,r=F("extractorBaseUrl").value.trim();t&&(F("crawlResult").textContent=V("status.testing_analyzer"));try{const a=await Fe("/extractors/models",{method:"POST",body:JSON.stringify({provider:e,base_url:r||null})});if(!a.ok){t&&(F("crawlResult").textContent= ` $ { V ( "toast.analyzer_failed" ) } : $ { a . error } ` ,Ae(V("toast.analyzer_failed")));return}const n=a.models??[];n.length&&!F("extractorModel").value.trim()&&(F("extractorModel").value=n[0].id),t&&(F("crawlResult").textContent=n.length? ` $ { V ( "toast.analyzer_connected" ) } . Models : $ { n . map ( i => i . id ) . join ( ", " ) } ` : ` $ { V ( "toast.analyzer_connected" ) } . No models returned . ` ,Ae(V("toast.analyzer_connected")))}catch(a){t&&Ae(a.message)}}async function Vv(){if(F("extractorProvider").value==="lm_studio")try{await dd({announce:!1})}catch{}}let Rn=null;function Hv(t){Rn=t,An(),fr(An),window.addEventListener("inspector:update",An)}function ur(){An()}function An(){Rn&&(Rn.innerHTML=Gv(),xt(Rn))}function Gv(){const t=ue.selection;return `
2026-05-12 19:40:31 +09:00
< div class = "inspector-head" >
< h2 data - i18n = "inspector.title" > < / h 2 >
< p class = "muted" data - i18n = "inspector.hint" > < / p >
< / d i v >
$ { t ? Wv ( t ) : Uv ( ) }
` }function Uv(){const t=ue.projectDetail,e=ue.latestActivity;return `
< section class = "inspector-section" >
< h3 data - i18n = "inspector.project_info" > < / h 3 >
$ { t ? `
< dl class = "kv" >
< dt > $ { z ( V ( "overview.project" ) ) } < / d t > < d d > $ { z ( t . n a m e ) } < / d d >
< dt > $ { z ( V ( "overview.domain" ) ) } < / d t > < d d > $ { z ( t . d o m a i n ) } < / d d >
< dt > $ { z ( V ( "overview.sources" ) ) } < / d t > < d d > $ { ( t . s o u r c e s ? ? [ ] ) . l e n g t h } < / d d >
< / d l >
` :'<p class="muted" data-i18n="inspector.no_selection"></p>'}
< / s e c t i o n >
< section class = "inspector-section" >
< h3 data - i18n = "inspector.latest_activity" > < / h 3 >
$ { e ? Kv ( e ) : '<p class="muted" data-i18n="inspector.latest_activity.empty"></p>' }
< / s e c t i o n >
` }function Kv(t){if(t.kind==="site_crawl"){const e=t.job??{},r=e.progress??{};return `
< dl class = "kv" >
< dt > job < / d t > < d d > $ { z ( e . j o b _ i d ? ? " - " ) } < / d d >
< dt > status < / d t > < d d > $ { z ( e . s t a t u s ? ? " - " ) } < / d d >
< dt > visited < / d t > < d d > $ { r . v i s i t e d _ c o u n t ? ? 0 } < / d d >
< dt > analyzed < / d t > < d d > $ { r . a n a l y z e d _ c o u n t ? ? 0 } < / d d >
< dt > skipped < / d t > < d d > $ { r . s k i p p e d _ c o u n t ? ? 0 } < / d d >
< dt > queued < / d t > < d d > $ { r . q u e u e d _ c o u n t ? ? 0 } < / d d >
< / d l >
` }if(t.kind==="url_crawl"){const e=t.result??{};return `
< dl class = "kv" >
< dt > page < / d t > < d d > $ { z ( e . p a g e _ i d ? ? " - " ) } < / d d >
< dt > page _type < / d t > < d d > $ { z ( e . p a g e _ t y p e ? ? " - " ) } < / d d >
< dt > crawl < / d t > < d d > $ { z ( e . c r a w l _ s t a t u s ? ? " - " ) } < / d d >
< dt > extraction < / d t > < d d > $ { z ( e . e x t r a c t i o n _ s t a t u s ? ? " - " ) } < / d d >
< dt > claims < / d t > < d d > $ { e . c l a i m _ c o u n t ? ? 0 } < / d d >
< dt > entities < / d t > < d d > $ { e . e n t i t y _ c o u n t ? ? 0 } < / d d >
< / d l >
` }return""}function Wv(t){if(t.kind==="entity"){const e=t.data;return `
< section class = "inspector-section" >
< h3 > $ { z ( e . name ) } < / h 3 >
< dl class = "kv" >
< dt > $ { z ( V ( "table.id" ) ) } < / d t > < d d > $ { z ( e . i d ) } < / d d >
< dt > $ { z ( V ( "table.type" ) ) } < / d t > < d d > $ { z ( e . t y p e ) } < / d d >
< / d l >
< pre class = "code" > $ { z ( JSON . stringify ( e . metadata ? ? { } , null , 2 ) ) } < / p r e >
< / s e c t i o n >
` }if(t.kind==="claim"){const e=t.data;return `
< section class = "inspector-section" >
< h3 > $ { z ( e . subject ) } · $ { z ( e . predicate ) } < / h 3 >
< dl class = "kv" >
< dt > $ { z ( V ( "table.object" ) ) } < / d t > < d d > $ { z ( e . o b j e c t ? ? J S O N . s t r i n g i f y ( e . o b j e c t _ v a l u e ? ? " " ) ) } < / d d >
< dt > $ { z ( V ( "table.status" ) ) } < / d t > < d d > $ { z ( e . s t a t u s ? ? " " ) } < / d d >
< dt > $ { z ( V ( "table.confidence" ) ) } < / d t > < d d > $ { M a t h . r o u n d ( ( e . c o n f i d e n c e ? ? 0 ) * 1 0 0 ) } % < / d d >
< / d l >
$ { e . evidence _text ? ` <p class="evidence"> ${ z ( e . evidence _text ) } </p> ` : "" }
< / s e c t i o n >
` }if(t.kind==="graph_node"){const e=t.data;return `
< section class = "inspector-section" >
< h3 > $ { z ( e . label ) } < / h 3 >
< dl class = "kv" >
< dt > $ { z ( V ( "table.id" ) ) } < / d t > < d d > $ { z ( e . e n t i t y I d ) } < / d d >
< dt > $ { z ( V ( "table.type" ) ) } < / d t > < d d > $ { z ( e . t y p e ? ? " " ) } < / d d >
$ { e . canonical ? ` <dt>canonical</dt><dd> ${ z ( e . canonical ) } </dd> ` : "" }
< / d l >
$ { e . metadata && Object . keys ( e . metadata ) . length ? ` <pre class="code"> ${ z ( JSON . stringify ( e . metadata , null , 2 ) ) } </pre> ` : "" }
< / s e c t i o n >
` }if(t.kind==="graph_edge"){const e=t.data;return `
< section class = "inspector-section" >
< h3 > $ { z ( e . predicate ) } < / h 3 >
< dl class = "kv" >
< dt > $ { z ( V ( "table.confidence" ) ) } < / d t > < d d > $ { M a t h . r o u n d ( ( e . c o n f i d e n c e ? ? 0 ) * 1 0 0 ) } % < / d d >
$ { e . targetName ? ` <dt> ${ z ( V ( "table.object" ) ) } </dt><dd> ${ z ( e . targetName ) } </dd> ` : "" }
< dt > claim < / d t > < d d > $ { z ( e . c l a i m I d ) } < / d d >
< / d l >
$ { e . metadata && Object . keys ( e . metadata ) . length ? ` <pre class="code"> ${ z ( JSON . stringify ( e . metadata , null , 2 ) ) } </pre> ` : "" }
< / s e c t i o n >
` }return""}function ho(t,e){(e==null||e>t.length)&&(e=t.length);for(var r=0,a=Array(e);r<e;r++)a[r]=t[r];return a}function jv(t){if(Array.isArray(t))return t}function Yv(t){if(Array.isArray(t))return ho(t)}function Ar(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function Xv(t,e){for(var r=0;r<e.length;r++){var a=e[r];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(t,vd(a.key),a)}}function Lr(t,e,r){return e&&Xv(t.prototype,e),Object.defineProperty(t,"prototype",{writable:!1}),t}function Lt(t,e){var r=typeof Symbol<"u"&&t[Symbol.iterator]||t["@@iterator"];if(!r){if(Array.isArray(t)||(r=Uo(t))||e){r&&(t=r);var a=0,n=function(){};return{s:n,n:function(){return a>=t.length?{done:!0}:{done:!1,value:t[a++]}},e:function(l){throw l},f:n}}throw new TypeError( ` Invalid attempt to iterate non - iterable instance .
In order to be iterable , non - array objects must have a [ Symbol . iterator ] ( ) method . ` )}var i,s=!0,o=!1;return{s:function(){r=r.call(t)},n:function(){var l=r.next();return s=l.done,l},e:function(l){o=!0,i=l},f:function(){try{s||r.return==null||r.return()}finally{if(o)throw i}}}}function fd(t,e,r){return(e=vd(e))in t?Object.defineProperty(t,e,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[e]=r,t}function Zv(t){if(typeof Symbol<"u"&&t[Symbol.iterator]!=null||t["@@iterator"]!=null)return Array.from(t)}function Qv(t,e){var r=t==null?null:typeof Symbol<"u"&&t[Symbol.iterator]||t["@@iterator"];if(r!=null){var a,n,i,s,o=[],l=!0,u=!1;try{if(i=(r=r.call(t)).next,e===0){if(Object(r)!==r)return;l=!1}else for(;!(l=(a=i.call(r)).done)&&(o.push(a.value),o.length!==e);l=!0);}catch(c){u=!0,n=c}finally{try{if(!l&&r.return!=null&&(s=r.return(),Object(s)!==s))return}finally{if(u)throw n}}return o}}function Jv(){throw new TypeError( ` Invalid attempt to destructure non - iterable instance .
In order to be iterable , non - array objects must have a [ Symbol . iterator ] ( ) method . ` )}function eh(){throw new TypeError( ` Invalid attempt to spread non - iterable instance .
2026-05-13 19:57:34 +09:00
In order to be iterable , non - array objects must have a [ Symbol . iterator ] ( ) method . ` )}function at(t,e){return jv(t)||Qv(t,e)||Uo(t,e)||Jv()}function Gn(t){return Yv(t)||Zv(t)||Uo(t)||eh()}function th(t,e){if(typeof t!="object"||!t)return t;var r=t[Symbol.toPrimitive];if(r!==void 0){var a=r.call(t,e);if(typeof a!="object")return a;throw new TypeError("@@toPrimitive must return a primitive value.")}return String(t)}function vd(t){var e=th(t,"string");return typeof e=="symbol"?e:e+""}function ot(t){"@babel/helpers - typeof";return ot=typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?function(e){return typeof e}:function(e){return e&&typeof Symbol=="function"&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},ot(t)}function Uo(t,e){if(t){if(typeof t=="string")return ho(t,e);var r={}.toString.call(t).slice(8,-1);return r==="Object"&&t.constructor&&(r=t.constructor.name),r==="Map"||r==="Set"?Array.from(t):r==="Arguments"||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array $ /.test(r)?ho(t,e):void 0}}var it=typeof window>"u"?null:window,Dl=it?it.navigator:null;it&&it.document;var rh=ot(""),hd=ot({}),ah=ot(function(){}),nh=typeof HTMLElement>"u"?"undefined":ot(HTMLElement),Qa=function(e){return e&&e.instanceString&&Ze(e.instanceString)?e.instanceString():null},me=function(e){return e!=null&&ot(e)==rh},Ze=function(e){return e!=null&&ot(e)===ah},Ue=function(e){return!It(e)&&(Array.isArray?Array.isArray(e):e!=null&&e instanceof Array)},Ne=function(e){return e!=null&&ot(e)===hd&&!Ue(e)&&e.constructor===Object},ih=function(e){return e!=null&&ot(e)===hd},se=function(e){return e!=null&&ot(e)===ot(1)&&!isNaN(e)},sh=function(e){return se(e)&&Math.floor(e)===e},Un=function(e){if(nh!=="undefined")return e!=null&&e instanceof HTMLElement},It=function(e){return Ja(e)||pd(e)},Ja=function(e){return Qa(e)==="collection"&&e._private.single},pd=function(e){return Qa(e)==="collection"&&!e._private.single},Ko=function(e){return Qa(e)==="core"},gd=function(e){return Qa(e)==="stylesheet"},oh=function(e){return Qa(e)==="event"},Sr=function(e){return e==null?!0:!!(e===""||e.match(/^ \s + $ /))},lh=function(e){return typeof HTMLElement>"u"?!1:e instanceof HTMLElement},uh=function(e){return Ne(e)&&se(e.x1)&&se(e.x2)&&se(e.y1)&&se(e.y2)},ch=function(e){return ih(e)&&Ze(e.then)},dh=function(){return Dl&&Dl.userAgent.match(/msie|trident|edge/i)},pa=function(e,r){r||(r=function(){if(arguments.length===1)return arguments[0];if(arguments.length===0)return"undefined";for(var i=[],s=0;s<arguments.length;s++)i.push(arguments[s]);return i.join(" $ ")});var a=function(){var i=this,s=arguments,o,l=r.apply(i,s),u=a.cache;return(o=u[l])||(o=u[l]=e.apply(i,s)),o};return a.cache={},a},Wo=pa(function(t){return t.replace(/([A-Z])/g,function(e){return"-"+e.toLowerCase()})}),oi=pa(function(t){return t.replace(/(- \w )/g,function(e){return e[1].toUpperCase()})}),yd=pa(function(t,e){return t+e[0].toUpperCase()+e.substring(1)},function(t,e){return t+" $ "+e}),Rl=function(e){return Sr(e)?e:e.charAt(0).toUpperCase()+e.substring(1)},br=function(e,r){return e.slice(-1*r.length)===r},st="(?:[-+]?(?:(?: \\ d+| \\ d* \\ . \\ d+)(?:[Ee][+-]? \\ d+)?))",fh="rgb[a]? \\ (("+st+"[%]?) \\ s*, \\ s*("+st+"[%]?) \\ s*, \\ s*("+st+"[%]?)(?: \\ s*, \\ s*("+st+"))? \\ )",vh="rgb[a]? \\ ((?:"+st+"[%]?) \\ s*, \\ s*(?:"+st+"[%]?) \\ s*, \\ s*(?:"+st+"[%]?)(?: \\ s*, \\ s*(?:"+st+"))? \\ )",hh="hsl[a]? \\ (("+st+") \\ s*, \\ s*("+st+"[%]) \\ s*, \\ s*("+st+"[%])(?: \\ s*, \\ s*("+st+"))? \\ )",ph="hsl[a]? \\ ((?:"+st+") \\ s*, \\ s*(?:"+st+"[%]) \\ s*, \\ s*(?:"+st+"[%])(?: \\ s*, \\ s*(?:"+st+"))? \\ )",gh=" \\ #[0-9a-fA-F]{3}",yh=" \\ #[0-9a-fA-F]{6}",md=function(e,r){return e<r?-1:e>r?1:0},mh=function(e,r){return-1*md(e,r)},xe=Object.assign!=null?Object.assign.bind(Object):function(t){for(var e=arguments,r=1;r<e.length;r++){var a=e[r];if(a!=null)for(var n=Object.keys(a),i=0;i<n.length;i++){var s=n[i];t[s]=a[s]}}return t},bh=function(e){if(!(!(e.length===4||e.length===7)||e[0]!=="#")){var r=e.length===4,a,n,i,s=16;return r?(a=parseInt(e[1]+e[1],s),n=parseInt(e[2]+e[2],s),i=parseInt(e[3]+e[3],s)):(a=parseInt(e[1]+e[2],s),n=parseInt(e[3]+e[4],s),i=parseInt(e[5]+e[6],s)),[
2026-05-12 19:40:31 +09:00
` ),d=t.pstyle("text-max-width").pfValue,f=t.pstyle("text-overflow-wrap").value,h=f==="anywhere",v=[],y=/[ \s \u 200b]+| $ /g,p=0;p<c.length;p++){var g=c[p],m=this.calculateLabelDimensions(t,g),b=m.width;if(h){var w=g.split("").join(u);g=w}if(b>d){var E=g.matchAll(y),C="",x=0,T=Lt(E),k;try{for(T.s();!(k=T.n()).done;){var P=k.value,B=P[0],D=g.substring(x,P.index);x=P.index+B.length;var R=C.length===0?D:C+D+B,A=this.calculateLabelDimensions(t,R),M=A.width;M<=d?C+=D+B:(C&&v.push(C),C=D+B)}}catch( $ ){T.e( $ )}finally{T.f()}C.match(/^[ \s \u 200b]+ $ /)||v.push(C)}else v.push(g)}s("labelWrapCachedLines",v),n=s("labelWrapCachedText",v.join( `
` )),s("labelWrapKey",l)}else if(o==="ellipsis"){var _=t.pstyle("text-max-width").pfValue,L="",I="…",H=!1;if(this.calculateLabelDimensions(t,n).width<_)return n;for(var G=0;G<n.length;G++){var O=this.calculateLabelDimensions(t,L+n[G]+I).width;if(O>_)break;L+=n[G],G===n.length-1&&(H=!0)}return H||(L+=I),L}return n};tr.getLabelJustification=function(t){var e=t.pstyle("text-justification").strValue,r=t.pstyle("text-halign").strValue;if(e==="auto")if(t.isNode())switch(r){case"left":return"right";case"right":return"left";default:return"center"}else return"center";else return e};tr.calculateLabelDimensions=function(t,e){var r=this,a=r.cy.window(),n=a.document,i=0,s=t.pstyle("font-style").strValue,o=t.pstyle("font-size").pfValue,l=t.pstyle("font-family").strValue,u=t.pstyle("font-weight").strValue,c=this.labelCalcCanvas,d=this.labelCalcCanvasContext;if(!c){c=this.labelCalcCanvas=n.createElement("canvas"),d=this.labelCalcCanvasContext=c.getContext("2d");var f=c.style;f.position="absolute",f.left="-9999px",f.top="-9999px",f.zIndex="-1",f.visibility="hidden",f.pointerEvents="none"}d.font="".concat(s," ").concat(u," ").concat(o,"px ").concat(l);for(var h=0,v=0,y=e.split( `
2026-05-13 19:57:34 +09:00
` ),p=0;p<y.length;p++){var g=y[p],m=d.measureText(g),b=Math.ceil(m.width),w=o;h=Math.max(b,h),v+=w}return h+=i,v+=i,{width:h,height:v}};tr.calculateLabelAngle=function(t,e){var r=t._private,a=r.rscratch,n=t.isEdge(),i=e?e+"-":"",s=t.pstyle(i+"text-rotation"),o=s.strValue;return o==="none"?0:n&&o==="autorotate"?a.labelAutoAngle:o==="autorotate"?0:s.pfValue};tr.calculateLabelAngles=function(t){var e=this,r=t.isEdge(),a=t._private,n=a.rscratch;n.labelAngle=e.calculateLabelAngle(t),r&&(n.sourceLabelAngle=e.calculateLabelAngle(t,"source"),n.targetLabelAngle=e.calculateLabelAngle(t,"target"))};var _f={},zc=28, $ c=!1;_f.getNodeShape=function(t){var e=this,r=t.pstyle("shape").value;if(r==="cutrectangle"&&(t.width()<zc||t.height()<zc))return $ c||(He("The ` cutrectangle ` node shape can not be used at small sizes so ` rectangle ` is used instead"), $ c=!0),"rectangle";if(t.isParent())return r==="rectangle"||r==="roundrectangle"||r==="round-rectangle"||r==="cutrectangle"||r==="cut-rectangle"||r==="barrel"?r:"rectangle";if(r==="polygon"){var a=t.pstyle("shape-polygon-points").value;return e.nodeShapes.makePolygon(a).name}return r};var Ci={};Ci.registerCalculationListeners=function(){var t=this.cy,e=t.collection(),r=this,a=function(s){var o=arguments.length>1&&arguments[1]!==void 0?arguments[1]:!0;if(e.merge(s),o)for(var l=0;l<s.length;l++){var u=s[l],c=u._private,d=c.rstyle;d.clean=!1,d.cleanConnected=!1}};r.binder(t).on("bounds.* dirty.*",function(s){var o=s.target;a(o)}).on("style.* background.*",function(s){var o=s.target;a(o,!1)});var n=function(s){if(s){var o=r.onUpdateEleCalcsFns;e.cleanStyle();for(var l=0;l<e.length;l++){var u=e[l],c=u._private.rstyle;u.isNode()&&!c.cleanConnected&&(a(u.connectedEdges()),c.cleanConnected=!0)}if(o)for(var d=0;d<o.length;d++){var f=o[d];f(s,e)}r.recalculateRenderedStyle(e),e=t.collection()}};r.flushRenderedStyleQueue=function(){n(!0)},r.beforeRender(n,r.beforeRenderPriorities.eleCalcs)};Ci.onUpdateEleCalcs=function(t){var e=this.onUpdateEleCalcsFns=this.onUpdateEleCalcsFns||[];e.push(t)};Ci.recalculateRenderedStyle=function(t,e){var r=function(w){return w._private.rstyle.cleanConnected};if(t.length!==0){var a=[],n=[];if(!this.destroyed){e===void 0&&(e=!0);for(var i=0;i<t.length;i++){var s=t[i],o=s._private,l=o.rstyle;s.isEdge()&&(!r(s.source())||!r(s.target()))&&(l.clean=!1),s.isEdge()&&s.isBundledBezier()&&s.parallelEdges().some(function(b){return!b._private.rstyle.clean&&b.isBundledBezier()})&&(l.clean=!1),!(e&&l.clean||s.removed())&&s.pstyle("display").value!=="none"&&(o.group==="nodes"?n.push(s):a.push(s),l.clean=!0)}for(var u=0;u<n.length;u++){var c=n[u],d=c._private,f=d.rstyle,h=c.position();this.recalculateNodeLabelProjection(c),f.nodeX=h.x,f.nodeY=h.y,f.nodeW=c.pstyle("width").pfValue,f.nodeH=c.pstyle("height").pfValue}this.recalculateEdgeProjections(a);for(var v=0;v<a.length;v++){var y=a[v],p=y._private,g=p.rstyle,m=p.rscratch;g.srcX=m.arrowStartX,g.srcY=m.arrowStartY,g.tgtX=m.arrowEndX,g.tgtY=m.arrowEndY,g.midX=m.midX,g.midY=m.midY,g.labelAngle=m.labelAngle,g.sourceLabelAngle=m.sourceLabelAngle,g.targetLabelAngle=m.targetLabelAngle}}}};var Ti={};Ti.updateCachedGrabbedEles=function(){var t=this.cachedZSortedEles;if(t){t.drag=[],t.nondrag=[];for(var e=[],r=0;r<t.length;r++){var a=t[r],n=a._private.rscratch;a.grabbed()&&!a.isParent()?e.push(a):n.inDragLayer?t.drag.push(a):t.nondrag.push(a)}for(var r=0;r<e.length;r++){var a=e[r];t.drag.push(a)}}};Ti.invalidateCachedZSortedEles=function(){this.cachedZSortedEles=null};Ti.getCachedZSortedEles=function(t){if(t||!this.cachedZSortedEles){var e=this.cy.mutableElements().toArray();e.sort(pf),e.interactive=e.filter(function(r){return r.interactive()}),this.cachedZSortedEles=e,this.updateCachedGrabbedEles()}else e=this.cachedZSortedEles;return e};var If={};[Zr,ei,Tt,ln,vl,tr,_f,Ci,Ti].forEach(function(t){xe(If,t)});var Of={};Of.getCachedImage=function(t,e,r){var a=this,n=a.imageCache=a.imageCache||{},i=n[t];if(i)return i.image.complete||i.image.addEventListener("load",r),i.image;i=n[t]=n[t]||{};var s=i.image=new Image;s.addEventListener("load",r),s.addEv
2026-05-12 19:40:31 +09:00
float circleSD ( vec2 p , float r ) {
return distance ( vec2 ( 0 ) , p ) - r ; // signed distance
}
` ,nb= `
float rectangleSD ( vec2 p , vec2 b ) {
vec2 d = abs ( p ) - b ;
return distance ( vec2 ( 0 ) , max ( d , 0.0 ) ) + min ( max ( d . x , d . y ) , 0.0 ) ;
}
` ,ib= `
float roundRectangleSD ( vec2 p , vec2 b , vec4 cr ) {
cr . xy = ( p . x > 0.0 ) ? cr . xy : cr . zw ;
cr . x = ( p . y > 0.0 ) ? cr . x : cr . y ;
vec2 q = abs ( p ) - b + cr . x ;
return min ( max ( q . x , q . y ) , 0.0 ) + distance ( vec2 ( 0 ) , max ( q , 0.0 ) ) - cr . x ;
}
` ,sb= `
float ellipseSD ( vec2 p , vec2 ab ) {
p = abs ( p ) ; // symmetry
// find root with Newton solver
vec2 q = ab * ( p - ab ) ;
float w = ( q . x < q . y ) ? 1.570796327 : 0.0 ;
for ( int i = 0 ; i < 5 ; i ++ ) {
vec2 cs = vec2 ( cos ( w ) , sin ( w ) ) ;
vec2 u = ab * vec2 ( cs . x , cs . y ) ;
vec2 v = ab * vec2 ( - cs . y , cs . x ) ;
w = w + dot ( p - u , v ) / ( dot ( p - u , u ) + dot ( v , v ) ) ;
}
// compute final point and distance
float d = length ( p - ab * vec2 ( cos ( w ) , sin ( w ) ) ) ;
// return signed distance
return ( dot ( p / ab , p / ab ) > 1.0 ) ? d : - d ;
}
` ,Fa={SCREEN:{name:"screen",screen:!0},PICKING:{name:"picking",picking:!0}},ri={IGNORE:1,USE_BB:2},ro=0,Qc=1,Jc=2,ao=3,ia=4,Sn=5,Ma=6,_a=7,ob=(function(){function t(e,r,a){Ar(this,t),this.r=e,this.gl=r,this.maxInstances=a.webglBatchSize,this.atlasSize=a.webglTexSize,this.bgColor=a.bgColor,this.debug=a.webglDebug,this.batchDebugInfo=[],a.enableWrapping=!0,a.createTextureCanvas= $ 0,this.atlasManager=new tb(e,a),this.batchManager=new rb(a),this.simpleShapeOptions=new Map,this.program=this._createShaderProgram(Fa.SCREEN),this.pickingProgram=this._createShaderProgram(Fa.PICKING),this.vao=this._createVAO()}return Lr(t,[{key:"addAtlasCollection",value:function(r,a){this.atlasManager.addAtlasCollection(r,a)}},{key:"addTextureAtlasRenderType",value:function(r,a){this.atlasManager.addRenderType(r,a)}},{key:"addSimpleShapeRenderType",value:function(r,a){this.simpleShapeOptions.set(r,a)}},{key:"invalidate",value:function(r){var a=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{},n=a.type,i=this.atlasManager;return n?i.invalidate(r,{filterType:function(o){return o===n},forceRedraw:!0}):i.invalidate(r)}},{key:"gc",value:function(){this.atlasManager.gc()}},{key:"_createShaderProgram",value:function(r){var a=this.gl,n= ` # version 300 es
precision highp float ;
uniform mat3 uPanZoomMatrix ;
uniform int uAtlasSize ;
// instanced
in vec2 aPosition ; // a vertex from the unit square
in mat3 aTransform ; // used to transform verticies, eg into a bounding box
in int aVertType ; // the type of thing we are rendering
// the z-index that is output when using picking mode
in vec4 aIndex ;
// For textures
in int aAtlasId ; // which shader unit/atlas to use
in vec4 aTex ; // x/y/w/h of texture in atlas
// for edges
in vec4 aPointAPointB ;
in vec4 aPointCPointD ;
in vec2 aLineWidth ; // also used for node border width
// simple shapes
in vec4 aCornerRadius ; // for round-rectangle [top-right, bottom-right, top-left, bottom-left]
in vec4 aColor ; // also used for edges
in vec4 aBorderColor ; // aLineWidth is used for border width
// output values passed to the fragment shader
out vec2 vTexCoord ;
out vec4 vColor ;
out vec2 vPosition ;
// flat values are not interpolated
flat out int vAtlasId ;
flat out int vVertType ;
flat out vec2 vTopRight ;
flat out vec2 vBotLeft ;
flat out vec4 vCornerRadius ;
flat out vec4 vBorderColor ;
flat out vec2 vBorderWidth ;
flat out vec4 vIndex ;
void main ( void ) {
int vid = gl _VertexID ;
vec2 position = aPosition ; // TODO make this a vec3, simplifies some code below
if ( aVertType == ` .concat(ro, ` ) {
float texX = aTex . x ; // texture coordinates
float texY = aTex . y ;
float texW = aTex . z ;
float texH = aTex . w ;
if ( vid == 1 || vid == 2 || vid == 4 ) {
texX += texW ;
}
if ( vid == 2 || vid == 4 || vid == 5 ) {
texY += texH ;
}
float d = float ( uAtlasSize ) ;
vTexCoord = vec2 ( texX / d , texY / d ) ; // tex coords must be between 0 and 1
gl _Position = vec4 ( uPanZoomMatrix * aTransform * vec3 ( position , 1.0 ) , 1.0 ) ;
}
else if ( aVertType == ` ).concat(ia," || aVertType == ").concat(_a, `
|| aVertType == ` ).concat(Sn," || aVertType == ").concat(Ma, ` ) { // simple shapes
// the bounding box is needed by the fragment shader
vBotLeft = ( aTransform * vec3 ( 0 , 0 , 1 ) ) . xy ; // flat
vTopRight = ( aTransform * vec3 ( 1 , 1 , 1 ) ) . xy ; // flat
vPosition = ( aTransform * vec3 ( position , 1 ) ) . xy ; // will be interpolated
// calculations are done in the fragment shader, just pass these along
vColor = aColor ;
vCornerRadius = aCornerRadius ;
vBorderColor = aBorderColor ;
vBorderWidth = aLineWidth ;
gl _Position = vec4 ( uPanZoomMatrix * aTransform * vec3 ( position , 1.0 ) , 1.0 ) ;
}
else if ( aVertType == ` ).concat(Qc, ` ) {
vec2 source = aPointAPointB . xy ;
vec2 target = aPointAPointB . zw ;
// adjust the geometry so that the line is centered on the edge
position . y = position . y - 0.5 ;
// stretch the unit square into a long skinny rectangle
vec2 xBasis = target - source ;
vec2 yBasis = normalize ( vec2 ( - xBasis . y , xBasis . x ) ) ;
vec2 point = source + xBasis * position . x + yBasis * aLineWidth [ 0 ] * position . y ;
gl _Position = vec4 ( uPanZoomMatrix * vec3 ( point , 1.0 ) , 1.0 ) ;
vColor = aColor ;
}
else if ( aVertType == ` ).concat(Jc, ` ) {
vec2 pointA = aPointAPointB . xy ;
vec2 pointB = aPointAPointB . zw ;
vec2 pointC = aPointCPointD . xy ;
vec2 pointD = aPointCPointD . zw ;
// adjust the geometry so that the line is centered on the edge
position . y = position . y - 0.5 ;
vec2 p0 , p1 , p2 , pos ;
if ( position . x == 0.0 ) { // The left side of the unit square
p0 = pointA ;
p1 = pointB ;
p2 = pointC ;
pos = position ;
} else { // The right side of the unit square, use same approach but flip the geometry upside down
p0 = pointD ;
p1 = pointC ;
p2 = pointB ;
pos = vec2 ( 0.0 , - position . y ) ;
}
vec2 p01 = p1 - p0 ;
vec2 p12 = p2 - p1 ;
vec2 p21 = p1 - p2 ;
// Find the normal vector.
vec2 tangent = normalize ( normalize ( p12 ) + normalize ( p01 ) ) ;
vec2 normal = vec2 ( - tangent . y , tangent . x ) ;
// Find the vector perpendicular to p0 -> p1.
vec2 p01Norm = normalize ( vec2 ( - p01 . y , p01 . x ) ) ;
// Determine the bend direction.
float sigma = sign ( dot ( p01 + p21 , normal ) ) ;
float width = aLineWidth [ 0 ] ;
if ( sign ( pos . y ) == - sigma ) {
// This is an intersecting vertex. Adjust the position so that there's no overlap.
vec2 point = 0.5 * width * normal * - sigma / dot ( normal , p01Norm ) ;
gl _Position = vec4 ( uPanZoomMatrix * vec3 ( p1 + point , 1.0 ) , 1.0 ) ;
} else {
// This is a non-intersecting vertex. Treat it like a mitre join.
vec2 point = 0.5 * width * normal * sigma * dot ( normal , p01Norm ) ;
gl _Position = vec4 ( uPanZoomMatrix * vec3 ( p1 + point , 1.0 ) , 1.0 ) ;
}
vColor = aColor ;
}
else if ( aVertType == ` ).concat(ao, ` && vid < 3 ) {
// massage the first triangle into an edge arrow
if ( vid == 0 )
position = vec2 ( - 0.15 , - 0.3 ) ;
if ( vid == 1 )
position = vec2 ( 0.0 , 0.0 ) ;
if ( vid == 2 )
position = vec2 ( 0.15 , - 0.3 ) ;
gl _Position = vec4 ( uPanZoomMatrix * aTransform * vec3 ( position , 1.0 ) , 1.0 ) ;
vColor = aColor ;
}
else {
gl _Position = vec4 ( 2.0 , 0.0 , 0.0 , 1.0 ) ; // discard vertex by putting it outside webgl clip space
}
vAtlasId = aAtlasId ;
vVertType = aVertType ;
vIndex = aIndex ;
}
` ),i=this.batchManager.getIndexArray(),s= ` # version 300 es
precision highp float ;
// declare texture unit for each texture atlas in the batch
` .concat(i.map(function(u){return"uniform sampler2D uTexture".concat(u,";")}).join( `
` ), `
uniform vec4 uBGColor ;
uniform float uZoom ;
in vec2 vTexCoord ;
in vec4 vColor ;
in vec2 vPosition ; // model coordinates
flat in int vAtlasId ;
flat in vec4 vIndex ;
flat in int vVertType ;
flat in vec2 vTopRight ;
flat in vec2 vBotLeft ;
flat in vec4 vCornerRadius ;
flat in vec4 vBorderColor ;
flat in vec2 vBorderWidth ;
out vec4 outColor ;
` ).concat(ab, `
` ).concat(nb, `
` ).concat(ib, `
` ).concat(sb, `
vec4 blend ( vec4 top , vec4 bot ) { // blend colors with premultiplied alpha
return vec4 (
top . rgb + ( bot . rgb * ( 1.0 - top . a ) ) ,
top . a + ( bot . a * ( 1.0 - top . a ) )
) ;
}
vec4 distInterp ( vec4 cA , vec4 cB , float d ) { // interpolate color using Signed Distance
// scale to the zoom level so that borders don't look blurry when zoomed in
// note 1.5 is an aribitrary value chosen because it looks good
return mix ( cA , cB , 1.0 - smoothstep ( 0.0 , 1.5 / uZoom , abs ( d ) ) ) ;
}
void main ( void ) {
if ( vVertType == ` ).concat(ro, ` ) {
// look up the texel from the texture unit
` ).concat(i.map(function(u){return"if(vAtlasId == ".concat(u,") outColor = texture(uTexture").concat(u,", vTexCoord);")}).join( `
else ` ), `
}
else if ( vVertType == ` ).concat(ao, ` ) {
// mimics how canvas renderer uses context.globalCompositeOperation = 'destination-out';
outColor = blend ( vColor , uBGColor ) ;
outColor . a = 1.0 ; // make opaque, masks out line under arrow
}
else if ( vVertType == ` ).concat(ia, ` && vBorderWidth == vec2 ( 0.0 ) ) { // simple rectangle with no border
outColor = vColor ; // unit square is already transformed to the rectangle, nothing else needs to be done
}
else if ( vVertType == ` ).concat(ia," || vVertType == ").concat(_a, `
|| vVertType == ` ).concat(Sn," || vVertType == ").concat(Ma, ` ) { // use SDF
float outerBorder = vBorderWidth [ 0 ] ;
float innerBorder = vBorderWidth [ 1 ] ;
float borderPadding = outerBorder * 2.0 ;
float w = vTopRight . x - vBotLeft . x - borderPadding ;
float h = vTopRight . y - vBotLeft . y - borderPadding ;
vec2 b = vec2 ( w / 2.0 , h / 2.0 ) ; // half width, half height
vec2 p = vPosition - vec2 ( vTopRight . x - b [ 0 ] - outerBorder , vTopRight . y - b [ 1 ] - outerBorder ) ; // translate to center
float d ; // signed distance
if ( vVertType == ` ).concat(ia, ` ) {
d = rectangleSD ( p , b ) ;
} else if ( vVertType == ` ).concat(_a, ` && w == h ) {
d = circleSD ( p , b . x ) ; // faster than ellipse
} else if ( vVertType == ` ).concat(_a, ` ) {
d = ellipseSD ( p , b ) ;
} else {
d = roundRectangleSD ( p , b , vCornerRadius . wzyx ) ;
}
// use the distance to interpolate a color to smooth the edges of the shape, doesn't need multisampling
// we must smooth colors inwards, because we can't change pixels outside the shape's bounding box
if ( d > 0.0 ) {
if ( d > outerBorder ) {
discard ;
} else {
outColor = distInterp ( vBorderColor , vec4 ( 0 ) , d - outerBorder ) ;
}
} else {
if ( d > innerBorder ) {
vec4 outerColor = outerBorder == 0.0 ? vec4 ( 0 ) : vBorderColor ;
vec4 innerBorderColor = blend ( vBorderColor , vColor ) ;
outColor = distInterp ( innerBorderColor , outerColor , d ) ;
}
else {
vec4 outerColor ;
if ( innerBorder == 0.0 && outerBorder == 0.0 ) {
outerColor = vec4 ( 0 ) ;
} else if ( innerBorder == 0.0 ) {
outerColor = vBorderColor ;
} else {
outerColor = blend ( vBorderColor , vColor ) ;
}
outColor = distInterp ( vColor , outerColor , d - innerBorder ) ;
}
}
}
else {
outColor = vColor ;
}
` ).concat(r.picking? ` if ( outColor . a == 0.0 ) discard ;
else outColor = vIndex ; ` :"", `
}
2026-05-13 19:57:34 +09:00
` ),o=z0(a,n,s);o.aPosition=a.getAttribLocation(o,"aPosition"),o.aIndex=a.getAttribLocation(o,"aIndex"),o.aVertType=a.getAttribLocation(o,"aVertType"),o.aTransform=a.getAttribLocation(o,"aTransform"),o.aAtlasId=a.getAttribLocation(o,"aAtlasId"),o.aTex=a.getAttribLocation(o,"aTex"),o.aPointAPointB=a.getAttribLocation(o,"aPointAPointB"),o.aPointCPointD=a.getAttribLocation(o,"aPointCPointD"),o.aLineWidth=a.getAttribLocation(o,"aLineWidth"),o.aColor=a.getAttribLocation(o,"aColor"),o.aCornerRadius=a.getAttribLocation(o,"aCornerRadius"),o.aBorderColor=a.getAttribLocation(o,"aBorderColor"),o.uPanZoomMatrix=a.getUniformLocation(o,"uPanZoomMatrix"),o.uAtlasSize=a.getUniformLocation(o,"uAtlasSize"),o.uBGColor=a.getUniformLocation(o,"uBGColor"),o.uZoom=a.getUniformLocation(o,"uZoom"),o.uTextures=[];for(var l=0;l<this.batchManager.getMaxAtlasesPerBatch();l++)o.uTextures.push(a.getUniformLocation(o,"uTexture".concat(l)));return o}},{key:"_createVAO",value:function(){var r=[0,0,1,0,1,1,0,0,1,1,0,1];this.vertexCount=r.length/2;var a=this.maxInstances,n=this.gl,i=this.program,s=n.createVertexArray();return n.bindVertexArray(s),W0(n,"vec2",i.aPosition,r),this.transformBuffer=j0(n,a,i.aTransform),this.indexBuffer=Xt(n,a,"vec4",i.aIndex),this.vertTypeBuffer=Xt(n,a,"int",i.aVertType),this.atlasIdBuffer=Xt(n,a,"int",i.aAtlasId),this.texBuffer=Xt(n,a,"vec4",i.aTex),this.pointAPointBBuffer=Xt(n,a,"vec4",i.aPointAPointB),this.pointCPointDBuffer=Xt(n,a,"vec4",i.aPointCPointD),this.lineWidthBuffer=Xt(n,a,"vec2",i.aLineWidth),this.colorBuffer=Xt(n,a,"vec4",i.aColor),this.cornerRadiusBuffer=Xt(n,a,"vec4",i.aCornerRadius),this.borderColorBuffer=Xt(n,a,"vec4",i.aBorderColor),n.bindVertexArray(null),s}},{key:"buffers",get:function(){var r=this;return this._buffers||(this._buffers=Object.keys(this).filter(function(a){return br(a,"Buffer")}).map(function(a){return r[a]})),this._buffers}},{key:"startFrame",value:function(r){var a=arguments.length>1&&arguments[1]!==void 0?arguments[1]:Fa.SCREEN;this.panZoomMatrix=r,this.renderTarget=a,this.batchDebugInfo=[],this.wrappedCount=0,this.simpleCount=0,this.startBatch()}},{key:"startBatch",value:function(){this.instanceCount=0,this.batchManager.startBatch()}},{key:"endFrame",value:function(){this.endBatch()}},{key:"_isVisible",value:function(r,a){return r.visible()?a&&a.isVisible?a.isVisible(r):!0:!1}},{key:"drawTexture",value:function(r,a,n){var i=this.atlasManager,s=this.batchManager,o=i.getRenderTypeOpts(n);if(this._isVisible(r,o)&&!(r.isEdge()&&!this._isValidEdge(r))){if(this.renderTarget.picking&&o.getTexPickingMode){var l=o.getTexPickingMode(r);if(l===ri.IGNORE)return;if(l==ri.USE_BB){this.drawPickingRectangle(r,a,n);return}}var u=i.getAtlasInfo(r,n),c=Lt(u),d;try{for(c.s();!(d=c.n()).done;){var f=d.value,h=f.atlas,v=f.tex1,y=f.tex2;s.canAddToCurrentBatch(h)||this.endBatch();for(var p=s.getAtlasIndexForBatch(h),g=0,m=[[v,!0],[y,!1]];g<m.length;g++){var b=at(m[g],2),w=b[0],E=b[1];if(w.w!=0){var C=this.instanceCount;this.vertTypeBuffer.getView(C)[0]=ro;var x=this.indexBuffer.getView(C);na(a,x);var T=this.atlasIdBuffer.getView(C);T[0]=p;var k=this.texBuffer.getView(C);k[0]=w.x,k[1]=w.y,k[2]=w.w,k[3]=w.h;var P=this.transformBuffer.getMatrixView(C);this.setTransformMatrix(r,P,o,f,E),this.instanceCount++,E||this.wrappedCount++,this.instanceCount>=this.maxInstances&&this.endBatch()}}}}catch(B){c.e(B)}finally{c.f()}}}},{key:"setTransformMatrix",value:function(r,a,n,i){var s=arguments.length>4&&arguments[4]!==void 0?arguments[4]:!0,o=0;if(n.shapeProps&&n.shapeProps.padding&&(o=r.pstyle(n.shapeProps.padding).pfValue),i){var l=i.bb,u=i.tex1,c=i.tex2,d=u.w/(u.w+c.w);s||(d=1-d);var f=this._getAdjustedBB(l,o,s,d);this._applyTransformMatrix(a,f,n,r)}else{var h=n.getBoundingBox(r),v=this._getAdjustedBB(h,o,!0,1);this._applyTransformMatrix(a,v,n,r)}}},{key:"_applyTransformMatrix",value:function(r,a,n,i){var s,o;Xc(r);var l=n.getRotation?n.getRotation(i):0;if(l!==0){var u=n.getRotationPoint(i),c=u.x,d=u.y;Vn(r,r,[c,d]),Zc(r,r,l);var f=n.getRotationOffset(i);s=f.x+(a.xOffset||0),o=f.y+(a.yOffset||0)}else s=a.x1,o=a.y1;Vn
2026-05-12 19:40:31 +09:00
< section id = "graph" class = "tab-panel" >
< div class = "graph-toolbar" >
< input id = "graphSearch" type = "search" data - i18n - placeholder = "graph.search_placeholder" / >
< select id = "graphEntityType" > < option value = "" data - i18n = "graph.entity_type_all" > < / o p t i o n > < / s e l e c t >
< select id = "graphPredicate" > < option value = "" data - i18n = "graph.predicate_all" > < / o p t i o n > < / s e l e c t >
< label class = "graph-slider" >
< span data - i18n = "graph.min_confidence" > < / s p a n >
< input id = "graphMinConfidence" type = "range" min = "0" max = "1" step = "0.05" value = "0" / >
< output id = "graphMinConfidenceOut" > 0 % < / o u t p u t >
< / l a b e l >
< label class = "graph-slider" >
< span data - i18n = "graph.layout" > < / s p a n >
< select id = "graphLayout" >
< option value = "cose" data - i18n = "graph.layout.cose" > < / o p t i o n >
< option value = "concentric" data - i18n = "graph.layout.concentric" > < / o p t i o n >
< option value = "circle" data - i18n = "graph.layout.circle" > < / o p t i o n >
< option value = "breadthfirst" data - i18n = "graph.layout.breadthfirst" > < / o p t i o n >
< option value = "grid" data - i18n = "graph.layout.grid" > < / o p t i o n >
< / s e l e c t >
< / l a b e l >
< button id = "graphFitBtn" data - i18n = "graph.fit" > < / b u t t o n >
< button id = "graphReloadBtn" class = "primary" data - i18n = "graph.reload" > < / b u t t o n >
< / d i v >
< div class = "graph-stats" >
< span id = "graphStats" class = "muted" > < / s p a n >
< span id = "graphLegend" class = "graph-legend" > < / s p a n >
< / d i v >
< div class = "graph-stage" >
< div id = "graphContainer" > < / d i v >
< div id = "graphEmpty" class = "graph-empty muted" data - i18n = "graph.empty" > < / d i v >
< / d i v >
< / s e c t i o n >
2026-05-13 19:57:34 +09:00
` }function Pb(){xt(F("graph")),F("graphSearch").addEventListener("input",t=>{bt.search=t.target.value.trim().toLowerCase(),kn()}),F("graphEntityType").addEventListener("change",t=>{bt.entity_type=t.target.value,kn()}),F("graphPredicate").addEventListener("change",t=>{bt.predicate=t.target.value,kn()}),F("graphMinConfidence").addEventListener("input",t=>{bt.min_confidence=Number(t.target.value),F("graphMinConfidenceOut").textContent= ` $ { Math . round ( bt . min _confidence * 100 ) } % ` ,kn()}),F("graphLayout").addEventListener("change",t=>{bt.layout=t.target.value,iv()}),F("graphFitBtn").addEventListener("click",()=>Qt?.fit(void 0,40)),F("graphReloadBtn").addEventListener("click",()=>gl().catch(()=>{})),fr(()=>xt(F("graph")))}async function gl(){if(!ue.selectedProject)return;lr=await Fe( ` / projects / $ { encodeURIComponent ( ue . selectedProject ) } / graph / neighborhood ? limit = 300 ` )??{nodes:[],edges:[]},Bb(lr.nodes),Db(lr),_o()}function Bb(t){const e=[...new Set(t.map(r=>r.type).filter(Boolean))].sort();ni=new Map,e.forEach((r,a)=>ni.set(r,ad[a%ad.length]))}function Db(t){const e=F("graphEntityType"),r=F("graphPredicate"),a=[...new Set(t.nodes.map(i=>i.type).filter(Boolean))].sort(),n=[...new Set(t.edges.map(i=>i.predicate).filter(Boolean))].sort();e.innerHTML= ` < option value = "" > $ { z ( V ( "graph.entity_type_all" ) ) } < / o p t i o n > ` + a . m a p ( i = > ` < o p t i o n v a l u e = " $ { z ( i ) } " $ { i = = = b t . e n t i t y _ t y p e ? " s e l e c t e d " : " " } > $ { z ( i ) } < / o p t i o n > ` ) . j o i n ( " " ) , r . i n n e r H T M L = ` < o p t i o n v a l u e = " " > $ { z ( V ( " g r a p h . p r e d i c a t e _ a l l " ) ) } < / o p t i o n > ` + n . m a p ( i = > ` < o p t i o n v a l u e = " $ { z ( i ) } " $ { i = = = b t . p r e d i c a t e ? " s e l e c t e d " : " " } > $ { z ( i ) } < / o p t i o n > ` ) . j o i n ( " " ) , R b ( a ) } f u n c t i o n R b ( t ) { F ( " g r a p h L e g e n d " ) . i n n e r H T M L = t . s l i c e ( 0 , 1 2 ) . m a p ( e = > `
2026-05-12 19:40:31 +09:00
< span class = "legend-item" > < i style = "background:${ni.get(e)}" > < / i > $ { z ( e ) } < / s p a n >
2026-05-13 19:57:34 +09:00
` ).join("")}function Ab(){const t=bt.min_confidence,e=bt.search,r=bt.entity_type,a=bt.predicate,n=new Set,i=[];for(const l of lr.edges)l.confidence<t||a&&l.predicate!==a||l.target!=null&&(n.add(l.source),n.add(l.target));const s=lr.nodes.filter(l=>r&&l.type!==r||e&&!(l.name||"").toLowerCase().includes(e)&&!(l.canonical_name||"").toLowerCase().includes(e)?!1:bt.predicate||bt.min_confidence>0?n.has(l.id):!0),o=new Set(s.map(l=>l.id));return s.forEach(l=>{i.push({group:"nodes",data:{id: ` n$ { l . id } ` ,entityId:l.id,label:l.name,type:l.type,canonical:l.canonical_name,metadata:l.metadata,color:ni.get(l.type)||"#7aa2ff"}})}),lr.edges.forEach(l=>{l.confidence<t||a&&l.predicate!==a||l.target!=null&&(!o.has(l.source)||!o.has(l.target)||i.push({group:"edges",data:{id: ` c$ { l . claim _id } ` ,claimId:l.claim_id,source: ` n$ { l . source } ` ,target: ` n$ { l . target } ` ,predicate:l.predicate,confidence:l.confidence,metadata:l.metadata,targetName:l.object?.name}}))}),{elements:i,visibleNodeCount:s.length}}function _o(){const{elements:t,visibleNodeCount:e}=Ab();Lb(e);const r=F("graphEmpty");lr.nodes.length?r.style.display="none":r.style.display="flex",Qt?(Qt.elements().remove(),Qt.add(t),iv()):(Qt=Xr({container:F("graphContainer"),elements:t,wheelSensitivity:.2,style:Mb(),layout:sv(bt.layout)}),Qt.on("tap","node",a=>{const n=a.target.data();ue.selection={kind:"graph_node",data:n},ur()}),Qt.on("tap","edge",a=>{const n=a.target.data();ue.selection={kind:"graph_edge",data:n},ur()}))}function kn(){if(!Qt)return _o();_o()}function iv(){Qt&&Qt.layout(sv(bt.layout)).run()}function sv(t){return t==="cose"?{name:"cose",animate:!1,idealEdgeLength:110,nodeRepulsion:16e3,padding:40}:t==="concentric"?{name:"concentric",concentric:e=>e.degree(!1),levelWidth:()=>1,animate:!1,padding:30}:t==="breadthfirst"?{name:"breadthfirst",directed:!0,animate:!1,padding:30,spacingFactor:1.2}:{name:t,animate:!1,padding:30}}function Lb(t){const e=lr.nodes.length,r=lr.edges.length;F("graphStats").textContent= ` $ { e } $ { V ( "graph.stats.nodes" ) } · $ { r } $ { V ( "graph.stats.edges" ) } · $ { t } $ { V ( "graph.stats.shown" ) } ` }function Mb(){return[{selector:"node",style:{"background-color":"data(color)",label:"data(label)",color:"#e6ecf3","font-size":11,"text-outline-color":"#0f1216","text-outline-width":2,"text-valign":"bottom","text-margin-y":6,width:24,height:24,"border-width":1,"border-color":"#0f1216"}},{selector:"node:selected",style:{"border-color":"#ffffff","border-width":2,width:28,height:28}},{selector:"edge",style:{width:"mapData(confidence, 0, 1, 1, 4)","line-color":"#364154","target-arrow-color":"#364154","target-arrow-shape":"triangle","curve-style":"bezier",label:"data(predicate)","font-size":9,color:"#8c98ab","text-rotation":"autorotate","text-background-color":"#0f1216","text-background-opacity":.85,"text-background-padding":2,"arrow-scale":.8}},{selector:"edge:selected",style:{"line-color":"#7aa2ff","target-arrow-color":"#7aa2ff",color:"#7aa2ff",width:3}}]}let Si=[],_t=[],Ot=null;const wt=new Set,sr={status:"",predicate:"",search:""};let Pn=null;function _b(){return `
2026-05-12 19:40:31 +09:00
< section id = "claims" class = "tab-panel" >
< div class = "workbench" >
< div class = "workbench-toolbar" >
< select id = "wbStatusFilter" >
< option value = "" data - i18n = "workbench.status.all" > < / o p t i o n >
< option value = "active" data - i18n = "workbench.status.active" > < / o p t i o n >
< option value = "validated_claim" data - i18n = "workbench.status.validated_claim" > < / o p t i o n >
< option value = "rejected" data - i18n = "workbench.status.rejected" > < / o p t i o n >
< / s e l e c t >
< select id = "wbPredicateFilter" >
< option value = "" data - i18n = "workbench.predicate_all" > < / o p t i o n >
< / s e l e c t >
< input id = "wbSearch" type = "search" data - i18n - placeholder = "workbench.search_placeholder" / >
< span class = "wb-selected" id = "wbSelectedCount" > < / s p a n >
< button id = "wbBulkAcceptBtn" class = "wb-success" disabled data - i18n = "workbench.action.accept" > < / b u t t o n >
< button id = "wbBulkRejectBtn" class = "wb-danger" disabled data - i18n = "workbench.action.reject" > < / b u t t o n >
< / d i v >
< div class = "workbench-body" >
< div class = "workbench-list" id = "wbList" > < / d i v >
< div class = "workbench-detail" id = "wbDetail" > < / d i v >
< / d i v >
< div class = "workbench-shortcuts" >
< strong data - i18n = "workbench.shortcuts" > < / s t r o n g >
< span data - i18n = "workbench.shortcut.nav" > < / s p a n >
< span data - i18n = "workbench.shortcut.accept" > < / s p a n >
< span data - i18n = "workbench.shortcut.reject" > < / s p a n >
< span data - i18n = "workbench.shortcut.toggle" > < / s p a n >
< span data - i18n = "workbench.shortcut.bulk_accept" > < / s p a n >
< span data - i18n = "workbench.shortcut.bulk_reject" > < / s p a n >
< span data - i18n = "workbench.shortcut.search" > < / s p a n >
< span data - i18n = "workbench.shortcut.escape" > < / s p a n >
< / d i v >
< / d i v >
< / s e c t i o n >
2026-05-13 19:57:34 +09:00
` }function Ib(){const t=F("claims");xt(t),fr(()=>{xt(t),Er()}),F("wbStatusFilter").addEventListener("change",e=>{sr.status=e.target.value,Er()}),F("wbPredicateFilter").addEventListener("change",e=>{sr.predicate=e.target.value,Er()}),F("wbSearch").addEventListener("input",e=>{sr.search=e.target.value.trim().toLowerCase(),Er()}),F("wbBulkAcceptBtn").addEventListener("click",()=>ii("validated_claim")),F("wbBulkRejectBtn").addEventListener("click",()=>ii("rejected")),Hb()}async function Ta(){if(!ue.selectedProject)return;const t=encodeURIComponent(ue.selectedProject),[e,r]=await Promise.all([Fe( ` / projects / $ { t } / claims ? limit = 200 & include _candidates = true ` ),Fe( ` / projects / $ { t } / claims ? limit = 200 & status = rejected ` ).catch(()=>[])]),a=new Map;for(const n of[...e,...r])a.set(n.id,n);Si=[...a.values()].sort((n,i)=>(i.last_seen_at??"").localeCompare(n.last_seen_at??"")),Ob(),Er()}function Ob(){const t=F("wbPredicateFilter");if(!t)return;const e=[...new Set(Si.map(a=>a.predicate).filter(Boolean))].sort(),r=sr.predicate;t.innerHTML= ` < option value = "" > $ { z ( V ( "workbench.predicate_all" ) ) } < / o p t i o n > ` + e . m a p ( a = > ` < o p t i o n v a l u e = " $ { z ( a ) } " $ { a = = = r ? " s e l e c t e d " : " " } > $ { z ( a ) } < / o p t i o n > ` ) . j o i n ( " " ) } f u n c t i o n N b ( ) { c o n s t t = s r . s e a r c h ; _ t = S i . f i l t e r ( e = > ! ( s r . s t a t u s & & e . s t a t u s ! = = s r . s t a t u s | | s r . p r e d i c a t e & & e . p r e d i c a t e ! = = s r . p r e d i c a t e | | t & & ! ` $ { e . s u b j e c t ? ? " " } $ { e . p r e d i c a t e ? ? " " } $ { e . o b j e c t ? ? " " } $ { e . e v i d e n c e _ t e x t ? ? " " } ` . t o L o w e r C a s e ( ) . i n c l u d e s ( t ) ) ) , _ t . s o m e ( e = > e . i d = = = O t ) | | ( O t = _ t [ 0 ] ? . i d ? ? n u l l ) ; f o r ( c o n s t e o f [ . . . w t ] ) _ t . s o m e ( r = > r . i d = = = e ) | | w t . d e l e t e ( e ) } f u n c t i o n E r ( ) { N b ( ) , o v ( ) , l v ( ) , u v ( ) } f u n c t i o n o v ( ) { c o n s t t = F ( " w b L i s t " ) ; i f ( ! _ t . l e n g t h ) { t . i n n e r H T M L = ` < d i v c l a s s = " w b - e m p t y m u t e d " d a t a - i 1 8 n = " w o r k b e n c h . e m p t y " > $ { z ( V ( " w o r k b e n c h . e m p t y " ) ) } < / d i v > ` ; r e t u r n } t . i n n e r H T M L = _ t . m a p ( e = > z b ( e ) ) . j o i n ( " " ) , t . q u e r y S e l e c t o r A l l ( " [ d a t a - c l a i m - r o w ] " ) . f o r E a c h ( e = > { c o n s t r = N u m b e r ( e . d a t a s e t . c l a i m R o w ) ; e . a d d E v e n t L i s t e n e r ( " c l i c k " , a = > { a . s h i f t K e y | | a . c t r l K e y | | a . m e t a K e y ? c v ( r ) : ( O t = r , w t . c l e a r ( ) , w t . a d d ( r ) ) , o v ( ) , l v ( ) , u v ( ) , n d ( ) } ) } ) , n d ( ) } f u n c t i o n z b ( t ) { c o n s t e = t . i d = = = O t , r = w t . h a s ( t . i d ) , a = ` w o r k b e n c h . s t a t u s . $ { t . s t a t u s ? ? " a c t i v e " } ` ; r e t u r n `
2026-05-12 19:40:31 +09:00
< button class = "wb-row ${e?" active ":" "} ${r?" selected ":" "}"
data - claim - row = "${t.id}" data - status = "${z(t.status??" active ")}" >
< span class = "wb-row-main" >
< strong > $ { z ( t . subject ? ? "" ) } < / s t r o n g >
< em class = "predicate" > $ { z ( t . predicate ? ? "" ) } < / e m >
< span > $ { z ( t . object ? ? "" ) } < / s p a n >
< / s p a n >
< span class = "wb-row-meta" >
< span class = "wb-status" data - status = "${z(t.status??" active ")}" > $ { z ( V ( a , t . status ? ? "" ) ) } < / s p a n >
< span class = "wb-confidence" > $ { Math . round ( ( t . confidence ? ? 0 ) * 100 ) } % < / s p a n >
< / s p a n >
< / b u t t o n >
2026-05-13 19:57:34 +09:00
` }function lv(){const t=F("wbDetail"),e=_t.find(n=>n.id===Ot);if(!e){t.innerHTML= ` < div class = "wb-empty muted" > $ { z ( V ( "workbench.select_hint" ) ) } < / d i v > ` ; r e t u r n } c o n s t r = ` w o r k b e n c h . s t a t u s . $ { e . s t a t u s ? ? " a c t i v e " } ` , a = e . c o n f i d e n c e _ b r e a k d o w n ? ` L L M $ { B n ( e . c o n f i d e n c e _ b r e a k d o w n . l l m _ c o n f i d e n c e ) } · e v i d e n c e $ { B n ( e . c o n f i d e n c e _ b r e a k d o w n . e v i d e n c e _ c o n f i d e n c e ) } · o n t o l o g y $ { B n ( e . c o n f i d e n c e _ b r e a k d o w n . o n t o l o g y _ c o n f i d e n c e ) } · s t o r e d $ { B n ( e . c o n f i d e n c e _ b r e a k d o w n . s t o r e d _ c o n f i d e n c e ? ? e . c o n f i d e n c e ) } ` : " " ; t . i n n e r H T M L = `
2026-05-12 19:40:31 +09:00
< div class = "wb-detail-head" >
< div >
< h3 > $ { z ( e . subject ? ? "" ) } < span class = "predicate" > $ { z ( e . predicate ? ? "" ) } < / s p a n > $ { z ( e . o b j e c t ? ? " " ) } < / h 3 >
< div class = "wb-detail-status" >
< span class = "wb-status" data - status = "${z(e.status??" active ")}" > $ { z ( V ( r , e . status ? ? "" ) ) } < / s p a n >
< span class = "wb-confidence" > $ { Math . round ( ( e . confidence ? ? 0 ) * 100 ) } % < / s p a n >
< / d i v >
< / d i v >
< div class = "wb-actions" >
< button class = "wb-success" data - action = "accept" > $ { z ( V ( "workbench.action.accept" ) ) } < kbd > A < / k b d > < / b u t t o n >
< button class = "wb-danger" data - action = "reject" > $ { z ( V ( "workbench.action.reject" ) ) } < kbd > R < / k b d > < / b u t t o n >
< button data - action = "unreview" > $ { z ( V ( "workbench.action.unreview" ) ) } < / b u t t o n >
< / d i v >
< / d i v >
< dl class = "wb-kv" >
< dt > $ { z ( V ( "workbench.detail.subject" ) ) } < / d t > < d d > $ { z ( e . s u b j e c t ? ? " " ) } < s p a n c l a s s = " m u t e d " > ( $ { z ( e . s u b j e c t _ t y p e ? ? " " ) } ) < / s p a n > < / d d >
< dt > $ { z ( V ( "workbench.detail.predicate" ) ) } < / d t > < d d > $ { z ( e . p r e d i c a t e ? ? " " ) } < / d d >
< dt > $ { z ( V ( "workbench.detail.object" ) ) } < / d t > < d d > $ { z ( e . o b j e c t ? ? J S O N . s t r i n g i f y ( e . o b j e c t _ v a l u e ? ? " " ) ) } < / d d >
< dt > $ { z ( V ( "workbench.detail.source" ) ) } < / d t > < d d > $ { z ( e . s o u r c e ? ? " " ) } < / d d >
< dt > $ { z ( V ( "workbench.detail.page" ) ) } < / d t > < d d > $ { e . p a g e _ u r l ? ` < a h r e f = " $ { z ( e . p a g e _ u r l ) } " t a r g e t = " _ b l a n k " r e l = " n o r e f e r r e r " > $ { z ( e . p a g e _ u r l ) } < / a > ` : " - " } < / d d >
$ { a ? ` <dt> ${ z ( V ( "workbench.detail.breakdown" ) ) } </dt><dd> ${ z ( a ) } </dd> ` : "" }
< / d l >
$ { e . evidence _text ? `
< section class = "wb-evidence" >
< h4 > $ { z ( V ( "workbench.detail.evidence" ) ) } < / h 4 >
< pre > $ { $b ( e . evidence _text , e ) } < / p r e >
< / s e c t i o n >
` :""}
< div class = "wb-confidence-edit" >
< label > $ { z ( V ( "workbench.detail.confidence" ) ) }
< input id = "wbConfidence" type = "number" min = "0" max = "1" step = "0.01" value = "${e.confidence??0}" / >
< / l a b e l >
< input id = "wbReason" data - i18n - placeholder = "workbench.detail.reason_placeholder" value = "${z(e.confidence_reason??" ")}" / >
< button data - action = "save-confidence" > $ { z ( V ( "workbench.action.save_confidence" ) ) } < / b u t t o n >
< button data - action = "accept-similar" > $ { z ( V ( "workbench.action.accept_similar" ) ) } < / b u t t o n >
< / d i v >
2026-05-13 19:57:34 +09:00
` ,xt(t),t.querySelectorAll("[data-action]").forEach(n=>{n.addEventListener("click",()=>Io(n.dataset.action))})}function $ b(t,e){const r=[];e.subject&&r.push(e.subject),e.object&&r.push(e.object);let a=z(t);for(const n of r){if(!n||n.length<2)continue;const i=Fb(n);a=a.replace(new RegExp(i,"gi"),s=> ` < mark > $ { s } < /mark>`)}return a}function Fb(t){return t.replace(/ [ . * + ? ^ $ { } ( ) | [ \ ] \ \ ] / g , "\\$&" ) } function uv ( ) { const t = wt . size ; F ( "wbSelectedCount" ) . textContent = t > 1 ? V ( "workbench.bulk_count" ) . replace ( "{count}" , t ) : "" ; const e = t > 1 ; F ( "wbBulkAcceptBtn" ) . disabled = ! e , F ( "wbBulkRejectBtn" ) . disabled = ! e } function Bn ( t ) { return t == null ? "-" : ` ${ Math . round ( t * 100 ) } % ` } function cv ( t ) { wt . has ( t ) ? wt . delete ( t ) : wt . add ( t ) , wt . size === 1 && ( Ot = [ ... wt ] [ 0 ] ) } function nd ( ) { const t = document . querySelector ( ` [data-claim-row=" ${ Ot } "] ` ) ; t && t . scrollIntoView ( { block : "nearest" } ) } async function Io ( t ) { const e = _t . find ( r => r . id === Ot ) ; e && ( t === "accept" ? await oo ( e . id , "validated_claim" ) : t === "reject" ? await oo ( e . id , "rejected" ) : t === "unreview" ? await oo ( e . id , "active" ) : t === "save-confidence" ? await qb ( e ) : t === "accept-similar" && await Vb ( e ) ) } async function oo ( t , e ) { const r = F ( "wbReason" ) ? . value ? . trim ( ) || null ; try { await Fe ( ` /claims/ ${ t } /status ` , { method : "PATCH" , body : JSON . stringify ( { status : e , reason : r } ) } ) , Ae ( V ( "workbench.toast.reviewed" ) ) , await Ta ( ) } catch ( a ) { Ae ( a . message ) } } async function qb ( t ) { const e = Number ( F ( "wbConfidence" ) . value ) , r = F ( "wbReason" ) . value . trim ( ) || null ; try { await Fe ( ` /claims/ ${ t . id } /confidence ` , { method : "PATCH" , body : JSON . stringify ( { confidence : e , reason : r } ) } ) , Ae ( V ( "toast.claim_updated" ) ) , await Ta ( ) } catch ( a ) { Ae ( a . message ) } } async function Vb ( t ) { const e = t . object ? ? JSON . stringify ( t . object _value ? ? "" ) , r = Si . filter ( a => a . predicate === t . predicate && ( a . object ? ? JSON . stringify ( a . object _value ? ? "" ) ) === e ) . map ( a => a . id ) ; if ( r . length ) try { const a = await Fe ( "/claims/bulk-status" , { method : "POST" , body : JSON . stringify ( { claim _ids : r , status : "validated_claim" , reason : F ( "wbReason" ) ? . value ? . trim ( ) || null } ) } ) ; Ae ( V ( "workbench.toast.bulk_done" ) . replace ( "{count}" , a . updated ? ? r . length ) ) , await Ta ( ) } catch ( a ) { Ae ( a . message ) } } async function ii ( t ) { const e = [ ... wt ] ; if ( ! ( e . length < 2 ) ) try { const r = await Fe ( "/claims/bulk-status" , { method : "POST" , body : JSON . stringify ( { claim _ids : e , status : t , reason : null } ) } ) ; Ae ( V ( "workbench.toast.bulk_done" ) . replace ( "{count}" , r . updated ? ? e . length ) ) , wt . clear ( ) , await Ta ( ) } catch ( r ) { Ae ( r . message ) } } function Hb ( ) { Pn && document . removeEventListener ( "keydown" , Pn ) , Pn = t => { if ( ! Gb ( ) || t . target . matches ( "input, textarea, select" ) ) return ; const e = t . key ; if ( e === "j" || e === "ArrowDown" ) { t . preventDefault ( ) , id ( 1 ) ; return } if ( e === "k" || e === "ArrowUp" ) { t . preventDefault ( ) , id ( - 1 ) ; return } if ( e === " " ) { t . preventDefault ( ) , Ot != null && ( cv ( Ot ) , Er ( ) ) ; return } if ( e === "Escape" ) { wt . clear ( ) , Er ( ) ; return } if ( e === "/" ) { t . preventDefault ( ) , F ( "wbSearch" ) ? . focus ( ) ; return } if ( e === "a" && ! t . shiftKey ) { t . preventDefault ( ) , Io ( "accept" ) ; return } if ( e === "r" && ! t . shiftKey ) { t . preventDefault ( ) , Io ( "reject" ) ; return } if ( t . shiftKey && ( e === "A" || e === "a" ) ) { t . preventDefault ( ) , ii ( "validated_claim" ) ; return } if ( t . shiftKey && ( e === "R" || e === "r" ) ) { t . preventDefault ( ) , ii ( "rejected" ) ; return } } , document . addEventListener ( "keydown" , Pn ) } function Gb ( ) { const t = F ( "claims" ) ; return t && t . classList . contains ( "active" ) } function id ( t ) { if ( ! _t . length ) return ; let r = _t . findIndex ( a => a . id === Ot ) + t ; r < 0 && ( r = 0 ) , r >= _t . length && ( r = _t . length - 1 ) , Ot = _t [ r ] . id , wt . clear ( ) , wt . add ( Ot ) , Er ( ) } let qr = null ; function Ub ( ) { return `
2026-05-12 19:40:31 +09:00
< section id = "overview" class = "tab-panel active" >
< div class = "pipeline-head" >
< h2 data - i18n = "pipeline.heading" > < / h 2 >
< button id = "pipelineRefreshBtn" class = "ghost" data - i18n = "pipeline.refresh" > < / b u t t o n >
< / d i v >
< div class = "pipeline-stages" id = "pipelineStages" > < / d i v >
< div class = "summary-grid" id = "pipelineSummary" > < / d i v >
< div class = "wide-panel" >
< h2 data - i18n = "pipeline.entity_types_heading" > < / h 2 >
< div id = "pipelineEntityTypes" class = "entity-type-bars" > < / d i v >
< / d i v >
< div class = "split" >
< div class = "wide-panel" >
< h2 data - i18n = "pipeline.recent_pages" > < / h 2 >
< div id = "pipelineRecentPages" class = "recent-list" > < / d i v >
< / d i v >
< div class = "wide-panel" >
< h2 data - i18n = "pipeline.recent_claims" > < / h 2 >
< div id = "pipelineRecentClaims" class = "recent-list" > < / d i v >
< / d i v >
< / d i v >
< div class = "wide-panel" >
< h2 data - i18n = "overview.sources_heading" > < / h 2 >
< div id = "sourceTable" class = "table" > < / d i v >
< / d i v >
< / s e c t i o n >
2026-05-13 19:57:34 +09:00
` }function Kb(){const t=F("overview");xt(t),F("pipelineRefreshBtn").addEventListener("click",()=>yl().catch(()=>{})),fr(()=>{xt(t),dv()})}async function yl(){ue.selectedProject&&(qr=await Fe( ` / projects / $ { encodeURIComponent ( ue . selectedProject ) } / pipeline ` ),dv())}function dv(){qr&&(jb(qr.stages||[]),Xb(qr.stages||[]),Zb(qr.entity_types||[]),Qb(qr.recent_pages||[]),Jb(qr.recent_claims||[]))}const Wb={crawled:"#7aa2ff",extracted:"#22d3ee",claims:"#facc15",validated:"#4ade80",graph:"#a78bfa"};function jb(t){const e=Math.max(1,...t.map(a=>a.count||0)),r=F("pipelineStages");r.innerHTML=t.map((a,n)=>{const i=n>0?t[n-1].count:null,s=i&&i>0?Math.round(a.count/i*100):null,o=a.count/e*100,l=Wb[a.key]||"#7aa2ff",u=Yb(a);return `
2026-05-12 19:40:31 +09:00
< div class = "pipeline-card" style = "--stage-color:${l}" >
< div class = "pipeline-card-head" >
< span class = "pipeline-stage-name" > $ { z ( V ( ` pipeline.stage. ${ a . key } ` , a . key ) ) } < / s p a n >
$ { s != null ? ` <span class="pipeline-retention"> ${ s } % ${ z ( V ( "pipeline.retained" ) ) } </span> ` : "" }
< / d i v >
< div class = "pipeline-count" > $ { a . count } < / d i v >
< div class = "pipeline-bar" > < div class = "pipeline-bar-fill" style = "width:${o}%" > < / d i v > < / d i v >
$ { u ? ` <div class="pipeline-extra muted"> ${ u } </div> ` : "" }
< / d i v >
2026-05-13 19:57:34 +09:00
` }).join("")}function Yb(t){return t.extra?t.key==="extracted"? ` events $ { t . extra . events ? ? 0 } · errors $ { t . extra . errors ? ? 0 } ` :t.key==="claims"?Object.entries(t.extra).map(([e,r])=> ` $ { z ( e ) } $ { r } ` ).join(" · "):t.key==="graph"? ` entities $ { t . extra . entities ? ? 0 } ` :"":""}function Xb(t){const e=ue.projectDetail,r=t.find(n=>n.key==="claims"),a=t.find(n=>n.key==="validated");F("pipelineSummary").innerHTML= `
2026-05-12 19:40:31 +09:00
< div class = "metric" > < span > $ { z ( V ( "overview.project" ) ) } < / s p a n > < s t r o n g > $ { z ( e ? . n a m e ? ? " - " ) } < / s t r o n g > < / d i v >
< div class = "metric" > < span > $ { z ( V ( "overview.domain" ) ) } < / s p a n > < s t r o n g > $ { z ( e ? . d o m a i n ? ? " - " ) } < / s t r o n g > < / d i v >
< div class = "metric" > < span > $ { z ( V ( "overview.sources" ) ) } < / s p a n > < s t r o n g > $ { ( e ? . s o u r c e s ? ? [ ] ) . l e n g t h } < / s t r o n g > < / d i v >
< div class = "metric" > < span > $ { z ( V ( "overview.entities" ) ) } < / s p a n > < s t r o n g i d = " m e t r i c E n t i t i e s " > $ { t . f i n d ( n = > n . k e y = = = " g r a p h " ) ? . e x t r a ? . e n t i t i e s ? ? 0 } < / s t r o n g > < / d i v >
< div class = "metric" > < span > $ { z ( V ( "pipeline.stage.claims" ) ) } < / s p a n > < s t r o n g > $ { r ? . c o u n t ? ? 0 } < / s t r o n g > < / d i v >
< div class = "metric" > < span > $ { z ( V ( "pipeline.stage.validated" ) ) } < / s p a n > < s t r o n g > $ { a ? . c o u n t ? ? 0 } < / s t r o n g > < / d i v >
2026-05-13 19:57:34 +09:00
` }function Zb(t){const e=F("pipelineEntityTypes");if(!t.length){e.innerHTML= ` < p class = "muted" style = "font-size:11px;margin:0" > $ { z ( V ( "pipeline.empty.claims" ) ) } < / p > ` ; r e t u r n } c o n s t r = M a t h . m a x ( 1 , . . . t . m a p ( a = > a . c o u n t ) ) ; e . i n n e r H T M L = t . m a p ( a = > { c o n s t n = a . c o u n t / r * 1 0 0 ; r e t u r n `
2026-05-12 19:40:31 +09:00
< div class = "entity-type-row" >
< span class = "entity-type-name" > $ { z ( a . type ) } < / s p a n >
< div class = "entity-type-bar" > < div class = "entity-type-bar-fill" style = "width:${n}%" > < / d i v > < / d i v >
< span class = "entity-type-count" > $ { a . count } < / s p a n >
< / d i v >
2026-05-13 19:57:34 +09:00
` }).join("")}function Qb(t){const e=F("pipelineRecentPages");if(!t.length){e.innerHTML= ` < p class = "muted" style = "font-size:11px;margin:0" > $ { z ( V ( "pipeline.empty.pages" ) ) } < / p > ` ; r e t u r n } e . i n n e r H T M L = t . m a p ( r = > `
2026-05-12 19:40:31 +09:00
< div class = "recent-item" >
< div class = "recent-line" >
< span class = "recent-badge" > $ { z ( r . page _type ? ? "" ) } < / s p a n >
< span class = "recent-code" > $ { z ( r . status _code ? ? "-" ) } < / s p a n >
< span class = "recent-time" > $ { z ( fv ( r . fetched _at ) ) } < / s p a n >
< / d i v >
< div class = "recent-title" > $ { z ( r . title ? ? r . url ? ? "" ) } < / d i v >
< a class = "recent-url" href = "${z(r.url??" ")}" target = "_blank" rel = "noreferrer" > $ { z ( r . url ? ? "" ) } < / a >
< / d i v >
2026-05-13 19:57:34 +09:00
` ).join("")}function Jb(t){const e=F("pipelineRecentClaims");if(!t.length){e.innerHTML= ` < p class = "muted" style = "font-size:11px;margin:0" > $ { z ( V ( "pipeline.empty.claims" ) ) } < / p > ` ; r e t u r n } e . i n n e r H T M L = t . m a p ( r = > `
2026-05-12 19:40:31 +09:00
< div class = "recent-item" >
< div class = "recent-line" >
< strong > $ { z ( r . subject ? ? "" ) } < / s t r o n g >
< span class = "recent-predicate" > $ { z ( r . predicate ? ? "" ) } < / s p a n >
< / d i v >
< div class = "recent-line" >
< span class = "wb-status" data - status = "${z(r.status??" active ")}" > $ { z ( r . status ? ? "" ) } < / s p a n >
< span class = "recent-conf" > $ { Math . round ( ( r . confidence ? ? 0 ) * 100 ) } % < / s p a n >
< span class = "recent-time" > $ { z ( fv ( r . last _seen _at ) ) } < / s p a n >
< / d i v >
< / d i v >
2026-05-13 19:57:34 +09:00
` ).join("")}function fv(t){if(!t)return"";const e=new Date(t);if(isNaN(e.getTime()))return"";const a=(Date.now()-e.getTime())/1e3;return a<60? ` $ { Math . floor ( a ) } s ` :a<3600? ` $ { Math . floor ( a / 60 ) } m ` :a<86400? ` $ { Math . floor ( a / 3600 ) } h ` : ` $ { Math . floor ( a / 86400 ) } d ` }function ew(t){const e=F("sourceTable");if(!e)return;const r=t?.sources??[];if(!r.length){e.innerHTML= ` < table > < tbody > < tr > < td class = "muted" > $ { z ( V ( "table.no_data" ) ) } < / t d > < / t r > < / t b o d y > < / t a b l e > ` ; r e t u r n } e . i n n e r H T M L = `
2026-05-12 19:40:31 +09:00
< table >
< thead > < tr >
< th > $ { z ( V ( "table.name" ) ) } < / t h >
< th > $ { z ( V ( "table.type" ) ) } < / t h >
< th > $ { z ( V ( "table.trust" ) ) } < / t h >
< th > $ { z ( V ( "table.robots" ) ) } < / t h >
< th > $ { z ( V ( "table.rate" ) ) } < / t h >
< / t r > < / t h e a d >
< tbody > $ { r . map ( a => `
< tr >
< td > $ { z ( a . name ) } < / t d >
< td > $ { z ( a . type ) } < / t d >
< td > $ { a . trust _level } < / t d >
< td > $ { a . respect _robots _txt ? "on" : "off" } < / t d >
< td > $ { a . rate _limit _per _minute } / min < / t d >
< / t r >
` ).join("")}</tbody>
< / t a b l e >
2026-05-13 19:57:34 +09:00
` }let Dn=null;function tw(t){Dn=t,Dn.innerHTML=rw(),xt(Dn),document.querySelectorAll(".tab").forEach(e=>{e.addEventListener("click",()=>{document.querySelectorAll(".tab").forEach(r=>r.classList.remove("active")),document.querySelectorAll(".tab-panel").forEach(r=>r.classList.remove("active")),e.classList.add("active"),document.getElementById(e.dataset.tab).classList.add("active")})}),Pb(),Ib(),Kb(),F("loadOntologyRegistryBtn").addEventListener("click",Oo),F("loadEntitiesBtn").addEventListener("click",No),F("mergeEntitiesBtn").addEventListener("click",aw),F("loadExtractionLogsBtn").addEventListener("click",zo),F("runResearchBtn").addEventListener("click",iw),F("loadResearchBtn").addEventListener("click", $ o),F("loadGraphQueryBtn").addEventListener("click",Fo),F("loadTagsBtn").addEventListener("click",qo),F("recommendBtn").addEventListener("click",lw),fr(()=>{xt(Dn),vv(),hv(),yl().catch(()=>{}),Oo().catch(()=>{}),No().catch(()=>{}),Ta().catch(()=>{}),zo().catch(()=>{}), $ o().catch(()=>{}),Fo().catch(()=>{}),qo().catch(()=>{}),gl().catch(()=>{})})}function rw(){return `
2026-05-12 19:40:31 +09:00
< nav class = "tabs" aria - label = "Admin sections" >
< button class = "tab active" data - tab = "overview" data - i18n = "tabs.overview" > < / b u t t o n >
< button class = "tab" data - tab = "graph" data - i18n = "tabs.graph" > < / b u t t o n >
< button class = "tab" data - tab = "ontology" data - i18n = "tabs.ontology" > < / b u t t o n >
< button class = "tab" data - tab = "entities" data - i18n = "tabs.entities" > < / b u t t o n >
< button class = "tab" data - tab = "claims" data - i18n = "tabs.claims" > < / b u t t o n >
< button class = "tab" data - tab = "debug" data - i18n = "tabs.debug" > < / b u t t o n >
< button class = "tab" data - tab = "research" data - i18n = "tabs.research" > < / b u t t o n >
< button class = "tab" data - tab = "tags" data - i18n = "tabs.tags" > < / b u t t o n >
< button class = "tab" data - tab = "recommend" data - i18n = "tabs.recommend" > < / b u t t o n >
< / n a v >
$ { kb ( ) }
$ { Ub ( ) }
< section id = "ontology" class = "tab-panel" >
< div class = "toolbar" >
< button id = "loadOntologyRegistryBtn" data - i18n = "ontology.refresh_registry" > < / b u t t o n >
< / d i v >
< div class = "split" >
< div class = "wide-panel" >
< h2 data - i18n = "ontology.configured_entity_types" > < / h 2 >
< div id = "ontologyEntities" class = "chips" > < / d i v >
< / d i v >
< div class = "wide-panel" >
< h2 data - i18n = "ontology.configured_predicates" > < / h 2 >
< div id = "ontologyPredicates" class = "chips" > < / d i v >
< / d i v >
< / d i v >
< div class = "split" >
< div class = "wide-panel" >
< h2 data - i18n = "ontology.registry_entity_types" > < / h 2 >
< div id = "ontologyRegistryEntityTable" class = "table" > < / d i v >
< / d i v >
< div class = "wide-panel" >
< h2 data - i18n = "ontology.registry_relation_types" > < / h 2 >
< div id = "ontologyRegistryRelationTable" class = "table" > < / d i v >
< / d i v >
< / d i v >
< div class = "wide-panel" >
< h2 data - i18n = "ontology.triples" > < / h 2 >
< div id = "ontologyTripleTable" class = "table" > < / d i v >
< / d i v >
< div class = "split" >
< div class = "wide-panel" >
< h2 data - i18n = "ontology.proposals" > < / h 2 >
< div id = "ontologyProposalTable" class = "table" > < / d i v >
< / d i v >
< div class = "wide-panel" >
< h2 data - i18n = "ontology.knowledge_gaps" > < / h 2 >
< div id = "knowledgeGapTable" class = "table" > < / d i v >
< / d i v >
< / d i v >
< / s e c t i o n >
< section id = "entities" class = "tab-panel" >
< div class = "toolbar wrap" >
< select id = "entityTypeFilter" > < / s e l e c t >
< button id = "loadEntitiesBtn" data - i18n = "entities.load" > < / b u t t o n >
< / d i v >
< div class = "merge-bar" >
< input id = "mergeSourceId" data - i18n - placeholder = "entities.merge_source_placeholder" data - i18n - aria - label = "entities.merge_source_placeholder" / >
< input id = "mergeTargetId" data - i18n - placeholder = "entities.merge_target_placeholder" data - i18n - aria - label = "entities.merge_target_placeholder" / >
< button id = "mergeEntitiesBtn" data - i18n = "entities.merge" > < / b u t t o n >
< / d i v >
< div id = "entityTable" class = "table" > < / d i v >
< / s e c t i o n >
$ { _b ( ) }
< section id = "debug" class = "tab-panel" >
< div class = "toolbar" >
< button id = "loadExtractionLogsBtn" data - i18n = "debug.refresh_logs" > < / b u t t o n >
< / d i v >
< div id = "extractionLogTable" class = "claim-list" > < / d i v >
< / s e c t i o n >
< section id = "research" class = "tab-panel" >
< div class = "wide-panel" >
< h2 data - i18n = "research.heading" > < / h 2 >
< div class = "recommend-grid" >
< label >
< span data - i18n = "research.goal" > < / s p a n >
< input id = "researchGoal" value = "Forment perfume ecosystem exploration" / >
< / l a b e l >
< label >
< span data - i18n = "research.seed_entity" > < / s p a n >
< input id = "researchSeedEntityId" placeholder = "optional entity id" / >
< / l a b e l >
< label >
< span data - i18n = "research.max_steps" > < / s p a n >
< input id = "researchMaxSteps" type = "number" min = "1" max = "50" value = "8" / >
< / l a b e l >
< label >
< span data - i18n = "research.min_relevance" > < / s p a n >
< input id = "researchMinRelevance" type = "number" min = "0" max = "1" step = "0.05" value = "0.35" / >
< / l a b e l >
< / d i v >
< div class = "button-grid" >
< button id = "runResearchBtn" class = "primary" data - i18n = "research.run" > < / b u t t o n >
< button id = "loadResearchBtn" data - i18n = "research.load_sessions" > < / b u t t o n >
< / d i v >
< div id = "researchResult" class = "mini-log" > < / d i v >
< div id = "researchSessions" class = "claim-list" > < / d i v >
< / d i v >
< div class = "wide-panel" >
< h2 data - i18n = "research.graph_query" > < / h 2 >
< div class = "toolbar wrap" >
< select id = "graphQueryKind" >
< option value = "trend_summary" data - i18n = "research.query.trend_summary" > < / o p t i o n >
< option value = "brand_products" data - i18n = "research.query.brand_products" > < / o p t i o n >
< option value = "products_by_tag" data - i18n = "research.query.products_by_tag" > < / o p t i o n >
< option value = "relation_summary" data - i18n = "research.query.relation_summary" > < / o p t i o n >
< option value = "entity_type_summary" data - i18n = "research.query.entity_type_summary" > < / o p t i o n >
< / s e l e c t >
< input id = "graphQueryText" data - i18n - placeholder = "research.filter_placeholder" / >
< button id = "loadGraphQueryBtn" data - i18n = "research.run_query" > < / b u t t o n >
< / d i v >
< div id = "graphQueryTable" class = "table" > < / d i v >
< / d i v >
< / s e c t i o n >
< section id = "tags" class = "tab-panel" >
< div class = "toolbar" >
< button id = "loadTagsBtn" data - i18n = "tags.load" > < / b u t t o n >
< / d i v >
< div id = "tagTable" class = "table" > < / d i v >
< / s e c t i o n >
< section id = "recommend" class = "tab-panel" >
< div class = "recommend-grid" >
< label > < span data - i18n = "recommend.preferred_notes" > < /span><input id="preferredNotes" value="Bergamot, Musk" / > < / l a b e l >
< label > < span data - i18n = "recommend.avoided_notes" > < /span><input id="avoidedNotes" value="" / > < / l a b e l >
< label > < span data - i18n = "recommend.preferred_moods" > < /span><input id="preferredMoods" value="Fresh" / > < / l a b e l >
< label > < span data - i18n = "recommend.season" > < /span><input id="seasonContext" value="Summer" / > < / l a b e l >
< label > < span data - i18n = "recommend.occasion" > < /span><input id="occasionContext" value="Daily" / > < / l a b e l >
< / d i v >
< button id = "recommendBtn" class = "primary" data - i18n = "recommend.test" > < / b u t t o n >
< div id = "recommendTable" class = "table" > < / d i v >
< / s e c t i o n >
2026-05-13 19:57:34 +09:00
` }function vv(){ew(ue.projectDetail)}function hv(){const t=ue.ontology?.entity_types??[],e=ue.ontology?.predicates??[];F("ontologyEntities").innerHTML=t.map(Pl).join(""),F("ontologyPredicates").innerHTML=e.map(Pl).join(""),F("entityTypeFilter").innerHTML= ` < option value = "" > $ { z ( V ( "entities.all_types" ) ) } < / o p t i o n > $ { t . m a p ( r = > ` < o p t i o n v a l u e = " $ { z ( r ) } " > $ { z ( r ) } < / o p t i o n > ` ) . j o i n ( " " ) } ` } a s y n c f u n c t i o n O o ( ) { i f ( ! u e . s e l e c t e d P r o j e c t ) r e t u r n ; c o n s t t = e n c o d e U R I C o m p o n e n t ( u e . s e l e c t e d P r o j e c t ) , [ e , r , a , n ] = a w a i t P r o m i s e . a l l ( [ F e ( ` / p r o j e c t s / $ { t } / o n t o l o g y / r e g i s t r y ` ) , F e ( ` / p r o j e c t s / $ { t } / o n t o l o g y / p r o p o s a l s ? l i m i t = 5 0 ` ) , F e ( ` / p r o j e c t s / $ { t } / k n o w l e d g e - g a p s ? l i m i t = 5 0 ` ) , F e ( ` / p r o j e c t s / $ { t } / o n t o l o g y / t r i p l e s ? l i m i t = 5 0 ` ) ] ) ; F ( " o n t o l o g y R e g i s t r y E n t i t y T a b l e " ) . i n n e r H T M L = M t ( [ V ( " t a b l e . t y p e " ) , V ( " t a b l e . d o m a i n " ) , V ( " t a b l e . s t a t u s " ) , V ( " t a b l e . c o n f i d e n c e " ) ] , ( e . e n t i t y _ t y p e s ? ? [ ] ) . m a p ( i = > [ i . n a m e , i . d o m a i n , i . s t a t u s , M a t h . r o u n d ( ( i . c o n f i d e n c e ? ? 0 ) * 1 0 0 ) + " % " ] ) ) , F ( " o n t o l o g y R e g i s t r y R e l a t i o n T a b l e " ) . i n n e r H T M L = M t ( [ V ( " t a b l e . r e l a t i o n " ) , V ( " t a b l e . d o m a i n " ) , V ( " t a b l e . s u b j e c t " ) , V ( " t a b l e . o b j e c t " ) , V ( " t a b l e . s t a t u s " ) ] , ( e . r e l a t i o n _ t y p e s ? ? [ ] ) . m a p ( i = > [ i . n a m e , i . d o m a i n , ( i . a l l o w e d _ s u b j e c t _ t y p e s ? ? [ ] ) . j o i n ( " , " ) , ( i . a l l o w e d _ o b j e c t _ t y p e s ? ? [ ] ) . j o i n ( " , " ) | | ( i . s e m a n t i c _ c o n s t r a i n t s ? . l i t e r a l _ v a l u e ? " l i t e r a l " : " " ) , i . s t a t u s ] ) ) , F ( " o n t o l o g y P r o p o s a l T a b l e " ) . i n n e r H T M L = M t ( [ V ( " t a b l e . t y p e " ) , V ( " t a b l e . n a m e " ) , V ( " t a b l e . s t a t u s " ) , V ( " t a b l e . r e a s o n " ) ] , ( r ? ? [ ] ) . m a p ( i = > [ i . p r o p o s a l _ t y p e , i . n a m e , i . s t a t u s , z ( i . r e a s o n ? ? " " ) ] ) ) , F ( " k n o w l e d g e G a p T a b l e " ) . i n n e r H T M L = M t ( [ V ( " t a b l e . g a p " ) , V ( " t a b l e . t a r g e t " ) , V ( " t a b l e . p r i o r i t y " ) , V ( " t a b l e . d e s c r i p t i o n " ) ] , ( a ? ? [ ] ) . m a p ( i = > [ i . g a p _ t y p e , ` $ { i . t a r g e t _ t y p e ? ? " " } : $ { i . t a r g e t _ n a m e ? ? " " } ` , M a t h . r o u n d ( ( i . p r i o r i t y ? ? 0 ) * 1 0 0 ) + " % " , z ( i . d e s c r i p t i o n ? ? " " ) ] ) ) , F ( " o n t o l o g y T r i p l e T a b l e " ) . i n n e r H T M L = M t ( [ V ( " t a b l e . s u b j e c t " ) , V ( " t a b l e . r e l a t i o n " ) , V ( " t a b l e . o b j e c t " ) , V ( " t a b l e . s t a t u s " ) , V ( " t a b l e . s u p p o r t " ) ] , ( n ? ? [ ] ) . m a p ( i = > [ i . s u b j e c t ? ? " " , i . p r e d i c a t e , i . o b j e c t ? ? J S O N . s t r i n g i f y ( i . o b j e c t _ v a l u e ? ? " " ) , i . s t a t u s , i . s u p p o r t _ c o u n t ] ) ) } l e t s d = [ ] ; a s y n c f u n c t i o n N o ( ) { i f ( ! u e . s e l e c t e d P r o j e c t ) r e t u r n ; c o n s t t = F ( " e n t i t y T y p e F i l t e r " ) . v a l u e , e = t ? ` ? e n t i t y _ t y p e = $ { e n c o d e U R I C o m p o n e n t ( t ) } & l i m i t = 1 0 0 ` : " ? l i m i t = 1 0 0 " , r = a w a i t F e ( ` / p r o j e c t s / $ { e n c o d e U R I C o m p o n e n t ( u e . s e l e c t e d P r o j e c t ) } / e n t i t i e s $ { e } ` ) ; s d = r , F ( " m e t r i c E n t i t i e s " ) . t e x t C o n t e n t = r . l e n g t h , F ( " e n t i t y T a b l e " ) . i n n e r H T M L = M t ( [ V ( " t a b l e . i d " ) , V ( " t a b l e . t y p e " ) , V ( " t a b l e . n a m e " ) , V ( " t a b l e . m e t a d a t a " ) ] , r . m a p ( a = > [ ` < b u t t o n c l a s s = " r o w - l i n k " d a t a - e n t i t y - i d = " $ { a . i d } " > $ { z ( a . i d ) } < / b u t t o n > ` , a . t y p e , z ( a . n a m e ) , ` < c o d e > $ { z ( J S O N . s t r i n g i f y ( a . m e t a d a t a ? ? { } ) ) } < / c o d e > ` ] ) ) , F ( " e n t i t y T a b l e " ) . q u e r y S e l e c t o r A l l ( " [ d a t a - e n t i t y - i d ] " ) . f o r E a c h ( a = > { a . a d d E v e n t L i s t e n e r ( " c l i c k " , ( ) = > { c o n s t n = N u m b e r ( a . d a t a s e t . e n t i t y I d ) , i = s d . f i n d ( s = > s . i d = = = n ) ; i & & ( u e . s e l e c t i o n = { k i n d : " e n t i t y " , d a t a : i } , u r ( ) ) } ) } ) } a s y n c f u n c t i o n a w ( ) { i f ( ! u e . s e l e c t e d P r o j e c t ) r e t u r n ; c o n s t t = N u m b e r ( F ( " m e r g e S o u r c e I d " ) . v a l u e ) , e = N u m b e r ( F ( " m e r g e T a r g e t I d " ) . v a l u e ) ; i f ( ! t | | ! e | | t = = = e ) { A e ( V ( " t o a s t . m e r g e _ c h e c k " ) ) ; r e t u r n } t r y { c o n s t r = a w a i t F e ( " / e n t i t i e s / m e r g e " , { m e t h o d : " P O S T " , b o d y : J S O N . s t r i n g i f y ( { p r o j e c t _ n a m e : u e . s e l e c t e d P r o j e c t , s o u r c e _ e n t i t y _ i d : t , t a r g e t _ e n t i t y _ i d : e } ) } ) ; i f ( ! r . o k ) { A e ( r . e r r o r ? ? V ( " t o a s t . m e r g e _ c h e c k " ) ) ; r e t u r n } A e ( V ( " t o a s t . e n t i t y _ m e r g e d " ) ) , F ( " m e r g e S o u r c e I d " ) . v a l u e = " " , F ( " m e r g e T a r g e t I d " ) . v a l u e = " " ; c o n s t a = n e w C u s t o m E v e n t ( " w o r k s p a c e : r e f r e s h " ) ; w i n d o w . d i s p a t c h E v e n t ( a ) } c a t c h ( r ) { A e ( r . m e s s a g e ) } } a s y n c f u n c t i o n z o ( ) { i f ( ! u e . s e l e c t e d P r o j e c t ) r e t u r n ; c o n s t t = a w a i t F e ( ` / p r o j e c t s / $ { e n c o d e U R I C o m p o n e n t ( u e . s e l e c t e d P r o j e c t ) } / e x t r a c t i o n - l o g s ? l i m i t = 5 0 ` ) ; F ( " e x t r a c t i o n L o g T a b l e " ) . i n n e r H T M L = t . m a p ( n w ) . j o i n ( " " ) } f u n c t i o n n w ( t ) { c o n s t e = t . v a l i d a t i o n ? ? { } , r = t . p a g e _ c o n t e x t ? ? { } , n = ( e . r e j e c t e d _ c l a i m s ? ? [ ] ) . s l i c e ( 0 , 3 ) . m a p ( i = > ` $ { i . p r e d i c a t e ? ? " " } : $ { i . r e a s o n ? ? " " } ` ) . j o i n ( " | " ) ; r e t u r n `
2026-05-12 19:40:31 +09:00
< article class = "claim-card" >
< div class = "claim-main" >
< strong > $ { z ( t . extractor _name ) } < / s t r o n g >
< span > $ { z ( t . provider ) } < / s p a n >
< span > $ { z ( e . claim _status ? ? "" ) } < / s p a n >
< span > accepted $ { e . accepted _claim _count ? ? 0 } < / s p a n >
< span > rejected $ { e . rejected _claim _count ? ? 0 } < / s p a n >
< / d i v >
< div class = "evidence" > $ { z ( r . page _type ? ? "" ) } / $ { z ( r . crawl _status ? ? "" ) } / $ { z ( r . extraction _status ? ? "" ) } < / d i v >
< div class = "evidence" > $ { z ( t . page _url ? ? "" ) } < / d i v >
< div class = "evidence" > $ { z ( n ) } < / d i v >
< / a r t i c l e >
2026-05-13 19:57:34 +09:00
` }async function iw(){if(!ue.selectedProject)return;F("researchResult").textContent=V("status.research_running");const t=F("researchSeedEntityId").value.trim();try{const e=await Fe("/research/run",{method:"POST",body:JSON.stringify({...Ho(),project_name:ue.selectedProject,seed_entity_id:t?Number(t):null,goal:F("researchGoal").value.trim()||"Semantic ontology exploration",max_depth:Number(F("siteMaxDepth").value||2),max_steps:Number(F("researchMaxSteps").value||8),max_branch:8,min_relevance:Number(F("researchMinRelevance").value||.35),same_domain_only:F("sameDomainOnly").checked,analyze_page_types:["ProductPage","BrandStoryPage","ReviewPage"]})});F("researchResult").textContent= ` Research $ { e . status } : explored $ { e . explored _count } , analyzed $ { e . analyzed _count } , queued $ { e . queued _count } , skipped $ { e . skipped _count } ` ,Ae(V("toast.research_completed"));const r=new CustomEvent("workspace:refresh");window.dispatchEvent(r)}catch(e){F("researchResult").textContent= ` $ { V ( "toast.research_failed" ) } : $ { e . message } ` ,Ae(V("toast.research_failed"))}}async function $ o(){if(!ue.selectedProject)return;const t=await Fe( ` / projects / $ { encodeURIComponent ( ue . selectedProject ) } / research / sessions ? limit = 20 ` );F("researchSessions").innerHTML=t.map(sw).join("")}function sw(t){const e=t.history??[],r=e.length?e[e.length-1]:null,n=(t.memory??{}).conflicts??[];return `
2026-05-12 19:40:31 +09:00
< article class = "claim-card" >
< div class = "claim-main" >
< strong > $ { z ( t . name ? ? "Research session" ) } < / s t r o n g >
< span > $ { z ( t . status ? ? "" ) } < / s p a n >
< span > history $ { e . length } < / s p a n >
< span > queue $ { ( t . queue ? ? [ ] ) . length } < / s p a n >
< span > conflicts $ { n . length } < / s p a n >
< / d i v >
< div class = "evidence" > $ { z ( t . goal ? ? "" ) } < / d i v >
< div class = "evidence" > seed $ { z ( t . seed ? ? "" ) } < / d i v >
< div class = "evidence" > $ { z ( r ? . outcome ? . reason ? ? r ? . outcome ? . status ? ? "" ) } < / d i v >
< / a r t i c l e >
2026-05-13 19:57:34 +09:00
` }async function Fo(){if(!ue.selectedProject)return;const t=F("graphQueryKind")?.value??"trend_summary",e=F("graphQueryText")?.value.trim()??"";let r= ` kind = $ { encodeURIComponent ( t ) } ` ;t==="brand_products"&&e&&(r+= ` & brand = $ { encodeURIComponent ( e ) } ` ),t==="products_by_tag"&&e&&(r+= ` & tag = $ { encodeURIComponent ( e ) } ` );const a=await Fe( ` / projects / $ { encodeURIComponent ( ue . selectedProject ) } / graph / query ? $ { r } ` );F("graphQueryTable").innerHTML=ow(t,a)}function ow(t,e){return t==="brand_products"?Mt([V("table.product"),V("table.type"),V("table.brand"),V("table.confidence")],e.map(r=>[r.product,r.product_type,r.brand??"",Math.round(r.confidence*100)+"%"])):t==="products_by_tag"?Mt([V("table.product"),V("table.predicate"),V("table.tag"),V("table.confidence")],e.map(r=>[r.product,r.predicate,r.tag,Math.round(r.confidence*100)+"%"])):t==="relation_summary"?Mt([V("table.predicate"),V("table.status"),V("table.support"),V("table.confidence")],e.map(r=>[r.predicate,r.status,r.support_count,Math.round((r.max_confidence??0)*100)+"%"])):t==="entity_type_summary"?Mt([V("table.type"),V("table.count")],e.map(r=>[r.entity_type,r.count])):Mt([V("table.predicate"),V("table.name"),V("table.type"),V("table.support"),V("table.confidence")],e.map(r=>[r.predicate,r.name,r.entity_type,r.support_count,Math.round((r.max_confidence??0)*100)+"%"]))}async function qo(){if(!ue.selectedProject)return;const t=await Fe( ` / projects / $ { encodeURIComponent ( ue . selectedProject ) } / recommendation - tags ` );F("tagTable").innerHTML=Mt([V("table.predicate"),V("table.type"),V("table.name"),V("table.support"),V("table.confidence")],t.map(e=>[e.predicate,e.type,e.name,e.support_count,Math.round((e.max_confidence??0)*100)+"%"]))}async function lw(){if(ue.selectedProject)try{const t=await Fe("/recommend",{method:"POST",body:JSON.stringify({project_name:ue.selectedProject,target_entity_type:ue.projectDetail?.config?.recommendation?.target_entity_type??"Perfume",preferences:{preferred_notes:Di(F("preferredNotes").value),avoided_notes:Di(F("avoidedNotes").value),preferred_moods:Di(F("preferredMoods").value),season_context:F("seasonContext").value.trim()||null,occasion_context:F("occasionContext").value.trim()||null},limit:10})});F("recommendTable").innerHTML=Mt([V("table.name"),V("table.type"),V("table.score"),V("table.reasons")],t.map(e=>[e.name,e.entity_type,e.score,(e.reasons??[]).join(", ")]))}catch(t){Ae(t.message)}}let lo=null,pv="",qa=null;function uw(){const t=F("globalSearchInput"),e=F("globalSearchPanel");xt(t.parentElement),t.addEventListener("input",()=>{const r=t.value.trim();lo&&window.clearTimeout(lo),lo=window.setTimeout(()=>cw(r),200)}),t.addEventListener("focus",()=>{pv?Vo(qa):gv(),e.hidden=!1}),t.addEventListener("keydown",r=>{r.key==="Escape"&&(t.value="",e.hidden=!0,t.blur()),r.key==="ArrowDown"&&(r.preventDefault(),e.querySelector("[data-search-item]")?.focus())}),document.addEventListener("click",r=>{!e.contains(r.target)&&r.target!==t&&(e.hidden=!0)}),document.addEventListener("keydown",r=>{r.key==="/"&&!r.target.matches("input, textarea, select")&&(r.preventDefault(),t.focus(),t.select())}),fr(()=>{xt(t.parentElement),qa&&Vo(qa)})}async function cw(t){if(!ue.selectedProject)return;pv=t;const e=F("globalSearchPanel");if(!t){gv();return}try{qa=await Fe( ` / projects / $ { encodeURIComponent ( ue . selectedProject ) } / search ? q = $ { encodeURIComponent ( t ) } & limit = 8 ` ),Vo(qa)}catch(r){e.innerHTML= ` < div class = "search-empty muted" > $ { z ( r . message ) } < / d i v > ` , e . h i d d e n = ! 1 } } f u n c t i o n g v ( ) { c o n s t t = F ( " g l o b a l S e a r c h P a n e l " ) ; t . i n n e r H T M L = ` < d i v c l a s s = " s e a r c h - e m p t y m u t e d " > $ { z ( V ( " s e a r c h . h i n t " ) ) } < / d i v > ` , t . h i d d e n = ! 1 } f u n c t i o n V o ( t ) { c o n s t e = F ( " g l o b a l S e a r c h P a n e l " ) ; i f ( ! t ) r e t u r n ; c o n s t r = [ { k e y : " e n t i t i e s " , i t e m s : t . e n t i t i e s , r e n d e r : d w } , { k e y : " c l a i m s " , i t e m s : t . c l a i m s , r e n d e r : f w } , { k e y : " p a g e s " , i t e m s : t . p a g e s , r e n d e r : v w } , { k e y : " p r e d i c a t e s " , i t e m s : t . p r e d i c a t e s , r e n d e r : h w } ] . f i l t e r ( a = > ( a . i t e m s ? ? [ ] ) . l e n g t h > 0 ) ; r . l e n g t h ? ( e . i n n e r H T M L = r . m a p ( a = > `
2026-05-12 19:40:31 +09:00
< div class = "search-group" >
< div class = "search-group-head" > $ { z ( V ( ` search.group. ${ a . key } ` ) ) } < / d i v >
$ { a . items . map ( ( n , i ) => a . render ( n , i ) ) . join ( "" ) }
< / d i v >
2026-05-13 19:57:34 +09:00
` ).join(""),e.querySelectorAll("[data-search-item]").forEach(a=>{a.addEventListener("click",()=>pw(a.dataset.searchItem,JSON.parse(a.dataset.payload))),a.addEventListener("keydown",n=>{n.key==="Enter"&&(n.preventDefault(),a.click()),n.key==="ArrowDown"&&(n.preventDefault(),(a.nextElementSibling||e.querySelector("[data-search-item]"))?.focus?.()),n.key==="ArrowUp"&&(n.preventDefault(),(a.previousElementSibling||e.querySelector("[data-search-item]:last-of-type"))?.focus?.()),n.key==="Escape"&&F("globalSearchInput").focus()})})):e.innerHTML= ` < div class = "search-empty muted" > $ { z ( V ( "search.empty" ) ) } < / d i v > ` , e . h i d d e n = ! 1 } f u n c t i o n d w ( t ) { r e t u r n `
2026-05-12 19:40:31 +09:00
< button class = "search-item" data - search - item = "entity" data - payload = '${ki(JSON.stringify(t))}' >
< span class = "search-item-main" > $ { z ( t . name ) } < / s p a n >
< span class = "search-item-meta" > $ { z ( t . type ? ? "" ) } < / s p a n >
< / b u t t o n >
` }function fw(t){const e=t.object_value?JSON.stringify(t.object_value):"";return `
< button class = "search-item" data - search - item = "claim" data - payload = '${ki(JSON.stringify(t))}' >
< span class = "search-item-main" > $ { z ( t . subject ? ? "" ) } · $ { z ( t . predicate ? ? "" ) } $ { z ( e ) } < / s p a n >
< span class = "search-item-meta" > $ { Math . round ( ( t . confidence ? ? 0 ) * 100 ) } % < / s p a n >
< / b u t t o n >
` }function vw(t){return `
< button class = "search-item" data - search - item = "page" data - payload = '${ki(JSON.stringify(t))}' >
< span class = "search-item-main" > $ { z ( t . title ? ? t . url ? ? "" ) } < / s p a n >
< span class = "search-item-meta" > $ { z ( t . url ? ? "" ) } < / s p a n >
< / b u t t o n >
` }function hw(t){return `
< button class = "search-item" data - search - item = "predicate" data - payload = '${ki(JSON.stringify(t))}' >
< span class = "search-item-main" > $ { z ( t ) } < / s p a n >
< / b u t t o n >
2026-05-13 19:57:34 +09:00
` }function ki(t){return String(t).replaceAll("&","&").replaceAll("'","'").replaceAll('"',""")}function pw(t,e){const r=F("globalSearchPanel");if(r.hidden=!0,t==="entity")uo("entities"),ue.selection={kind:"entity",data:{id:e.id,name:e.name,type:e.type,metadata:{}}},ur();else if(t==="claim")uo("claims"),ue.selection={kind:"claim",data:{...e,object:void 0}},ur();else if(t==="page")e.url&&window.open(e.url,"_blank","noreferrer");else if(t==="predicate"){uo("graph");const a=F("graphPredicate");a&&(a.value=e,a.dispatchEvent(new Event("change")))}}function uo(t){document.querySelectorAll(".tab").forEach(e=>e.classList.toggle("active",e.dataset.tab===t)),document.querySelectorAll(".tab-panel").forEach(e=>e.classList.toggle("active",e.id===t))}const gw=document.getElementById("app"),ml=Rv(gw);Av(ml.sidebarHost,{onProjectChanged:bl,onCrawlUpdate:()=>ur(),refreshAll:wl});tw(ml.workspaceHost);Hv(ml.inspectorHost);uw();document.getElementById("refreshBtn").addEventListener("click",bl);window.addEventListener("project:select",t=>yv(t.detail));window.addEventListener("workspace:refresh",wl);fr(()=>ur());bl().catch(t=>Ae(t.message));async function bl(){ue.projects=await Fe("/projects"),!ue.selectedProject&&ue.projects.length&&(ue.selectedProject=ue.projects[0].name),Go(),ue.selectedProject&&await yv(ue.selectedProject)}async function yv(t){ue.selectedProject=t,ue.projectDetail=await Fe( ` / projects / $ { encodeURIComponent ( t ) } ` ),ue.ontology=await Fe( ` / ontology / $ { encodeURIComponent ( ue . projectDetail . domain ) } ` ),Go(),Mv(ue.projectDetail),vv(),hv(),ur(),await wl()}async function wl(){if(!ue.selectedProject)return;const t=[["pipeline",yl],["ontology registry",Oo],["entities",No],["claims workbench",Ta],["extraction logs",zo],["research sessions", $ o],["graph query",Fo],["tags",qo],["graph",gl]];await Promise.all(t.map(async([e,r])=>{try{await r()}catch(a){console.warn( ` $ { e } load failed ` ,a)}})),ur()}
//# sourceMappingURL=index-BsoXaTIL.js.map