Skip to content

Commit

Permalink
Merge pull request #2 from hipcall/b0.3.0
Browse files Browse the repository at this point in the history
Add TTS endpoint.
  • Loading branch information
onurozgurozkan authored Feb 3, 2024
2 parents 981ecee + 88e079e commit 122ab7a
Show file tree
Hide file tree
Showing 5 changed files with 158 additions and 14 deletions.
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@

Unofficial OpenAI API Wrapper written in Elixir.

This Hex package is beta right now. [Please use another one](https://hex.pm/packages?search=openai&sort=name).

## Installation

If [available in Hex](https://hex.pm/docs/publish), the package can be installed
Expand All @@ -12,7 +10,7 @@ by adding `hipcall_openai` to your list of dependencies in `mix.exs`:
```elixir
def deps do
[
{:hipcall_openai, "~> 0.2.0"}
{:hipcall_openai, "~> 0.3.0"}
]
end
```
Expand Down Expand Up @@ -44,7 +42,7 @@ Documentation for using, please check the `HipcallOpenai` module.

- [x] Add `Models` endpoint
- [x] Add `Chat` endpoint
- [ ] Add `Audio` endpoints
- [x] Add `Audio` endpoints
- [ ] Add `Embeddings` endpoint
- [ ] Add `Fine-tuning` endpoint
- [ ] Add `Files` endpoint
Expand All @@ -62,4 +60,5 @@ All [Hipcall](https://www.hipcall.com/en-gb/) libraries:

- [HipcallDisposableEmail](https://github.com/hipcall/hipcall_disposable_email) - Simple library checking the email's domain is disposable or not.
- [HipcallDeepgram](https://github.com/hipcall/hipcall_deepgram) - Unofficial Deepgram API Wrapper written in Elixir.
- [HipcallOpenai](https://github.com/hipcall/hipcall_openai) - Unofficial OpenAI API Wrapper written in Elixir.
- [HipcallOpenai](https://github.com/hipcall/hipcall_openai) - Unofficial OpenAI API Wrapper written in Elixir.
- [HipcallWhichtech](https://github.com/hipcall/hipcall_whichtech) - Find out what the website is built with.
113 changes: 109 additions & 4 deletions lib/hipcall_openai.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ defmodule HipcallOpenai do
@moduledoc """
Documentation for `HipcallOpenai`.
"""
alias HipcallOpenai.Audio.Speech
alias HipcallOpenai.Chat
alias HipcallOpenai.Config
alias HipcallOpenai.Models
Expand Down Expand Up @@ -66,6 +67,47 @@ defmodule HipcallOpenai do
]
]

@audio_create_speech_schema [
model: [
type: :string,
doc: """
One of the available TTS models: `tts-1` or `tts-1-hd`
""",
default: "tts-1",
required: true
],
input: [
type: :string,
doc: """
The text to generate audio for. The maximum length is 4096 characters.
""",
default: "Hello world!",
required: true
],
voice: [
type: :string,
doc: """
The voice to use when generating the audio. Supported voices are `alloy`, `echo`, `fable`, `onyx`, `nova`, and `shimmer`. Previews of the voices are available in the Text to speech guide.
""",
default: "nova",
required: true
],
response_format: [
type: :string,
doc: """
The voice to use when generating the audio. Supported voices are `alloy`, `echo`, `fable`, `onyx`, `nova`, and `shimmer`. Previews of the voices are available in the Text to speech guide.
""",
default: "mp3"
],
speed: [
type: :float,
doc: """
The speed of the generated audio. Select a value from 0.25 to 4.0. 1.0 is the default.
""",
default: 1.0
]
]

@doc """
List models
Expand Down Expand Up @@ -213,18 +255,18 @@ defmodule HipcallOpenai do
...> }
...> }}
## Params
## Arguments
#{NimbleOptions.docs(@chat_completions_schema)}
## Raises
- Raise `NimbleOptions.ValidationError` if params are not valid.
- Raise `NimbleOptions.ValidationError` if params are not valid.
## Returns
- `{:ok, Finch.Response.t()}`
- `{:error, Exception.t()}`
- `{:ok, Finch.Response.t()}`
- `{:error, Exception.t()}`
"""
@spec chat_completions(params :: keyword()) :: {:ok, map()} | {:error, map()} | {:error, any()}
Expand All @@ -242,4 +284,67 @@ defmodule HipcallOpenai do
NimbleOptions.validate!(params, @chat_completions_schema)
Chat.completions(params, config)
end

@doc """
Create an audio from text.
For more information
- https://platform.openai.com/docs/guides/text-to-speech
- https://platform.openai.com/docs/api-reference/audio/createSpeech
## Examples
iex> %HipcallOpenai.Config{
iex> api_key: "YOUR_TOKEN_HERE",
iex> api_organization: "YOUR_ORG_KEY_HERE",
iex> api_url: nil
iex> }
iex> params = [
iex> model: "tts-1",
iex> input: "Hello, I'm an Elixir wrapper for OpenAI.",
iex> voice: "nova"
iex> ]
iex> HipcallOpenai.audio_create_speech(params, config_override)
...> {:ok, <<255, 243, 228, 196, 0, 103, 84, 58, 0, 5, 90, 208, 0, 1, 141, 82, 99, 56, 64,
...> 88, 0, 132, 9, 139, 34, 101, 75, 153, 147, 38, 100, 201, 155, 42, 104, 14,
...> 25, 227, 198, 120, 241, 158, 56, 102, 139, 25, 66, 6, ...>>}
You can easily create a new mp3 file. For example
iex> {:ok, finch_body} = HipcallOpenai.audio_create_speech(params, config_override)
iex> File.write!("test.mp3", finch_body)
...> :ok
## Arguments
#{NimbleOptions.docs(@chat_completions_schema)}
## Raises
- Raise `NimbleOptions.ValidationError` if params are not valid.
## Returns
- `{:ok, Finch.Response.t()}`
- `{:error, Exception.t()}`
"""
@spec audio_create_speech(params :: keyword()) ::
{:ok, map()} | {:error, map()} | {:error, any()}
def audio_create_speech(params) do
NimbleOptions.validate!(params, @audio_create_speech_schema)
Speech.create(params, %Config{})
end

@doc """
The same `audio_create_speech/1` just overwrite config.
"""
@spec audio_create_speech(params :: keyword(), config :: struct()) ::
{:ok, map()} | {:error, map()} | {:error, any()}
def audio_create_speech(params, %Config{} = config) do
NimbleOptions.validate!(params, @audio_create_speech_schema)
Speech.create(params, config)
end
end
42 changes: 42 additions & 0 deletions lib/hipcall_openai/audio/speech.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
defmodule HipcallOpenai.Audio.Speech do
@moduledoc false

alias HipcallOpenai.Config

@endpoint_url "/audio/speech"

def create(params, config \\ %Config{}) do
Finch.build(
:post,
"#{Config.api_url()}#{@endpoint_url}",
header(config),
body(params)
)
|> Finch.request(HipcallOpenaiFinch, receive_timeout: 600_000)
|> case do
{:ok, %Finch.Response{status: 200, body: body}} ->
{:ok, body}

{:ok, %Finch.Response{status: status, body: body, headers: headers}} ->
{:error, %{status: status, body: body, headers: headers}}

{:error, reason} ->
{:error, reason}
end
end

defp body(params) do
params |> Enum.into(%{}) |> Jason.encode!()
end

defp header(config) do
api_key = config.api_key || Config.api_key()
api_organization = config.api_organization || Config.api_organization()

[
{"Authorization", "Bearer #{api_key}"},
{"OpenAI-Organization", "#{api_organization}"},
{"content-type", "application/json"}
]
end
end
5 changes: 1 addition & 4 deletions lib/hipcall_openai/config.ex
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
defmodule HipcallOpenai.Config do
@moduledoc """
Reads configuration on application start, parses all environment variables (if any)
and caches the final config in memory to avoid parsing on each read afterwards.
"""
@moduledoc false

defstruct api_key: nil,
api_organization: nil,
Expand Down
3 changes: 2 additions & 1 deletion mix.exs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ defmodule HipcallOpenai.MixProject do
use Mix.Project

@source_url "https://github.com/hipcall/hipcall_openai"
@version "0.2.0"
@version "0.3.0"

def project do
[
Expand Down Expand Up @@ -38,6 +38,7 @@ defmodule HipcallOpenai.MixProject do

def package do
[
maintainers: ["Onur Ozgur OZKAN"],
licenses: ["MIT"],
links: %{
"Website" => "https://www.hipcall.com/en-gb/",
Expand Down

0 comments on commit 122ab7a

Please sign in to comment.