Spaces:
Running
Running
MingruiZhang
commited on
fetch vision agent (stream doesn't work) (#8)
Browse files* check-in code
* image rendering and vision agent endpoint boilerplate
* save
* conflict
* fix ts
- app/api/vision-agent/route.ts +52 -37
- components/chat/ChatList.tsx +1 -1
- components/chat/index.tsx +1 -1
app/api/vision-agent/route.ts
CHANGED
@@ -11,6 +11,52 @@ import { fetcher } from '@/lib/utils';
|
|
11 |
|
12 |
export const runtime = 'edge';
|
13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
export async function POST(req: Request) {
|
15 |
const json = await req.json();
|
16 |
const { messages, url } = json as {
|
@@ -26,46 +72,13 @@ export async function POST(req: Request) {
|
|
26 |
});
|
27 |
}
|
28 |
|
29 |
-
function parseVisionAgentStream(): AIStreamParser {
|
30 |
-
let previous = '';
|
31 |
-
|
32 |
-
return data => {
|
33 |
-
console.log('[Ming] ~ parseVisionAgentStream ~ data:', data);
|
34 |
-
// const json = JSON.parse(data) as {
|
35 |
-
// completion: string;
|
36 |
-
// stop: string | null;
|
37 |
-
// stop_reason: string | null;
|
38 |
-
// truncated: boolean;
|
39 |
-
// log_id: string;
|
40 |
-
// model: string;
|
41 |
-
// exception: string | null;
|
42 |
-
// };
|
43 |
-
|
44 |
-
// // Anthropic's `completion` field is cumulative unlike OpenAI's
|
45 |
-
// // deltas. In order to compute the delta, we must slice out the text
|
46 |
-
// // we previously received.
|
47 |
-
// const text = json.completion;
|
48 |
-
// console.log('[Ming] ~ parseVisionAgentStream ~ text:', text);
|
49 |
-
// const delta = text.slice(previous.length);
|
50 |
-
// previous = text;
|
51 |
-
|
52 |
-
return data;
|
53 |
-
};
|
54 |
-
}
|
55 |
-
|
56 |
-
function visionAgentStream(
|
57 |
-
res: Response,
|
58 |
-
cb?: AIStreamCallbacksAndOptions,
|
59 |
-
): ReadableStream {
|
60 |
-
return AIStream(res, parseVisionAgentStream(), cb);
|
61 |
-
}
|
62 |
-
|
63 |
const formData = new FormData();
|
64 |
formData.append('input', JSON.stringify(messages));
|
65 |
formData.append('image', url);
|
66 |
|
67 |
-
const fetchResponse = await
|
68 |
-
'https://api.dev.landing.ai/v1/agent/chat?agent_class=vision_agent',
|
|
|
69 |
{
|
70 |
method: 'POST',
|
71 |
headers: {
|
@@ -74,7 +87,9 @@ export async function POST(req: Request) {
|
|
74 |
body: formData,
|
75 |
},
|
76 |
);
|
77 |
-
|
|
|
|
|
78 |
const stream = visionAgentStream(fetchResponse, {
|
79 |
onStart: async () => {
|
80 |
console.log('Stream started');
|
|
|
11 |
|
12 |
export const runtime = 'edge';
|
13 |
|
14 |
+
function parseVisionAgentStream(): AIStreamParser {
|
15 |
+
let previous = '';
|
16 |
+
|
17 |
+
return data => {
|
18 |
+
console.log('[Ming] ~ parseVisionAgentStream ~ data:', data);
|
19 |
+
// const json = JSON.parse(data) as {
|
20 |
+
// completion: string;
|
21 |
+
// stop: string | null;
|
22 |
+
// stop_reason: string | null;
|
23 |
+
// truncated: boolean;
|
24 |
+
// log_id: string;
|
25 |
+
// model: string;
|
26 |
+
// exception: string | null;
|
27 |
+
// };
|
28 |
+
|
29 |
+
// // Anthropic's `completion` field is cumulative unlike OpenAI's
|
30 |
+
// // deltas. In order to compute the delta, we must slice out the text
|
31 |
+
// // we previously received.
|
32 |
+
// const text = json.completion;
|
33 |
+
// console.log('[Ming] ~ parseVisionAgentStream ~ text:', text);
|
34 |
+
// const delta = text.slice(previous.length);
|
35 |
+
// previous = text;
|
36 |
+
|
37 |
+
return data;
|
38 |
+
};
|
39 |
+
}
|
40 |
+
|
41 |
+
function visionAgentStream(
|
42 |
+
res: Response,
|
43 |
+
cb?: AIStreamCallbacksAndOptions,
|
44 |
+
): ReadableStream {
|
45 |
+
return AIStream(res, parseVisionAgentStream(), cb);
|
46 |
+
}
|
47 |
+
|
48 |
+
function readChunks(reader: any) {
|
49 |
+
return {
|
50 |
+
async *[Symbol.asyncIterator]() {
|
51 |
+
let readResult = await reader.read();
|
52 |
+
while (!readResult.done) {
|
53 |
+
yield readResult.value;
|
54 |
+
readResult = await reader.read();
|
55 |
+
}
|
56 |
+
},
|
57 |
+
};
|
58 |
+
}
|
59 |
+
|
60 |
export async function POST(req: Request) {
|
61 |
const json = await req.json();
|
62 |
const { messages, url } = json as {
|
|
|
72 |
});
|
73 |
}
|
74 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
const formData = new FormData();
|
76 |
formData.append('input', JSON.stringify(messages));
|
77 |
formData.append('image', url);
|
78 |
|
79 |
+
const fetchResponse = await fetch(
|
80 |
+
// 'https://api.dev.landing.ai/v1/agent/chat?agent_class=vision_agent',
|
81 |
+
'http://localhost:5050/v1/agent/chat?agent_class=vision_agent',
|
82 |
{
|
83 |
method: 'POST',
|
84 |
headers: {
|
|
|
87 |
body: formData,
|
88 |
},
|
89 |
);
|
90 |
+
|
91 |
+
// console.log('[Ming] ~ POST ~ fetchResponse:', fetchResponse);
|
92 |
+
|
93 |
const stream = visionAgentStream(fetchResponse, {
|
94 |
onStart: async () => {
|
95 |
console.log('Stream started');
|
components/chat/ChatList.tsx
CHANGED
@@ -12,7 +12,7 @@ export function ChatList({ messages }: ChatList) {
|
|
12 |
return (
|
13 |
<div className="relative mx-auto max-w-3xl px-8 pr-12">
|
14 |
{messages
|
15 |
-
.filter(message => message.role !== 'system')
|
16 |
.map((message, index) => (
|
17 |
<div key={index}>
|
18 |
<ChatMessage message={message} />
|
|
|
12 |
return (
|
13 |
<div className="relative mx-auto max-w-3xl px-8 pr-12">
|
14 |
{messages
|
15 |
+
// .filter(message => message.role !== 'system')
|
16 |
.map((message, index) => (
|
17 |
<div key={index}>
|
18 |
<ChatMessage message={message} />
|
components/chat/index.tsx
CHANGED
@@ -28,7 +28,7 @@ export function Chat({ chat }: ChatProps) {
|
|
28 |
src={url}
|
29 |
alt={url}
|
30 |
fill
|
31 |
-
|
32 |
/>
|
33 |
</div>
|
34 |
</div>
|
|
|
28 |
src={url}
|
29 |
alt={url}
|
30 |
fill
|
31 |
+
className="object-contain"
|
32 |
/>
|
33 |
</div>
|
34 |
</div>
|