import React, { useState } from "react"; import { Box, Paper, Typography, TextField, Button, FormControl, FormLabel, RadioGroup, FormControlLabel, Radio, InputLabel, Select, MenuItem, Stack, Grid, CircularProgress, Alert, } from "@mui/material"; import RocketLaunchIcon from "@mui/icons-material/RocketLaunch"; import CheckCircleOutlineIcon from "@mui/icons-material/CheckCircleOutline"; import { alpha } from "@mui/material/styles"; import InfoIconWithTooltip from "../../../../components/shared/InfoIconWithTooltip"; import { FINETUNING_STRATEGIES, HEADS, PEFT_STRATEGIES, OEB_DATASETS, } from "../../../../pages/LeaderboardPage/components/Leaderboard/constants/modelTypes"; import AuthContainer from "../../../../components/shared/AuthContainer"; const HELP_TEXTS = { modelClass: ( Model Class (dotted import path) Fully-qualified import path to the model class evaluated by OpenEEGBench. The class must accept (batch, n_chans, n_times) and return (batch, n_outputs). Example: braindecode.models.BIOT ), modelName: ( Model Name A human-readable name for your submission. This is how your model will appear on the leaderboard. ), weightsSource: ( Weights Source Provide exactly one source for the pre-trained weights: a public Hugging Face Hub repository (with a license tag) or a direct http(s) URL to a checkpoint. ), headModuleName: ( Head Module Name Name of the model's classification head module. OpenEEGBench replaces this module to attach evaluation heads. Default: final_layer ), finetuningStrategies: ( Fine-tuning Strategies Frozen: linear probing (encoder frozen). LoRA / IA3 / AdaLoRA / DoRA / OFT: parameter-efficient fine-tuning. Full fine-tune: all parameters updated. Two stages: probe then fine-tune. Select one or more. ), heads: ( Evaluation Heads Linear head: single linear layer. MLP head: small multi-layer perceptron. Original head: keep the model's own head. Select one or more. ), peftTargetModules: ( PEFT Target Modules Comma-separated module names to which the PEFT adapter is applied (e.g. to_q, to_v). Required when a PEFT strategy (LoRA, IA3, AdaLoRA, DoRA, OFT) is selected. ), peftFfModules: ( PEFT Feed-Forward Modules Comma-separated feed-forward module names scaled by IA3. Required when the IA3 strategy is selected. ), datasets: ( Datasets The downstream datasets to evaluate on. Leave empty to run all 10 datasets in the OpenEEGBench classification suite. ), nSeeds: ( Number of Seeds How many random seeds to average over per dataset. More seeds give a more stable estimate but take longer. Default: 3 ), contactEmail: ( Contact Email Optional. Stored privately and used only to reach you about your submission. It is never shown on the public leaderboard. ), visibility: ( Visibility Public submissions appear on the leaderboard. Private submissions are evaluated but kept out of the public table. ), }; const VISIBILITY_OPTIONS = ["Public", "Private"]; const INITIAL_FORM_DATA = { modelClass: "", // dotted import path modelName: "", organization: "", weightsSource: "hub_repo", // "hub_repo" | "checkpoint_url" hubRepo: "", checkpointUrl: "", headModuleName: "final_layer", finetuningStrategies: ["frozen"], heads: ["linear_head"], peftTargetModules: "", // comma-separated -> array on submit peftFfModules: "", // comma-separated -> array on submit datasets: [], // empty = all nSeeds: 3, modelUrl: "", paperUrl: "", contactEmail: "", additionalInfo: "", visibility: "Public", }; const toList = (s) => s .split(",") .map((x) => x.trim()) .filter(Boolean); const strategyLabel = (value) => FINETUNING_STRATEGIES.find((s) => s.value === value)?.label || value; const headLabel = (value) => HEADS.find((h) => h.value === value)?.label || value; function ModelSubmissionForm({ user, isAuthenticated }) { const [formData, setFormData] = useState(INITIAL_FORM_DATA); const [error, setError] = useState(null); const [submitting, setSubmitting] = useState(false); const [success, setSuccess] = useState(false); const [submittedData, setSubmittedData] = useState(null); const showPeftTargetModules = formData.finetuningStrategies.some((s) => PEFT_STRATEGIES.includes(s) ); const showPeftFfModules = formData.finetuningStrategies.includes("ia3"); 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 body = { user_id: user.username, model_cls: formData.modelClass, model_name: formData.modelName, organization: formData.organization, hub_repo: formData.weightsSource === "hub_repo" ? formData.hubRepo : "", checkpoint_url: formData.weightsSource === "checkpoint_url" ? formData.checkpointUrl : "", head_module_name: formData.headModuleName, finetuning_strategies: formData.finetuningStrategies, heads: formData.heads, peft_target_modules: toList(formData.peftTargetModules), peft_ff_modules: toList(formData.peftFfModules), datasets: formData.datasets, n_seeds: Number(formData.nSeeds), model_url: formData.modelUrl, paper_url: formData.paperUrl, contact_email: formData.contactEmail, additional_info: formData.additionalInfo, visibility: formData.visibility, }; const response = await fetch("/api/models/submit", { method: "POST", headers: { "Content-Type": "application/json", }, body: JSON.stringify(body), }); 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 ( ({ p: 6, mb: 3, bgcolor: alpha(theme.palette.success.main, 0.05), borderColor: alpha(theme.palette.success.main, 0.2), })} > Model submitted successfully! Your model {submittedData.modelName} has been added to the evaluation queue with the following parameters: Model: {submittedData.modelName} Model class: {submittedData.modelClass} Strategies: {submittedData.finetuningStrategies .map(strategyLabel) .join(", ")} Visibility: {submittedData.visibility} A worker will run oeb.benchmark() and post the official scores to the leaderboard. ); } return ( <> {error && ( {error} )} {isAuthenticated && ( {/* Header */} 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", }} > Model Submission Form {/* Form Content */} {/* Model Information */} Model Information ), }} /> ), }} /> {/* Weights Source */} Weights Source Provide one weights source } label="Hugging Face Hub repo" /> } label="Checkpoint URL" /> {formData.weightsSource === "hub_repo" ? ( ) : ( )} ), }} /> {/* Evaluation Configuration */} Evaluation Configuration Fine-tuning Strategies Heads {showPeftTargetModules && ( ), }} /> )} {showPeftFfModules && ( ), }} /> )} Datasets ), }} /> {/* Additional Information */} Additional Information ), }} /> Visibility {/* Submit Button */} All fields marked with * are required )} ); } export default ModelSubmissionForm;