Current section

Files

Jump to
langchain lib file_uploaders file_uploader.ex
Raw

lib/file_uploaders/file_uploader.ex

defmodule LangChain.FileUploader do
@moduledoc """
Behaviour for uploading files to LLM providers.
Provides a unified interface for uploading files to OpenAI, Anthropic,
and Google Gemini. Each provider returns a `LangChain.FileUploader.FileResult`
containing the file reference needed for subsequent API calls.
## Usage
# OpenAI
{:ok, uploader} = LangChain.FileUploader.FileOpenAI.new(%{api_key: "sk-..."})
{:ok, result} = LangChain.FileUploader.upload(uploader, file_bytes, %{
filename: "doc.pdf",
mime_type: "application/pdf"
})
result.file_id
#=> "file-abc123"
# Google Gemini
{:ok, uploader} = LangChain.FileUploader.FileGoogle.new(%{api_key: "AI..."})
{:ok, result} = LangChain.FileUploader.upload(uploader, file_bytes, %{
filename: "doc.pdf",
mime_type: "application/pdf"
})
result.file_uri
#=> "https://generativelanguage.googleapis.com/v1beta/files/..."
## File Metadata
The `file_meta` map passed to `upload/3` accepts the following keys:
- `:filename` (required) - The name to give the uploaded file.
- `:mime_type` (required) - The MIME type of the file content.
- `:purpose` - Provider-specific purpose string. Used by OpenAI
(e.g. `"user_data"`, `"assistants"`). Ignored by other providers.
- `:display_name` - A human-readable display name. Used by Google.
Falls back to `:filename` if not provided.
"""
alias LangChain.FileUploader.FileResult
alias LangChain.LangChainError
@type file_meta :: %{
required(:filename) => String.t(),
required(:mime_type) => String.t(),
optional(:purpose) => String.t(),
optional(:display_name) => String.t()
}
@type upload_result :: {:ok, FileResult.t()} | {:error, LangChainError.t()}
@type get_result :: {:ok, FileResult.t()} | {:error, LangChainError.t()}
@type delete_result :: :ok | {:error, LangChainError.t()}
@type list_result :: {:ok, [FileResult.t()]} | {:error, LangChainError.t()}
@doc """
Upload file bytes to the provider and return a FileResult on success.
"""
@callback upload(config :: struct(), file_bytes :: binary(), file_meta :: file_meta()) ::
upload_result()
@doc """
Retrieve metadata for a previously uploaded file by its ID.
"""
@callback get(config :: struct(), file_ref :: FileResult.t() | String.t()) :: get_result()
@doc """
Delete a previously uploaded file by its ID or URI.
"""
@callback delete(config :: struct(), file_ref :: FileResult.t() | String.t()) :: delete_result()
@doc """
List files previously uploaded to the provider.
"""
@callback list(config :: struct()) :: list_result()
@optional_callbacks [get: 2, delete: 2, list: 1]
@doc """
Upload a file using any configured uploader implementation.
Delegates to the provider module's `upload/3` callback.
"""
@spec upload(struct(), binary(), file_meta()) :: upload_result()
def upload(%mod{} = uploader, file_bytes, %{} = file_meta) do
mod.upload(uploader, file_bytes, file_meta)
end
@doc """
Retrieve file metadata using any configured uploader implementation.
Returns an error if the provider does not implement `get/2`.
"""
@spec get(struct(), FileResult.t() | String.t()) :: get_result()
def get(%mod{} = uploader, file_ref) do
if function_exported?(mod, :get, 2) do
mod.get(uploader, file_ref)
else
{:error, LangChainError.exception(message: "get/2 not implemented for #{inspect(mod)}")}
end
end
@doc """
Delete a file using any configured uploader implementation.
Returns an error if the provider does not implement `delete/2`.
"""
@spec delete(struct(), FileResult.t() | String.t()) :: delete_result()
def delete(%mod{} = uploader, file_ref) do
if function_exported?(mod, :delete, 2) do
mod.delete(uploader, file_ref)
else
{:error, LangChainError.exception(message: "delete/2 not implemented for #{inspect(mod)}")}
end
end
@doc """
List files using any configured uploader implementation.
Returns an error if the provider does not implement `list/1`.
"""
@spec list(struct()) :: list_result()
def list(%mod{} = uploader) do
if function_exported?(mod, :list, 1) do
mod.list(uploader)
else
{:error, LangChainError.exception(message: "list/1 not implemented for #{inspect(mod)}")}
end
end
end