Open-Greek-Financial-LLM-Leaderboard
/
frontend
/src
/pages
/AddModelPage
/components
/ModelSubmissionForm
/ModelSubmissionForm.js
import React, { useState } from "react"; | |
import { | |
Box, | |
Paper, | |
Typography, | |
TextField, | |
Button, | |
FormControl, | |
InputLabel, | |
Select, | |
MenuItem, | |
FormControlLabel, | |
Switch, | |
Stack, | |
Grid, | |
CircularProgress, | |
Alert, | |
} from "@mui/material"; | |
import RocketLaunchIcon from "@mui/icons-material/RocketLaunch"; | |
import CheckCircleOutlineIcon from "@mui/icons-material/CheckCircleOutline"; | |
import ThumbUpIcon from "@mui/icons-material/ThumbUp"; | |
import { alpha } from "@mui/material/styles"; | |
import InfoIconWithTooltip from "../../../../components/shared/InfoIconWithTooltip"; | |
import { MODEL_TYPES } from "../../../../pages/LeaderboardPage/components/Leaderboard/constants/modelTypes"; | |
import { SUBMISSION_PRECISIONS } from "../../../../pages/LeaderboardPage/components/Leaderboard/constants/defaults"; | |
import AuthContainer from "../../../../components/shared/AuthContainer"; | |
const WEIGHT_TYPES = [ | |
{ value: "Original", label: "Original" }, | |
{ value: "Delta", label: "Delta" }, | |
{ value: "Adapter", label: "Adapter" }, | |
]; | |
const HELP_TEXTS = { | |
modelName: ( | |
<Box sx={{ p: 1 }}> | |
<Typography variant="subtitle2" sx={{ fontWeight: 600, mb: 0.5 }}> | |
Model Name on Hugging Face Hub | |
</Typography> | |
<Typography variant="body2" sx={{ opacity: 0.9, lineHeight: 1.4 }}> | |
Your model must be public and loadable with AutoClasses without | |
trust_remote_code. The model should be in Safetensors format for better | |
safety and loading performance. Example: mistralai/Mistral-7B-v0.1 | |
</Typography> | |
</Box> | |
), | |
revision: ( | |
<Box sx={{ p: 1 }}> | |
<Typography variant="subtitle2" sx={{ fontWeight: 600, mb: 0.5 }}> | |
Model Revision | |
</Typography> | |
<Typography variant="body2" sx={{ opacity: 0.9, lineHeight: 1.4 }}> | |
Git branch, tag or commit hash. The evaluation will be strictly tied to | |
this specific commit to ensure consistency. Make sure this version is | |
stable and contains all necessary files. | |
</Typography> | |
</Box> | |
), | |
modelType: ( | |
<Box sx={{ p: 1 }}> | |
<Typography variant="subtitle2" sx={{ fontWeight: 600, mb: 0.5 }}> | |
Model Category | |
</Typography> | |
<Typography variant="body2" sx={{ opacity: 0.9, lineHeight: 1.4 }}> | |
🟢 Pretrained: Base models trained on text using masked modeling 🟩 | |
Continuously Pretrained: Extended training on additional corpus 🔶 | |
Fine-tuned: Domain-specific optimization 💬 Chat: Models using RLHF, | |
DPO, or IFT for conversation 🤝 Merge: Combined weights without | |
additional training 🌸 Multimodal: Handles multiple input types | |
</Typography> | |
</Box> | |
), | |
baseModel: ( | |
<Box sx={{ p: 1 }}> | |
<Typography variant="subtitle2" sx={{ fontWeight: 600, mb: 0.5 }}> | |
Base Model Reference | |
</Typography> | |
<Typography variant="body2" sx={{ opacity: 0.9, lineHeight: 1.4 }}> | |
Required for delta weights or adapters. This information is used to | |
identify the original model and calculate the total parameter count by | |
combining base model and adapter/delta parameters. | |
</Typography> | |
</Box> | |
), | |
precision: ( | |
<Box sx={{ p: 1 }}> | |
<Typography variant="subtitle2" sx={{ fontWeight: 600, mb: 0.5 }}> | |
Model Precision | |
</Typography> | |
<Typography variant="body2" sx={{ opacity: 0.9, lineHeight: 1.4 }}> | |
Size limits vary by precision: • FP16/BF16: up to 100B parameters • | |
8-bit: up to 280B parameters (2x) • 4-bit: up to 560B parameters (4x) | |
Choose carefully as incorrect precision can cause evaluation errors. | |
</Typography> | |
</Box> | |
), | |
weightsType: ( | |
<Box sx={{ p: 1 }}> | |
<Typography variant="subtitle2" sx={{ fontWeight: 600, mb: 0.5 }}> | |
Weights Format | |
</Typography> | |
<Typography variant="body2" sx={{ opacity: 0.9, lineHeight: 1.4 }}> | |
Original: Complete model weights in safetensors format Delta: Weight | |
differences from base model (requires base model for size calculation) | |
Adapter: Lightweight fine-tuning layers (requires base model for size | |
calculation) | |
</Typography> | |
</Box> | |
), | |
chatTemplate: ( | |
<Box sx={{ p: 1 }}> | |
<Typography variant="subtitle2" sx={{ fontWeight: 600, mb: 0.5 }}> | |
Chat Template Support | |
</Typography> | |
<Typography variant="body2" sx={{ opacity: 0.9, lineHeight: 1.4 }}> | |
Activates automatically for chat models. It uses the standardized Hugging | |
Face chat template for consistent prompt formatting during evaluation. | |
Required for models using RLHF, DPO, or instruction fine-tuning. | |
</Typography> | |
</Box> | |
), | |
}; | |
// Convert MODEL_TYPES to format expected by Select component | |
const modelTypeOptions = Object.entries(MODEL_TYPES).map( | |
([value, { icon, label }]) => ({ | |
value, | |
label: `${icon} ${label}`, | |
}) | |
); | |
function ModelSubmissionForm({ user, isAuthenticated }) { | |
const [formData, setFormData] = useState({ | |
modelName: "", | |
revision: "main", | |
modelType: "fine-tuned", | |
isChatModel: false, | |
useChatTemplate: false, | |
precision: "float16", | |
weightsType: "Original", | |
baseModel: "", | |
}); | |
const [error, setError] = useState(null); | |
const [submitting, setSubmitting] = useState(false); | |
const [success, setSuccess] = useState(false); | |
const [submittedData, setSubmittedData] = useState(null); | |
const handleChange = (event) => { | |
const { name, value, checked } = event.target; | |
setFormData((prev) => ({ | |
...prev, | |
[name]: event.target.type === "checkbox" ? checked : value, | |
})); | |
}; | |
const handleSubmit = async (e) => { | |
e.preventDefault(); | |
setError(null); | |
setSubmitting(true); | |
try { | |
const response = await fetch("/api/models/submit", { | |
method: "POST", | |
headers: { | |
"Content-Type": "application/json", | |
}, | |
body: JSON.stringify({ | |
model_id: formData.modelName, | |
revision: formData.revision, | |
model_type: formData.modelType, | |
precision: formData.precision, | |
weight_type: formData.weightsType, | |
base_model: formData.baseModel, | |
use_chat_template: formData.useChatTemplate, | |
user_id: user.username, | |
}), | |
}); | |
if (!response.ok) { | |
const error = await response.json(); | |
throw new Error(error.detail || "Failed to submit model"); | |
} | |
setSubmittedData(formData); | |
setSuccess(true); | |
} catch (error) { | |
setError(error.message); | |
} finally { | |
setSubmitting(false); | |
} | |
}; | |
if (success && submittedData) { | |
return ( | |
<Paper | |
variant="outlined" | |
sx={(theme) => ({ | |
p: 6, | |
mb: 3, | |
bgcolor: alpha(theme.palette.success.main, 0.05), | |
borderColor: alpha(theme.palette.success.main, 0.2), | |
})} | |
> | |
<Stack spacing={3}> | |
<Stack direction="row" spacing={2} alignItems="center"> | |
<CheckCircleOutlineIcon color="success" sx={{ fontSize: 28 }} /> | |
<Typography | |
variant="h5" | |
sx={{ fontWeight: 600, color: "success.800" }} | |
> | |
Model submitted successfully! | |
</Typography> | |
</Stack> | |
<Typography variant="body1"> | |
Your model <strong>{submittedData.modelName}</strong> has been added | |
to the evaluation queue with the following parameters: | |
</Typography> | |
<Paper | |
variant="outlined" | |
sx={{ | |
p: 2, | |
borderColor: "divider", | |
}} | |
> | |
<Stack spacing={1.5}> | |
<Stack direction="row" spacing={2}> | |
<Typography | |
variant="body2" | |
color="text.secondary" | |
sx={{ width: 120 }} | |
> | |
Model: | |
</Typography> | |
<Typography variant="body2" sx={{ fontFamily: "monospace" }}> | |
{submittedData.modelName} | |
</Typography> | |
</Stack> | |
<Stack direction="row" spacing={2}> | |
<Typography | |
variant="body2" | |
color="text.secondary" | |
sx={{ width: 120 }} | |
> | |
Type: | |
</Typography> | |
<Typography variant="body2"> | |
{submittedData.modelType} | |
</Typography> | |
</Stack> | |
<Stack direction="row" spacing={2}> | |
<Typography | |
variant="body2" | |
color="text.secondary" | |
sx={{ width: 120 }} | |
> | |
Revision: | |
</Typography> | |
<Typography variant="body2" sx={{ fontFamily: "monospace" }}> | |
{submittedData.revision} | |
</Typography> | |
</Stack> | |
<Stack direction="row" spacing={2}> | |
<Typography | |
variant="body2" | |
color="text.secondary" | |
sx={{ width: 120 }} | |
> | |
Precision: | |
</Typography> | |
<Typography variant="body2"> | |
{submittedData.precision} | |
</Typography> | |
</Stack> | |
<Stack direction="row" spacing={2}> | |
<Typography | |
variant="body2" | |
color="text.secondary" | |
sx={{ width: 120 }} | |
> | |
Weight type: | |
</Typography> | |
<Typography variant="body2"> | |
{submittedData.weightsType} | |
</Typography> | |
</Stack> | |
{submittedData.baseModel && ( | |
<Stack direction="row" spacing={2}> | |
<Typography | |
variant="body2" | |
color="text.secondary" | |
sx={{ width: 120 }} | |
> | |
Base model: | |
</Typography> | |
<Typography variant="body2"> | |
{submittedData.baseModel} | |
</Typography> | |
</Stack> | |
)} | |
<Stack direction="row" spacing={2}> | |
<Typography | |
variant="body2" | |
color="text.secondary" | |
sx={{ width: 120 }} | |
> | |
Chat template: | |
</Typography> | |
<Typography variant="body2"> | |
{submittedData.useChatTemplate ? "Yes" : "No"} | |
</Typography> | |
</Stack> | |
</Stack> | |
</Paper> | |
<Typography variant="body2" color="text.secondary"> | |
An automatic upvote has been added to your model to help with | |
prioritization. | |
</Typography> | |
<Stack direction="row" spacing={2}> | |
<Button | |
variant="outlined" | |
size="large" | |
onClick={() => { | |
setSuccess(false); | |
setSubmittedData(null); | |
setFormData({ | |
modelName: "", | |
revision: "main", | |
modelType: "fine-tuned", | |
isChatModel: false, | |
useChatTemplate: false, | |
precision: "float16", | |
weightsType: "Original", | |
baseModel: "", | |
}); | |
}} | |
> | |
Submit another model | |
</Button> | |
</Stack> | |
</Stack> | |
</Paper> | |
); | |
} | |
return ( | |
<> | |
{error && ( | |
<Alert severity="error" sx={{ mb: 2 }}> | |
{error} | |
</Alert> | |
)} | |
<AuthContainer actionText="submit a model" /> | |
{isAuthenticated && ( | |
<Paper | |
elevation={0} | |
component="form" | |
onSubmit={handleSubmit} | |
sx={{ | |
p: 0, | |
border: "1px solid", | |
borderColor: "grey.300", | |
mb: 3, | |
overflow: "hidden", | |
}} | |
> | |
{/* Header */} | |
<Box | |
sx={{ | |
px: 3, | |
py: 2, | |
borderBottom: "1px solid", | |
borderColor: (theme) => | |
theme.palette.mode === "dark" | |
? alpha(theme.palette.divider, 0.1) | |
: "grey.200", | |
bgcolor: (theme) => | |
theme.palette.mode === "dark" | |
? alpha(theme.palette.background.paper, 0.5) | |
: "grey.50", | |
}} | |
> | |
<Typography | |
variant="h6" | |
sx={{ fontWeight: 600, color: "text.primary" }} | |
> | |
Model Submission Form | |
</Typography> | |
</Box> | |
{/* Form Content */} | |
<Box sx={{ p: 3 }}> | |
<Grid container spacing={3}> | |
{/* Model Information */} | |
<Grid item xs={12}> | |
<Stack direction="row" spacing={1} alignItems="center"> | |
<Typography variant="h6">Model Information</Typography> | |
<InfoIconWithTooltip tooltip={HELP_TEXTS.modelName} /> | |
</Stack> | |
</Grid> | |
<Grid item xs={12} sm={8}> | |
<TextField | |
required | |
fullWidth | |
name="modelName" | |
label="Model Name" | |
placeholder="organization/model-name" | |
value={formData.modelName} | |
onChange={handleChange} | |
helperText="Example: meta-llama/Llama-2-7b-hf" | |
InputProps={{ | |
endAdornment: ( | |
<InfoIconWithTooltip tooltip={HELP_TEXTS.modelName} /> | |
), | |
}} | |
/> | |
</Grid> | |
<Grid item xs={12} sm={4}> | |
<TextField | |
fullWidth | |
name="revision" | |
label="Revision commit" | |
value={formData.revision} | |
onChange={handleChange} | |
helperText="Default: main" | |
InputProps={{ | |
endAdornment: ( | |
<InfoIconWithTooltip tooltip={HELP_TEXTS.revision} /> | |
), | |
}} | |
/> | |
</Grid> | |
{/* Model Configuration */} | |
<Grid item xs={12}> | |
<Stack direction="row" spacing={1} alignItems="center"> | |
<Typography variant="h6">Model Configuration</Typography> | |
</Stack> | |
</Grid> | |
<Grid item xs={12} sm={6}> | |
<FormControl fullWidth> | |
<InputLabel>Model Type</InputLabel> | |
<Select | |
name="modelType" | |
value={formData.modelType} | |
onChange={handleChange} | |
label="Model Type" | |
endAdornment={ | |
<InfoIconWithTooltip | |
tooltip={HELP_TEXTS.modelType} | |
sx={{ mr: 2 }} | |
/> | |
} | |
> | |
{modelTypeOptions.map((type) => ( | |
<MenuItem key={type.value} value={type.value}> | |
{type.label} | |
</MenuItem> | |
))} | |
</Select> | |
</FormControl> | |
</Grid> | |
<Grid item xs={12} sm={6}> | |
<Stack | |
direction="row" | |
spacing={2} | |
alignItems="center" | |
sx={{ height: "100%" }} | |
> | |
<FormControlLabel | |
control={ | |
<Switch | |
name="useChatTemplate" | |
checked={formData.useChatTemplate} | |
onChange={handleChange} | |
/> | |
} | |
label="Use Chat Template" | |
/> | |
<InfoIconWithTooltip tooltip={HELP_TEXTS.chatTemplate} /> | |
</Stack> | |
</Grid> | |
<Grid item xs={12} sm={6}> | |
<FormControl fullWidth> | |
<InputLabel>Precision</InputLabel> | |
<Select | |
name="precision" | |
value={formData.precision} | |
onChange={handleChange} | |
label="Precision" | |
endAdornment={ | |
<InfoIconWithTooltip | |
tooltip={HELP_TEXTS.precision} | |
sx={{ mr: 2 }} | |
/> | |
} | |
> | |
{SUBMISSION_PRECISIONS.map((option) => ( | |
<MenuItem key={option.value} value={option.value}> | |
{option.label} | |
</MenuItem> | |
))} | |
</Select> | |
</FormControl> | |
</Grid> | |
<Grid item xs={12} sm={6}> | |
<FormControl fullWidth> | |
<InputLabel>Weights Type</InputLabel> | |
<Select | |
name="weightsType" | |
value={formData.weightsType} | |
onChange={handleChange} | |
label="Weights Type" | |
endAdornment={ | |
<InfoIconWithTooltip | |
tooltip={HELP_TEXTS.weightsType} | |
sx={{ mr: 2 }} | |
/> | |
} | |
> | |
{WEIGHT_TYPES.map((type) => ( | |
<MenuItem key={type.value} value={type.value}> | |
{type.label} | |
</MenuItem> | |
))} | |
</Select> | |
</FormControl> | |
</Grid> | |
{formData.weightsType !== "Original" && ( | |
<Grid item xs={12}> | |
<TextField | |
fullWidth | |
required={ | |
formData.weightsType === "Delta" || | |
formData.weightsType === "Adapter" | |
} | |
name="baseModel" | |
label="Base Model" | |
value={formData.baseModel} | |
onChange={handleChange} | |
InputProps={{ | |
endAdornment: ( | |
<InfoIconWithTooltip tooltip={HELP_TEXTS.baseModel} /> | |
), | |
}} | |
/> | |
</Grid> | |
)} | |
{/* Submit Button */} | |
<Grid item xs={12}> | |
<Box | |
sx={{ | |
display: "flex", | |
justifyContent: "space-between", | |
alignItems: "center", | |
mt: 2, | |
}} | |
> | |
<Typography variant="body2" color="text.secondary"> | |
All fields marked with * are required | |
</Typography> | |
<Button | |
type="submit" | |
variant="contained" | |
disabled={submitting} | |
endIcon={submitting ? null : <RocketLaunchIcon />} | |
sx={{ | |
minWidth: 120, | |
position: "relative", | |
}} | |
> | |
{submitting ? ( | |
<CircularProgress size={24} color="inherit" /> | |
) : ( | |
"Submit" | |
)} | |
</Button> | |
</Box> | |
</Grid> | |
</Grid> | |
</Box> | |
</Paper> | |
)} | |
</> | |
); | |
} | |
export default ModelSubmissionForm; | |