Skip to content

Commit c95d31c

Browse files
committed
add aimodel creation flow
1 parent 6948872 commit c95d31c

File tree

9 files changed

+1958
-0
lines changed

9 files changed

+1958
-0
lines changed
Lines changed: 205 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,205 @@
1+
'use client';
2+
3+
import { useEffect, useState } from 'react';
4+
import { useParams } from 'next/navigation';
5+
import { graphql } from '@/gql';
6+
import { useMutation, useQuery } from '@tanstack/react-query';
7+
import { Button, FormLayout, Text, TextField, toast } from 'opub-ui';
8+
9+
import { GraphQL } from '@/lib/api';
10+
import { useEditStatus } from '../../context';
11+
12+
const FetchAIModelConfig: any = graphql(`
13+
query AIModelConfig($filters: AIModelFilter) {
14+
aiModels(filters: $filters) {
15+
id
16+
inputSchema
17+
outputSchema
18+
metadata
19+
}
20+
}
21+
`);
22+
23+
const UpdateAIModelConfigMutation: any = graphql(`
24+
mutation updateAIModelConfig($input: UpdateAIModelInput!) {
25+
updateAiModel(input: $input) {
26+
success
27+
data {
28+
id
29+
inputSchema
30+
outputSchema
31+
metadata
32+
}
33+
}
34+
}
35+
`);
36+
37+
export default function ConfigurationPage() {
38+
const params = useParams<{
39+
entityType: string;
40+
entitySlug: string;
41+
id: string;
42+
}>();
43+
44+
const { setStatus } = useEditStatus();
45+
46+
const ConfigData: { data: any; isLoading: boolean; refetch: any } = useQuery(
47+
[`fetch_AIModelConfig_${params.id}`],
48+
() =>
49+
GraphQL(
50+
FetchAIModelConfig,
51+
{
52+
[params.entityType]: params.entitySlug,
53+
},
54+
{
55+
filters: {
56+
id: parseInt(params.id),
57+
},
58+
}
59+
),
60+
{
61+
refetchOnMount: true,
62+
}
63+
);
64+
65+
const model = ConfigData.data?.aiModels[0];
66+
67+
const { mutate, isLoading: updateLoading } = useMutation(
68+
(data: any) =>
69+
GraphQL(
70+
UpdateAIModelConfigMutation,
71+
{
72+
[params.entityType]: params.entitySlug,
73+
},
74+
{
75+
input: {
76+
id: parseInt(params.id),
77+
...data,
78+
},
79+
}
80+
),
81+
{
82+
onSuccess: () => {
83+
toast('Configuration updated successfully');
84+
setStatus('saved');
85+
ConfigData.refetch();
86+
},
87+
onError: (error: any) => {
88+
toast(`Error: ${error.message}`);
89+
setStatus('unsaved');
90+
},
91+
}
92+
);
93+
94+
const [formData, setFormData] = useState({
95+
inputSchema: '{}',
96+
outputSchema: '{}',
97+
metadata: '{}',
98+
});
99+
100+
useEffect(() => {
101+
if (model) {
102+
setFormData({
103+
inputSchema: JSON.stringify(model.inputSchema || {}, null, 2),
104+
outputSchema: JSON.stringify(model.outputSchema || {}, null, 2),
105+
metadata: JSON.stringify(model.metadata || {}, null, 2),
106+
});
107+
}
108+
}, [model]);
109+
110+
const handleInputChange = (field: string, value: string) => {
111+
setFormData((prev) => ({ ...prev, [field]: value }));
112+
setStatus('unsaved');
113+
};
114+
115+
const handleSave = () => {
116+
setStatus('saving');
117+
try {
118+
const updateData = {
119+
inputSchema: JSON.parse(formData.inputSchema),
120+
outputSchema: JSON.parse(formData.outputSchema),
121+
metadata: JSON.parse(formData.metadata),
122+
};
123+
mutate(updateData);
124+
} catch (error) {
125+
toast('Invalid JSON format. Please check your input.');
126+
setStatus('unsaved');
127+
}
128+
};
129+
130+
if (ConfigData.isLoading) {
131+
return <div>Loading...</div>;
132+
}
133+
134+
return (
135+
<div className="flex flex-col gap-6">
136+
<div className="rounded-lg border border-gray-200 bg-white p-6">
137+
<Text variant="headingMd" as="h2" className="mb-4">
138+
Input Schema
139+
</Text>
140+
<Text variant="bodySm" color="subdued" className="mb-4">
141+
Define the expected input format and parameters for the model. Use
142+
JSON format.
143+
</Text>
144+
<FormLayout>
145+
<TextField
146+
name="inputSchema"
147+
label="Input Schema (JSON)"
148+
value={formData.inputSchema}
149+
onChange={(value) => handleInputChange('inputSchema', value)}
150+
multiline={10}
151+
helpText="Example: { 'prompt': 'string', 'max_tokens': 'number' }"
152+
monospaced
153+
/>
154+
</FormLayout>
155+
</div>
156+
157+
<div className="rounded-lg border border-gray-200 bg-white p-6">
158+
<Text variant="headingMd" as="h2" className="mb-4">
159+
Output Schema
160+
</Text>
161+
<Text variant="bodySm" color="subdued" className="mb-4">
162+
Define the expected output format from the model. Use JSON format.
163+
</Text>
164+
<FormLayout>
165+
<TextField
166+
name="outputSchema"
167+
label="Output Schema (JSON)"
168+
value={formData.outputSchema}
169+
onChange={(value) => handleInputChange('outputSchema', value)}
170+
multiline={10}
171+
helpText="Example: { 'text': 'string', 'tokens_used': 'number' }"
172+
monospaced
173+
/>
174+
</FormLayout>
175+
</div>
176+
177+
<div className="rounded-lg border border-gray-200 bg-white p-6">
178+
<Text variant="headingMd" as="h2" className="mb-4">
179+
Additional Metadata
180+
</Text>
181+
<Text variant="bodySm" color="subdued" className="mb-4">
182+
Store additional information about the model such as training data,
183+
limitations, use cases, etc.
184+
</Text>
185+
<FormLayout>
186+
<TextField
187+
name="metadata"
188+
label="Metadata (JSON)"
189+
value={formData.metadata}
190+
onChange={(value) => handleInputChange('metadata', value)}
191+
multiline={10}
192+
helpText="Example: { 'training_data': 'Description', 'limitations': ['List', 'of', 'limitations'] }"
193+
monospaced
194+
/>
195+
</FormLayout>
196+
</div>
197+
198+
<div className="flex justify-end gap-4">
199+
<Button onClick={handleSave} loading={updateLoading}>
200+
Save Configuration
201+
</Button>
202+
</div>
203+
</div>
204+
);
205+
}

0 commit comments

Comments
 (0)