3d-arena / src /routes /ModelDetails.svelte
dylanebert's picture
dylanebert HF staff
coming soon label
2310af8
<script lang="ts">
import { onMount } from "svelte";
import { ProgressBarRound, ArrowLeft } from "carbon-icons-svelte";
interface Scene {
name: string;
url: string;
thumbnail: string;
}
interface Config {
Model: string;
Space: string;
Paper: string;
}
export let modelName: string;
export let onBack: () => void;
export let onSceneClick: (scene: Scene) => void;
let scenes: Scene[] = [];
let config: Config;
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;
}, []);
const configUrl = `https://huggingface.co/datasets/dylanebert/3d-arena/resolve/main/outputs/${modelName}/config.json`;
const configResponse = await fetch(configUrl);
config = (await configResponse.json()) as Config;
scenes = [...scenes];
}
function isValidUrl(url: string): boolean {
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">{modelName}</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">Coming Soon</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>