import { useState, useEffect, useCallback } from "react"; import Dropdown from "./Dropdown"; import NumberInput from "./NumberInput"; import { getModelLayerCounts, initializeDefaultCookies, } from "../utils/modelCookies"; const Recipe = ({ layerRecipe, setLayerRecipe, embeddingLambdas, setEmbeddingLambdas, linearLambdas, setLinearLambdas, numLayers, selectedModel1, selectedModel2, }) => { const [modelLayerCounts, setModelLayerCounts] = useState({ model1: 12, model2: 12, }); const [expandedBlock, setExpandedBlock] = useState(null); useEffect(() => { initializeDefaultCookies(selectedModel1, selectedModel2); const counts = getModelLayerCounts(selectedModel1, selectedModel2); setModelLayerCounts(counts); }, [selectedModel1, selectedModel2]); const adjustLayerRecipe = useCallback(() => { const currentLength = layerRecipe.length; if (currentLength === numLayers) { return; // No change needed } let newRecipe = [...layerRecipe]; if (currentLength < numLayers) { // Add new layers to the end for (let i = currentLength; i < numLayers; i++) { newRecipe.push([[1, 0, 1.0]]); } } else { // Remove layers from the end newRecipe = newRecipe.slice(0, numLayers); } setLayerRecipe(newRecipe); }, [numLayers, layerRecipe, setLayerRecipe]); const initializeLayerRecipe = useCallback(() => { const recipe = []; for (let i = 0; i < numLayers; i++) { recipe.push([[1, 0, 1.0]]); } setLayerRecipe(recipe); }, [numLayers, setLayerRecipe]); useEffect(() => { if (layerRecipe.length === 0) { // Initialize if recipe is empty initializeLayerRecipe(); } else if (layerRecipe.length !== numLayers) { // Adjust existing recipe adjustLayerRecipe(); } }, [numLayers, layerRecipe.length, initializeLayerRecipe, adjustLayerRecipe]); const addBlockToLayer = (layerIndex) => { const newRecipe = [...layerRecipe]; // layer 1, model 0 or 1, weight 0.5 const newBlock = [1, Math.random() < 0.5 ? 0 : 1, 0.5]; newRecipe[layerIndex] = [...newRecipe[layerIndex], newBlock]; setLayerRecipe(newRecipe); }; const removeBlockFromLayer = (layerIndex, blockIndex) => { const newRecipe = [...layerRecipe]; if (newRecipe[layerIndex].length > 1) { newRecipe[layerIndex] = newRecipe[layerIndex].filter( (_, i) => i !== blockIndex ); setLayerRecipe(newRecipe); } }; const updateBlock = (layerIndex, blockIndex, field, value) => { const newRecipe = [...layerRecipe]; const block = [...newRecipe[layerIndex][blockIndex]]; if (field === "model") { block[1] = value; block[0] = 1; } else if (field === "sourceLayer") { // Ensure layer value is within valid range (1 to max layers for selected model) const selectedModel = block[1]; const maxLayers = selectedModel === 0 ? modelLayerCounts.model1 : modelLayerCounts.model2; const maxLayerValue = maxLayers === "N/A" ? 1 : maxLayers; block[0] = Math.max(1, Math.min(maxLayerValue, value)); } else if (field === "percentage") { block[2] = value / 100; } newRecipe[layerIndex][blockIndex] = block; setLayerRecipe(newRecipe); }; const updateEmbeddingLambda = (index, value) => { const newLambdas = [...embeddingLambdas]; newLambdas[index] = value / 100; setEmbeddingLambdas(newLambdas); }; const updateLinearLambda = (index, value) => { const newLambdas = [...linearLambdas]; newLambdas[index] = value / 100; setLinearLambdas(newLambdas); }; const modelOptions = [ { value: 0, label: "Model 1" }, { value: 1, label: "Model 2" }, ]; const getModelName = (modelValue) => { return modelValue === 0 ? "Model 1" : "Model 2"; }; const generateRandomRecipe = () => { const randomEmbedding1 = Math.random(); const randomEmbedding2 = 1 - randomEmbedding1; setEmbeddingLambdas([randomEmbedding1, randomEmbedding2]); const randomLinear1 = Math.random(); const randomLinear2 = 1 - randomLinear1; setLinearLambdas([randomLinear1, randomLinear2]); const newRecipe = []; for (let i = 0; i < numLayers; i++) { const numBlocks = Math.floor(Math.random() * 5) + 1; const layer = []; const weights = []; for (let j = 0; j < numBlocks; j++) { weights.push(Math.random()); } const totalWeight = weights.reduce((sum, w) => sum + w, 0); const normalizedWeights = weights.map((w) => w / totalWeight); for (let j = 0; j < numBlocks; j++) { const randomModel = Math.floor(Math.random() * 2); // 0 or 1 const maxLayers = randomModel === 0 ? modelLayerCounts.model1 : modelLayerCounts.model2; const maxLayerValue = maxLayers === "N/A" ? 1 : maxLayers; const randomLayer = Math.floor(Math.random() * maxLayerValue) + 1; layer.push([randomLayer, randomModel, normalizedWeights[j]]); } newRecipe.push(layer); } setLayerRecipe(newRecipe); }; const getBlockId = (layerIndex, blockIndex) => { return `${layerIndex}-${blockIndex}`; }; const toggleBlockExpanded = (layerIndex, blockIndex) => { const blockId = getBlockId(layerIndex, blockIndex); setExpandedBlock(expandedBlock === blockId ? null : blockId); }; return (