From 64f57034610a5cc8553d8eadd2df3f6a3d4c0576 Mon Sep 17 00:00:00 2001 From: Louis Date: Mon, 26 May 2025 15:13:22 +0700 Subject: [PATCH] chore: allow users to import hf repo (#5103) * chore: allow users to input HF repo id / url * chore: allow users to search HuggingFace models * chore: normalize input * chore: normalize input from FE * chore: clean up * chore: clean up * fix: conflict * fix: model name from metada instead id * chore: enable ryhype raw for desc card hub * fix: broken link * chore: remove log --------- Co-authored-by: Faisal Amir --- web-app/src/containers/Card.tsx | 2 +- web-app/src/containers/RenderMarkdown.tsx | 7 ++- web-app/src/routes/hub.tsx | 57 +++++++++++++++++++---- 3 files changed, 55 insertions(+), 11 deletions(-) diff --git a/web-app/src/containers/Card.tsx b/web-app/src/containers/Card.tsx index 324b98b2d..5147a9396 100644 --- a/web-app/src/containers/Card.tsx +++ b/web-app/src/containers/Card.tsx @@ -36,7 +36,7 @@ export function CardItem({ )} >
-

{title}

+

{title}

{description && ( {description} diff --git a/web-app/src/containers/RenderMarkdown.tsx b/web-app/src/containers/RenderMarkdown.tsx index cfba11187..09fe6a448 100644 --- a/web-app/src/containers/RenderMarkdown.tsx +++ b/web-app/src/containers/RenderMarkdown.tsx @@ -14,15 +14,18 @@ import { cn } from '@/lib/utils' import { useCodeblock } from '@/hooks/useCodeblock' import 'katex/dist/katex.min.css' import { IconCopy, IconCopyCheck } from '@tabler/icons-react' +import rehypeRaw from 'rehype-raw' interface MarkdownProps { content: string className?: string components?: Components + enableRawHtml?: boolean } function RenderMarkdownComponent({ content, + enableRawHtml, className, components, }: MarkdownProps) { @@ -147,7 +150,9 @@ function RenderMarkdownComponent({ }, []) // Memoize the rehypePlugins to prevent unnecessary re-renders - const rehypePlugins = useMemo(() => [rehypeKatex], []) + const rehypePlugins = useMemo(() => { + return enableRawHtml ? [rehypeKatex, rehypeRaw] : [rehypeKatex] + }, [enableRawHtml]) // Merge custom components with default components const mergedComponents = useMemo( diff --git a/web-app/src/routes/hub.tsx b/web-app/src/routes/hub.tsx index 7b22a4531..83faf3597 100644 --- a/web-app/src/routes/hub.tsx +++ b/web-app/src/routes/hub.tsx @@ -2,7 +2,14 @@ import { createFileRoute, Link, useNavigate } from '@tanstack/react-router' import { route } from '@/constants/routes' import { useModelSources } from '@/hooks/useModelSources' import { cn, fuzzySearch, toGigabytes } from '@/lib/utils' -import { useState, useMemo, useEffect, ChangeEvent, useCallback } from 'react' +import { + useState, + useMemo, + useEffect, + ChangeEvent, + useCallback, + useRef, +} from 'react' import { Button } from '@/components/ui/button' import { useModelProvider } from '@/hooks/useModelProvider' import { Card, CardItem } from '@/containers/Card' @@ -16,10 +23,11 @@ import { DropdownMenuItem, DropdownMenuTrigger, } from '@/components/ui/dropdown-menu' -import { downloadModel } from '@/services/models' +import { addModelSource, downloadModel } from '@/services/models' import { useDownloadStore } from '@/hooks/useDownloadStore' import { Progress } from '@/components/ui/progress' import HeaderPage from '@/containers/HeaderPage' +import { Loader } from 'lucide-react' type ModelProps = { model: { @@ -47,6 +55,10 @@ function Hub() { const [expandedModels, setExpandedModels] = useState>( {} ) + const [isSearching, setIsSearching] = useState(false) + const addModelSourceTimeoutRef = useRef | null>( + null + ) const toggleModelExpansion = (modelId: string) => { setExpandedModels((prev) => ({ @@ -87,7 +99,26 @@ function Hub() { }, [fetchSources]) const handleSearchChange = (e: ChangeEvent) => { + setIsSearching(false) setSearchValue(e.target.value) + if (addModelSourceTimeoutRef.current) { + clearTimeout(addModelSourceTimeoutRef.current) + } + if ( + e.target.value.length && + (e.target.value.includes('/') || e.target.value.startsWith('http')) + ) { + setIsSearching(true) + addModelSourceTimeoutRef.current = setTimeout(() => { + addModelSource(e.target.value) + .then(() => { + fetchSources() + }) + .finally(() => { + setIsSearching(false) + }) + }, 500) + } } const { downloads } = useDownloadStore() @@ -163,10 +194,14 @@ function Hub() {
-
- +
+ {isSearching ? ( + + ) : ( + + )}

- {extractModelName(model.id) || ''} + {extractModelName(model.metadata?.id) || ''}