forked from lobehub/lobe-chat
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
18 changed files
with
348 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
'use client'; | ||
|
||
import { Form, type ItemGroup, Input } from '@lobehub/ui'; | ||
import { Switch } from 'antd'; | ||
import { memo, useEffect, useState } from 'react'; | ||
import { useTranslation } from 'react-i18next'; | ||
|
||
import { FORM_STYLE } from '@/const/layoutTokens'; | ||
|
||
import { useStore } from '../store'; | ||
import { useUserStore } from '@/store/user'; | ||
|
||
const AgentMeta = memo(() => { | ||
const { t } = useTranslation('setting'); | ||
|
||
const [setAgentConfig, agentConfig ] = useStore((s) => [ | ||
s.setAgentConfig, | ||
s.config | ||
]); | ||
|
||
const updateKeyVaultConfig = useUserStore((s)=>s.updateKeyVaultConfig) | ||
|
||
const [difyBaseUrl, setDifyBaseUrl] = useState<string>('https://api.dify.ai/v1') | ||
const [difyToken, setDifyToken] = useState<string>('app-1WHrUsnegCQqYgSjN952dHyt') | ||
const [difyUserId, setDifyUserId] = useState<string>('dev') | ||
const [difyEnabled, setDifyEnable] = useState<boolean>(true) | ||
|
||
useEffect(() => { | ||
setAgentConfig({ | ||
dify: { | ||
baseUrl: difyBaseUrl, | ||
token: difyToken, | ||
userId: difyUserId, | ||
enabled: difyEnabled, | ||
}, | ||
provider: 'dify', | ||
model: 'Dofy Workflow' | ||
}) | ||
updateKeyVaultConfig('dify', { | ||
baseUrl: difyBaseUrl, | ||
token: difyToken, | ||
userId: difyUserId, | ||
}) | ||
}, [difyBaseUrl, difyToken, difyUserId, difyEnabled]) | ||
|
||
const metaData: ItemGroup = { | ||
children: [ | ||
{ | ||
children: ( | ||
<Input | ||
onChange={(event) => setDifyBaseUrl(event.currentTarget.value)} | ||
placeholder='https://api.dify.ai/v1' | ||
value={agentConfig.dify.baseUrl} /> | ||
), | ||
label: 'BaseUrl' | ||
}, | ||
{ | ||
children: ( | ||
<Input | ||
onChange={(event) => setDifyToken(event.currentTarget.value)} | ||
value={agentConfig.dify.token} | ||
/> | ||
), | ||
label: 'Token' | ||
}, | ||
{ | ||
children: ( | ||
<Input | ||
onChange={(event) => setDifyUserId(event.currentTarget.value)} | ||
value={agentConfig.dify.userId} | ||
/> | ||
), | ||
label: 'UserId' | ||
}, | ||
{ | ||
children: ( | ||
<Switch | ||
onChange={setDifyEnable} | ||
value={agentConfig.dify.enabled} | ||
/> | ||
), | ||
label: 'BaseUrl' | ||
} | ||
], | ||
title: t('settingAgent.title'), | ||
}; | ||
|
||
return <Form items={[metaData]} itemsType={'group'} variant={'pure'} {...FORM_STYLE} />; | ||
}); | ||
|
||
export default AgentMeta; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import { ChatClient } from 'dify-client' | ||
import { LobeRuntimeAI } from '../BaseAI'; | ||
import { AgentRuntimeErrorType } from '../error'; | ||
import { ChatCompetitionOptions, ChatStreamPayload, ModelProvider } from '../types'; | ||
import { AgentRuntimeError } from '../utils/createError'; | ||
import { StreamingResponse } from '../utils/response'; | ||
import { DifyStream } from '../utils/streams/dify'; | ||
import urlJoin from 'url-join'; | ||
|
||
export interface DifyParams { | ||
baseUrl: string | ||
token?: string | ||
userId: string | ||
conversation_id?: string | ||
} | ||
|
||
export class LobeDify implements LobeRuntimeAI { | ||
client: ChatClient; | ||
difyParams: DifyParams | ||
|
||
constructor({ baseUrl, token, userId, conversation_id }: Partial<DifyParams>) { | ||
console.log('[LobeDify]: ', {baseUrl, token, userId, conversation_id}); | ||
|
||
if (!(userId && token)) | ||
throw AgentRuntimeError.createError(AgentRuntimeErrorType.InvalidProviderAPIKey); | ||
|
||
this.difyParams = { | ||
baseUrl: baseUrl ?? 'https://api.dify.ai/v1', | ||
conversation_id, | ||
userId, | ||
token, | ||
} | ||
this.client = new ChatClient(token, this.difyParams.baseUrl) | ||
} | ||
|
||
async chat(payload: ChatStreamPayload, options?: ChatCompetitionOptions) { | ||
const { messages } = payload | ||
// Get the last message as query | ||
const query = messages.at(-1) | ||
if (!query) { | ||
throw new Error('[Dify]: No query') | ||
} | ||
let textQuery = '' | ||
if (typeof query.content === 'string') | ||
textQuery = query.content | ||
else | ||
throw new Error('[Dify]: Unsupport user message type') | ||
|
||
console.log('[Dify]: textQuery', textQuery); | ||
|
||
const response = await fetch(urlJoin(this.difyParams.baseUrl, '/chat-messages'), { | ||
method: 'POST', | ||
// signal: options?.signal, | ||
headers: { | ||
Authorization: `Bearer ${this.difyParams.token}`, | ||
'Content-Type': 'application/json' | ||
}, | ||
body: JSON.stringify({ | ||
query: textQuery, | ||
user: this.difyParams.userId, | ||
conversation_id: this.difyParams?.conversation_id ?? '', | ||
response_mode: 'streaming', | ||
inputs: [], | ||
files: [], | ||
}) | ||
}) | ||
if (!response.body || !response.ok) { | ||
throw AgentRuntimeError.chat({ | ||
error: { | ||
status: response.status, | ||
statusText: response.statusText, | ||
}, | ||
errorType: AgentRuntimeErrorType.ProviderBizError, | ||
provider: ModelProvider.Dify, | ||
}); | ||
} | ||
const [prod, _] = response.body.tee(); | ||
return StreamingResponse(DifyStream(prod), { headers: options?.headers }); | ||
} | ||
} | ||
|
||
export default LobeDify; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import { convertIterableToStream, createCallbacksTransformer, createSSEProtocolTransformer, StreamProtocolChunk, StreamStack } from "."; | ||
import { ChatStreamCallbacks } from "../.."; | ||
|
||
interface DifyChunk { | ||
event: string; | ||
task_id?: string; | ||
answer?: string; | ||
message?: string; // 错误信息 | ||
message_id?: string; | ||
id?: string | ||
} | ||
|
||
const processDifyData = (buffer: string): DifyChunk => { | ||
try { | ||
// Remove the prefix `data:` | ||
if (buffer.startsWith('data:')) | ||
return JSON.parse(buffer.slice(5).trim()) as DifyChunk | ||
return JSON.parse(buffer.trim()) | ||
} catch (error) { | ||
console.error('[Dify - transformDifyStream - processDifyData]: ', { | ||
error, | ||
buffer, | ||
}) | ||
} | ||
return { raw: buffer } as any | ||
} | ||
|
||
export const transformDifyStream = (buffer: Uint8Array): StreamProtocolChunk => { | ||
const decoder = new TextDecoder() | ||
const chunk = processDifyData(decoder.decode(buffer, { stream: true })) | ||
// console.log('[transformDifyStrem]: ', chunk); | ||
let type: StreamProtocolChunk['type'] = 'text' | ||
switch(chunk.event){ | ||
case 'message_end': | ||
type = 'stop' | ||
break; | ||
case 'message': | ||
type = 'text' | ||
break; | ||
case 'message_replace': | ||
type = 'text' | ||
break; | ||
case 'workflow_started': | ||
type = 'tool_calls' | ||
break; | ||
case 'node_started': | ||
type = 'tool_calls' | ||
break; | ||
case 'node_finished ': | ||
type = 'tool_calls' | ||
break | ||
case 'workflow_finished': | ||
type = 'tool_calls' | ||
break; | ||
} | ||
return { | ||
id: chunk?.task_id ?? chunk?.id, | ||
data: chunk, | ||
type: type, | ||
} | ||
} | ||
|
||
export const DifyStream = (stream: ReadableStream, callbacks?: ChatStreamCallbacks) => { | ||
return stream | ||
.pipeThrough(createSSEProtocolTransformer(transformDifyStream)) | ||
.pipeThrough(createCallbacksTransformer(callbacks)); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.