@@ -100,7 +100,10 @@ function request_body_live(url; method, input, headers, streamcallback, kwargs..
100
100
r = HTTP. startread (stream) # start reading the response
101
101
isdone = false
102
102
103
- while ! eof (stream) || ! isdone
103
+ while ! isdone
104
+ if eof (stream)
105
+ break
106
+ end
104
107
# Extract all available messages
105
108
masterchunk = String (readavailable (stream))
106
109
@@ -114,6 +117,7 @@ function request_body_live(url; method, input, headers, streamcallback, kwargs..
114
117
for chunk in chunks
115
118
if occursin (chunk, " data: [DONE]" ) # TODO - maybe don't strip, but instead us a regex in the endswith call
116
119
isdone = true
120
+ break
117
121
end
118
122
119
123
# call the callback (if present) on the latest chunk
@@ -180,14 +184,14 @@ function _request(api::AbstractString,
180
184
return if isnothing (streamcallback)
181
185
OpenAIResponse (resp. status, JSON3. read (body))
182
186
else
183
- # assemble the streaming response body into a proper JSON object
184
- lines = split (body, " \n " ) # split body into lines
187
+ # Assemble the streaming response body into a proper JSON object
188
+ lines = split (body, " \n " ) # Split body into lines
185
189
186
- # throw out empty lines, skip "data: [DONE] bits
187
- lines = filter (x -> ! isempty (x) && ! occursin ( " [DONE] " , x ), lines)
190
+ # Filter out empty lines and lines that are not JSON (e.g., "event: ...")
191
+ lines = filter (x -> ! isempty (x) && startswith (x, " data: " ), lines)
188
192
189
- # read each line, which looks like "data: {<json elements>}"
190
- parsed = map (line -> JSON3. read (line[6 : end ]), lines)
193
+ # Parse each line, removing the "data: " prefix
194
+ parsed = map (line -> JSON3. read (line[7 : end ]), lines)
191
195
192
196
OpenAIResponse (resp. status, parsed)
193
197
end
466
470
467
471
include (" assistants.jl" )
468
472
473
+
474
+ """
475
+ Create responses
476
+
477
+ https://platform.openai.com/docs/api-reference/responses/create
478
+
479
+ # Arguments:
480
+ - `api_key::String`: OpenAI API key
481
+ - `input`: The input text to generate the response(s) for, as String or Dict.
482
+ To get responses for multiple inputs in a single request, pass an array of strings
483
+ or array of token arrays. Each input must not exceed 8192 tokens in length.
484
+ - `model::String`: Model id. Defaults to "gpt-4o-mini".
485
+ - `kwargs...`: Additional arguments to pass to the API.
486
+ - `tools::Int`: The number of responses to generate for the input. Defaults to 1.
487
+
488
+ # Examples:
489
+ ```julia
490
+
491
+ ## Image input
492
+ input = [Dict("role" => "user",
493
+ "content" => [Dict("type" => "input_text", "text" => "What is in this image?"),
494
+ Dict("type" => "input_image", "image_url" => "https://upload.wikimedia.org/wikipedia/commons/thumb/d/dd/Gfp-wisconsin-madison-the-nature-boardwalk.jpg/2560px-Gfp-wisconsin-madison-the-nature-boardwalk.jpg")])
495
+ ]
496
+ create_responses(api_key, input)
497
+
498
+ ## Web search
499
+ create_responses(api_key, "What was a positive news story from today?"; tools=[Dict("type" => "web_search_preview")])
500
+
501
+ ## File search - fails because example vector store does not exist
502
+ tools = [Dict("type" => "file_search",
503
+ "vector_store_ids" => ["vs_1234567890"],
504
+ "max_num_results" => 20)]
505
+ create_responses(api_key, "What are the attributes of an ancient brown dragon?"; tools=tools)
506
+
507
+ ## Streaming
508
+ resp = create_responses(api_key, "Hello!"; instructions="You are a helpful assistant.", stream=true, streamcallback = x->println(x))
509
+
510
+ ## Functions
511
+ tools = [
512
+ Dict(
513
+ "type" => "function",
514
+ "name" => "get_current_weather",
515
+ "description" => "Get the current weather in a given location",
516
+ "parameters" => Dict(
517
+ "type" => "object",
518
+ "properties" => Dict(
519
+ "location" => Dict(
520
+ "type" => "string",
521
+ "description" => "The city and state, e.g. San Francisco, CA",
522
+ ),
523
+ "unit"=> Dict("type" => "string", "enum" => ["celsius", "fahrenheit"]),
524
+ ),
525
+ "required" => ["location", "unit"],
526
+ )
527
+ )
528
+ ]
529
+ resp = create_responses(api_key, "What is the weather in Boston?"; tools=tools, tool_choice="auto")
530
+
531
+ ## Reasoning
532
+
533
+ response = create_responses(api_key, "How much wood would a woodchuck chuck?";
534
+ model = "o3-mini",
535
+ reasoning=Dict("effort" => "high"))
536
+ ```
537
+
538
+ """
539
+ function create_responses (api_key:: String , input, model= " gpt-4o-mini" ; http_kwargs:: NamedTuple = NamedTuple (), kwargs... )
540
+ return openai_request (" responses" ,
541
+ api_key;
542
+ method = " POST" ,
543
+ input = input,
544
+ model= model,
545
+ http_kwargs = http_kwargs,
546
+ kwargs... )
547
+ end
548
+
469
549
export OpenAIResponse
470
550
export list_models
471
551
export retrieve_model
@@ -500,5 +580,6 @@ export list_runs
500
580
export retrieve_run
501
581
export delete_run
502
582
export modify_run
583
+ export create_responses
503
584
504
585
end # module
0 commit comments