diff --git a/packages/backend/server/src/plugins/copilot/resolver.ts b/packages/backend/server/src/plugins/copilot/resolver.ts index f2e46f027b..d81a496de6 100644 --- a/packages/backend/server/src/plugins/copilot/resolver.ts +++ b/packages/backend/server/src/plugins/copilot/resolver.ts @@ -4,6 +4,7 @@ import { BadRequestException, NotFoundException } from '@nestjs/common'; import { Args, Field, + Float, ID, InputType, Mutation, @@ -205,16 +206,16 @@ class CopilotPromptConfigType { @Field(() => Boolean, { nullable: true }) jsonMode!: boolean | null; - @Field(() => Number, { nullable: true }) + @Field(() => Float, { nullable: true }) frequencyPenalty!: number | null; - @Field(() => Number, { nullable: true }) + @Field(() => Float, { nullable: true }) presencePenalty!: number | null; - @Field(() => Number, { nullable: true }) + @Field(() => Float, { nullable: true }) temperature!: number | null; - @Field(() => Number, { nullable: true }) + @Field(() => Float, { nullable: true }) topP!: number | null; } @@ -238,8 +239,8 @@ class CopilotPromptType { @Field(() => String) name!: string; - @Field(() => AvailableModels) - model!: AvailableModels; + @Field(() => String) + model!: string; @Field(() => String, { nullable: true }) action!: string | null; diff --git a/packages/backend/server/src/schema.gql b/packages/backend/server/src/schema.gql index 7288f8e09f..58d6a2f01d 100644 --- a/packages/backend/server/src/schema.gql +++ b/packages/backend/server/src/schema.gql @@ -61,19 +61,19 @@ enum CopilotModels { } input CopilotPromptConfigInput { - frequencyPenalty: Int + frequencyPenalty: Float jsonMode: Boolean - presencePenalty: Int - temperature: Int - topP: Int + presencePenalty: Float + temperature: Float + topP: Float } type CopilotPromptConfigType { - frequencyPenalty: Int + frequencyPenalty: Float jsonMode: Boolean - presencePenalty: Int - temperature: Int - topP: Int + presencePenalty: Float + temperature: Float + topP: Float } input CopilotPromptMessageInput { @@ -102,7 +102,7 @@ type CopilotPromptType { action: String config: CopilotPromptConfigType messages: [CopilotPromptMessageType!]! - model: CopilotModels! + model: String! name: String! } diff --git a/packages/frontend/admin/src/app.tsx b/packages/frontend/admin/src/app.tsx index be20ba24f2..f8e6be011b 100644 --- a/packages/frontend/admin/src/app.tsx +++ b/packages/frontend/admin/src/app.tsx @@ -51,6 +51,10 @@ export const router = _createBrowserRouter( path: '/admin/auth', lazy: () => import('./modules/auth'), }, + { + path: '/admin/ai', + lazy: () => import('./modules/ai'), + }, { path: '/admin/setup', lazy: () => import('./modules/setup'), diff --git a/packages/frontend/admin/src/modules/ai/discard-changes.tsx b/packages/frontend/admin/src/modules/ai/discard-changes.tsx new file mode 100644 index 0000000000..ba7696e771 --- /dev/null +++ b/packages/frontend/admin/src/modules/ai/discard-changes.tsx @@ -0,0 +1,44 @@ +import { Button } from '@affine/admin/components/ui/button'; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTitle, +} from '@affine/admin/components/ui/dialog'; + +export const DiscardChanges = ({ + open, + onClose, + onConfirm, + onOpenChange, +}: { + open: boolean; + onClose: () => void; + onConfirm: () => void; + onOpenChange: (open: boolean) => void; +}) => { + return ( + + + + Discard Changes + + Changes to this prompt will not be saved. + + + +
+ + +
+
+
+
+ ); +}; diff --git a/packages/frontend/admin/src/modules/ai/edit-prompt.tsx b/packages/frontend/admin/src/modules/ai/edit-prompt.tsx new file mode 100644 index 0000000000..21350f5627 --- /dev/null +++ b/packages/frontend/admin/src/modules/ai/edit-prompt.tsx @@ -0,0 +1,146 @@ +import { Button } from '@affine/admin/components/ui/button'; +import { ScrollArea } from '@affine/admin/components/ui/scroll-area'; +import { Separator } from '@affine/admin/components/ui/separator'; +import { Textarea } from '@affine/admin/components/ui/textarea'; +import { CheckIcon, XIcon } from 'lucide-react'; +import { useCallback, useEffect, useMemo, useState } from 'react'; + +import { useRightPanel } from '../layout'; +import type { Prompt } from './prompts'; +import { usePrompt } from './use-prompt'; + +export function EditPrompt({ item }: { item: Prompt }) { + const { closePanel } = useRightPanel(); + + const [messages, setMessages] = useState(item.messages); + const { updatePrompt } = usePrompt(); + + const handleChange = useCallback( + (e: React.ChangeEvent, index: number) => { + const newMessages = [...messages]; + newMessages[index] = { + ...newMessages[index], + content: e.target.value, + }; + setMessages(newMessages); + }, + [messages] + ); + const handleClose = useCallback(() => { + setMessages(item.messages); + closePanel(); + }, [closePanel, item.messages]); + + const onConfirm = useCallback(() => { + updatePrompt({ name: item.name, messages }); + handleClose(); + }, [handleClose, item.name, messages, updatePrompt]); + + const disableSave = useMemo( + () => JSON.stringify(messages) === JSON.stringify(item.messages), + [item.messages, messages] + ); + + useEffect(() => { + setMessages(item.messages); + }, [item.messages]); + + return ( +
+
+ + Edit Prompt + +
+ + +
+
+
Name
+
{item.name}
+
+ {item.action ? ( +
+
Action
+
+ {item.action} +
+
+ ) : null} +
+
Model
+
+ {item.model} +
+
+ {item.config ? ( +
+
Config
+ {Object.entries(item.config).map(([key, value], index) => ( +
+ {index !== 0 && } + {key} + + {value?.toString()} + +
+ ))} +
+ ) : null} +
+
+
Messages
+ {messages.map((message, index) => ( +
+ {index !== 0 && } +
+
Role
+
+ {message.role} +
+
+ + {message.params ? ( +
+
Params
+ {Object.entries(message.params).map(([key, value], index) => ( +
+ {index !== 0 && } + {key} + + {value.toString()} + +
+ ))} +
+ ) : null} +
Content
+