mirror of
https://github.com/langgenius/dify.git
synced 2026-11-10 21:35:45 +08:00
179 lines
5.4 KiB
TypeScript
179 lines
5.4 KiB
TypeScript
import type { AdvancedPromptTemplateResponse } from '@dify/contracts/api/console/app/types.gen'
|
|
import type { AppMode } from '@dify/contracts/api/console/apps/types.gen'
|
|
import type { PostInstructionGenerateData } from '@dify/contracts/api/console/instruction-generate/types.gen'
|
|
import type { PostRuleGenerateData } from '@dify/contracts/api/console/rule-generate/types.gen'
|
|
import type { IOnCompleted, IOnData, IOnError, IOnMessageReplace } from './base'
|
|
import type { Model, ModelModeType } from '@/types/app'
|
|
import { ssePost } from './base'
|
|
import { consoleClient } from './console'
|
|
|
|
export type GenRes = {
|
|
modified: string
|
|
message?: string // tip for human
|
|
variables?: string[] // only for basic app first time rule
|
|
opening_statement?: string // only for basic app first time rule
|
|
error?: string
|
|
}
|
|
|
|
const getString = (record: Record<string, unknown>, key: string) => {
|
|
const value = record[key]
|
|
return typeof value === 'string' ? value : undefined
|
|
}
|
|
|
|
/**
|
|
* The instruction generator answers with the generated rule, generated code or an LLM-written
|
|
* JSON object, depending on what is being edited; read the fields the editors understand.
|
|
*/
|
|
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
typeof value === 'object' && value !== null && !Array.isArray(value)
|
|
|
|
const toGenRes = (value: unknown): GenRes & { code?: string } => {
|
|
const fields = isRecord(value) ? value : {}
|
|
const variables = fields.variables
|
|
return {
|
|
modified: getString(fields, 'modified') ?? getString(fields, 'prompt') ?? '',
|
|
message: getString(fields, 'message'),
|
|
variables: Array.isArray(variables)
|
|
? variables.filter((item): item is string => typeof item === 'string')
|
|
: undefined,
|
|
opening_statement: getString(fields, 'opening_statement'),
|
|
code: getString(fields, 'code'),
|
|
error: getString(fields, 'error') || undefined,
|
|
}
|
|
}
|
|
|
|
export const stopChatMessageResponding = async (appId: string, taskId: string) => {
|
|
return consoleClient.apps.byAppId.chatMessages.byTaskId.stop.post({
|
|
params: { app_id: appId, task_id: taskId },
|
|
})
|
|
}
|
|
|
|
export const sendCompletionMessage = async (
|
|
appId: string,
|
|
body: Record<string, unknown>,
|
|
handlers: {
|
|
onData: IOnData
|
|
onCompleted: IOnCompleted
|
|
onError: IOnError
|
|
onMessageReplace: IOnMessageReplace
|
|
onNotifyError?: IOnError
|
|
},
|
|
) => {
|
|
return ssePost(
|
|
`apps/${appId}/completion-messages`,
|
|
{
|
|
body: {
|
|
...body,
|
|
response_mode: 'streaming',
|
|
},
|
|
},
|
|
handlers,
|
|
)
|
|
}
|
|
|
|
const createAbortSignal = (getAbortController?: (abortController: AbortController) => void) => {
|
|
const abortController = new AbortController()
|
|
getAbortController?.(abortController)
|
|
return abortController.signal
|
|
}
|
|
|
|
export const fetchSuggestedQuestions = (
|
|
appId: string,
|
|
messageId: string,
|
|
getAbortController?: (abortController: AbortController) => void,
|
|
) => {
|
|
return consoleClient.apps.byAppId.chatMessages.byMessageId.suggestedQuestions.get(
|
|
{ params: { app_id: appId, message_id: messageId } },
|
|
{ signal: createAbortSignal(getAbortController) },
|
|
)
|
|
}
|
|
|
|
export const fetchConversationMessages = (
|
|
appId: string,
|
|
conversation_id: string,
|
|
getAbortController?: (abortController: AbortController) => void,
|
|
) => {
|
|
return consoleClient.apps.byAppId.chatMessages.get(
|
|
{ params: { app_id: appId }, query: { conversation_id } },
|
|
{ signal: createAbortSignal(getAbortController) },
|
|
)
|
|
}
|
|
|
|
// The model selector keeps an unset mode as '' and generators may omit the flow id; the
|
|
// backend validates both, so the UI request shapes are passed through as the contract bodies.
|
|
type RuleGenerateRequest = Omit<PostRuleGenerateData['body'], 'model_config'> & {
|
|
model_config: Model
|
|
}
|
|
|
|
type InstructionGenerateRequest = Omit<
|
|
PostInstructionGenerateData['body'],
|
|
'model_config' | 'flow_id'
|
|
> & {
|
|
model_config: Model
|
|
flow_id?: string
|
|
}
|
|
|
|
export const generateBasicAppFirstTimeRule = (body: RuleGenerateRequest) => {
|
|
return consoleClient.ruleGenerate.post({ body: body as PostRuleGenerateData['body'] })
|
|
}
|
|
|
|
export const generateRule = (body: InstructionGenerateRequest) => {
|
|
return consoleClient.instructionGenerate
|
|
.post({ body: body as PostInstructionGenerateData['body'] })
|
|
.then(toGenRes)
|
|
}
|
|
|
|
// A completion template without history prefixes keeps them empty, as the console's default does.
|
|
const toPromptTemplates = ({
|
|
chat_prompt_config,
|
|
completion_prompt_config,
|
|
stop,
|
|
}: AdvancedPromptTemplateResponse) => ({
|
|
chat_prompt_config: chat_prompt_config ?? undefined,
|
|
completion_prompt_config: completion_prompt_config
|
|
? {
|
|
prompt: completion_prompt_config.prompt,
|
|
conversation_histories_role: completion_prompt_config.conversation_histories_role ?? {
|
|
user_prefix: '',
|
|
assistant_prefix: '',
|
|
},
|
|
}
|
|
: undefined,
|
|
stop: stop ?? [],
|
|
})
|
|
|
|
export const fetchPromptTemplate = ({
|
|
appMode,
|
|
mode,
|
|
modelName,
|
|
hasSetDataSet,
|
|
}: {
|
|
appMode: AppMode
|
|
mode: ModelModeType
|
|
modelName: string
|
|
hasSetDataSet: boolean
|
|
}) => {
|
|
return consoleClient.app.promptTemplates
|
|
.get({
|
|
query: {
|
|
app_mode: appMode,
|
|
model_mode: mode,
|
|
model_name: modelName,
|
|
has_context: String(hasSetDataSet),
|
|
},
|
|
})
|
|
.then(toPromptTemplates)
|
|
}
|
|
|
|
export const fetchTextGenerationMessage = ({
|
|
appId,
|
|
messageId,
|
|
}: {
|
|
appId: string
|
|
messageId: string
|
|
}) => {
|
|
return consoleClient.apps.byAppId.messages.byMessageId.get({
|
|
params: { app_id: appId, message_id: messageId },
|
|
})
|
|
}
|