dylanebert HF staff commited on
Commit
6aa9047
·
1 Parent(s): 535fccf

ensure valid arrays

Browse files
viewer/src/routes/+page.svelte CHANGED
@@ -1,22 +1,11 @@
1
  <script lang="ts">
2
  import { onMount } from "svelte";
3
  import SvelteTable, { type TableColumn } from "svelte-table";
4
-
5
- class Row {
6
- Name: string | null = null;
7
- Orgs: string[] = [];
8
- Authors: string[] = [];
9
- Tags: string[] = [];
10
- CodeStatus: string | null = null;
11
- Paper: string | null = null;
12
- Code: string | null = null;
13
- Space: string | null = null;
14
- Model: string | null = null;
15
- Dataset: string | null = null;
16
- Project: string | null = null;
17
- License: string | null = null;
18
- Date: string | null = null;
19
- }
20
 
21
  let rows: Row[] = [];
22
  let columns: TableColumn<Row>[] = [
@@ -257,9 +246,17 @@
257
  filterValue: (v: Row) => (v.Tags.includes("ReachedOut") ? "Yes" : "No"),
258
  filterOptions: ["Yes", "No"],
259
  },
 
 
 
 
 
 
 
 
260
  ];
261
 
262
- let selection = {};
263
  let overrideSelection = false;
264
  let searchValue = "";
265
 
@@ -275,406 +272,44 @@
275
  }
276
  }
277
 
278
- let statusMessage = "";
279
- const baseURL = "https://dylanebert-research-tracker-backend.hf.space";
280
- // const baseURL = "http://localhost:8000";
281
 
282
- const addEntry = async () => {
283
- if (!("Name" in selection)) return;
284
- const value = selection["Name"] as string;
285
- const row = new Row();
286
- const field = await inferField(row, value);
287
- if (!field) return;
288
- if (field === "Name") {
289
- row.Name = value;
290
- } else if (field === "Paper") {
291
- row.Paper = value;
292
- } else if (field === "Code") {
293
- row.Code = value;
294
- } else if (field === "Space") {
295
- row.Space = value;
296
- } else if (field === "Model") {
297
- row.Model = value;
298
- } else if (field === "Dataset") {
299
- row.Dataset = value;
300
- } else if (field === "Project") {
301
- row.Project = value;
302
- } else {
303
- statusMessage = `<span style="color: red;">Error: Failed to infer field type for "${value}"</span>`;
304
- return;
305
- }
306
- const paper = row.Paper || (await inferPaper(row));
307
- const code = row.Code || (await inferCode(row));
308
- const name = row.Name || (await inferName(row));
309
- if (!name) {
310
- statusMessage += `<br><span style="color: red;">Error: Failed to add entry</span>`;
311
- return;
312
- }
313
- const authors = await inferAuthors(row);
314
- const orgs = await inferOrgs(row);
315
- const date = await inferDate(row);
316
- const model = await inferModel(row);
317
- const dataset = await inferDataset(row);
318
- if (paper) {
319
- row.Paper = paper;
320
- }
321
- if (code) {
322
- row.Code = code;
323
- }
324
- if (name) {
325
- row.Name = name;
326
- }
327
- if (authors) {
328
- row.Authors = authors.split(", ");
329
- }
330
- if (orgs) {
331
- row.Orgs = orgs.split(", ");
332
- }
333
- if (date) {
334
- row.Date = date;
335
- }
336
- if (model) {
337
- row.Model = model;
338
- }
339
- if (dataset) {
340
- row.Dataset = dataset;
341
- }
342
- const response = await fetch(baseURL + "/add-entry", {
343
- method: "POST",
344
- headers: {
345
- "Content-Type": "application/json",
346
- Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
347
- },
348
- body: JSON.stringify(row),
349
- });
350
- const data = await response.json();
351
- if (data.error || !data.success) {
352
- if (data.error) {
353
- statusMessage += `<br><span style="color: red;">Error: ${data.error}</span>`;
354
- } else {
355
- statusMessage += `<br><span style="color: red;">Error: Failed to add entry</span>`;
356
- }
357
- return;
358
- }
359
- statusMessage += `<br><span style="color: green;">Added entry for "${row.Name}"</span>`;
360
  rows = [row, ...rows];
361
- };
362
-
363
- const inferField = async (row: Row, value: string): Promise<string | null> => {
364
- let data;
365
- try {
366
- const response = await fetch(baseURL + "/infer-field", {
367
- method: "POST",
368
- headers: {
369
- "Content-Type": "application/json",
370
- Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
371
- },
372
- body: JSON.stringify({ value }),
373
- });
374
- data = await response.json();
375
- } catch (e) {
376
- statusMessage += `<br><span style="color: red;">Error: Failed to infer field type for "${value}"</span>`;
377
- return null;
378
- }
379
- if (data.error || !data.field || !(data.field in row)) {
380
- statusMessage = `<span style="color: red;">Error: Failed to infer field type for "${value}"</span>`;
381
- return null;
382
- }
383
- statusMessage = `<span style="color: green;">Inferred field type: ${data.field}</span>`;
384
- return data.field;
385
- };
386
-
387
- const inferPaper = async (row: Row) => {
388
- statusMessage += `<br><span>Inferring paper...</span>`;
389
- let data;
390
- try {
391
- const response = await fetch(baseURL + "/infer-paper", {
392
- method: "POST",
393
- headers: {
394
- "Content-Type": "application/json",
395
- Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
396
- },
397
- body: JSON.stringify(row),
398
- });
399
- data = await response.json();
400
- } catch (e) {
401
- statusMessage = statusMessage.split("<br><span>Inferring paper...</span>")[0];
402
- statusMessage += `<br><span style="color: red;">Error: Failed to infer paper</span>`;
403
- return null;
404
- }
405
- statusMessage = statusMessage.split("<br><span>Inferring paper...</span>")[0];
406
- if (data.error || !data.paper) {
407
- if (data.error) {
408
- statusMessage += `<br><span style="color: red;">Error: ${data.error}</span>`;
409
- } else if (data.message) {
410
- statusMessage += `<br><span>${data.message}</span>`;
411
- } else {
412
- statusMessage += `<br><span style="color: red;">Error: Failed to infer paper</span>`;
413
- }
414
- return null;
415
- }
416
- const link = `<a href="${data.paper}" target="_blank">${data.paper}</a>`;
417
- statusMessage += `<br><span style="color: green;">Inferred paper: ${link}</span>`;
418
- return data.paper;
419
- };
420
-
421
- const inferCode = async (row: Row) => {
422
- statusMessage += `<br><span>Inferring code...</span>`;
423
- let data;
424
- try {
425
- const response = await fetch(baseURL + "/infer-code", {
426
- method: "POST",
427
- headers: {
428
- "Content-Type": "application/json",
429
- Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
430
- },
431
- body: JSON.stringify(row),
432
- });
433
- data = await response.json();
434
- } catch (e) {
435
- statusMessage = statusMessage.split("<br><span>Inferring code...</span>")[0];
436
- statusMessage += `<br><span style="color: red;">Error: Failed to infer code</span>`;
437
- return null;
438
- }
439
- statusMessage = statusMessage.split("<br><span>Inferring code...</span>")[0];
440
- if (data.error || !data.code) {
441
- if (data.error) {
442
- statusMessage += `<br><span style="color: red;">Error: ${data.error}</span>`;
443
- } else if (data.message) {
444
- statusMessage += `<br><span>${data.message}</span>`;
445
- } else {
446
- statusMessage += `<br><span style="color: red;">Error: Failed to infer code</span>`;
447
- }
448
- return null;
449
- }
450
- const link = `<a href="${data.code}" target="_blank">${data.code}</a>`;
451
- statusMessage += `<br><span style="color: green;">Inferred code: ${link}</span>`;
452
- return data.code;
453
- };
454
-
455
- const inferName = async (row: Row) => {
456
- statusMessage += `<br><span>Inferring name...</span>`;
457
- let data;
458
- try {
459
- const response = await fetch(baseURL + "/infer-name", {
460
- method: "POST",
461
- headers: {
462
- "Content-Type": "application/json",
463
- Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
464
- },
465
- body: JSON.stringify(row),
466
- });
467
- data = await response.json();
468
- } catch (e) {
469
- statusMessage = statusMessage.split("<br><span>Inferring name...</span>")[0];
470
- statusMessage += `<br><span style="color: red;">Error: Failed to infer name</span>`;
471
- return null;
472
- }
473
- statusMessage = statusMessage.split("<br><span>Inferring name...</span>")[0];
474
- if (data.error || !data.name) {
475
- if (data.error) {
476
- statusMessage += `<br><span style="color: red;">Error: ${data.error}</span>`;
477
- } else if (data.message) {
478
- statusMessage += `<br><span>${data.message}</span>`;
479
- } else {
480
- statusMessage += `<br><span style="color: red;">Error: Failed to infer name</span>`;
481
- }
482
- return null;
483
- }
484
- statusMessage += `<br><span style="color: green;">Inferred name: ${data.name}</span>`;
485
- return data.name;
486
- };
487
-
488
- const inferAuthors = async (row: Row) => {
489
- statusMessage += `<br><span>Inferring authors...</span>`;
490
- let data;
491
- try {
492
- const response = await fetch(baseURL + "/infer-authors", {
493
- method: "POST",
494
- headers: {
495
- "Content-Type": "application/json",
496
- Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
497
- },
498
- body: JSON.stringify(row),
499
- });
500
- data = await response.json();
501
- } catch (e) {
502
- statusMessage = statusMessage.split("<br><span>Inferring authors...</span>")[0];
503
- statusMessage += `<br><span style="color: red;">Error: Failed to infer authors</span>`;
504
- return null;
505
- }
506
- statusMessage = statusMessage.split("<br><span>Inferring authors...</span>")[0];
507
- if (data.error || !data.authors) {
508
- if (data.error) {
509
- statusMessage += `<br><span style="color: red;">Error: ${data.error}</span>`;
510
- } else if (data.message) {
511
- statusMessage += `<br><span>${data.message}</span>`;
512
- } else {
513
- statusMessage += `<br><span style="color: red;">Error: Failed to infer authors</span>`;
514
- }
515
- return null;
516
- }
517
- statusMessage += `<br><span style="color: green;">Inferred authors: ${data.authors}</span>`;
518
- return data.authors;
519
- };
520
-
521
- const inferOrgs = async (row: Row) => {
522
- statusMessage += `<br><span>Inferring orgs...</span>`;
523
- let data;
524
- try {
525
- const response = await fetch(baseURL + "/infer-orgs", {
526
- method: "POST",
527
- headers: {
528
- "Content-Type": "application/json",
529
- Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
530
- },
531
- body: JSON.stringify(row),
532
- });
533
- data = await response.json();
534
- } catch (e) {
535
- statusMessage = statusMessage.split("<br><span>Inferring orgs...</span>")[0];
536
- statusMessage += `<br><span style="color: red;">Error: Failed to infer orgs</span>`;
537
- return null;
538
- }
539
- statusMessage = statusMessage.split("<br><span>Inferring orgs...</span>")[0];
540
- if (data.error || !data.orgs) {
541
- if (data.error) {
542
- statusMessage += `<br><span style="color: red;">Error: ${data.error}</span>`;
543
- } else if (data.message) {
544
- statusMessage += `<br><span>${data.message}</span>`;
545
- } else {
546
- statusMessage += `<br><span style="color: red;">Error: Failed to infer orgs</span>`;
547
- }
548
- return null;
549
- }
550
- statusMessage += `<br><span style="color: green;">Inferred orgs: ${data.orgs}</span>`;
551
- return data.orgs;
552
- };
553
-
554
- const inferDate = async (row: Row) => {
555
- statusMessage += `<br><span>Inferring date...</span>`;
556
- let data;
557
- try {
558
- const response = await fetch(baseURL + "/infer-date", {
559
- method: "POST",
560
- headers: {
561
- "Content-Type": "application/json",
562
- Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
563
- },
564
- body: JSON.stringify(row),
565
- });
566
- data = await response.json();
567
- } catch (e) {
568
- statusMessage = statusMessage.split("<br><span>Inferring date...</span>")[0];
569
- statusMessage += `<br><span style="color: red;">Error: Failed to infer date</span>`;
570
- return null;
571
- }
572
- statusMessage = statusMessage.split("<br><span>Inferring date...</span>")[0];
573
- if (data.error || !data.date) {
574
- if (data.error) {
575
- statusMessage += `<br><span style="color: red;">Error: ${data.error}</span>`;
576
- } else if (data.message) {
577
- statusMessage += `<br><span>${data.message}</span>`;
578
- } else {
579
- statusMessage += `<br><span style="color: red;">Error: Failed to infer date</span>`;
580
- }
581
- return null;
582
- }
583
- statusMessage += `<br><span style="color: green;">Inferred date: ${data.date}</span>`;
584
- return data.date;
585
- };
586
 
587
- const inferModel = async (row: Row) => {
588
- statusMessage += `<br><span>Inferring model...</span>`;
589
- let data;
590
- try {
591
- const response = await fetch(baseURL + "/infer-model", {
592
- method: "POST",
593
- headers: {
594
- "Content-Type": "application/json",
595
- Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
596
- },
597
- body: JSON.stringify(row),
598
- });
599
- data = await response.json();
600
- } catch (e) {
601
- statusMessage = statusMessage.split("<br><span>Inferring model...</span>")[0];
602
- statusMessage += `<br><span style="color: red;">Error: Failed to infer model</span>`;
603
- return null;
604
- }
605
- statusMessage = statusMessage.split("<br><span>Inferring model...</span>")[0];
606
- if (data.error || !data.model) {
607
- if (data.error) {
608
- statusMessage += `<br><span style="color: red;">Error: ${data.error}</span>`;
609
- } else if (data.message) {
610
- statusMessage += `<br><span>${data.message}</span>`;
611
- } else {
612
- statusMessage += `<br><span style="color: red;">Error: Failed to infer model</span>`;
613
- }
614
- return null;
615
  }
616
- statusMessage += `<br><span style="color: green;">Inferred model: ${data.model}</span>`;
617
- return data.model;
618
- };
619
 
620
- const inferDataset = async (row: Row) => {
621
- statusMessage += `<br><span>Inferring dataset...</span>`;
622
- let data;
623
- try {
624
- const response = await fetch(baseURL + "/infer-dataset", {
625
- method: "POST",
626
- headers: {
627
- "Content-Type": "application/json",
628
- Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
629
- },
630
- body: JSON.stringify(row),
631
- });
632
- data = await response.json();
633
- } catch (e) {
634
- statusMessage = statusMessage.split("<br><span>Inferring dataset...</span>")[0];
635
- statusMessage += `<br><span style="color: red;">Error: Failed to infer dataset</span>`;
636
- return null;
637
- }
638
- statusMessage = statusMessage.split("<br><span>Inferring dataset...</span>")[0];
639
- if (data.error || !data.dataset) {
640
- if (data.error) {
641
- statusMessage += `<br><span style="color: red;">Error: ${data.error}</span>`;
642
- } else if (data.message) {
643
- statusMessage += `<br><span>${data.message}</span>`;
644
- } else {
645
- statusMessage += `<br><span style="color: red;">Error: Failed to infer dataset</span>`;
646
- }
647
- return null;
648
  }
649
- statusMessage += `<br><span style="color: green;">Inferred dataset: ${data.dataset}</span>`;
650
- return data.dataset;
651
- };
652
-
653
- onMount(() => {
654
- fetchRows();
655
- });
656
 
657
  let fetching = false;
658
- const fetchRows = async () => {
659
- if (fetching) return;
660
- fetching = true;
661
- statusMessage = `<span>Fetching data from https://dylanebert-research-tracker-backend.hf.space/data"</span>`;
662
- try {
663
- const response = await fetch(baseURL + "/data", {
664
- method: "GET",
665
- headers: {
666
- Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
667
- "Cache-Control": "no-cache",
668
- },
669
- });
670
- rows = await response.json();
671
- fetching = false;
672
- statusMessage = "";
673
- } catch (e) {
674
- console.error(e);
675
- statusMessage = `<span style="color: red;">Error: Failed to fetch data from https://dylanebert-research-tracker-backend.hf.space/data</span>`;
676
- }
677
- };
678
  </script>
679
 
680
  {#if !import.meta.env.VITE_HF_TOKEN}
@@ -683,7 +318,7 @@
683
  </div>
684
  {:else if fetching}
685
  <div style="text-align: center; margin-top: 1rem;">
686
- <p>{@html statusMessage}</p>
687
  </div>
688
  {:else}
689
  <div style="text-align: center; margin-top: 1rem;">
@@ -693,11 +328,15 @@
693
  style="width: 100%; max-width: 512px;"
694
  bind:value={searchValue}
695
  />
696
- <button on:click={addEntry}>New Entry</button>
697
  </div>
698
 
699
  {#if statusMessage}
700
- <div style="text-align: center; margin-top: 0.5rem;">{@html statusMessage}</div>
 
 
 
 
701
  {/if}
702
 
703
  <!--spacer-->
@@ -705,3 +344,5 @@
705
 
706
  <SvelteTable {columns} {rows} bind:filterSelections={selection} />
707
  {/if}
 
 
 
1
  <script lang="ts">
2
  import { onMount } from "svelte";
3
  import SvelteTable, { type TableColumn } from "svelte-table";
4
+ import Row from "./Row";
5
+ import EditButtonComponent from "./EditButtonComponent.svelte";
6
+ import EditModal from "./EditModal.svelte";
7
+ import { fetchRows, addEntry } from "./bridge";
8
+ import { statusMessage } from "./store";
 
 
 
 
 
 
 
 
 
 
 
9
 
10
  let rows: Row[] = [];
11
  let columns: TableColumn<Row>[] = [
 
246
  filterValue: (v: Row) => (v.Tags.includes("ReachedOut") ? "Yes" : "No"),
247
  filterOptions: ["Yes", "No"],
248
  },
249
+ {
250
+ key: "Edit",
251
+ title: "",
252
+ value: (v: Row) => "",
253
+ sortable: false,
254
+ renderComponent: EditButtonComponent,
255
+ hideFilterHeader: true,
256
+ },
257
  ];
258
 
259
+ let selection: Record<string | number, any> = {};
260
  let overrideSelection = false;
261
  let searchValue = "";
262
 
 
272
  }
273
  }
274
 
275
+ onMount(async () => {
276
+ rows = (await fetchRows()) || [];
277
+ });
278
 
279
+ async function newEntry() {
280
+ const row = await addEntry(selection);
281
+ if (!row) return;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
282
  rows = [row, ...rows];
283
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
284
 
285
+ function handleRowUpdated(event: Event) {
286
+ const updatedRow = (event as CustomEvent).detail;
287
+ const rowIndex = rows.findIndex(
288
+ (row) =>
289
+ row.Code === updatedRow.Code || row.Paper === updatedRow.Paper || row.Project === updatedRow.Project
290
+ );
291
+ if (rowIndex !== -1) {
292
+ rows[rowIndex] = updatedRow;
293
+ } else {
294
+ console.error("Row not found");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
295
  }
296
+ }
 
 
297
 
298
+ function handleRowDeleted(event: Event) {
299
+ const deletedRow = (event as CustomEvent).detail;
300
+ const rowIndex = rows.findIndex(
301
+ (row) =>
302
+ row.Code === deletedRow.Code || row.Paper === deletedRow.Paper || row.Project === deletedRow.Project
303
+ );
304
+ if (rowIndex !== -1) {
305
+ rows = [...rows.slice(0, rowIndex), ...rows.slice(rowIndex + 1)];
306
+ } else {
307
+ console.error("Row not found");
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
308
  }
309
+ }
 
 
 
 
 
 
310
 
311
  let fetching = false;
312
+ let isModalOpen = false;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313
  </script>
314
 
315
  {#if !import.meta.env.VITE_HF_TOKEN}
 
318
  </div>
319
  {:else if fetching}
320
  <div style="text-align: center; margin-top: 1rem;">
321
+ <p>{@html $statusMessage}</p>
322
  </div>
323
  {:else}
324
  <div style="text-align: center; margin-top: 1rem;">
 
328
  style="width: 100%; max-width: 512px;"
329
  bind:value={searchValue}
330
  />
331
+ <button on:click={newEntry}>New Entry</button>
332
  </div>
333
 
334
  {#if statusMessage}
335
+ <div style="text-align: center; margin-top: 0.5rem;">
336
+ {#if !isModalOpen}
337
+ {@html $statusMessage}
338
+ {/if}
339
+ </div>
340
  {/if}
341
 
342
  <!--spacer-->
 
344
 
345
  <SvelteTable {columns} {rows} bind:filterSelections={selection} />
346
  {/if}
347
+
348
+ <EditModal bind:isOpen={isModalOpen} on:rowUpdated={handleRowUpdated} on:rowDeleted={handleRowDeleted} />
viewer/src/routes/EditButtonComponent.svelte ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { editingRow } from "./store";
3
+ import Row from "./Row";
4
+
5
+ export let row: Row;
6
+ export let col;
7
+
8
+ let key = col.key;
9
+
10
+ function onEditButtonClick(row: Row) {
11
+ editingRow.set(row);
12
+ }
13
+ </script>
14
+
15
+ <button on:click={() => onEditButtonClick(row)}>{key}</button>
viewer/src/routes/EditModal.svelte ADDED
@@ -0,0 +1,235 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <script lang="ts">
2
+ import { onDestroy, createEventDispatcher } from "svelte";
3
+ import { editingRow, statusMessage } from "./store";
4
+ import type Row from "./Row";
5
+ import { inferFields, editEntry, deleteEntry } from "./bridge";
6
+
7
+ const dispatch = createEventDispatcher();
8
+ let row: Row | null = null;
9
+
10
+ export let isOpen = false;
11
+
12
+ const unsubscribe = editingRow.subscribe((value: Row | null) => {
13
+ row = value;
14
+ isOpen = !!value;
15
+ if (!isOpen) {
16
+ statusMessage.reset();
17
+ }
18
+ });
19
+
20
+ async function saveEntry() {
21
+ if (!row) return;
22
+ statusMessage.set(`<span>Sending edit request to backend...</span>`);
23
+
24
+ const result = await editEntry(row);
25
+ if (!result) return;
26
+ dispatch("rowUpdated", row);
27
+ }
28
+
29
+ async function tryInfer() {
30
+ if (!row) return;
31
+ const result = await inferFields(row);
32
+ if (!result) return;
33
+ editingRow.set(result);
34
+ }
35
+
36
+ async function tryDelete() {
37
+ if (!row) return;
38
+ statusMessage.set(`<span style="color: red">Sending delete request to backend...</span>`);
39
+ const result = await deleteEntry(row);
40
+ if (!result) return;
41
+ dispatch("rowDeleted", row);
42
+ close();
43
+ }
44
+
45
+ function close() {
46
+ editingRow.set(null);
47
+ }
48
+
49
+ onDestroy(unsubscribe);
50
+ </script>
51
+
52
+ {#if $editingRow}
53
+ <div class="modal">
54
+ <button class="modal-backdrop" on:click={close} />
55
+ <div class="modal-content">
56
+ <button class="close-button" on:click={close}> &times; </button>
57
+ <h2>Edit Entry</h2>
58
+ <div class="button-group">
59
+ <button class="delete-button" on:click={tryDelete}>Delete Entry</button>
60
+ </div>
61
+ {#if row}
62
+ <div class="input-group">
63
+ <label for="name">Name</label>
64
+ <input id="name" bind:value={row.Name} />
65
+ </div>
66
+ <div class="input-group">
67
+ <label for="date">Date</label>
68
+ <input id="date" bind:value={row.Date} />
69
+ </div>
70
+ <div class="input-group">
71
+ <label for="orgs">Orgs</label>
72
+ <input id="orgs" bind:value={row.Orgs} />
73
+ </div>
74
+ <div class="input-group">
75
+ <label for="authors">Authors</label>
76
+ <input id="authors" bind:value={row.Authors} />
77
+ </div>
78
+ <div class="input-group">
79
+ <label for="paper">Paper</label>
80
+ <input id="paper" bind:value={row.Paper} />
81
+ </div>
82
+ <div class="input-group">
83
+ <label for="code">Code</label>
84
+ <input id="code" bind:value={row.Code} />
85
+ </div>
86
+ <div class="input-group">
87
+ <label for="project">Project</label>
88
+ <input id="project" bind:value={row.Project} />
89
+ </div>
90
+ <div class="input-group">
91
+ <label for="space">Space</label>
92
+ <input id="space" bind:value={row.Space} />
93
+ </div>
94
+ <div class="input-group">
95
+ <label for="model">Model</label>
96
+ <input id="model" bind:value={row.Model} />
97
+ </div>
98
+ <div class="input-group">
99
+ <label for="dataset">Dataset</label>
100
+ <input id="dataset" bind:value={row.Dataset} />
101
+ </div>
102
+ <div class="input-group">
103
+ <label for="license">License</label>
104
+ <input id="license" bind:value={row.License} />
105
+ </div>
106
+ <div class="input-group">
107
+ <label for="code-status">Code Status</label>
108
+ <input id="code-status" bind:value={row.CodeStatus} />
109
+ </div>
110
+ <div class="input-group">
111
+ <label for="tags">Tags</label>
112
+ <input id="tags" bind:value={row.Tags} />
113
+ </div>
114
+ {/if}
115
+ <div class="button-group">
116
+ <button class="infer-button" on:click={tryInfer}>Infer Fields</button>
117
+ <button class="save-button" on:click={saveEntry}>Save</button>
118
+ </div>
119
+ <div class="status">
120
+ <span>{@html $statusMessage}</span>
121
+ </div>
122
+ </div>
123
+ </div>
124
+ {/if}
125
+
126
+ <style>
127
+ .modal {
128
+ position: fixed;
129
+ top: 0;
130
+ left: 0;
131
+ z-index: 1000;
132
+ width: 100%;
133
+ height: 100%;
134
+ background-color: rgba(0, 0, 0, 0.5);
135
+ display: flex;
136
+ justify-content: center;
137
+ align-items: center;
138
+ }
139
+
140
+ .modal-backdrop {
141
+ position: absolute;
142
+ top: 0;
143
+ left: 0;
144
+ z-index: -1;
145
+ width: 100%;
146
+ height: 100%;
147
+ background-color: transparent;
148
+ border: none;
149
+ }
150
+
151
+ .modal-content {
152
+ position: relative;
153
+ background-color: white;
154
+ padding: 20px;
155
+ border-radius: 5px;
156
+ width: 50%;
157
+ max-width: 768px;
158
+ }
159
+
160
+ .modal-content h2 {
161
+ margin: 0;
162
+ margin-bottom: 10px;
163
+ }
164
+
165
+ .input-group {
166
+ display: flex;
167
+ justify-content: space-between;
168
+ margin-bottom: 10px;
169
+ }
170
+
171
+ .input-group label {
172
+ flex: 1;
173
+ margin-right: 10px;
174
+ }
175
+
176
+ .input-group input {
177
+ flex: 2;
178
+ }
179
+
180
+ .modal-content input {
181
+ width: 100%;
182
+ }
183
+
184
+ .close-button {
185
+ position: absolute;
186
+ top: 10px;
187
+ right: 10px;
188
+ background: none;
189
+ border: none;
190
+ font-size: 1.5em;
191
+ cursor: pointer;
192
+ }
193
+
194
+ .button-group {
195
+ margin: 10px 0;
196
+ width: 100%;
197
+ display: flex;
198
+ justify-content: left;
199
+ }
200
+
201
+ .infer-button {
202
+ background-color: rgb(68, 127, 215);
203
+ color: white;
204
+ border: none;
205
+ padding: 5px 10px;
206
+ border-radius: 5px;
207
+ cursor: pointer;
208
+ flex: 1;
209
+ }
210
+
211
+ .save-button {
212
+ background-color: #53c457;
213
+ color: white;
214
+ border: none;
215
+ padding: 5px 10px;
216
+ border-radius: 5px;
217
+ cursor: pointer;
218
+ flex: 1;
219
+ }
220
+
221
+ .delete-button {
222
+ background-color: rgb(248, 39, 39);
223
+ color: white;
224
+ border: none;
225
+ padding: 5px 10px;
226
+ border-radius: 5px;
227
+ cursor: pointer;
228
+ }
229
+
230
+ .status {
231
+ width: 100%;
232
+ text-align: center;
233
+ margin: 10px 0;
234
+ }
235
+ </style>
viewer/src/routes/Row.ts ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ class Row {
2
+ Name: string | null = null;
3
+ Orgs: string[] = [];
4
+ Authors: string[] = [];
5
+ Tags: string[] = [];
6
+ CodeStatus: string | null = null;
7
+ Paper: string | null = null;
8
+ Code: string | null = null;
9
+ Space: string | null = null;
10
+ Model: string | null = null;
11
+ Dataset: string | null = null;
12
+ Project: string | null = null;
13
+ License: string | null = null;
14
+ Date: string | null = null;
15
+ }
16
+
17
+ export default Row;
viewer/src/routes/bridge.ts ADDED
@@ -0,0 +1,463 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import Row from "./Row";
2
+ import { statusMessage } from "./store";
3
+
4
+ // const baseURL = "https://dylanebert-research-tracker-backend.hf.space";
5
+ const baseURL = "http://localhost:8000";
6
+
7
+ export const fetchRows = async (): Promise<Row[] | null> => {
8
+ statusMessage.set(`<span>Fetching data from https://dylanebert-research-tracker-backend.hf.space/data</span>`);
9
+ try {
10
+ const response = await fetch(baseURL + "/data", {
11
+ method: "GET",
12
+ headers: {
13
+ Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
14
+ "Cache-Control": "no-cache",
15
+ },
16
+ });
17
+ const rows = await response.json();
18
+ statusMessage.reset();
19
+ return rows;
20
+ } catch (e) {
21
+ console.error(e);
22
+ statusMessage.set(
23
+ `<span style="color: red;">Error: Failed to fetch data from https://dylanebert-research-tracker-backend.hf.space/data</span>`
24
+ );
25
+ return null;
26
+ }
27
+ };
28
+
29
+ export const addEntry = async (selection: Record<string | number, any>): Promise<Row | null> => {
30
+ if (!("Name" in selection)) return null;
31
+ const value = selection["Name"] as string;
32
+ let row: Row | null = new Row();
33
+ const field = await inferFieldType(row, value);
34
+ if (!field) return null;
35
+ if (field === "Name") {
36
+ row.Name = value;
37
+ } else if (field === "Paper") {
38
+ row.Paper = value;
39
+ } else if (field === "Code") {
40
+ row.Code = value;
41
+ } else if (field === "Space") {
42
+ row.Space = value;
43
+ } else if (field === "Model") {
44
+ row.Model = value;
45
+ } else if (field === "Dataset") {
46
+ row.Dataset = value;
47
+ } else if (field === "Project") {
48
+ row.Project = value;
49
+ } else {
50
+ statusMessage.set(`<span style="color: red;">Error: Failed to infer field type for <b>${value}</b></span>`);
51
+ return null;
52
+ }
53
+ row = await inferFields(row);
54
+ if (!row) {
55
+ return null;
56
+ }
57
+ const response = await fetch(baseURL + "/add-entry", {
58
+ method: "POST",
59
+ headers: {
60
+ "Content-Type": "application/json",
61
+ Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
62
+ },
63
+ body: JSON.stringify(row),
64
+ });
65
+ const data = await response.json();
66
+ if (data.error || !data.success) {
67
+ if (data.error) {
68
+ statusMessage.append(`<br><span style="color: red;">Error: ${data.error}</span>`);
69
+ } else {
70
+ statusMessage.append(`<br><span style="color: red;">Error: Failed to add entry</span>`);
71
+ }
72
+ return null;
73
+ }
74
+ statusMessage.append(`<br><span style="color: green;">Added entry for "${row.Name}"</span>`);
75
+
76
+ return row;
77
+ };
78
+
79
+ export const editEntry = async (row: Row): Promise<Row | null> => {
80
+ row.Orgs = Array.isArray(row.Orgs) ? row.Orgs : (row.Orgs as any).split(",").map((org: string) => org.trim());
81
+ row.Authors = Array.isArray(row.Authors)
82
+ ? row.Authors
83
+ : (row.Authors as any).split(",").map((author: string) => author.trim());
84
+ row.Tags = Array.isArray(row.Tags) ? row.Tags : (row.Tags as any).split(",").map((tag: string) => tag.trim());
85
+ const response = await fetch(baseURL + "/edit-entry", {
86
+ method: "POST",
87
+ headers: {
88
+ "Content-Type": "application/json",
89
+ Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
90
+ },
91
+ body: JSON.stringify(row),
92
+ });
93
+ const data = await response.json();
94
+ if (data.error || !data.success) {
95
+ if (data.error) {
96
+ statusMessage.append(`<br><span style="color: red;">Error: ${data.error}</span>`);
97
+ } else {
98
+ statusMessage.append(`<br><span style="color: red;">Error: Failed to edit entry</span>`);
99
+ }
100
+ return null;
101
+ }
102
+ statusMessage.append(`<br><span style="color: green;">Edited entry for "${row.Name}"</span>`);
103
+ return row;
104
+ };
105
+
106
+ export const deleteEntry = async (row: Row): Promise<Row | null> => {
107
+ row.Orgs = Array.isArray(row.Orgs) ? row.Orgs : (row.Orgs as any).split(",").map((org: string) => org.trim());
108
+ row.Authors = Array.isArray(row.Authors)
109
+ ? row.Authors
110
+ : (row.Authors as any).split(",").map((author: string) => author.trim());
111
+ row.Tags = Array.isArray(row.Tags) ? row.Tags : (row.Tags as any).split(",").map((tag: string) => tag.trim());
112
+ const response = await fetch(baseURL + "/delete-entry", {
113
+ method: "POST",
114
+ headers: {
115
+ "Content-Type": "application/json",
116
+ Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
117
+ },
118
+ body: JSON.stringify(row),
119
+ });
120
+ const data = await response.json();
121
+ if (data.error || !data.success) {
122
+ if (data.error) {
123
+ statusMessage.append(`<br><span style="color: red;">Error: ${data.error}</span>`);
124
+ } else {
125
+ statusMessage.append(`<br><span style="color: red;">Error: Failed to delete entry</span>`);
126
+ }
127
+ return null;
128
+ }
129
+ statusMessage.append(`<br><span style="color: green;">Deleted entry for "${row.Name}"</span>`);
130
+ return row;
131
+ };
132
+
133
+ export const inferFields = async (row: Row): Promise<Row | null> => {
134
+ const key = row.Name || row.Paper || row.Code || row.Space || row.Model || row.Dataset || row.Project;
135
+ statusMessage.set(`<span>Inferring fields for <b>${key}</b></span>`);
136
+ const paper = row.Paper || (await inferPaper(row));
137
+ const code = row.Code || (await inferCode(row));
138
+ const name = row.Name || (await inferName(row));
139
+ if (!name) {
140
+ return null;
141
+ }
142
+ row.Name = name;
143
+ const authors = row.Authors.length == 0 ? await inferAuthors(row) : row.Authors;
144
+ const orgs = row.Orgs.length == 0 ? await inferOrgs(row) : row.Orgs;
145
+ const date = row.Date || (await inferDate(row));
146
+ const model = row.Model || (await inferModel(row));
147
+ const dataset = row.Dataset || (await inferDataset(row));
148
+ if (paper) {
149
+ row.Paper = paper;
150
+ }
151
+ if (code) {
152
+ row.Code = code;
153
+ }
154
+ if (authors) {
155
+ row.Authors = Array.isArray(authors) ? authors : authors.split(",").map((author: string) => author.trim());
156
+ }
157
+ if (orgs) {
158
+ row.Orgs = Array.isArray(orgs) ? orgs : orgs.split(",").map((org: string) => org.trim());
159
+ }
160
+ if (date) {
161
+ row.Date = date;
162
+ }
163
+ if (model) {
164
+ row.Model = model;
165
+ }
166
+ if (dataset) {
167
+ row.Dataset = dataset;
168
+ }
169
+ statusMessage.append(`<br><span style="color: green;">Finished inferring fields for <b>${row.Name}</b></span>`);
170
+ return row;
171
+ };
172
+
173
+ const inferFieldType = async (row: Row, value: string): Promise<string | null> => {
174
+ let data;
175
+ try {
176
+ const response = await fetch(baseURL + "/infer-field", {
177
+ method: "POST",
178
+ headers: {
179
+ "Content-Type": "application/json",
180
+ Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
181
+ },
182
+ body: JSON.stringify({ value }),
183
+ });
184
+ data = await response.json();
185
+ } catch (e) {
186
+ statusMessage.append(
187
+ `<br><span style="color: red;">Error: Failed to infer field type for <b>${value}</b></span>`
188
+ );
189
+ return null;
190
+ }
191
+ if (data.error || !data.field || !(data.field in row)) {
192
+ statusMessage.set(`<span style="color: red;">Error: Failed to infer field type for <b>${value}</b></span>`);
193
+ return null;
194
+ }
195
+ statusMessage.set(`<span style="color: green;">Inferred field type: ${data.field}</span>`);
196
+ return data.field;
197
+ };
198
+
199
+ const inferPaper = async (row: Row) => {
200
+ statusMessage.append(`<br><span>Inferring paper...</span>`);
201
+ let data;
202
+ try {
203
+ const response = await fetch(baseURL + "/infer-paper", {
204
+ method: "POST",
205
+ headers: {
206
+ "Content-Type": "application/json",
207
+ Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
208
+ },
209
+ body: JSON.stringify(row),
210
+ });
211
+ data = await response.json();
212
+ } catch (e) {
213
+ statusMessage.remove("<br><span>Inferring paper...</span>");
214
+ statusMessage.append(`<br><span style="color: red;">Error: Failed to infer paper</span>`);
215
+ return null;
216
+ }
217
+ statusMessage.remove("<br><span>Inferring paper...</span>");
218
+ if (data.error || !data.paper) {
219
+ if (data.error) {
220
+ statusMessage.append(`<br><span style="color: red;">Error: ${data.error}</span>`);
221
+ } else if (data.message) {
222
+ statusMessage.append(`<br><span>${data.message}</span>`);
223
+ } else {
224
+ statusMessage.append(`<br><span style="color: red;">Error: Failed to infer paper</span>`);
225
+ }
226
+ return null;
227
+ }
228
+ const link = `<a href="${data.paper}" target="_blank">${data.paper}</a>`;
229
+ statusMessage.append(`<br><span style="color: green;">Inferred paper: ${link}</span>`);
230
+ return data.paper;
231
+ };
232
+
233
+ const inferCode = async (row: Row) => {
234
+ statusMessage.append(`<br><span>Inferring code...</span>`);
235
+ let data;
236
+ try {
237
+ const response = await fetch(baseURL + "/infer-code", {
238
+ method: "POST",
239
+ headers: {
240
+ "Content-Type": "application/json",
241
+ Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
242
+ },
243
+ body: JSON.stringify(row),
244
+ });
245
+ data = await response.json();
246
+ } catch (e) {
247
+ statusMessage.remove("<br><span>Inferring code...</span>");
248
+ statusMessage.append(`<br><span style="color: red;">Error: Failed to infer code</span>`);
249
+ return null;
250
+ }
251
+ statusMessage.remove("<br><span>Inferring code...</span>");
252
+ if (data.error || !data.code) {
253
+ if (data.error) {
254
+ statusMessage.append(`<br><span style="color: red;">Error: ${data.error}</span>`);
255
+ } else if (data.message) {
256
+ statusMessage.append(`<br><span>${data.message}</span>`);
257
+ } else {
258
+ statusMessage.append(`<br><span style="color: red;">Error: Failed to infer code</span>`);
259
+ }
260
+ return null;
261
+ }
262
+ const link = `<a href="${data.code}" target="_blank">${data.code}</a>`;
263
+ statusMessage.append(`<br><span style="color: green;">Inferred code: ${link}</span>`);
264
+ return data.code;
265
+ };
266
+
267
+ const inferName = async (row: Row) => {
268
+ statusMessage.append(`<br><span>Inferring name...</span>`);
269
+ let data;
270
+ try {
271
+ const response = await fetch(baseURL + "/infer-name", {
272
+ method: "POST",
273
+ headers: {
274
+ "Content-Type": "application/json",
275
+ Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
276
+ },
277
+ body: JSON.stringify(row),
278
+ });
279
+ data = await response.json();
280
+ } catch (e) {
281
+ statusMessage.remove("<br><span>Inferring name...</span>");
282
+ statusMessage.append(`<br><span style="color: red;">Error: Failed to infer name</span>`);
283
+ return null;
284
+ }
285
+ statusMessage.remove("<br><span>Inferring name...</span>");
286
+ if (data.error || !data.name) {
287
+ if (data.error) {
288
+ statusMessage.append(`<br><span style="color: red;">Error: ${data.error}</span>`);
289
+ } else if (data.message) {
290
+ statusMessage.append(`<br><span style="color: red;">Error: ${data.message}</span>`);
291
+ } else {
292
+ statusMessage.append(`<br><span style="color: red;">Error: Failed to infer name</span>`);
293
+ }
294
+ return null;
295
+ }
296
+ statusMessage.append(`<br><span style="color: green;">Inferred name: <b>${data.name}</b></span>`);
297
+ return data.name;
298
+ };
299
+
300
+ const inferAuthors = async (row: Row) => {
301
+ statusMessage.append(`<br><span>Inferring authors...</span>`);
302
+ let data;
303
+ try {
304
+ const response = await fetch(baseURL + "/infer-authors", {
305
+ method: "POST",
306
+ headers: {
307
+ "Content-Type": "application/json",
308
+ Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
309
+ },
310
+ body: JSON.stringify(row),
311
+ });
312
+ data = await response.json();
313
+ } catch (e) {
314
+ statusMessage.remove("<br><span>Inferring authors...</span>");
315
+ statusMessage.append(`<br><span style="color: red;">Error: Failed to infer authors</span>`);
316
+ return null;
317
+ }
318
+ statusMessage.remove("<br><span>Inferring authors...</span>");
319
+ if (data.error || !data.authors) {
320
+ if (data.error) {
321
+ statusMessage.append(`<br><span style="color: red;">Error: ${data.error}</span>`);
322
+ } else if (data.message) {
323
+ statusMessage.append(`<br><span>${data.message}</span>`);
324
+ } else {
325
+ statusMessage.append(`<br><span style="color: red;">Error: Failed to infer authors</span>`);
326
+ }
327
+ return null;
328
+ }
329
+ statusMessage.append(`<br><span style="color: green;">Inferred authors: ${data.authors}</span>`);
330
+ return data.authors;
331
+ };
332
+
333
+ const inferOrgs = async (row: Row) => {
334
+ statusMessage.append(`<br><span>Inferring orgs...</span>`);
335
+ let data;
336
+ try {
337
+ const response = await fetch(baseURL + "/infer-orgs", {
338
+ method: "POST",
339
+ headers: {
340
+ "Content-Type": "application/json",
341
+ Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
342
+ },
343
+ body: JSON.stringify(row),
344
+ });
345
+ data = await response.json();
346
+ } catch (e) {
347
+ statusMessage.remove("<br><span>Inferring orgs...</span>");
348
+ statusMessage.append(`<br><span style="color: red;">Error: Failed to infer orgs</span>`);
349
+ return null;
350
+ }
351
+ statusMessage.remove("<br><span>Inferring orgs...</span>");
352
+ if (data.error || !data.orgs) {
353
+ if (data.error) {
354
+ statusMessage.append(`<br><span style="color: red;">Error: ${data.error}</span>`);
355
+ } else if (data.message) {
356
+ statusMessage.append(`<br><span>${data.message}</span>`);
357
+ } else {
358
+ statusMessage.append(`<br><span style="color: red;">Error: Failed to infer orgs</span>`);
359
+ }
360
+ return null;
361
+ }
362
+ statusMessage.append(`<br><span style="color: green;">Inferred orgs: ${data.orgs}</span>`);
363
+ return data.orgs;
364
+ };
365
+
366
+ const inferDate = async (row: Row) => {
367
+ statusMessage.append(`<br><span>Inferring date...</span>`);
368
+ let data;
369
+ try {
370
+ const response = await fetch(baseURL + "/infer-date", {
371
+ method: "POST",
372
+ headers: {
373
+ "Content-Type": "application/json",
374
+ Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
375
+ },
376
+ body: JSON.stringify(row),
377
+ });
378
+ data = await response.json();
379
+ } catch (e) {
380
+ statusMessage.remove("<br><span>Inferring date...</span>");
381
+ statusMessage.append(`<br><span style="color: red;">Error: Failed to infer date</span>`);
382
+ return null;
383
+ }
384
+ statusMessage.remove("<br><span>Inferring date...</span>");
385
+ if (data.error || !data.date) {
386
+ if (data.error) {
387
+ statusMessage.append(`<br><span style="color: red;">Error: ${data.error}</span>`);
388
+ } else if (data.message) {
389
+ statusMessage.append(`<br><span>${data.message}</span>`);
390
+ } else {
391
+ statusMessage.append(`<br><span style="color: red;">Error: Failed to infer date</span>`);
392
+ }
393
+ return null;
394
+ }
395
+ statusMessage.append(`<br><span style="color: green;">Inferred date: ${data.date}</span>`);
396
+ return data.date;
397
+ };
398
+
399
+ const inferModel = async (row: Row) => {
400
+ statusMessage.append(`<br><span>Inferring model...</span>`);
401
+ let data;
402
+ try {
403
+ const response = await fetch(baseURL + "/infer-model", {
404
+ method: "POST",
405
+ headers: {
406
+ "Content-Type": "application/json",
407
+ Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
408
+ },
409
+ body: JSON.stringify(row),
410
+ });
411
+ data = await response.json();
412
+ } catch (e) {
413
+ statusMessage.remove("<br><span>Inferring model...</span>");
414
+ statusMessage.append(`<br><span style="color: red;">Error: Failed to infer model</span>`);
415
+ return null;
416
+ }
417
+ statusMessage.remove("<br><span>Inferring model...</span>");
418
+ if (data.error || !data.model) {
419
+ if (data.error) {
420
+ statusMessage.append(`<br><span style="color: red;">Error: ${data.error}</span>`);
421
+ } else if (data.message) {
422
+ statusMessage.append(`<br><span>${data.message}</span>`);
423
+ } else {
424
+ statusMessage.append(`<br><span style="color: red;">Error: Failed to infer model</span>`);
425
+ }
426
+ return null;
427
+ }
428
+ statusMessage.append(`<br><span style="color: green;">Inferred model: ${data.model}</span>`);
429
+ return data.model;
430
+ };
431
+
432
+ const inferDataset = async (row: Row) => {
433
+ statusMessage.append(`<br><span>Inferring dataset...</span>`);
434
+ let data;
435
+ try {
436
+ const response = await fetch(baseURL + "/infer-dataset", {
437
+ method: "POST",
438
+ headers: {
439
+ "Content-Type": "application/json",
440
+ Authorization: "Bearer " + import.meta.env.VITE_HF_TOKEN,
441
+ },
442
+ body: JSON.stringify(row),
443
+ });
444
+ data = await response.json();
445
+ } catch (e) {
446
+ statusMessage.remove("<br><span>Inferring dataset...</span>");
447
+ statusMessage.append(`<br><span style="color: red;">Error: Failed to infer dataset</span>`);
448
+ return null;
449
+ }
450
+ statusMessage.remove("<br><span>Inferring dataset...</span>");
451
+ if (data.error || !data.dataset) {
452
+ if (data.error) {
453
+ statusMessage.append(`<br><span style="color: red;">Error: ${data.error}</span>`);
454
+ } else if (data.message) {
455
+ statusMessage.append(`<br><span>${data.message}</span>`);
456
+ } else {
457
+ statusMessage.append(`<br><span style="color: red;">Error: Failed to infer dataset</span>`);
458
+ }
459
+ return null;
460
+ }
461
+ statusMessage.append(`<br><span style="color: green;">Inferred dataset: ${data.dataset}</span>`);
462
+ return data.dataset;
463
+ };
viewer/src/routes/store.ts ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { writable } from "svelte/store";
2
+ import type Row from "./Row";
3
+
4
+ export const editingRow = writable<Row | null>(null);
5
+ export const statusMessage = createStatusStore();
6
+
7
+ function createStatusStore() {
8
+ const { subscribe, set, update } = writable("");
9
+
10
+ return {
11
+ subscribe,
12
+ set,
13
+ append: (value: string) => update((n) => n + value),
14
+ remove: (value: string) => update((n) => n.split(value)[0]),
15
+ reset: () => set(""),
16
+ };
17
+ }