Spaces:
Sleeping
Sleeping
wuyiqunLu
commited on
Commit
•
139a0f4
1
Parent(s):
54a4eaa
feat: vision agent streaming (#32)
Browse files<img width="1493" alt="image"
src="https://github.com/landing-ai/vision-agent-ui/assets/132986242/bcaf6c02-6076-41a0-a1b0-83197bc90af7">
Not able to test error logging at the moment, will add later
- app/api/vision-agent/route.ts +58 -4
- lib/logger.ts +27 -14
app/api/vision-agent/route.ts
CHANGED
@@ -1,8 +1,12 @@
|
|
1 |
-
import {
|
|
|
|
|
|
|
|
|
2 |
|
3 |
// import { auth } from '@/auth';
|
4 |
import { MessageBase } from '../../../lib/types';
|
5 |
-
import { withLogging } from '@/lib/logger';
|
6 |
import { CLEANED_SEPARATOR } from '@/lib/constants';
|
7 |
import { cleanAnswerMessage, cleanInputMessage } from '@/lib/messageUtils';
|
8 |
|
@@ -12,12 +16,13 @@ export const maxDuration = 300; // This function can run for a maximum of 5 minu
|
|
12 |
|
13 |
export const POST = withLogging(
|
14 |
async (
|
15 |
-
|
16 |
json: {
|
17 |
messages: MessageBase[];
|
18 |
id: string;
|
19 |
url: string;
|
20 |
},
|
|
|
21 |
) => {
|
22 |
const { messages, url } = json;
|
23 |
|
@@ -65,8 +70,57 @@ export const POST = withLogging(
|
|
65 |
},
|
66 |
);
|
67 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
if (fetchResponse.body) {
|
69 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
} else {
|
71 |
return fetchResponse;
|
72 |
}
|
|
|
1 |
+
import {
|
2 |
+
StreamingTextResponse,
|
3 |
+
experimental_StreamData,
|
4 |
+
createStreamDataTransformer,
|
5 |
+
} from 'ai';
|
6 |
|
7 |
// import { auth } from '@/auth';
|
8 |
import { MessageBase } from '../../../lib/types';
|
9 |
+
import { logger, withLogging } from '@/lib/logger';
|
10 |
import { CLEANED_SEPARATOR } from '@/lib/constants';
|
11 |
import { cleanAnswerMessage, cleanInputMessage } from '@/lib/messageUtils';
|
12 |
|
|
|
16 |
|
17 |
export const POST = withLogging(
|
18 |
async (
|
19 |
+
session,
|
20 |
json: {
|
21 |
messages: MessageBase[];
|
22 |
id: string;
|
23 |
url: string;
|
24 |
},
|
25 |
+
request,
|
26 |
) => {
|
27 |
const { messages, url } = json;
|
28 |
|
|
|
70 |
},
|
71 |
);
|
72 |
|
73 |
+
if (!fetchResponse.ok) {
|
74 |
+
if (fetchResponse.body) {
|
75 |
+
const reader = fetchResponse.body.getReader();
|
76 |
+
return new StreamingTextResponse(
|
77 |
+
new ReadableStream({
|
78 |
+
async start(controller) {
|
79 |
+
const { done, value } = await reader.read();
|
80 |
+
if (!done) {
|
81 |
+
const errorText = new TextDecoder().decode(value);
|
82 |
+
logger.error(session, errorText, request);
|
83 |
+
controller.error(new Error(`Response error: ${errorText}`));
|
84 |
+
}
|
85 |
+
},
|
86 |
+
}),
|
87 |
+
{
|
88 |
+
status: 400,
|
89 |
+
},
|
90 |
+
);
|
91 |
+
} else {
|
92 |
+
return new StreamingTextResponse(
|
93 |
+
new ReadableStream({
|
94 |
+
start(controller) {
|
95 |
+
logger.error(
|
96 |
+
session,
|
97 |
+
'Response error: No response body',
|
98 |
+
request,
|
99 |
+
);
|
100 |
+
controller.error(new Error('Response error: No response body'));
|
101 |
+
},
|
102 |
+
}),
|
103 |
+
{
|
104 |
+
status: 400,
|
105 |
+
},
|
106 |
+
);
|
107 |
+
}
|
108 |
+
}
|
109 |
+
|
110 |
if (fetchResponse.body) {
|
111 |
+
const encoder = new TextEncoder();
|
112 |
+
const decoder = new TextDecoder();
|
113 |
+
|
114 |
+
const stream = fetchResponse.body.pipeThrough(
|
115 |
+
new TransformStream({
|
116 |
+
transform: async (chunk, controller) => {
|
117 |
+
const message = decoder.decode(chunk);
|
118 |
+
logger.info(session, { message }, request, '__AGENT_RESPONSE');
|
119 |
+
controller.enqueue(encoder.encode(message));
|
120 |
+
},
|
121 |
+
}),
|
122 |
+
);
|
123 |
+
return new StreamingTextResponse(stream);
|
124 |
} else {
|
125 |
return fetchResponse;
|
126 |
}
|
lib/logger.ts
CHANGED
@@ -38,16 +38,20 @@ class Logger {
|
|
38 |
}
|
39 |
|
40 |
private createLogMessage(
|
41 |
-
request: Request,
|
42 |
message: Object | string,
|
43 |
session: Session | null,
|
|
|
44 |
logDescription?: string,
|
45 |
) {
|
46 |
const body = {
|
47 |
type: logDescription || '__DEFAULT',
|
48 |
context: {
|
49 |
-
|
50 |
-
|
|
|
|
|
|
|
|
|
51 |
sessionUserId: session?.user.id,
|
52 |
sessionUserName: session?.user.name,
|
53 |
sessionUserEmail: session?.user.email,
|
@@ -58,62 +62,71 @@ class Logger {
|
|
58 |
}
|
59 |
|
60 |
info(
|
61 |
-
request: Request,
|
62 |
session: Session | null,
|
63 |
message: string | Object,
|
|
|
64 |
logDescription?: string,
|
65 |
) {
|
66 |
this.lokiLogger.info(
|
67 |
-
this.createLogMessage(
|
68 |
);
|
69 |
}
|
70 |
warn(
|
71 |
-
request: Request,
|
72 |
session: Session | null,
|
73 |
message: string | Object,
|
|
|
74 |
logDescription?: string,
|
75 |
) {
|
76 |
this.lokiLogger.warn(
|
77 |
-
this.createLogMessage(
|
78 |
);
|
79 |
}
|
80 |
debug(
|
81 |
-
request: Request,
|
82 |
session: Session | null,
|
83 |
message: string | Object,
|
|
|
84 |
logDescription?: string,
|
85 |
) {
|
86 |
this.lokiLogger.debug(
|
87 |
-
this.createLogMessage(
|
88 |
);
|
89 |
}
|
90 |
error(
|
91 |
-
request: Request,
|
92 |
session: Session | null,
|
93 |
message: string | Object,
|
|
|
94 |
logDescription?: string,
|
95 |
) {
|
96 |
this.lokiLogger.error(
|
97 |
-
this.createLogMessage(
|
|
|
|
|
|
|
|
|
|
|
98 |
);
|
99 |
}
|
100 |
}
|
101 |
|
102 |
export const withLogging = (
|
103 |
-
handler: (
|
|
|
|
|
|
|
|
|
104 |
) => {
|
105 |
return async (req: Request) => {
|
106 |
const session = await auth();
|
107 |
const json = await req.json();
|
108 |
logger.info(
|
109 |
-
req,
|
110 |
session,
|
111 |
{
|
112 |
params: json,
|
113 |
},
|
|
|
114 |
'_API_REQUEST',
|
115 |
);
|
116 |
-
return handler(session, json);
|
117 |
};
|
118 |
};
|
119 |
|
|
|
38 |
}
|
39 |
|
40 |
private createLogMessage(
|
|
|
41 |
message: Object | string,
|
42 |
session: Session | null,
|
43 |
+
request?: Request,
|
44 |
logDescription?: string,
|
45 |
) {
|
46 |
const body = {
|
47 |
type: logDescription || '__DEFAULT',
|
48 |
context: {
|
49 |
+
...(request
|
50 |
+
? {
|
51 |
+
method: request?.method,
|
52 |
+
url: request.url,
|
53 |
+
}
|
54 |
+
: {}),
|
55 |
sessionUserId: session?.user.id,
|
56 |
sessionUserName: session?.user.name,
|
57 |
sessionUserEmail: session?.user.email,
|
|
|
62 |
}
|
63 |
|
64 |
info(
|
|
|
65 |
session: Session | null,
|
66 |
message: string | Object,
|
67 |
+
request?: Request,
|
68 |
logDescription?: string,
|
69 |
) {
|
70 |
this.lokiLogger.info(
|
71 |
+
this.createLogMessage(message, session, request, logDescription),
|
72 |
);
|
73 |
}
|
74 |
warn(
|
|
|
75 |
session: Session | null,
|
76 |
message: string | Object,
|
77 |
+
request?: Request,
|
78 |
logDescription?: string,
|
79 |
) {
|
80 |
this.lokiLogger.warn(
|
81 |
+
this.createLogMessage(message, session, request, logDescription),
|
82 |
);
|
83 |
}
|
84 |
debug(
|
|
|
85 |
session: Session | null,
|
86 |
message: string | Object,
|
87 |
+
request?: Request,
|
88 |
logDescription?: string,
|
89 |
) {
|
90 |
this.lokiLogger.debug(
|
91 |
+
this.createLogMessage(message, session, request, logDescription),
|
92 |
);
|
93 |
}
|
94 |
error(
|
|
|
95 |
session: Session | null,
|
96 |
message: string | Object,
|
97 |
+
request?: Request,
|
98 |
logDescription?: string,
|
99 |
) {
|
100 |
this.lokiLogger.error(
|
101 |
+
this.createLogMessage(
|
102 |
+
message,
|
103 |
+
session,
|
104 |
+
request,
|
105 |
+
logDescription ?? '__ERROR',
|
106 |
+
),
|
107 |
);
|
108 |
}
|
109 |
}
|
110 |
|
111 |
export const withLogging = (
|
112 |
+
handler: (
|
113 |
+
session: Session | null,
|
114 |
+
json: any,
|
115 |
+
request: Request,
|
116 |
+
) => Promise<Response>,
|
117 |
) => {
|
118 |
return async (req: Request) => {
|
119 |
const session = await auth();
|
120 |
const json = await req.json();
|
121 |
logger.info(
|
|
|
122 |
session,
|
123 |
{
|
124 |
params: json,
|
125 |
},
|
126 |
+
req,
|
127 |
'_API_REQUEST',
|
128 |
);
|
129 |
+
return handler(session, json, req);
|
130 |
};
|
131 |
};
|
132 |
|