|
<script lang="ts"> |
|
import { onMount } from "svelte"; |
|
import { ProgressBarRound, ArrowLeft } from "carbon-icons-svelte"; |
|
import { getConfig } from "./utils/getConfig"; |
|
import type { Config } from "./utils/Config"; |
|
|
|
interface Scene { |
|
name: string; |
|
url: string; |
|
thumbnail: string; |
|
} |
|
|
|
export let modelName: string; |
|
export let onBack: () => void; |
|
export let onSceneClick: (scene: Scene) => void; |
|
|
|
let scenes: Scene[] = []; |
|
let config: Config; |
|
let displayName: string; |
|
|
|
async function fetchScenes() { |
|
scenes = []; |
|
|
|
const url = `https://huggingface.co/api/datasets/dylanebert/3d-arena`; |
|
const response = await fetch(url); |
|
const responseData = await response.json(); |
|
|
|
const directory = `outputs/${modelName}`; |
|
const extensions = ["obj", "glb", "ply", "splat"]; |
|
|
|
scenes = responseData.siblings |
|
.filter((scene: any) => { |
|
const fileExtension = scene.rfilename.split(".").pop(); |
|
return scene.rfilename.startsWith(directory) && extensions.includes(fileExtension); |
|
}) |
|
.reduce((acc: Scene[], scene: any) => { |
|
const name = scene.rfilename.split("/").pop().split(".").slice(0, -1).join("."); |
|
const url = `https://huggingface.co/datasets/dylanebert/3d-arena/resolve/main/${scene.rfilename}`; |
|
const thumbnail = url.replace(/\.[^.]+$/, ".png"); |
|
acc.push({ name, url, thumbnail }); |
|
return acc; |
|
}, []); |
|
|
|
config = await getConfig(modelName); |
|
displayName = config.DisplayName || modelName; |
|
|
|
scenes = [...scenes]; |
|
} |
|
|
|
function isValidUrl(url: string | undefined): boolean { |
|
if (!url) return false; |
|
try { |
|
new URL(url); |
|
return true; |
|
} catch (error) { |
|
return false; |
|
} |
|
} |
|
|
|
onMount(fetchScenes); |
|
</script> |
|
|
|
<div class="header"> |
|
<div class="back" aria-label="Back" aria-hidden="true" on:click={onBack}> |
|
<ArrowLeft size={24} /> |
|
</div> |
|
<div class="spacer" /> |
|
<button class="title-button" on:click={fetchScenes}> |
|
<h2 class="muted">{displayName || "Loading..."}</h2> |
|
</button> |
|
<div class="desktop-spacer" /> |
|
</div> |
|
|
|
<div class="model-details"> |
|
{#if config && (isValidUrl(config.Model) || isValidUrl(config.Space) || isValidUrl(config.Paper))} |
|
<div class="config-container"> |
|
{#if config.Model && isValidUrl(config.Model)} |
|
<div class="config-item"> |
|
<span class="config-label">Model:</span> |
|
<a class="muted" href={config.Model} target="_blank"> |
|
{config.Model.replace("https://huggingface.co/", "")} |
|
</a> |
|
</div> |
|
{/if} |
|
{#if config.Space && isValidUrl(config.Space)} |
|
<div class="config-item"> |
|
<span class="config-label">Space:</span> |
|
<a class="muted" href={config.Space} target="_blank"> |
|
{config.Space.replace("https://huggingface.co/spaces/", "")} |
|
</a> |
|
</div> |
|
{/if} |
|
{#if config.Paper && isValidUrl(config.Paper)} |
|
<div class="config-item"> |
|
<span class="config-label">Paper:</span> |
|
<a class="muted" href={config.Paper} target="_blank"> |
|
{config.Paper.replace("https://huggingface.co/papers/", "").replace( |
|
"https://arxiv.org/abs/", |
|
"", |
|
)} |
|
</a> |
|
</div> |
|
{/if} |
|
</div> |
|
{:else} |
|
<div class="config-container"> |
|
<div class="config-item"> |
|
<span class="config-label">Model:</span> |
|
<span class="muted">Anonymous</span> |
|
</div> |
|
</div> |
|
{/if} |
|
|
|
{#if scenes.length > 0} |
|
<div class="grid"> |
|
{#each scenes as scene} |
|
<button class="grid-item" on:click={() => onSceneClick(scene)}> |
|
<img loading="lazy" src={scene.thumbnail} alt={scene.name} class="thumbnail" /> |
|
<div class="title">{scene.name.length > 16 ? `${scene.name.slice(0, 16)}...` : scene.name}</div> |
|
</button> |
|
{/each} |
|
</div> |
|
{:else} |
|
<div class="loading-container"> |
|
<ProgressBarRound class="loading-icon" /> |
|
<div class="loading-text">Loading...</div> |
|
</div> |
|
{/if} |
|
</div> |
|
|