Skip to content

Commit 4b0c455

Browse files
author
Jonah Jung
committed
Implementing model parameters input
1 parent 42e8dfa commit 4b0c455

File tree

2 files changed

+225
-0
lines changed

2 files changed

+225
-0
lines changed

packages/jupyter-ai/src/components/chat-settings.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import WarningAmberIcon from '@mui/icons-material/WarningAmber';
88
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
99
import { IJaiCompletionProvider } from '../tokens';
1010
import { ModelIdInput } from './settings/model-id-input';
11+
import { ModelParametersInput } from './settings/model-parameters-input';
1112

1213
type ChatSettingsProps = {
1314
rmRegistry: IRenderMimeRegistry;
@@ -87,6 +88,10 @@ export function ChatSettings(props: ChatSettingsProps): JSX.Element {
8788
setCompletionModel(latestChatModelId);
8889
}}
8990
/>
91+
{/* Model parameters section */}
92+
<h2 className="jp-ai-ChatSettings-header">Model parameters</h2>
93+
<p>Configure additional parameters for the language model.</p>
94+
<ModelParametersInput />
9095
</Box>
9196
);
9297
}
Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
import React, { useState } from 'react';
2+
import { Button, TextField, Box, Alert, IconButton } from '@mui/material';
3+
import DeleteIcon from '@mui/icons-material/Delete';
4+
5+
interface ModelParameter {
6+
id: string;
7+
name: string;
8+
type: string;
9+
value: string;
10+
isStatic?: boolean;
11+
}
12+
13+
interface StaticParameterDef {
14+
name: string;
15+
type: string;
16+
label: string;
17+
}
18+
19+
// Add some common fields as static parameters here
20+
const STATIC_PARAMETERS: StaticParameterDef[] = [
21+
{ name: 'temperature', type: 'float', label: 'Temperature' },
22+
{ name: 'api_url', type: 'string', label: 'API URL' },
23+
{ name: 'max_tokens', type: 'integer', label: 'Max Tokens' }
24+
];
25+
26+
export function ModelParametersInput(): JSX.Element {
27+
const [parameters, setParameters] = useState<ModelParameter[]>([]);
28+
const [validationError, setValidationError] = useState<string>('');
29+
30+
const handleAddParameter = () => {
31+
const newParameter: ModelParameter = {
32+
id: Date.now().toString(),
33+
name: '',
34+
type: '',
35+
value: '',
36+
isStatic: false
37+
};
38+
setParameters([...parameters, newParameter]);
39+
setValidationError('');
40+
};
41+
42+
const handleAddStaticParameter = (staticParam: StaticParameterDef) => {
43+
// Check if static parameter already exists
44+
const exists = parameters.some(
45+
param => param.name === staticParam.name && param.isStatic
46+
);
47+
if (exists) {
48+
setValidationError(`Parameter "${staticParam.label}" is already added`);
49+
return;
50+
}
51+
const newParameter: ModelParameter = {
52+
id: Date.now().toString(),
53+
name: staticParam.name,
54+
type: staticParam.type,
55+
value: '',
56+
isStatic: true
57+
};
58+
setParameters([...parameters, newParameter]);
59+
setValidationError('');
60+
};
61+
// For when user changes their parameter
62+
const handleParameterChange = (
63+
id: string,
64+
field: keyof ModelParameter,
65+
value: string
66+
) => {
67+
setParameters(prev =>
68+
prev.map(param =>
69+
param.id === id ? { ...param, [field]: value } : param
70+
)
71+
);
72+
setValidationError('');
73+
};
74+
75+
// For when user deletes parameter
76+
const handleDeleteParameter = (id: string) => {
77+
setParameters(prev => prev.filter(param => param.id !== id));
78+
setValidationError('');
79+
};
80+
81+
const handleSaveParameters = () => {
82+
// Validation: Check if any parameter has a value but missing name or type (only for custom parameters)
83+
const invalidParams = parameters.filter(
84+
param =>
85+
param.value.trim() !== '' &&
86+
!param.isStatic &&
87+
(param.name.trim() === '' || param.type.trim() === '')
88+
);
89+
90+
if (invalidParams.length > 0) {
91+
setValidationError(
92+
'Parameter value specified but name or type is missing'
93+
);
94+
return;
95+
}
96+
97+
// Filter out parameters with empty values
98+
const validParams = parameters.filter(param => param.value.trim() !== '');
99+
100+
// Creates JSON object of valid parameters ONLY if all 3 fields are given valid inputs
101+
const paramsObject = validParams.reduce((acc, param) => {
102+
acc[param.name] = param.value;
103+
return acc;
104+
}, {} as Record<string, string>);
105+
106+
// Logs the JSON object of its input state to the browser console
107+
console.log('Model Parameters:', paramsObject);
108+
};
109+
110+
const showSaveButton = parameters.length > 0;
111+
const availableStaticParams = STATIC_PARAMETERS.filter(
112+
staticParam =>
113+
!parameters.some(
114+
param => param.name === staticParam.name && param.isStatic
115+
)
116+
);
117+
118+
return (
119+
<Box>
120+
<Button variant="outlined" onClick={handleAddParameter} sx={{ mb: 2 }}>
121+
Add a custom model parameter
122+
</Button>
123+
{/* Static parameter buttons */}
124+
{availableStaticParams.length > 0 && (
125+
<Box sx={{ mb: 2 }}>
126+
<Box sx={{ mb: 1, fontWeight: 'medium', fontSize: '0.875rem' }}>
127+
Common parameters:
128+
</Box>
129+
<Box sx={{ display: 'flex', gap: 1, flexWrap: 'wrap', mb: 2 }}>
130+
{availableStaticParams.map(staticParam => (
131+
<Button
132+
key={staticParam.name}
133+
variant="outlined"
134+
size="small"
135+
onClick={() => handleAddStaticParameter(staticParam)}
136+
>
137+
{staticParam.label}
138+
</Button>
139+
))}
140+
</Box>
141+
</Box>
142+
)}
143+
144+
{parameters.map(param => (
145+
<Box
146+
key={param.id}
147+
sx={{
148+
display: 'flex',
149+
gap: 2,
150+
mb: 2,
151+
alignItems: 'center'
152+
}}
153+
>
154+
<TextField
155+
label="Parameter name"
156+
placeholder="e.g. temperature, api_url"
157+
value={param.name}
158+
onChange={e =>
159+
handleParameterChange(param.id, 'name', e.target.value)
160+
}
161+
size="small"
162+
sx={{ flex: 1 }}
163+
disabled={param.isStatic}
164+
InputProps={{
165+
readOnly: param.isStatic
166+
}}
167+
/>
168+
<TextField
169+
label="Parameter type"
170+
placeholder="e.g. float, string"
171+
value={param.type}
172+
onChange={e =>
173+
handleParameterChange(param.id, 'type', e.target.value)
174+
}
175+
size="small"
176+
sx={{ flex: 1 }}
177+
disabled={param.isStatic}
178+
InputProps={{
179+
readOnly: param.isStatic
180+
}}
181+
/>
182+
<TextField
183+
label="Parameter value"
184+
placeholder="e.g. 0.7, https://localhost:8989"
185+
value={param.value}
186+
onChange={e =>
187+
handleParameterChange(param.id, 'value', e.target.value)
188+
}
189+
size="small"
190+
sx={{ flex: 1 }}
191+
/>
192+
<IconButton
193+
onClick={() => handleDeleteParameter(param.id)}
194+
color="error"
195+
size="small"
196+
sx={{ ml: 1 }}
197+
>
198+
<DeleteIcon />
199+
</IconButton>
200+
</Box>
201+
))}
202+
203+
{validationError && (
204+
<Alert severity="error" sx={{ mb: 2 }}>
205+
{validationError}
206+
</Alert>
207+
)}
208+
209+
{showSaveButton && (
210+
<Button
211+
variant="contained"
212+
onClick={handleSaveParameters}
213+
sx={{ mt: 1 }}
214+
>
215+
Save Model Parameters
216+
</Button>
217+
)}
218+
</Box>
219+
);
220+
}

0 commit comments

Comments
 (0)