Skip to content

Commit

Permalink
feat: add promptAI action
Browse files Browse the repository at this point in the history
  • Loading branch information
demetriusfeijoo committed Dec 31, 2024
1 parent 280f6fc commit c5baba3
Show file tree
Hide file tree
Showing 12 changed files with 187 additions and 4 deletions.
2 changes: 2 additions & 0 deletions packages/demo/src/components/NonModalView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { AssetSelector } from './AssetSelector'
import { ContextRequester } from './ContextRequester'
import { PluginComponent } from './FieldPluginDemo'
import { LanguageView } from './LanguageView'
import { PromptAI } from './PromptAI'

export const NonModalView: PluginComponent = (props) => (
<Paper>
Expand All @@ -17,6 +18,7 @@ export const NonModalView: PluginComponent = (props) => (
<ContextRequester {...props} />
<HeightChangeDemo {...props} />
<LanguageView {...props} />
<PromptAI {...props} />
</Stack>
</Paper>
)
66 changes: 66 additions & 0 deletions packages/demo/src/components/PromptAI.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import {
Button,
MenuItem,
Select,
Stack,
TextField,
Typography,
} from '@mui/material'
import { useState } from 'react'
import {
promptAIActionsList,
type PromptAIAction,
} from '@storyblok/field-plugin'
import type { PluginComponent } from './FieldPluginDemo'

export const PromptAI: PluginComponent = (props) => {
const { actions } = props

const [promptQuestion, setPromptQuestion] = useState<string>('')
const [promptType, setPromptType] = useState<PromptAIAction>('prompt')
const [promptOutput, setPromptOutput] = useState<string>('')

return (
<Stack
gap={2}
direction={'column'}
>
<Typography variant="subtitle1">Prompt AI</Typography>
<Stack gap={2}>
<TextField
label="Ask a question"
onChange={(e) => setPromptQuestion(e.target.value)}
required
/>
<Select
value={promptType}
onChange={(e) => setPromptType(e.target.value as PromptAIAction)}
>
{promptAIActionsList.map((promptAIAction) => (
<MenuItem
key={promptAIAction}
value={promptAIAction}
>
{promptAIAction}
</MenuItem>
))}
</Select>
<Typography>Output: {promptOutput}</Typography>
<Button
variant="outlined"
color="secondary"
onClick={async () =>
setPromptOutput(
await actions.promptAI({
action: promptType,
text: promptQuestion,
}),
)
}
>
Prompt
</Button>
</Stack>
</Stack>
)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Asset, StoryData } from '../messaging'
import { FieldPluginData } from './FieldPluginData'
import type { FieldPluginData } from './FieldPluginData'
import type { Asset, PromptAIPayload, StoryData } from '../messaging'

export type SetContent<Content> = (
content: Content,
Expand All @@ -8,12 +8,14 @@ export type SetModalOpen<Content> = (
isModalOpen: boolean,
) => Promise<FieldPluginData<Content>>
export type RequestContext = () => Promise<StoryData>
export type PromptAI = (payload: PromptAIPayload) => Promise<string>
export type SelectAsset = () => Promise<Asset>
export type Initialize<Content> = () => Promise<FieldPluginData<Content>>

export type FieldPluginActions<Content> = {
setContent: SetContent<Content>
setModalOpen: SetModalOpen<Content>
requestContext: RequestContext
promptAI: PromptAI
selectAsset: SelectAsset
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
import type {
PromptAIResponseMessage,
AssetSelectedMessage,
ContextRequestMessage,
LoadedMessage,
Expand All @@ -14,6 +15,7 @@ type CallbackMap = {
context: Record<CallbackId, OnMessage<ContextRequestMessage>>
stateChanged: Record<CallbackId, OnMessage<StateChangedMessage>>
loaded: Record<CallbackId, OnMessage<LoadedMessage>>
promptAI: Record<CallbackId, OnMessage<PromptAIResponseMessage>>
}
type CallbackType = keyof CallbackMap

Expand All @@ -23,7 +25,9 @@ export const callbackQueue = () => {
context: {},
stateChanged: {},
loaded: {},
promptAI: {},
}

const pushCallback = <T extends CallbackType>(
callbackType: T,
callback: CallbackMap[T][CallbackId],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
assetFromAssetSelectedMessage,
assetModalChangeMessage,
getContextMessage,
getResponseFromPromptAIMessage,
heightChangeMessage,
modalChangeMessage,
OnAssetSelectMessage,
Expand All @@ -12,7 +13,10 @@ import {
OnStateChangeMessage,
OnUnknownPluginMessage,
pluginLoadedMessage,
type PromptAIPayload,
getPromptAIMessage,
valueChangeMessage,
OnPromptAIMessage,
} from '../../messaging'
import { FieldPluginActions, Initialize } from '../FieldPluginActions'
import { pluginStateFromStateChangeMessage } from './partialPluginStateFromStateChangeMessage'
Expand Down Expand Up @@ -55,16 +59,24 @@ export const createPluginActions: CreatePluginActions = ({
popCallback('stateChanged', data.callbackId)?.(data)
onUpdateState(pluginStateFromStateChangeMessage(data, validateContent))
}

const onLoaded: OnLoadedMessage = (data) => {
popCallback('loaded', data.callbackId)?.(data)
onUpdateState(pluginStateFromStateChangeMessage(data, validateContent))
}

const onContextRequest: OnContextRequestMessage = (data) => {
popCallback('context', data.callbackId)?.(data)
}

const onAssetSelect: OnAssetSelectMessage = (data) => {
popCallback('asset', data.callbackId)?.(data)
}

const onPromptAI: OnPromptAIMessage = (data) => {
popCallback('promptAI', data.callbackId)?.(data)
}

const onUnknownMessage: OnUnknownPluginMessage = (data) => {
// TODO remove side-effect, making functions in this file pure.
// perhaps only show this message in development mode?
Expand All @@ -82,6 +94,7 @@ export const createPluginActions: CreatePluginActions = ({
onLoaded,
onContextRequest,
onAssetSelect,
onPromptAI,
onUnknownMessage,
}

Expand Down Expand Up @@ -135,6 +148,16 @@ export const createPluginActions: CreatePluginActions = ({
postToContainer(getContextMessage({ uid, callbackId }))
})
},
promptAI: (promptAIMessage: PromptAIPayload) => {
return new Promise((resolve) => {
const callbackId = pushCallback('promptAI', (message) =>
resolve(getResponseFromPromptAIMessage(message)),
)
postToContainer(
getPromptAIMessage(promptAIMessage, { uid, callbackId }),
)
})
},
},
messageCallbacks,
onHeightChange,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import {
import type {
OnAssetSelectMessage,
OnContextRequestMessage,
OnLoadedMessage,
OnPromptAIMessage,
OnStateChangeMessage,
OnUnknownPluginMessage,
} from '../../../messaging'
Expand All @@ -12,6 +13,7 @@ export type PluginMessageCallbacks = {
onLoaded: OnLoadedMessage
onContextRequest: OnContextRequestMessage
onAssetSelect: OnAssetSelectMessage
onPromptAI: OnPromptAIMessage
onUnknownMessage: OnUnknownPluginMessage
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
isAssetSelectedMessage,
isMessageToPlugin,
isLoadedMessage,
isPromptAIMessage,
} from '../../../messaging'
import { isContextRequestMessage } from '../../../messaging'
import { PluginMessageCallbacks } from './createPluginMessageListener'
Expand Down Expand Up @@ -32,6 +33,8 @@ export const handlePluginMessage = (
callbacks.onContextRequest(data)
} else if (isAssetSelectedMessage(data)) {
callbacks.onAssetSelect(data)
} else if (isPromptAIMessage(data)) {
callbacks.onPromptAI(data)
} else {
callbacks.onUnknownMessage(data)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { AssetSelectedMessage } from './AssetSelectedMessage'
import { ContextRequestMessage } from './ContextRequestMessage'
import { MessageToPlugin } from './MessageToPlugin'
import { StateChangedMessage } from './StateChangedMessage'
import { PromptAIResponseMessage } from './PromptAIResponseMessage'

/**
* The plugin container's sends it's state to the plugin
Expand All @@ -11,5 +12,6 @@ export type OnMessage<Message> = (message: Message) => void
export type OnStateChangeMessage = (message: StateChangedMessage) => void
export type OnLoadedMessage = (message: LoadedMessage) => void
export type OnAssetSelectMessage = (message: AssetSelectedMessage) => void
export type OnPromptAIMessage = (message: PromptAIResponseMessage) => void
export type OnContextRequestMessage = (message: ContextRequestMessage) => void
export type OnUnknownPluginMessage = (message: MessageToPlugin<string>) => void
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { hasKey } from '../../../utils'
import { isMessageToPlugin, type MessageToPlugin } from './MessageToPlugin'

/**
* The object returned when calling the "prompt-ai" action.
*/
export type PromptAIResponseMessage = MessageToPlugin<'prompt-ai'> & {
output: string
}

export const isPromptAIMessage = (
data: unknown,
): data is PromptAIResponseMessage =>
isMessageToPlugin(data) &&
hasKey(data, 'output') &&
typeof data.output === 'string'

export const getResponseFromPromptAIMessage = (
message: PromptAIResponseMessage,
): string => {
const { output } = message
return output
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ export * from './ContextRequestMessage'
export * from './MessageToPlugin'
export * from './StoryData'
export * from './Asset'
export * from './PromptAIResponseMessage'
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type { MessageToContainer } from './MessageToContainer'

export type PromptAIAction =
| 'prompt'
| 'complete'
| 'shorten'
| 'extend'
| 'rephrase'
| 'summarize'
| 'simplify'
| 'translate'
| 'tldr'
| 'adjust-tone'
| 'emojify'
| 'fix_spelling_and_grammar'

export const promptAIActionsList: PromptAIAction[] = [
'prompt',
'complete',
'shorten',
'extend',
'rephrase',
'summarize',
'simplify',
'translate',
'tldr',
'adjust-tone',
'emojify',
'fix_spelling_and_grammar',
]

export type PromptAIPayload = {
action: PromptAIAction
text: string
language?: string
textLength?: string
tone?: string
textLengthUnit?: string
}

export type PromptAIMessage = Omit<MessageToContainer<'promptAI'>, 'action'> & {
action: 'prompt-ai'
promptAI: PromptAIPayload
}

export const getPromptAIMessage = (
message: PromptAIPayload,
options: Pick<PromptAIMessage, 'uid' | 'callbackId'>,
): PromptAIMessage => ({
action: 'prompt-ai',
event: 'promptAI',
...options,
promptAI: { ...message },
})
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './PluginLoadedMessage'
export * from './HeightChangeMessage'
export * from './GetContextMessage'
export * from './AssetModalChangeMessage'
export * from './PromptAIMessage'

0 comments on commit c5baba3

Please sign in to comment.