Skip to content

Commit 600a87d

Browse files
committed
chaining
1 parent 0f961b5 commit 600a87d

File tree

4 files changed

+156
-9
lines changed

4 files changed

+156
-9
lines changed

components/x-request/index.ts

+62-6
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,21 @@ interface XRequestMessage extends AnyObject {
4646
content?: XRequestMessageContent;
4747
}
4848

49+
/** Debug usage */
50+
export interface InternalRequestConfig {
51+
/**
52+
* Replace the default base URL
53+
*/
54+
baseURL?: string;
55+
56+
/**
57+
* Attach files if needed
58+
*/
59+
files?: Blob[];
60+
61+
method?: 'GET' | 'POST' | 'PUT' | 'DELETE';
62+
}
63+
4964
/**
5065
* Compatible with the parameters of OpenAI's chat.completions.create,
5166
* with plans to support more parameters and adapters in the future
@@ -127,22 +142,55 @@ class XRequestClass {
127142
return XRequestClass.instanceBuffer.get(id) as XRequestClass;
128143
}
129144

130-
public create = async <Input = AnyObject, Output = SSEOutput>(
145+
/**
146+
* @private Internal dev usage, do not use it in production or lock your version
147+
*/
148+
public call = async <Input = AnyObject, Output = SSEOutput>(
131149
params: XRequestParams & Input,
150+
config: InternalRequestConfig,
132151
callbacks?: XRequestCallbacks<Output>,
133152
transformStream?: XStreamOptions<Output>['transformStream'],
134153
) => {
135-
const requestInit = {
136-
method: 'POST',
137-
body: JSON.stringify({
154+
const { baseURL, files, method = 'POST' } = config;
155+
156+
const isGetMethod = method === 'GET';
157+
158+
let body: string | FormData;
159+
160+
if (files?.length) {
161+
const formData = new FormData();
162+
files.forEach((file) => {
163+
formData.append('file', file);
164+
});
165+
formData.append('data', JSON.stringify(params));
166+
167+
body = formData;
168+
} else {
169+
body = JSON.stringify({
138170
model: this.model,
139171
...params,
140-
}),
172+
});
173+
}
174+
175+
const requestInit = {
176+
method,
177+
body: isGetMethod ? undefined : body,
141178
headers: this.defaultHeaders,
142179
};
143180

144181
try {
145-
const response = await xFetch(this.baseURL, {
182+
let mergedURL = baseURL || this.baseURL;
183+
184+
// Convert GET params to URL
185+
if (isGetMethod) {
186+
const url = new URL(mergedURL);
187+
Object.keys(params).forEach((key) => {
188+
url.searchParams.append(key, (params as any)[key]);
189+
});
190+
mergedURL = url.toString();
191+
}
192+
193+
const response = await xFetch(mergedURL, {
146194
fetch: this.customOptions.fetch,
147195
...requestInit,
148196
});
@@ -179,6 +227,14 @@ class XRequestClass {
179227
}
180228
};
181229

230+
public create = async <Input = AnyObject, Output = SSEOutput>(
231+
params: XRequestParams & Input,
232+
callbacks?: XRequestCallbacks<Output>,
233+
transformStream?: XStreamOptions<Output>['transformStream'],
234+
) => {
235+
return this.call<Input, Output>(params, {}, callbacks, transformStream);
236+
};
237+
182238
private customResponseHandler = async <Output = SSEOutput>(
183239
response: Response,
184240
callbacks?: XRequestCallbacks<Output>,

docs/playground/ChainReaction/ChatBox.tsx

+6
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,12 @@ export default function ChatBox(props: ChatBoxProps) {
5252
const [open, setOpen] = React.useState(false);
5353
const [files, setFiles] = React.useState<GetProp<AttachmentsProps, 'items'>>([]);
5454

55+
React.useEffect(() => {
56+
if (!files.length) {
57+
setOpen(false);
58+
}
59+
}, [files.length]);
60+
5561
// =========================== Sender ===========================
5662
const [text, setText] = React.useState('');
5763

docs/playground/ChainReaction/index.tsx

+2-2
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ function App() {
8282
const { styles } = useStyle();
8383

8484
// ============================ Data ============================
85-
const onChatSubmit = (text: string) => {
86-
onRequest([{ text, role: 'user' }]);
85+
const onChatSubmit = (text: string, files: File[]) => {
86+
onRequest([{ text, role: 'user', files }]);
8787
};
8888

8989
const [items, lastChainTask] = React.useMemo(() => {

docs/playground/ChainReaction/useChain.ts

+86-1
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,105 @@
1-
import { useXAgent, useXChat } from '@ant-design/x';
1+
import { useXAgent, useXChat, XRequest } from '@ant-design/x';
22

33
export interface AgentMessageSingleType {
44
role: 'user' | 'ai' | 'chain';
55
text: string;
6+
files?: File[];
67
}
78

89
export type AgentMessageType = AgentMessageSingleType[];
910

11+
// Used for chaining request
12+
const sharedRequest = XRequest({
13+
baseURL: '-',
14+
});
15+
1016
export default function useChain() {
1117
// =========================== Agent ============================
1218
const [agent] = useXAgent<AgentMessageType>({
1319
request: async ({ message = [] }, { onSuccess, onUpdate }) => {
1420
// Note: this is used for development usage.
1521
// You can realize with your own request logic.
1622
const sessionUrl = localStorage.getItem('api/session');
23+
const diagnosticsUrl = localStorage.getItem('api/diagnostics');
1724
console.log('sessionUrl', sessionUrl);
25+
26+
if (!sessionUrl || !diagnosticsUrl) {
27+
return;
28+
}
29+
30+
// Start Chain Reaction
31+
const [msg] = message;
32+
33+
const fetchResult = await fetch(sessionUrl, {
34+
method: 'POST',
35+
headers: {
36+
'Content-Type': 'application/json',
37+
},
38+
body: JSON.stringify({
39+
query: msg.text,
40+
// llmProvider: 'openai',
41+
// llmModelName: 'gpt-4o',
42+
llmProvider: 'alibaba',
43+
llmModelName: 'qwen-plus',
44+
}),
45+
});
46+
47+
const resultJSON = (await fetchResult.json()) as {
48+
message: string;
49+
task_id: string;
50+
};
51+
console.log('resultJSON', resultJSON);
52+
53+
let prevRetStr: string = '';
54+
55+
// Loop call
56+
setInterval(async () => {
57+
sharedRequest.call(
58+
{},
59+
{
60+
baseURL: diagnosticsUrl!,
61+
method: 'GET',
62+
},
63+
{
64+
onUpdate(chunk) {
65+
const nextRetStr = JSON.stringify(chunk);
66+
if (prevRetStr !== nextRetStr) {
67+
prevRetStr = nextRetStr;
68+
console.log('Info:', chunk);
69+
}
70+
// console.log('onUpdate', chunk);
71+
},
72+
onSuccess(chunk) {
73+
// console.log('onSuccess', chunk);
74+
},
75+
onError(error) {
76+
// console.log('onError', error);
77+
},
78+
},
79+
);
80+
}, 100);
81+
82+
// Get status
83+
// sharedRequest.call(
84+
// {
85+
// task_id: resultJSON.task_id,
86+
// },
87+
// {
88+
// baseURL: diagnosticsUrl!,
89+
// method: 'GET',
90+
// },
91+
// {
92+
// onUpdate(chunk) {
93+
// console.log('onUpdate', chunk);
94+
// },
95+
// onSuccess(chunk) {
96+
// console.log('onSuccess', chunk);
97+
// },
98+
// onError(error) {
99+
// console.log('onError', error);
100+
// },
101+
// },
102+
// );
18103
},
19104
});
20105

0 commit comments

Comments
 (0)