import { IconFont, StatusTag, TagsWrapper, TemplateCard, ThemeTag } from '@gpustack/core-ui'; import { useIntl, useNavigate } from '@umijs/max'; import { Button } from 'antd'; import _ from 'lodash'; import React, { useMemo } from 'react'; import styled from 'styled-components'; import { categoryConfig } from '../../_components/model-tag'; import { modelCategories, modelCategoriesMap, modelSourceMap, MyModelsStatusLabelMap, MyModelsStatusMap, MyModelsStatusValueMap } from '../config'; import { categoryToPathMap } from '../config/button-actions'; const CardWrapper = styled.div` &:hover { .content { .btn { display: block; } } } `; const Dot = styled.span` background-color: var(--ant-color-text-quaternary); border-radius: 50%; flex: none; height: 3px; width: 3px; `; const ModelItemContent = styled.div` display: flex; flex-direction: column; height: 100%; width: 100%; cursor: default; .content { display: flex; justify-content: space-between; flex: 1; } .footer { width: 100%; display: flex; justify-content: space-between; align-items: flex-end; .btn { display: none; } } .time { color: var(--ant-color-text-secondary); font-size: var(--font-size-small); font-weight: 400; } .extra-info { width: 100%; display: flex; align-items: center; gap: 8px; .tag-item { margin-right: 0; display: flex; align-items: center; justify-content: center; padding: 2px 6px; border-radius: 4px; font-size: 12px; height: 22px; opacity: 0.7; } } `; const Header = styled.div` margin-bottom: 8px; display: flex; align-items: center; justify-content: space-between; width: 100%; .anticon { font-size: 16px; color: var(--ant-color-text-secondary); } .text { display: flex; align-items: center; font-size: var(--font-size-middle); font-weight: 500; color: var(--ant-color-text); } `; const sourceIconMap = { [modelSourceMap.local_path_value]: 'icon-hard-disk', [modelSourceMap.huggingface_value]: 'icon-huggingface', [modelSourceMap.modelscope_value]: 'icon-tu2' }; const renderTag = (item: any, index = 0) => { return ( {item} ); }; const ModelItem: React.FC<{ model: Record; }> = (props) => { const { model } = props; const intl = useIntl(); const navigate = useNavigate(); // ``model.name`` from ``/v2/my-models`` is the OpenAI-style id // (org-prefixed for non-platform routes, bare for platform). Use it // verbatim — the playground / dispatcher both key off that exact id. const handleOpenPlayGroundClick = () => { const modelName = encodeURIComponent(model.name); for (const [category, path] of Object.entries(categoryToPathMap)) { if ( model.categories?.includes(category) && [ modelCategoriesMap.text_to_speech, modelCategoriesMap.speech_to_text ].includes(category) ) { navigate(`${path}&model=${modelName}`); return; } if (model.categories?.includes(category)) { navigate(`${path}?model=${modelName}`); return; } } navigate(`/playground/chat?model=${modelName}`); }; // context length const maxToken = useMemo(() => { const meta = model.meta || {}; const { max_model_len, n_ctx, n_slot, max_total_tokens } = meta || {}; let max_tokens: number = 0; if (n_ctx && n_slot) { max_tokens = _.divide(n_ctx, n_slot); } else if (max_model_len) { max_tokens = max_model_len; } else if (max_total_tokens) { max_tokens = max_total_tokens; } return _.round(max_tokens / 1024); }, [model]); return ( {model.name} } >
{model.categories?.length > 0 && model.categories.map((sItem: string) => { return ( {_.find(modelCategories, { value: sItem })?.label || sItem} ); })} {maxToken > 0 && ( <> {maxToken}K context )} {model.meta?.voices?.length > 0 && ( <> )}
{[MyModelsStatusValueMap.Active].includes(model.status) && ( )}
); }; export default ModelItem;