@@ -170,8 +170,13 @@ async def handle_assistant_stream(
170
170
async with stream_manager as event_handler :
171
171
event : AssistantStreamEvent
172
172
async for event in event_handler :
173
+ # Debug logging for all events
174
+ logger .debug (f"SSE Event Type: { type (event ).__name__ } " )
175
+ logger .debug (f"SSE Event Data: { event .data } " )
176
+
173
177
if isinstance (event , ThreadMessageCreated ):
174
178
step_id = event .data .id
179
+ logger .debug (f"Message Created - Step ID: { step_id } " )
175
180
176
181
yield sse_format (
177
182
"messageCreated" ,
@@ -192,6 +197,7 @@ async def handle_assistant_stream(
192
197
193
198
if isinstance (event , ThreadRunStepCreated ) and event .data .type == "tool_calls" :
194
199
step_id = event .data .id
200
+ logger .debug (f"Tool Call Created - Step ID: { step_id } " )
195
201
196
202
yield sse_format (
197
203
f"toolCallCreated" ,
@@ -207,6 +213,7 @@ async def handle_assistant_stream(
207
213
if tool_calls :
208
214
# TODO: Support parallel function calling
209
215
tool_call = tool_calls [0 ]
216
+ logger .debug (f"Tool Call Delta - Type: { tool_call .type } " )
210
217
211
218
# Handle function tool call
212
219
if tool_call .type == "function" :
@@ -224,27 +231,33 @@ async def handle_assistant_stream(
224
231
# Handle code interpreter tool calls
225
232
elif tool_call .type == "code_interpreter" :
226
233
if tool_call .code_interpreter and tool_call .code_interpreter .input :
234
+ logger .debug (f"Code Interpreter Input: { tool_call .code_interpreter .input } " )
227
235
yield sse_format (
228
236
f"toolDelta{ step_id } " ,
229
237
str (tool_call .code_interpreter .input )
230
238
)
231
239
if tool_call .code_interpreter and tool_call .code_interpreter .outputs :
232
240
for output in tool_call .code_interpreter .outputs :
241
+ logger .debug (f"Code Interpreter Output Type: { output .type } " )
233
242
if output .type == "logs" and output .logs :
234
243
yield sse_format (
235
244
f"toolDelta{ step_id } " ,
236
245
str (output .logs )
237
246
)
238
247
elif output .type == "image" and output .image and output .image .file_id :
248
+ logger .debug (f"Image Output - File ID: { output .image .file_id } " )
249
+ # Create the image HTML on the backend
250
+ image_html = f'<img src="/assistants/{ assistant_id } /messages/{ thread_id } /files/{ output .image .file_id } /content" class="code-interpreter-image">'
239
251
yield sse_format (
240
252
f"toolDelta{ step_id } " ,
241
- str ( output . image . file_id )
253
+ image_html
242
254
)
243
255
244
256
# If the assistant run requires an action (a tool call), break and handle it
245
257
if isinstance (event , ThreadRunRequiresAction ):
246
258
required_action = event .data .required_action
247
259
run_requires_action_event = event
260
+ logger .debug ("Run Requires Action Event" )
248
261
if required_action and required_action .submit_tool_outputs :
249
262
break
250
263
@@ -349,3 +362,28 @@ async def event_generator() -> AsyncGenerator[str, None]:
349
362
"Connection" : "keep-alive" ,
350
363
}
351
364
)
365
+
366
+ # Route to serve image files from OpenAI API
367
+ @router .get ("/files/{file_id}/content" )
368
+ async def get_file_content (
369
+ file_id : str ,
370
+ client : AsyncOpenAI = Depends (lambda : AsyncOpenAI ())
371
+ ) -> StreamingResponse :
372
+ """
373
+ Streams file content from OpenAI API.
374
+ This route is used to serve images and other files generated by the code interpreter.
375
+ """
376
+ try :
377
+ # Get the file content from OpenAI
378
+ file_content = await client .files .content (file_id )
379
+ file_bytes = file_content .read () # Remove await since read() returns bytes directly
380
+
381
+ # Return the file content as a streaming response
382
+ # Note: In a production environment, you might want to add caching
383
+ return StreamingResponse (
384
+ content = iter ([file_bytes ]),
385
+ media_type = "image/png" # You might want to make this dynamic based on file type
386
+ )
387
+ except Exception as e :
388
+ logger .error (f"Error getting file content: { e } " )
389
+ raise HTTPException (status_code = 500 , detail = str (e ))
0 commit comments