Current section
Files
Jump to
Current section
Files
src/glopenai@file.erl
-module(glopenai@file).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/glopenai/file.gleam").
-export([file_expiration_after_anchor_to_json/1, file_expiration_after_anchor_decoder/0, file_expiration_after_to_json/1, file_expiration_after_decoder/0, openai_file_purpose_to_json/1, openai_file_to_json/1, openai_file_purpose_decoder/0, openai_file_decoder/0, new_create_request/3, with_expires_after/2, create_response/1, create_request/3, list_request/1, list_response/1, retrieve_request/2, retrieve_response/1, delete_request/2, delete_response/1, content_request/2, content_response/1]).
-export_type([open_ai_file_purpose/0, open_ai_file/0, file_expiration_after_anchor/0, file_expiration_after/0, list_files_response/0, delete_file_response/0, create_file_request/0]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
-type open_ai_file_purpose() :: assistants |
assistants_output |
batch |
batch_output |
fine_tune |
fine_tune_results |
vision |
user_data.
-type open_ai_file() :: {open_ai_file,
binary(),
binary(),
integer(),
integer(),
gleam@option:option(integer()),
binary(),
open_ai_file_purpose()}.
-type file_expiration_after_anchor() :: created_at.
-type file_expiration_after() :: {file_expiration_after,
file_expiration_after_anchor(),
integer()}.
-type list_files_response() :: {list_files_response,
binary(),
list(open_ai_file()),
gleam@option:option(binary()),
gleam@option:option(binary()),
boolean()}.
-type delete_file_response() :: {delete_file_response,
binary(),
binary(),
boolean()}.
-type create_file_request() :: {create_file_request,
binary(),
bitstring(),
open_ai_file_purpose(),
gleam@option:option(file_expiration_after())}.
-file("src/glopenai/file.gleam", 46).
-spec file_expiration_after_anchor_to_json(file_expiration_after_anchor()) -> gleam@json:json().
file_expiration_after_anchor_to_json(Anchor) ->
gleam@json:string(case Anchor of
created_at ->
<<"created_at"/utf8>>
end).
-file("src/glopenai/file.gleam", 54).
-spec file_expiration_after_anchor_decoder() -> gleam@dynamic@decode:decoder(file_expiration_after_anchor()).
file_expiration_after_anchor_decoder() ->
gleam@dynamic@decode:then(
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Value) -> case Value of
<<"created_at"/utf8>> ->
gleam@dynamic@decode:success(created_at);
_ ->
gleam@dynamic@decode:failure(
created_at,
<<"FileExpirationAfterAnchor"/utf8>>
)
end end
).
-file("src/glopenai/file.gleam", 69).
-spec file_expiration_after_to_json(file_expiration_after()) -> gleam@json:json().
file_expiration_after_to_json(Expiration) ->
gleam@json:object(
[{<<"anchor"/utf8>>,
file_expiration_after_anchor_to_json(
erlang:element(2, Expiration)
)},
{<<"seconds"/utf8>>, gleam@json:int(erlang:element(3, Expiration))}]
).
-file("src/glopenai/file.gleam", 78).
-spec file_expiration_after_decoder() -> gleam@dynamic@decode:decoder(file_expiration_after()).
file_expiration_after_decoder() ->
gleam@dynamic@decode:field(
<<"anchor"/utf8>>,
file_expiration_after_anchor_decoder(),
fun(Anchor) ->
gleam@dynamic@decode:field(
<<"seconds"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_int/1},
fun(Seconds) ->
gleam@dynamic@decode:success(
{file_expiration_after, Anchor, Seconds}
)
end
)
end
).
-file("src/glopenai/file.gleam", 102).
-spec openai_file_purpose_to_json(open_ai_file_purpose()) -> gleam@json:json().
openai_file_purpose_to_json(Purpose) ->
gleam@json:string(case Purpose of
assistants ->
<<"assistants"/utf8>>;
assistants_output ->
<<"assistants_output"/utf8>>;
batch ->
<<"batch"/utf8>>;
batch_output ->
<<"batch_output"/utf8>>;
fine_tune ->
<<"fine-tune"/utf8>>;
fine_tune_results ->
<<"fine-tune-results"/utf8>>;
vision ->
<<"vision"/utf8>>;
user_data ->
<<"user_data"/utf8>>
end).
-file("src/glopenai/file.gleam", 115).
-spec openai_file_to_json(open_ai_file()) -> gleam@json:json().
openai_file_to_json(File) ->
gleam@json:object(
[{<<"id"/utf8>>, gleam@json:string(erlang:element(2, File))},
{<<"object"/utf8>>, gleam@json:string(erlang:element(3, File))},
{<<"bytes"/utf8>>, gleam@json:int(erlang:element(4, File))},
{<<"created_at"/utf8>>, gleam@json:int(erlang:element(5, File))},
{<<"expires_at"/utf8>>,
gleam@json:nullable(
erlang:element(6, File),
fun gleam@json:int/1
)},
{<<"filename"/utf8>>, gleam@json:string(erlang:element(7, File))},
{<<"purpose"/utf8>>,
openai_file_purpose_to_json(erlang:element(8, File))}]
).
-file("src/glopenai/file.gleam", 129).
-spec openai_file_purpose_decoder() -> gleam@dynamic@decode:decoder(open_ai_file_purpose()).
openai_file_purpose_decoder() ->
gleam@dynamic@decode:then(
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Value) -> case Value of
<<"assistants"/utf8>> ->
gleam@dynamic@decode:success(assistants);
<<"assistants_output"/utf8>> ->
gleam@dynamic@decode:success(assistants_output);
<<"batch"/utf8>> ->
gleam@dynamic@decode:success(batch);
<<"batch_output"/utf8>> ->
gleam@dynamic@decode:success(batch_output);
<<"fine-tune"/utf8>> ->
gleam@dynamic@decode:success(fine_tune);
<<"fine-tune-results"/utf8>> ->
gleam@dynamic@decode:success(fine_tune_results);
<<"vision"/utf8>> ->
gleam@dynamic@decode:success(vision);
<<"user_data"/utf8>> ->
gleam@dynamic@decode:success(user_data);
_ ->
gleam@dynamic@decode:failure(
fine_tune,
<<"OpenAiFilePurpose"/utf8>>
)
end end
).
-file("src/glopenai/file.gleam", 144).
-spec openai_file_decoder() -> gleam@dynamic@decode:decoder(open_ai_file()).
openai_file_decoder() ->
gleam@dynamic@decode:field(
<<"id"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Id) ->
gleam@dynamic@decode:field(
<<"object"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Object) ->
gleam@dynamic@decode:field(
<<"bytes"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_int/1},
fun(Bytes) ->
gleam@dynamic@decode:field(
<<"created_at"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_int/1},
fun(Created_at) ->
gleam@dynamic@decode:optional_field(
<<"expires_at"/utf8>>,
none,
gleam@dynamic@decode:optional(
{decoder,
fun gleam@dynamic@decode:decode_int/1}
),
fun(Expires_at) ->
gleam@dynamic@decode:field(
<<"filename"/utf8>>,
{decoder,
fun gleam@dynamic@decode:decode_string/1},
fun(Filename) ->
gleam@dynamic@decode:field(
<<"purpose"/utf8>>,
openai_file_purpose_decoder(
),
fun(Purpose) ->
gleam@dynamic@decode:success(
{open_ai_file,
Id,
Object,
Bytes,
Created_at,
Expires_at,
Filename,
Purpose}
)
end
)
end
)
end
)
end
)
end
)
end
)
end
).
-file("src/glopenai/file.gleam", 167).
-spec list_files_response_decoder() -> gleam@dynamic@decode:decoder(list_files_response()).
list_files_response_decoder() ->
gleam@dynamic@decode:field(
<<"object"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Object) ->
gleam@dynamic@decode:field(
<<"data"/utf8>>,
gleam@dynamic@decode:list(openai_file_decoder()),
fun(Data) ->
gleam@dynamic@decode:optional_field(
<<"first_id"/utf8>>,
none,
gleam@dynamic@decode:optional(
{decoder, fun gleam@dynamic@decode:decode_string/1}
),
fun(First_id) ->
gleam@dynamic@decode:optional_field(
<<"last_id"/utf8>>,
none,
gleam@dynamic@decode:optional(
{decoder,
fun gleam@dynamic@decode:decode_string/1}
),
fun(Last_id) ->
gleam@dynamic@decode:field(
<<"has_more"/utf8>>,
{decoder,
fun gleam@dynamic@decode:decode_bool/1},
fun(Has_more) ->
gleam@dynamic@decode:success(
{list_files_response,
Object,
Data,
First_id,
Last_id,
Has_more}
)
end
)
end
)
end
)
end
)
end
).
-file("src/glopenai/file.gleam", 190).
-spec delete_file_response_decoder() -> gleam@dynamic@decode:decoder(delete_file_response()).
delete_file_response_decoder() ->
gleam@dynamic@decode:field(
<<"id"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Id) ->
gleam@dynamic@decode:field(
<<"object"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Object) ->
gleam@dynamic@decode:field(
<<"deleted"/utf8>>,
{decoder, fun gleam@dynamic@decode:decode_bool/1},
fun(Deleted) ->
gleam@dynamic@decode:success(
{delete_file_response, Id, Object, Deleted}
)
end
)
end
)
end
).
-file("src/glopenai/file.gleam", 213).
-spec new_create_request(binary(), bitstring(), open_ai_file_purpose()) -> create_file_request().
new_create_request(Filename, File_bytes, Purpose) ->
{create_file_request, Filename, File_bytes, Purpose, none}.
-file("src/glopenai/file.gleam", 226).
-spec with_expires_after(create_file_request(), file_expiration_after()) -> create_file_request().
with_expires_after(Request, Expires_after) ->
{create_file_request,
erlang:element(2, Request),
erlang:element(3, Request),
erlang:element(4, Request),
{some, Expires_after}}.
-file("src/glopenai/file.gleam", 274).
-spec create_response(gleam@http@response:response(binary())) -> {ok,
open_ai_file()} |
{error, glopenai@error:glopenai_error()}.
create_response(Response) ->
glopenai@internal:parse_response(Response, openai_file_decoder()).
-file("src/glopenai/file.gleam", 305).
-spec ends_with(binary(), binary()) -> boolean().
ends_with(Haystack, Needle) ->
H = gleam_stdlib:identity(Haystack),
N = gleam_stdlib:identity(Needle),
H_size = erlang:byte_size(H),
N_size = erlang:byte_size(N),
case H_size >= N_size of
false ->
false;
true ->
case gleam_stdlib:bit_array_slice(H, H_size - N_size, N_size) of
{ok, Suffix} ->
Suffix =:= N;
{error, _} ->
false
end
end.
-file("src/glopenai/file.gleam", 283).
?DOC(
" Best-effort `Content-Type` guess from the filename extension. The OpenAI\n"
" API does not strictly enforce this for files, but a sensible value avoids\n"
" confusing logs and proxies.\n"
).
-spec guess_content_type(binary()) -> binary().
guess_content_type(Filename) ->
case gleam_stdlib:identity(Filename) of
_ ->
case ends_with(Filename, <<".pdf"/utf8>>) of
true ->
<<"application/pdf"/utf8>>;
false ->
case ends_with(Filename, <<".jsonl"/utf8>>) of
true ->
<<"application/jsonl"/utf8>>;
false ->
case ends_with(Filename, <<".json"/utf8>>) of
true ->
<<"application/json"/utf8>>;
false ->
case ends_with(Filename, <<".txt"/utf8>>) of
true ->
<<"text/plain"/utf8>>;
false ->
<<"application/octet-stream"/utf8>>
end
end
end
end
end.
-file("src/glopenai/file.gleam", 320).
-spec openai_file_purpose_to_string(open_ai_file_purpose()) -> binary().
openai_file_purpose_to_string(Purpose) ->
case Purpose of
assistants ->
<<"assistants"/utf8>>;
assistants_output ->
<<"assistants_output"/utf8>>;
batch ->
<<"batch"/utf8>>;
batch_output ->
<<"batch_output"/utf8>>;
fine_tune ->
<<"fine-tune"/utf8>>;
fine_tune_results ->
<<"fine-tune-results"/utf8>>;
vision ->
<<"vision"/utf8>>;
user_data ->
<<"user_data"/utf8>>
end.
-file("src/glopenai/file.gleam", 235).
?DOC(
" Build a `POST /files` multipart request. The caller chooses `boundary`;\n"
" it must not appear inside `request.file_bytes`.\n"
).
-spec create_request(glopenai@config:config(), create_file_request(), binary()) -> gleam@http@request:request(bitstring()).
create_request(Config, Request, Boundary) ->
Base_parts = [{file_part,
<<"file"/utf8>>,
erlang:element(2, Request),
guess_content_type(erlang:element(2, Request)),
erlang:element(3, Request)},
{field_part,
<<"purpose"/utf8>>,
openai_file_purpose_to_string(erlang:element(4, Request))}],
Parts = case erlang:element(5, Request) of
none ->
Base_parts;
{some, Expires} ->
[{field_part,
<<"expires_after[anchor]"/utf8>>,
case erlang:element(2, Expires) of
created_at ->
<<"created_at"/utf8>>
end},
{field_part,
<<"expires_after[seconds]"/utf8>>,
erlang:integer_to_binary(erlang:element(3, Expires))} |
Base_parts]
end,
glopenai@internal:multipart_request(
Config,
post,
<<"/files"/utf8>>,
Parts,
Boundary
).
-file("src/glopenai/file.gleam", 336).
?DOC(" Build a request to list files.\n").
-spec list_request(glopenai@config:config()) -> gleam@http@request:request(binary()).
list_request(Config) ->
glopenai@internal:get_request(Config, <<"/files"/utf8>>).
-file("src/glopenai/file.gleam", 341).
?DOC(" Parse the response from listing files.\n").
-spec list_response(gleam@http@response:response(binary())) -> {ok,
list_files_response()} |
{error, glopenai@error:glopenai_error()}.
list_response(Response) ->
glopenai@internal:parse_response(Response, list_files_response_decoder()).
-file("src/glopenai/file.gleam", 348).
?DOC(" Build a request to retrieve metadata for a specific file.\n").
-spec retrieve_request(glopenai@config:config(), binary()) -> gleam@http@request:request(binary()).
retrieve_request(Config, File_id) ->
glopenai@internal:get_request(Config, <<"/files/"/utf8, File_id/binary>>).
-file("src/glopenai/file.gleam", 353).
?DOC(" Parse the response from retrieving a file.\n").
-spec retrieve_response(gleam@http@response:response(binary())) -> {ok,
open_ai_file()} |
{error, glopenai@error:glopenai_error()}.
retrieve_response(Response) ->
glopenai@internal:parse_response(Response, openai_file_decoder()).
-file("src/glopenai/file.gleam", 360).
?DOC(" Build a request to delete a file.\n").
-spec delete_request(glopenai@config:config(), binary()) -> gleam@http@request:request(binary()).
delete_request(Config, File_id) ->
glopenai@internal:delete_request(Config, <<"/files/"/utf8, File_id/binary>>).
-file("src/glopenai/file.gleam", 365).
?DOC(" Parse the response from deleting a file.\n").
-spec delete_response(gleam@http@response:response(binary())) -> {ok,
delete_file_response()} |
{error, glopenai@error:glopenai_error()}.
delete_response(Response) ->
glopenai@internal:parse_response(Response, delete_file_response_decoder()).
-file("src/glopenai/file.gleam", 373).
?DOC(
" Build a request to download the content of a file.\n"
" The response body contains the raw file content.\n"
).
-spec content_request(glopenai@config:config(), binary()) -> gleam@http@request:request(binary()).
content_request(Config, File_id) ->
glopenai@internal:get_request(
Config,
<<<<"/files/"/utf8, File_id/binary>>/binary, "/content"/utf8>>
).
-file("src/glopenai/file.gleam", 379).
?DOC(
" Parse the response from downloading file content.\n"
" Returns the raw body string on success.\n"
).
-spec content_response(gleam@http@response:response(binary())) -> {ok, binary()} |
{error, glopenai@error:glopenai_error()}.
content_response(Response) ->
case (erlang:element(2, Response) >= 200) andalso (erlang:element(
2,
Response
)
< 300) of
true ->
{ok, erlang:element(4, Response)};
false ->
case gleam@json:parse(
erlang:element(4, Response),
glopenai@error:wrapped_error_decoder()
) of
{ok, Api_error} ->
{error,
{api_response_error,
erlang:element(2, Response),
Api_error}};
{error, _} ->
{error,
{unexpected_response,
erlang:element(2, Response),
erlang:element(4, Response)}}
end
end.