mirror of
https://github.com/langgenius/dify.git
synced 2026-08-30 04:23:20 +08:00
Signed-off-by: kenwoodjw <blackxin55+@gmail.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: zxhlyh <jasonapring2015@outlook.com> Co-authored-by: 起岚 <155608604+xiaoyaoqilan@users.noreply.github.com> Co-authored-by: Parman Mohammadalizadeh <prmma23@gmail.com> Co-authored-by: Escape0707 <tothesong@gmail.com> Co-authored-by: Xin Zhang <zhangxin@dify.ai> Co-authored-by: iridescentWen <66297467+iridescentWen@users.noreply.github.com> Co-authored-by: Bond Zhu <37842169+MRZHUH@users.noreply.github.com> Co-authored-by: KVOJJJin <jzongcode@gmail.com> Co-authored-by: Joel <iamjoel007@gmail.com> Co-authored-by: 非法操作 <hjlarry@163.com> Co-authored-by: yyh <92089059+lyzno1@users.noreply.github.com> Co-authored-by: Asuka Minato <i@asukaminato.eu.org> Co-authored-by: Chester <superdiao6@gmail.com> Co-authored-by: WH-2099 <wh2099@pm.me> Co-authored-by: Jony <619963502@qq.com> Co-authored-by: Jony <13896935+zyz619963502zyz@users.noreply.github.com> Co-authored-by: Harsh Kashyap <harsh.kashyap2001@gmail.com> Co-authored-by: Harsh Kashyap <Harsh23Kashyap@users.noreply.github.com> Co-authored-by: kenwoodjw <blackxin55+@gmail.com> Co-authored-by: csurong <csurong1@gmail.com> Co-authored-by: caosurong <surong.cao@thinkingdata.cn> Co-authored-by: Taranum Wasu <81034301+Taranum01@users.noreply.github.com> Co-authored-by: Taranum01 <50813317+Taranum01@users.noreply.github.com> Co-authored-by: Pranav Agarwal <agarwalpranav0711@gmail.com> Co-authored-by: Stephen Zhou <hi@hyoban.cc> Co-authored-by: zl86790 <marshal_li_b@163.com> Co-authored-by: QuantumGhost <obelisk.reg+git@gmail.com> Co-authored-by: yunlu.wen <yunlu.wen@dify.ai> Co-authored-by: yyh <yuanyouhuilyz@gmail.com>
216 lines
5.6 KiB
TypeScript
216 lines
5.6 KiB
TypeScript
import type {
|
|
SkillAssistAttachmentPayload,
|
|
SkillAssistHistoryMessagePayload,
|
|
SkillFileUploadResponse,
|
|
} from '@dify/contracts/api/console/workspaces/types.gen'
|
|
import type {
|
|
DefaultModel,
|
|
FormValue,
|
|
} from '@/app/components/header/account-setting/model-provider-page/declarations'
|
|
// oxlint-disable-next-line no-restricted-imports
|
|
import type { IOnCompleted, IOnData, IOnError } from '@/service/base'
|
|
// oxlint-disable-next-line no-restricted-imports
|
|
import { get, post, ssePost, upload } from '@/service/base'
|
|
|
|
function parseSkillUploadErrorMessage(message: string) {
|
|
const trimmedMessage = message.trim()
|
|
if (!trimmedMessage.startsWith('{')) return trimmedMessage
|
|
|
|
try {
|
|
const parsed: unknown = JSON.parse(trimmedMessage)
|
|
if (parsed && typeof parsed === 'object') {
|
|
const parsedMessage = (parsed as Record<string, unknown>).message
|
|
if (typeof parsedMessage === 'string' && parsedMessage.trim()) return parsedMessage.trim()
|
|
}
|
|
} catch {
|
|
return trimmedMessage
|
|
}
|
|
|
|
return trimmedMessage
|
|
}
|
|
|
|
function readSkillUploadErrorMessage(
|
|
error: unknown,
|
|
visited = new Set<unknown>(),
|
|
): string | undefined {
|
|
if (!error || visited.has(error)) return undefined
|
|
if (typeof error === 'string') return parseSkillUploadErrorMessage(error)
|
|
if (typeof error !== 'object') return undefined
|
|
|
|
visited.add(error)
|
|
const record = error as Record<string, unknown>
|
|
|
|
for (const key of ['data', 'body', 'error', 'cause', 'response']) {
|
|
const nestedMessage = readSkillUploadErrorMessage(record[key], visited)
|
|
if (nestedMessage) return nestedMessage
|
|
}
|
|
|
|
const message = record.message
|
|
if (typeof message === 'string' && message.trim()) return parseSkillUploadErrorMessage(message)
|
|
|
|
return undefined
|
|
}
|
|
|
|
async function getSkillUploadResponseErrorMessage(response: Response) {
|
|
try {
|
|
const data: unknown = await response.clone().json()
|
|
return readSkillUploadErrorMessage(data)
|
|
} catch {
|
|
try {
|
|
const text = await response.clone().text()
|
|
if (text.trim()) return parseSkillUploadErrorMessage(text)
|
|
} catch {}
|
|
}
|
|
}
|
|
|
|
export async function uploadSkillFile(
|
|
file: File,
|
|
options?: {
|
|
onProgress?: (progress: number) => void
|
|
xhr?: XMLHttpRequest
|
|
},
|
|
) {
|
|
const body = new FormData()
|
|
body.append('file', file)
|
|
|
|
try {
|
|
if (options?.onProgress) {
|
|
const onProgress = (event: ProgressEvent) => {
|
|
if (!event.lengthComputable) return
|
|
|
|
options.onProgress?.(Math.floor((event.loaded / event.total) * 100))
|
|
}
|
|
|
|
const response = await upload(
|
|
{
|
|
xhr: options.xhr ?? new XMLHttpRequest(),
|
|
data: body,
|
|
onprogress: onProgress,
|
|
},
|
|
false,
|
|
'/workspaces/current/skills/files/upload',
|
|
)
|
|
|
|
return response as SkillFileUploadResponse
|
|
}
|
|
|
|
return await post<SkillFileUploadResponse>(
|
|
'/workspaces/current/skills/files/upload',
|
|
{ body },
|
|
{
|
|
bodyStringify: false,
|
|
deleteContentType: true,
|
|
silent: true,
|
|
},
|
|
)
|
|
} catch (error) {
|
|
const message =
|
|
error instanceof Response
|
|
? await getSkillUploadResponseErrorMessage(error)
|
|
: readSkillUploadErrorMessage(error)
|
|
|
|
if (message) {
|
|
const normalizedError = new Error(message)
|
|
normalizedError.cause = error
|
|
throw normalizedError
|
|
}
|
|
|
|
throw error
|
|
}
|
|
}
|
|
|
|
export async function fetchSkillFileBlob({
|
|
download = false,
|
|
path,
|
|
skillId,
|
|
versionId,
|
|
}: {
|
|
download?: boolean
|
|
path: string
|
|
skillId: string
|
|
versionId: string | null
|
|
}) {
|
|
const params = new URLSearchParams({ path })
|
|
if (versionId) params.set('version_id', versionId)
|
|
if (download) params.set('download', '1')
|
|
|
|
const response = await get<Response>(
|
|
`/workspaces/current/skills/${encodeURIComponent(skillId)}/files/content?${params.toString()}`,
|
|
{},
|
|
{ needAllResponseContent: true },
|
|
)
|
|
return response.blob()
|
|
}
|
|
|
|
export async function fetchSkillArchiveBlob(skillId: string) {
|
|
const response = await get<Response>(
|
|
`/workspaces/current/skills/${encodeURIComponent(skillId)}/export`,
|
|
{},
|
|
{ needAllResponseContent: true },
|
|
)
|
|
return response.blob()
|
|
}
|
|
|
|
export function sendSkillAssistMessage({
|
|
attachments,
|
|
getAbortController,
|
|
message,
|
|
model,
|
|
onCompleted,
|
|
onData,
|
|
onError,
|
|
onUnhandledEvent,
|
|
skillId,
|
|
targetPath,
|
|
history,
|
|
}: {
|
|
attachments?: SkillAssistAttachmentPayload[]
|
|
history?: SkillAssistHistoryMessagePayload[]
|
|
getAbortController?: (abortController: AbortController) => void
|
|
message: string
|
|
model?: DefaultModel & {
|
|
model_settings?: FormValue
|
|
}
|
|
onCompleted?: IOnCompleted
|
|
onData?: IOnData
|
|
onError?: IOnError
|
|
onUnhandledEvent?: (event: Record<string, unknown>) => void
|
|
skillId: string
|
|
targetPath?: string
|
|
}) {
|
|
let streamErrorHandled = false
|
|
return ssePost(
|
|
`/workspaces/current/skills/${encodeURIComponent(skillId)}/assist/messages`,
|
|
{
|
|
body: {
|
|
attachments,
|
|
history,
|
|
message,
|
|
model,
|
|
target_path: targetPath,
|
|
},
|
|
},
|
|
{
|
|
silent: true,
|
|
getAbortController,
|
|
onCompleted: (hasError, errorMessage) => {
|
|
onCompleted?.(streamErrorHandled && hasError ? false : hasError, errorMessage)
|
|
},
|
|
onData: (chunk, isFirstMessage, moreInfo) => {
|
|
if (moreInfo.errorMessage) {
|
|
streamErrorHandled = true
|
|
onError?.(moreInfo.errorMessage, moreInfo.errorCode)
|
|
return
|
|
}
|
|
|
|
onData?.(chunk, isFirstMessage, moreInfo)
|
|
},
|
|
onError: (errorMessage, errorCode) => {
|
|
streamErrorHandled = true
|
|
onError?.(errorMessage, errorCode)
|
|
},
|
|
onUnhandledEvent,
|
|
},
|
|
)
|
|
}
|