naveenus commited on
Commit
cf94c68
·
verified ·
1 Parent(s): 43226f9

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +159 -50
index.html CHANGED
@@ -1,69 +1,178 @@
1
  <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
4
- <meta charset="UTF-8" />
5
- <title>Video Fit Flow (HF Space)</title>
 
6
  <script src="https://unpkg.com/[email protected]/dist/dagre.min.js"></script>
7
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jsPlumb/2.15.5/js/jsplumb.min.js"></script>
8
  <style>
9
- html,body{margin:0;padding:1rem;font-family:sans-serif;height:100%;}
10
- #wrapper{display:flex;flex-direction:column;height:100vh;overflow:hidden;}
11
- #chartContainer{flex:1;position:relative;background:#f5f5f5;overflow:auto;}
12
- .node{position:absolute;width:240px;padding:1rem;border:2px solid #888;border-radius:6px;background:#fff;text-align:center;transition:background .3s,border-color .3s;}
13
- .completed{border-color:#28a745;background:#e6ffed;}
14
- .title-label{background:#e0f7fa;padding:.2rem .5rem;border-radius:4px;margin-top:.5rem;}
15
- .score-box{margin-top:.5rem;font-size:1.2rem;}
16
- #descContainer{flex:none;border-top:2px solid #888;background:#fff;padding:1rem;max-height:200px;overflow-y:auto;}
17
- .controls input,.controls select,.controls button{width:90%;margin:6px auto;display:block;}
 
 
 
 
 
 
 
 
 
 
 
18
  </style>
19
  </head>
20
  <body>
21
- <div id="wrapper">
22
- <div id="chartContainer"></div>
23
- <div id="descContainer">
24
- <strong>Description:</strong>
25
- <div id="videoDesc"></div>
26
- </div>
 
 
 
27
  </div>
 
28
 
29
- <script>
30
- const nodes=[{id:'url',label:'Enter URL & Goal',controls:true},{id:'meta',label:'YouTube API',showTitle:true}];
31
- const models=["all-MiniLM-L6-v2","multi-qa-MiniLM-L6-cos-v1","paraphrase-MiniLM-L3-v2","all-mpnet-base-v2","distilbert-base-nli-mean-tokens"];
32
- models.forEach(m=>{nodes.push({id:`mod-${m}`,label:m});nodes.push({id:`scr-${m}`,label:'Score',hasScore:true});});
33
- const edges=[{v:'url',w:'meta'},...models.flatMap(m=>[{v:'meta',w:`mod-${m}`},{v:`mod-${m}`,w:`scr-${m}`}] )];
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
 
35
- const g=new dagre.graphlib.Graph();
36
- g.setGraph({rankdir:'TB',marginx:20,marginy:20});
37
- g.setDefaultEdgeLabel(()=>({}));
38
- nodes.forEach(n=>{const h=n.controls?160:(n.showTitle?100:50);g.setNode(n.id,{label:n.label,width:240,height:h});});
39
- edges.forEach(e=>g.setEdge(e.v,e.w));
40
- dagre.layout(g);
 
 
 
 
41
 
42
- const chart=document.getElementById('chartContainer');
43
- nodes.forEach(n=>{const {x,y,width,height}=g.node(n.id);const d=document.createElement('div');d.id=`node-${n.id}`;d.className='node';d.style.left=`${x-width/2}px`;d.style.top=`${y-height/2}px`;
44
- if(n.controls){d.innerHTML=`<strong>${n.label}</strong><div class="controls"><input id="urlInput" placeholder="YouTube URL"/><input id="goalInput" placeholder="Your Goal"/><select id="methodSelect"><option value="raw">Raw</option></select><button id="btnFetch">Fetch & Score</button></div>`;}
45
- else if(n.showTitle){d.innerHTML=`<strong>YouTube API</strong><br/><div class="title-label">Title:</div><div id="videoTitle"></div>`;}
46
- else {d.innerHTML=`<strong>${n.label}</strong>`+(n.hasScore?`<div id="score-${n.id}" class="score-box">–</div>`:'');}
47
- chart.appendChild(d);
48
- });
 
49
 
50
- jsPlumb.ready(()=>{
51
- const inst=jsPlumb.getInstance({Connector:['Flowchart',{cornerRadius:5}],Anchors:['Bottom','Top'],Endpoint:'Dot',PaintStyle:{stroke:'#888',strokeWidth:2},EndpointStyle:{fill:'#888',radius:3}});
52
- edges.forEach(e=>inst.connect({source:`node-${e.v}`,target:`node-${e.w}`}));
53
- new ResizeObserver(()=>inst.repaintEverything()).observe(document.getElementById('chartContainer'));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
54
  });
 
 
 
 
 
 
 
 
55
 
56
- document.getElementById('chartContainer').addEventListener('click',async e=>{
57
- if(e.target.id!=='btnFetch')return;
58
- document.getElementById('node-url').classList.add('completed');
59
- const url=document.getElementById('urlInput').value,goal=document.getElementById('goalInput').value;
60
- const res=await fetch('/api/score',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({url,goal,method:'raw'})});
61
- const data=await res.json();
62
- document.getElementById('videoTitle').textContent=data.title;
 
 
 
 
 
 
 
 
63
  document.getElementById('node-meta').classList.add('completed');
64
- document.getElementById('videoDesc').textContent=data.description;
65
- models.forEach(m=>{const sc=data.scores[m];const sd=document.getElementById(`score-scr-${m}`);sd.textContent=sc;const nd=document.getElementById(`node-scr-${m}`);nd.style.background=sc<70?'#ff6347':'#90ee90';nd.classList.add('completed');});
66
- });
67
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  </body>
69
  </html>
 
1
  <!DOCTYPE html>
2
  <html lang="en">
3
  <head>
4
+ <meta charset="UTF-8"/>
5
+ <title>Video Fit Flow</title>
6
+ <!-- Dagre (layout) & jsPlumb (connectors) via CDN -->
7
  <script src="https://unpkg.com/[email protected]/dist/dagre.min.js"></script>
8
  <script src="https://cdnjs.cloudflare.com/ajax/libs/jsPlumb/2.15.5/js/jsplumb.min.js"></script>
9
  <style>
10
+ html, body { margin:0; padding:1rem; font-family:sans-serif; height:100%; }
11
+ #wrapper { display:flex; flex-direction:column; height:100vh; overflow:hidden; }
12
+ #chartContainer { flex:1; position:relative; background:#f5f5f5; overflow:auto; }
13
+ .node {
14
+ position:absolute; width:240px; padding:1rem;
15
+ border:2px solid #888; border-radius:6px; background:#fff;
16
+ text-align:center; transition:background .3s, border-color .3s;
17
+ }
18
+ .completed { border-color:#28a745; background:#e6ffed; }
19
+ .title-label { background:#e0f7fa; padding:.2rem .5rem; border-radius:4px; margin-top:.5rem; }
20
+ .score-box { margin-top:.5rem; font-size:1.2rem; }
21
+ #descContainer {
22
+ flex:none; border-top:2px solid #888; background:#fff;
23
+ padding:1rem; max-height:200px; overflow-y:auto;
24
+ }
25
+ .controls input,
26
+ .controls select,
27
+ .controls button {
28
+ width:90%; margin:6px auto; display:block;
29
+ }
30
  </style>
31
  </head>
32
  <body>
33
+
34
+ <div id="wrapper">
35
+ <!-- Flowchart area -->
36
+ <div id="chartContainer"></div>
37
+
38
+ <!-- Always-visible description panel -->
39
+ <div id="descContainer">
40
+ <strong>Description:</strong>
41
+ <div id="videoDesc"></div>
42
  </div>
43
+ </div>
44
 
45
+ <script>
46
+ // 1) Node + edge definitions
47
+ const nodes = [
48
+ { id:'url', label:'Enter URL & Goal', controls:true },
49
+ { id:'meta', label:'YouTube API', showTitle:true }
50
+ ];
51
+ const models = [
52
+ "all-MiniLM-L6-v2","multi-qa-MiniLM-L6-cos-v1",
53
+ "paraphrase-MiniLM-L3-v2","all-mpnet-base-v2",
54
+ "distilbert-base-nli-mean-tokens"
55
+ ];
56
+ models.forEach(m=>{
57
+ nodes.push({ id:`mod-${m}`, label:m });
58
+ nodes.push({ id:`scr-${m}`, label:'Score', hasScore:true });
59
+ });
60
+ const edges = [
61
+ { v:'url', w:'meta' },
62
+ ...models.flatMap(m=>[
63
+ { v:'meta', w:`mod-${m}` },
64
+ { v:`mod-${m}`, w:`scr-${m}` }
65
+ ])
66
+ ];
67
 
68
+ // 2) Dagre layout
69
+ const g = new dagre.graphlib.Graph();
70
+ g.setGraph({ rankdir:'TB', marginx:20, marginy:20 });
71
+ g.setDefaultEdgeLabel(()=>({}));
72
+ nodes.forEach(n=>{
73
+ const h = n.controls ? 160 : (n.showTitle ? 100 : 50);
74
+ g.setNode(n.id, { label:n.label, width:240, height:h });
75
+ });
76
+ edges.forEach(e=>g.setEdge(e.v,e.w));
77
+ dagre.layout(g);
78
 
79
+ // Render nodes
80
+ const chart = document.getElementById('chartContainer');
81
+ nodes.forEach(n=>{
82
+ const { x,y,width,height } = g.node(n.id);
83
+ const d = document.createElement('div');
84
+ d.id = `node-${n.id}`; d.className='node';
85
+ d.style.left = `${x-width/2}px`;
86
+ d.style.top = `${y-height/2}px`;
87
 
88
+ if (n.controls) {
89
+ d.innerHTML = `
90
+ <strong>${n.label}</strong>
91
+ <div class="controls">
92
+ <input id="urlInput" placeholder="YouTube URL" />
93
+ <input id="goalInput" placeholder="Your Goal" />
94
+ <button id="btnFetchMeta">Fetch Meta</button>
95
+ <button id="btnScore" disabled>Generate Score</button>
96
+ </div>`;
97
+ }
98
+ else if (n.showTitle) {
99
+ d.innerHTML = `
100
+ <strong>YouTube API</strong><br/>
101
+ <div class="title-label">Title:</div>
102
+ <div id="videoTitle"></div>`;
103
+ }
104
+ else {
105
+ d.innerHTML = `<strong>${n.label}</strong>` +
106
+ (n.hasScore ? `<div id="score-${n.id}" class="score-box">–</div>` : '');
107
+ }
108
+ chart.appendChild(d);
109
+ });
110
+
111
+ // 3) jsPlumb connections + prevent duplicates
112
+ jsPlumb.ready(()=>{
113
+ const inst = jsPlumb.getInstance({
114
+ Connector:['Flowchart',{ cornerRadius:5 }],
115
+ Anchors:['Bottom','Top'],
116
+ Endpoint:'Dot',
117
+ PaintStyle:{ stroke:'#888', strokeWidth:2 },
118
+ EndpointStyle:{ fill:'#888', radius:3 }
119
+ });
120
+ // draw edges
121
+ edges.forEach(e=>{
122
+ inst.connect({ source:`node-${e.v}`, target:`node-${e.w}` });
123
  });
124
+ // block duplicate connections
125
+ inst.bind('beforeDrop', info=>
126
+ inst.select({ source: info.sourceId, target: info.targetId }).length === 0
127
+ );
128
+ // repaint on resize
129
+ new ResizeObserver(()=>inst.repaintEverything())
130
+ .observe(document.getElementById('chartContainer'));
131
+ });
132
 
133
+ // 4) Fetch meta vs score logic
134
+ let cached = null;
135
+ document.getElementById('chartContainer').addEventListener('click', async e=>{
136
+ if (e.target.id === 'btnFetchMeta') {
137
+ // Fetch metadata
138
+ const url = document.getElementById('urlInput').value;
139
+ const res = await fetch('/api/meta', {
140
+ method:'POST', headers:{'Content-Type':'application/json'},
141
+ body: JSON.stringify({url})
142
+ });
143
+ const data = await res.json();
144
+ cached = data;
145
+ // Display title & description
146
+ document.getElementById('videoTitle').textContent = data.title;
147
+ document.getElementById('videoDesc').textContent = data.description;
148
  document.getElementById('node-meta').classList.add('completed');
149
+ // Enable scoring
150
+ document.getElementById('btnScore').disabled = false;
151
+ document.getElementById('node-url').classList.add('completed');
152
+ }
153
+
154
+ if (e.target.id === 'btnScore' && cached) {
155
+ const goal = document.getElementById('goalInput').value;
156
+ const res = await fetch('/api/score', {
157
+ method:'POST', headers:{'Content-Type':'application/json'},
158
+ body: JSON.stringify({
159
+ title: cached.title,
160
+ description: cached.description,
161
+ goal
162
+ })
163
+ });
164
+ const out = await res.json();
165
+ models.forEach(m=>{
166
+ const sc = out.scores[m];
167
+ const sd = document.getElementById(`score-scr-${m}`);
168
+ sd.textContent = sc;
169
+ const nd = document.getElementById(`node-scr-${m}`);
170
+ nd.style.background = sc < 70 ? '#ff6347' : '#90ee90';
171
+ nd.classList.add('completed');
172
+ });
173
+ }
174
+ });
175
+ </script>
176
+
177
  </body>
178
  </html>