Skip to content

Commit

Permalink
feat: fetch the Hugging Face README file using a URL
Browse files Browse the repository at this point in the history
  • Loading branch information
agatha197 committed Sep 19, 2024
1 parent 96dce7b commit 6f06b46
Show file tree
Hide file tree
Showing 23 changed files with 203 additions and 64 deletions.
60 changes: 60 additions & 0 deletions react/src/components/HuggingFaceReadmeCard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { baiSignedRequestWithPromise } from '../helper';
import { useSuspendedBackendaiClient } from '../hooks';
import { useSuspenseTanQuery } from '../hooks/reactQueryAlias';
import Flex from './Flex';
import { FilterOutlined } from '@ant-design/icons';
import { Card, CardProps, theme } from 'antd';
import React from 'react';
import Markdown from 'react-markdown';

interface HuggingFaceReadmeCardProps extends CardProps {
huggingFaceUrl: string;
}

const HuggingFaceReadmeCard: React.FC<HuggingFaceReadmeCardProps> = ({
huggingFaceUrl,
...cardProps
}) => {
const baiClient = useSuspendedBackendaiClient();
const { token } = theme.useToken();

const { data } = useSuspenseTanQuery<{
author: string;
model_name: string;
markdown: string;
}>({
queryKey: ['huggingFaceReadme', huggingFaceUrl],
queryFn: () => {
return baiSignedRequestWithPromise({
method: 'GET',
url: `/services/_/huggingface/models?huggingface_url=${huggingFaceUrl}`,
client: baiClient,
});
},
});

return (
<Card
size="small"
title={
<Flex direction="row" gap="xs">
<FilterOutlined />
README.md
</Flex>
}
styles={{
body: {
padding: token.paddingLG,
overflow: 'auto',
minHeight: 200,
maxHeight: token.screenXS,
},
}}
{...cardProps}
>
<Markdown>{data?.markdown}</Markdown>
</Card>
);
};

export default HuggingFaceReadmeCard;
81 changes: 59 additions & 22 deletions react/src/components/ImportFromHuggingFaceModal.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
import BAIModal, { BAIModalProps } from './BAIModal';
import Flex from './Flex';
import HuggingFaceReadmeCard from './HuggingFaceReadmeCard';
import { FilterOutlined } from '@ant-design/icons';
import { useToggle } from 'ahooks';
import {
Button,
Card,
Empty,
Form,
FormInstance,
Input,
Switch,
theme,
Typography,
} from 'antd';
import Markdown from 'markdown-to-jsx';
import React, { useRef } from 'react';
import React, { Suspense, useRef } from 'react';
import { useTranslation } from 'react-i18next';

type Service = {
Expand All @@ -26,6 +27,31 @@ interface ImportFromHuggingFaceModalProps extends BAIModalProps {
onRequestClose: () => void;
}

const ReadmeFallbackCard = () => {
const { token } = theme.useToken();
return (
<Card
size="small"
title={
<Flex direction="row" gap="xs">
<FilterOutlined />
README.md
</Flex>
}
styles={{
body: {
padding: token.paddingLG,
overflow: 'auto',
minHeight: 200,
maxHeight: token.screenXS,
},
}}
>
<Empty image={Empty.PRESENTED_IMAGE_SIMPLE} />
</Card>
);
};

const ImportFromHuggingFaceModal: React.FC<ImportFromHuggingFaceModalProps> = ({
onRequestClose,
...baiModalProps
Expand All @@ -34,6 +60,9 @@ const ImportFromHuggingFaceModal: React.FC<ImportFromHuggingFaceModalProps> = ({
const { token } = theme.useToken();
const formRef = useRef<FormInstance<Service>>(null);
const [isImportOnly, { toggle: toggleIsImportOnly }] = useToggle(false);
const [huggingFaceUrl, setHuggingFaceUrl] = React.useState<
string | undefined
>();

const handleOnClick = () => {
formRef.current
Expand Down Expand Up @@ -65,28 +94,36 @@ const ImportFromHuggingFaceModal: React.FC<ImportFromHuggingFaceModalProps> = ({
layout="vertical"
requiredMark="optional"
>
<Form.Item name="url" rules={[{ required: true }]}>
<Input placeholder={t('data.modelStore.huggingFaceUrlPlaceholder')} />
</Form.Item>
<Card
size="small"
title={
<Flex direction="row" gap="xs">
<FilterOutlined />
README.md
</Flex>
}
styles={{
body: {
padding: token.paddingLG,
overflow: 'auto',
minHeight: 200,
maxHeight: token.screenXS,
<Form.Item
name="url"
rules={[
{ required: true },
{ type: 'url', message: t('error.InvalidUrl') },
{
pattern: /^https:\/\/huggingface.co\/.*/,
message: t('data.modelStore.StartWithHuggingFaceUrl'),
},
}}
]}
>
<Markdown>{''}</Markdown>
</Card>
<Input
placeholder={t('data.modelStore.huggingFaceUrlPlaceholder')}
onChange={(e) => {
formRef.current
?.validateFields(['url'])
.then((v) => {
setHuggingFaceUrl(v?.url);
})
.catch(() => {});
}}
/>
</Form.Item>
{huggingFaceUrl ? (
<Suspense fallback={<ReadmeFallbackCard />}>
<HuggingFaceReadmeCard huggingFaceUrl={huggingFaceUrl} />
</Suspense>
) : (
<ReadmeFallbackCard />
)}
<Flex
gap={'xs'}
style={{ marginTop: token.marginLG, marginBottom: token.marginLG }}
Expand Down
6 changes: 4 additions & 2 deletions resources/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,8 @@
"ReplicaNumber": "Replikatnummer",
"ImportAndStartService": "Dienst importieren und starten",
"huggingFaceUrlPlaceholder": "Geben Sie die URL Hugging Face ein",
"ImportOnly": "Nur importieren"
"ImportOnly": "Nur importieren",
"StartWithHuggingFaceUrl": "Es sollte mit https://huggingface.co beginnen"
}
},
"dialog": {
Expand Down Expand Up @@ -1483,7 +1484,8 @@
"SmallerResourceThenImageRequires": "Ihre Ressourcenanforderung ist kleiner als das für das Bild erforderliche Minimum. Versuchen Sie es mit mehr Ressourcen.",
"APINotSupported": "API wird nicht unterstützt. Erfordert die neueste Version des Backend.AI-Managers.",
"WrongAPIServerAddress": "Falsche API-Serveradresse.",
"ReachedResourceLimitPleaseContact": "Ihr Ressourcenlimit wurde erreicht. \nBitte wenden Sie sich an den Administrator."
"ReachedResourceLimitPleaseContact": "Ihr Ressourcenlimit wurde erreicht. \nBitte wenden Sie sich an den Administrator.",
"InvalidUrl": "Es handelt sich nicht um eine gültige URL"
},
"maxLength": {
"64chars": "(maximal 64 Zeichen)",
Expand Down
6 changes: 4 additions & 2 deletions resources/i18n/el.json
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,8 @@
"ReplicaNumber": "Αριθμός αντιγράφου",
"ImportAndStartService": "Εισαγωγή και έναρξη υπηρεσίας",
"huggingFaceUrlPlaceholder": "Εισαγάγετε τη διεύθυνση URL Hugging Face.",
"ImportOnly": "Μόνο εισαγωγή"
"ImportOnly": "Μόνο εισαγωγή",
"StartWithHuggingFaceUrl": "Θα πρέπει να ξεκινά με https://huggingface.co"
}
},
"dialog": {
Expand Down Expand Up @@ -1483,7 +1484,8 @@
"SmallerResourceThenImageRequires": "Το αίτημα πόρων είναι μικρότερο από το ελάχιστο απαιτούμενο από την εικόνα. Δοκιμάστε περισσότερους πόρους.",
"APINotSupported": "Το API δεν υποστηρίζεται. Απαιτείται η τελευταία έκδοση του διαχειριστή Backend.AI.",
"WrongAPIServerAddress": "Λάθος διεύθυνση διακομιστή API.",
"ReachedResourceLimitPleaseContact": "Φτάσατε το όριο των πόρων σας. \nΕπικοινωνήστε με τον διαχειριστή."
"ReachedResourceLimitPleaseContact": "Φτάσατε το όριο των πόρων σας. \nΕπικοινωνήστε με τον διαχειριστή.",
"InvalidUrl": "Δεν είναι έγκυρη διεύθυνση URL"
},
"maxLength": {
"64chars": "(έως 64 χαρακτήρες)",
Expand Down
6 changes: 4 additions & 2 deletions resources/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -911,7 +911,8 @@
"ReplicaNumber": "Replica Number",
"ImportAndStartService": "Import & Start Service",
"huggingFaceUrlPlaceholder": "Input Hugging Face URL",
"ImportOnly": "Import only"
"ImportOnly": "Import only",
"StartWithHuggingFaceUrl": "It should start with https://huggingface.co"
}
},
"dialog": {
Expand Down Expand Up @@ -1610,7 +1611,8 @@
"FolderSharingNotAvailableToUser": "Folder sharing is not available for requested user(s).",
"APINotSupported": "API not supported. Requires latest version of Backend.AI manager.",
"ErrorFetchingExternalContent": "Error fetching external content:",
"ReachedResourceLimitPleaseContact": "Reached your resource limit. Please contact the administrator."
"ReachedResourceLimitPleaseContact": "Reached your resource limit. Please contact the administrator.",
"InvalidUrl": "It is not a valid URL"
},
"maxLength": {
"64chars": "(maximum 64 chars)",
Expand Down
6 changes: 4 additions & 2 deletions resources/i18n/es.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@
"UserHasNoGroup": "El usuario no tiene grupo. Póngase en contacto con el administrador para solucionarlo.",
"UserNameAlreadyExist": "El nombre de usuario ya existe. No se puede duplicar.",
"VirtualFolderAlreadyExist": "Ya existe una carpeta virtual con el mismo nombre. Elimine su propia carpeta o rechace la invitación.",
"ReachedResourceLimitPleaseContact": "Alcanzó su límite de recursos. \nPor favor contacte al administrador."
"ReachedResourceLimitPleaseContact": "Alcanzó su límite de recursos. \nPor favor contacte al administrador.",
"InvalidUrl": "No es una URL válida"
},
"DownloadSSHKey": "Descargar clave SSH",
"ErrorBoundary": {
Expand Down Expand Up @@ -416,7 +417,8 @@
"ReplicaNumber": "Número de réplica",
"ImportAndStartService": "Servicio de importación e inicio",
"huggingFaceUrlPlaceholder": "Introduzca la URL Hugging Face",
"ImportOnly": "Sólo importar"
"ImportOnly": "Sólo importar",
"StartWithHuggingFaceUrl": "Debería comenzar con https://huggingface.co"
}
},
"dialog": {
Expand Down
6 changes: 4 additions & 2 deletions resources/i18n/fi.json
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@
"UserHasNoGroup": "Käyttäjällä ei ole ryhmää. Ota yhteyttä ylläpitäjään sen korjaamiseksi.",
"UserNameAlreadyExist": "Käyttäjätunnus on jo olemassa. Sitä ei voi kopioida.",
"VirtualFolderAlreadyExist": "Samanniminen virtuaalikansio on jo olemassa. Poista oma kansiosi tai hylkää kutsu.",
"ReachedResourceLimitPleaseContact": "Resurssiraja saavutettu. \nOta yhteyttä ylläpitäjään."
"ReachedResourceLimitPleaseContact": "Resurssiraja saavutettu. \nOta yhteyttä ylläpitäjään.",
"InvalidUrl": "Se ei ole kelvollinen URL-osoite"
},
"DownloadSSHKey": "Lataa SSH-avain",
"ErrorBoundary": {
Expand Down Expand Up @@ -416,7 +417,8 @@
"ReplicaNumber": "Replikan numero",
"ImportAndStartService": "Tuo ja käynnistä palvelu",
"huggingFaceUrlPlaceholder": "Syötä Hugging Face-URL-osoite",
"ImportOnly": "Vain tuonti"
"ImportOnly": "Vain tuonti",
"StartWithHuggingFaceUrl": "Sen pitäisi alkaa https://huggingface.co"
}
},
"dialog": {
Expand Down
6 changes: 4 additions & 2 deletions resources/i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,8 @@
"ReplicaNumber": "Numéro de réplique",
"ImportAndStartService": "Service d'importation et de démarrage",
"huggingFaceUrlPlaceholder": "Saisissez l'URL Hugging Face",
"ImportOnly": "Importer uniquement"
"ImportOnly": "Importer uniquement",
"StartWithHuggingFaceUrl": "Cela devrait commencer par https://huggingface.co"
}
},
"dialog": {
Expand Down Expand Up @@ -1483,7 +1484,8 @@
"SmallerResourceThenImageRequires": "Votre demande de ressources est inférieure au minimum requis par l'image. Essayez d'autres ressources.",
"APINotSupported": "L'API n'est pas prise en charge. Nécessite la dernière version du gestionnaire Backend.AI.",
"WrongAPIServerAddress": "Mauvaise adresse du serveur API.",
"ReachedResourceLimitPleaseContact": "Vous avez atteint votre limite de ressources. \nVeuillez contacter l'administrateur."
"ReachedResourceLimitPleaseContact": "Vous avez atteint votre limite de ressources. \nVeuillez contacter l'administrateur.",
"InvalidUrl": "Ce n'est pas une URL valide"
},
"maxLength": {
"64chars": "(maximum 64 caractères)",
Expand Down
6 changes: 4 additions & 2 deletions resources/i18n/id.json
Original file line number Diff line number Diff line change
Expand Up @@ -787,7 +787,8 @@
"ReplicaNumber": "Nomor Replika",
"ImportAndStartService": "Impor dan Mulai Layanan",
"huggingFaceUrlPlaceholder": "Masukkan URL Hugging Face",
"ImportOnly": "Impor saja"
"ImportOnly": "Impor saja",
"StartWithHuggingFaceUrl": "Ini harus dimulai dengan https://huggingface.co"
}
},
"dialog": {
Expand Down Expand Up @@ -1484,7 +1485,8 @@
"SmallerResourceThenImageRequires": "Permintaan sumber daya Anda lebih kecil dari jumlah minimum yang dibutuhkan oleh gambar. Coba lebih banyak sumber daya.",
"APINotSupported": "API tidak didukung. Memerlukan versi terbaru dari manajer Backend.AI.",
"WrongAPIServerAddress": "Alamat server API salah.",
"ReachedResourceLimitPleaseContact": "Mencapai batas sumber daya Anda. \nSilakan hubungi administrator."
"ReachedResourceLimitPleaseContact": "Mencapai batas sumber daya Anda. \nSilakan hubungi administrator.",
"InvalidUrl": "Ini bukan URL yang valid"
},
"maxLength": {
"64chars": "(maksimum 64 karakter)",
Expand Down
6 changes: 4 additions & 2 deletions resources/i18n/it.json
Original file line number Diff line number Diff line change
Expand Up @@ -787,7 +787,8 @@
"ReplicaNumber": "Numero di replica",
"ImportAndStartService": "Importa e avvia il servizio",
"huggingFaceUrlPlaceholder": "Inserisci l'URL Hugging Face.",
"ImportOnly": "Solo importazione"
"ImportOnly": "Solo importazione",
"StartWithHuggingFaceUrl": "Dovrebbe iniziare con https://huggingface.co"
}
},
"dialog": {
Expand Down Expand Up @@ -1483,7 +1484,8 @@
"SmallerResourceThenImageRequires": "La richiesta di risorse è inferiore al minimo richiesto dall'immagine. Provare con altre risorse.",
"APINotSupported": "API non supportata. Richiede l'ultima versione del gestore Backend.AI.",
"WrongAPIServerAddress": "Indirizzo del server API errato.",
"ReachedResourceLimitPleaseContact": "Raggiunto il limite delle risorse. \nSi prega di contattare l'amministratore."
"ReachedResourceLimitPleaseContact": "Raggiunto il limite delle risorse. \nSi prega di contattare l'amministratore.",
"InvalidUrl": "Non è un URL valido"
},
"maxLength": {
"64chars": "(massimo 64 caratteri)",
Expand Down
6 changes: 4 additions & 2 deletions resources/i18n/ja.json
Original file line number Diff line number Diff line change
Expand Up @@ -786,7 +786,8 @@
"ReplicaNumber": "レプリカ番号",
"ImportAndStartService": "サービスのインポートと開始",
"huggingFaceUrlPlaceholder": "Hugging Faceの URL を入力してください",
"ImportOnly": "輸入のみ"
"ImportOnly": "輸入のみ",
"StartWithHuggingFaceUrl": "https://huggingface.co で始まる必要があります"
}
},
"dialog": {
Expand Down Expand Up @@ -1482,7 +1483,8 @@
"SmallerResourceThenImageRequires": "リソース要求が画像に必要な最小値より小さい。より多くのリソースを試してください。",
"APINotSupported": "APIはサポートされていません。最新バージョンのBackend.AIマネージャが必要です。",
"WrongAPIServerAddress": "APIサーバーのアドレスが間違っています。",
"ReachedResourceLimitPleaseContact": "リソース制限に達しました。\n管理者にお問い合わせください。"
"ReachedResourceLimitPleaseContact": "リソース制限に達しました。\n管理者にお問い合わせください。",
"InvalidUrl": "有効な URL ではありません"
},
"maxLength": {
"64chars": "(最大64文字)",
Expand Down
6 changes: 4 additions & 2 deletions resources/i18n/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -898,7 +898,8 @@
"ReplicaNumber": "복제 번호",
"ImportAndStartService": "가져오기 및 서비스 시작",
"huggingFaceUrlPlaceholder": "Hugging Face URL을 입력하세요.",
"ImportOnly": "가져오기만 허용"
"ImportOnly": "가져오기만 허용",
"StartWithHuggingFaceUrl": "https://huggingface.co로 시작해야 합니다."
}
},
"dialog": {
Expand Down Expand Up @@ -1595,7 +1596,8 @@
"CannotSharePrivateAutomountFolder": "정책에 따라 자동마운트 폴더는 공유할 수 없습니다.",
"FolderSharingNotAvailableToUser": "요청한 사용자는 폴더 공유가 불가능한 상태입니다.",
"APINotSupported": "지원하지 않는 API입니다. 최신 버전의 Backend.AI 매니저가 필요합니다.",
"ReachedResourceLimitPleaseContact": "자원 제한에 도달했습니다. 관리자에게 문의하세요."
"ReachedResourceLimitPleaseContact": "자원 제한에 도달했습니다. 관리자에게 문의하세요.",
"InvalidUrl": "유효한 URL이 아닙니다."
},
"maxLength": {
"64chars": "(최대 길이 64자)",
Expand Down
Loading

0 comments on commit 6f06b46

Please sign in to comment.