Skip to content

Commit ae5b316

Browse files
committed
refactor: Migrate KnowledgeBase Prompts to React Hook Form with improved state management
1 parent 0d5d7a3 commit ae5b316

File tree

2 files changed

+156
-170
lines changed

2 files changed

+156
-170
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,192 +1,212 @@
11
'use client'
22

3-
import React, { useEffect, useState } from 'react'
3+
import React from 'react'
44
import { zodResolver } from '@hookform/resolvers/zod'
55
import { useMutation, useQuery } from '@tanstack/react-query'
66
import { useSession } from 'next-auth/react'
7-
import { useForm } from 'react-hook-form'
7+
import { Controller, useForm } from 'react-hook-form'
88
import { z } from 'zod'
99

1010
import { AddPrompt, GetPrompt } from '@/apis/admin/knowledgeBase'
11-
import {
12-
useKnowledgeStore
13-
} from '@/app/(chat)/_utils/store/knowledge-store'
1411
import { Button } from '@/components/ui/button'
1512
import { Slider } from '@/components/ui/slider'
1613
import { Textarea } from '@/components/ui/textarea'
1714
import { useToast } from '@/hooks/use-toast'
15+
interface PromptData {
16+
prompt: string
17+
modelConfiguration: {
18+
temperature: number
19+
topP: number
20+
}
21+
user?: string | null
22+
}
1823

19-
export default function KnowledgeBasePrompts() {
20-
const { toast } = useToast()
21-
22-
const { data: sessionData } = useSession();
23-
24-
const { prompt, setPrompt, modelConfiguration, setModelConfiguration } =
25-
useKnowledgeStore()
24+
const PromptSchema = z.object({
25+
prompt: z.string().min(10, {
26+
message: 'Prompt is Required',
27+
}),
28+
modelConfiguration: z.object({
29+
temperature: z.number().min(0).max(2),
30+
topP: z.number().min(0).max(1),
31+
}),
32+
})
2633

27-
const [buttonDisabled, setButtonDisabled] = useState(true)
34+
type TPromptSchema = z.infer<typeof PromptSchema>
2835

36+
export default function KnowledgeBasePrompts() {
37+
const { toast } = useToast()
38+
const { data: sessionData } = useSession()
2939

30-
interface Data {
31-
user: string | null
32-
prompt: string
33-
modelConfiguration: {
34-
temperature: number
35-
topP: number
36-
}
37-
}
3840

39-
const PromptSchema = z.object({
40-
prompt: z.string().min(10, {
41-
message: 'Prompt is Required',
42-
}),
43-
})
44-
type TPromptSchema = z.infer<typeof PromptSchema>
4541
const {
4642
register,
4743
handleSubmit,
48-
formState: { errors },
49-
reset,
44+
control,
45+
formState: { errors, isDirty },
46+
setValue,
47+
watch,
5048
} = useForm<TPromptSchema>({
5149
resolver: zodResolver(PromptSchema),
50+
defaultValues: {
51+
prompt: '',
52+
modelConfiguration: {
53+
temperature: 0.7,
54+
topP: 0.9,
55+
},
56+
},
5257
})
5358

54-
// add prompt
5559
const { mutate, isPending: promptPending } = useMutation({
56-
mutationFn: async (data: Data) => {
57-
return await AddPrompt(data)
60+
mutationFn: async (data: TPromptSchema) => {
61+
const promptData: PromptData = {
62+
user: sessionData?.user?.id || '',
63+
prompt: data.prompt,
64+
modelConfiguration: data.modelConfiguration,
65+
}
66+
return await AddPrompt(promptData)
5867
},
5968
onSuccess: () => {
6069
toast({
6170
title: 'Prompt Settings',
6271
description: 'Prompt Settings has Successfully Updated',
6372
})
64-
setButtonDisabled(true)
6573
},
6674
})
6775

68-
const handleClick = () => {
69-
mutate({ user: sessionData?.user?.id || '', prompt, modelConfiguration })
70-
reset()
71-
}
72-
73-
const handlePromptChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
74-
setPrompt(e.target.value)
75-
setButtonDisabled(false)
76-
}
77-
78-
const handleTemperatureChange = (value: number[]) => {
79-
setModelConfiguration({ ...modelConfiguration, temperature: value[0] })
80-
setButtonDisabled(false)
81-
}
82-
83-
const handleTopChange = (value: number[]) => {
84-
setModelConfiguration({ ...modelConfiguration, topP: value[0] })
85-
setButtonDisabled(false)
76+
const onSubmit = (data: TPromptSchema) => {
77+
mutate(data)
8678
}
8779

88-
// getPrompt
89-
const { data: promptData } = useQuery({
80+
useQuery({
9081
queryKey: ['getPrompt'],
91-
queryFn: GetPrompt,
92-
})
93-
useEffect(() => {
94-
if (promptData && promptData?.prompt[0]?.prompt) {
95-
setPrompt(promptData.prompt[0].prompt)
96-
setButtonDisabled(true)
82+
queryFn: async () => {
83+
const resp = await GetPrompt()
84+
if (resp && resp.prompt[0]) {
85+
const { prompt, modelConfiguration } = resp.prompt[0]
86+
setValue('prompt', prompt, { shouldDirty: false })
87+
setValue('modelConfiguration', modelConfiguration, {
88+
shouldDirty: false,
89+
})
90+
}
91+
return resp
9792
}
98-
}, [promptData, setPrompt])
93+
})
9994

10095
return (
10196
<div className='flex flex-col gap-4'>
102-
<div className='flex h-full w-full'>
103-
<div className='flex-[7] border-r-2 border-solid border-dashboardBorder py-4 pr-6'>
104-
<div className='mb-1 flex flex-col space-y-1 py-4'>
105-
<span className='text-lg font-medium text-dashboardHeading'>
106-
Prompt Settings
107-
</span>
108-
<span className='text-sm font-thin text-dashboardSecondaryText'>
109-
Give prompts to your bot on how it should act with the user
110-
</span>
111-
</div>
112-
<div className='flex flex-col gap-14'>
113-
<div>
114-
<Textarea
115-
{...register('prompt')}
116-
placeholder='Type here.'
117-
required
118-
rows={10}
119-
value={prompt}
120-
onChange={handlePromptChange}
121-
className='focus:border-gray-400 focus:ring-0'
122-
/>
123-
{errors.prompt && <>{errors.prompt.message}</>}
124-
</div>
125-
</div>
126-
</div>
127-
128-
<div className='flex flex-[3] flex-col justify-between p-5'>
129-
<div className='flex flex-col gap-6'>
130-
{/* Presets */}
131-
<div className='flex flex-col space-y-2'>
97+
<form onSubmit={handleSubmit(onSubmit)}>
98+
<div className='flex h-full w-full'>
99+
<div className='flex-[7] border-r-2 border-solid border-dashboardBorder py-4 pr-6'>
100+
<div className='mb-1 flex flex-col space-y-1 py-4'>
132101
<span className='text-lg font-medium text-dashboardHeading'>
133-
Model Configuration
102+
Prompt Settings
134103
</span>
135104
<span className='text-sm font-thin text-dashboardSecondaryText'>
136-
Adjust your model parameters here.
105+
Give prompts to your bot on how it should act with the user
137106
</span>
138107
</div>
139-
140-
<div className='flex flex-col space-y-2'>
141-
<div className='flex flex-col space-y-3'>
142-
<div className='flex justify-between'>
143-
<span className='text-sm text-dashboardSecondaryText'>
144-
Temperature
145-
</span>
146-
<span className='text-sm text-dashboardSecondaryText'>
147-
{modelConfiguration.temperature.toFixed(1)}
148-
</span>
149-
</div>
150-
<Slider
151-
defaultValue={[modelConfiguration.temperature]}
152-
className='py-2'
153-
min={0}
154-
max={2}
155-
step={0.1}
156-
onValueChange={handleTemperatureChange}
108+
<div className='flex flex-col gap-14'>
109+
<div>
110+
<Textarea
111+
{...register('prompt')}
112+
placeholder='Type here.'
113+
required
114+
rows={10}
115+
className='focus:border-gray-400 focus:ring-0'
157116
/>
117+
{errors.prompt && (
118+
<p className='mt-1 text-sm text-red-500'>
119+
{errors.prompt.message}
120+
</p>
121+
)}
158122
</div>
159-
<div className='flex flex-col space-y-3'>
160-
<div className='flex justify-between'>
161-
<span className='text-sm text-dashboardSecondaryText'>
162-
Top P
163-
</span>
164-
<span className='text-sm text-dashboardSecondaryText'>
165-
{modelConfiguration.topP.toFixed(2)}
166-
</span>
123+
</div>
124+
</div>
125+
126+
<div className='flex flex-[3] flex-col justify-between p-5'>
127+
<div className='flex flex-col gap-6'>
128+
<div className='flex flex-col space-y-2'>
129+
<span className='text-lg font-medium text-dashboardHeading'>
130+
Model Configuration
131+
</span>
132+
<span className='text-sm font-thin text-dashboardSecondaryText'>
133+
Adjust your model parameters here.
134+
</span>
135+
</div>
136+
137+
<div className='flex flex-col space-y-2'>
138+
<div className='flex flex-col space-y-3'>
139+
<div className='flex justify-between'>
140+
<span className='text-sm text-dashboardSecondaryText'>
141+
Temperature
142+
</span>
143+
<span className='text-sm text-dashboardSecondaryText'>
144+
{watch('modelConfiguration.temperature').toFixed(1)}
145+
</span>
146+
</div>
147+
<Controller
148+
name='modelConfiguration.temperature'
149+
control={control}
150+
render={({ field: { onChange, value } }) => (
151+
<Slider
152+
value={[value]}
153+
className='py-2'
154+
min={0}
155+
max={2}
156+
step={0.1}
157+
onValueChange={(values) => onChange(values[0])}
158+
/>
159+
)}
160+
/>
161+
{errors.modelConfiguration?.temperature && (
162+
<p className='text-sm text-red-500'>
163+
{errors.modelConfiguration.temperature.message}
164+
</p>
165+
)}
166+
</div>
167+
<div className='flex flex-col space-y-3'>
168+
<div className='flex justify-between'>
169+
<span className='text-sm text-dashboardSecondaryText'>
170+
Top P
171+
</span>
172+
<span className='text-sm text-dashboardSecondaryText'>
173+
{watch('modelConfiguration.topP').toFixed(2)}
174+
</span>
175+
</div>
176+
<Controller
177+
name='modelConfiguration.topP'
178+
control={control}
179+
render={({ field: { onChange, value } }) => (
180+
<Slider
181+
value={[value]}
182+
className='py-2'
183+
min={0}
184+
max={1}
185+
step={0.01}
186+
onValueChange={(values) => onChange(values[0])}
187+
/>
188+
)}
189+
/>
190+
{errors.modelConfiguration?.topP && (
191+
<p className='text-sm text-red-500'>
192+
{errors.modelConfiguration.topP.message}
193+
</p>
194+
)}
167195
</div>
168-
<Slider
169-
defaultValue={[modelConfiguration.topP]}
170-
className='py-2'
171-
min={0}
172-
max={1}
173-
step={0.01}
174-
onValueChange={handleTopChange}
175-
/>
176196
</div>
177197
</div>
178198
</div>
179199
</div>
180-
</div>
181-
<div className='flex justify-end'>
182-
<Button
183-
onClick={handleSubmit(handleClick)}
184-
disabled={buttonDisabled || promptPending}
185-
className='relative bg-black text-dashboardSecondary hover:bg-gray-800'
186-
>
187-
{promptPending ? 'Saving...' : 'Save changes'}
188-
</Button>
189-
</div>
200+
<div className='flex justify-end'>
201+
<Button
202+
type='submit'
203+
disabled={!isDirty || promptPending}
204+
className='relative bg-black text-dashboardSecondary hover:bg-gray-800'
205+
>
206+
{promptPending ? 'Saving...' : 'Save changes'}
207+
</Button>
208+
</div>
209+
</form>
190210
</div>
191211
)
192212
}

src/app/(chat)/_utils/store/knowledge-store.ts

-34
This file was deleted.

0 commit comments

Comments
 (0)