Geminix
Easy to use bindings to the Gemini API. These functions and structs follow the API very closely, making it very easy to follow their usage from the API docs.
The docs can be found at https://hexdocs.pm/geminix.
Why a new binding to a cloud AI API?
I have tried some packages that already exist, and some seem to have weird erros that seem to come from trying to use AI to translate from the API of some other langue into Elixir. This led to a lot of hard-to-debug errors which made me a bit frustrated and distrustful of some solutions out there. Additionally, not all solutions support the Gemini batch APIs, which are a very good fit for my projects.
I’ve decided to see if there was a good API reference, and it turns out Google already publishes a perfectly good REST API spec in JSON format, which is very easy to parse
and generate code from. The compile-time code generators don’t write any files to disk. They instead compile the quoted expressions directly. When required, manually written code is written to help with things such as polling long-running batch jobs.
A simple example from the test cases, showcasing support for the batch API:
alias Geminix.V1beta.{
GenerateContentRequest,
GenerateContentResponse,
BatchGenerateContentRequest,
GenerationConfig,
Content,
InlinedResponses
}
requests = [
%InlinedRequest{
metadata: %{
key: "request-001"
},
request: %GenerateContentRequest{
contents: [
Content.from_text("What is the capital of Mali?")
],
generation_config: %GenerationConfig{
response_mime_type: "text/plain"
}
}
},
%InlinedRequest{
metadata: %{
key: "request-002"
},
request: %GenerateContentRequest{
contents: [
Content.from_text("What is the capital of Germany?")
],
generation_config: %GenerationConfig{
response_mime_type: "text/plain"
}
}
},
%InlinedRequest{
metadata: %{
key: "request-002"
},
request: %GenerateContentRequest{
contents: [
Content.from_text("What is the capital of Spain?")
],
generation_config: %GenerationConfig{
response_mime_type: "text/plain"
}
}
}
]
{:ok, batch} =
BatchGenerateContentRequest.start(
"gemini-2.5-flash",
requests,
display_name: "Test batch"
)
{:ok, batch} =
BatchGenerateContentRequest.await(
batch,
poll_interval: 30_000
)
{:ok, inlined_responses} = BatchGenerateContentRequest.get_output(batch)
assert %Geminix.V1beta.InlinedResponses{} = inlined_responses
While the API is somewhat verbose, due to all the relative “strong typing” and the large amount of structures, it is very close to the official API, which makes it very easy to configure everything to your needs, unlike approaches which try to simiplify a very complex API into a small handfull of knobs and dials. You can always write a simple wrapper on top of all the complexity so that it works better for you.






















