Skip to content

Commit

Permalink
Speech to text
Browse files Browse the repository at this point in the history
  • Loading branch information
Reputeless committed Nov 19, 2023
1 parent 1892e46 commit b8c9020
Show file tree
Hide file tree
Showing 6 changed files with 127 additions and 17 deletions.
58 changes: 53 additions & 5 deletions Siv3D/include/Siv3D/OpenAI/Speech.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,68 @@ namespace s3d
{
namespace Speech
{
namespace Model
{
/// @brief 音声合成モデル tts-1 | Speech Synthesis Model tts-1
/// @see https://platform.openai.com/docs/models/tts
inline constexpr StringView TTS1{ U"tts-1" };

/// @brief 音声合成モデル tts-1-hd | Speech Synthesis Model tts-1-hd
/// @see https://platform.openai.com/docs/models/tts
/// @remark tts-1 よりも高品質な音声を生成します。 | Generates higher quality audio than tts-1.
inline constexpr StringView TTS1HD{ U"tts-1-hd" };
}

namespace Voice
{
inline constexpr StringView Alloy{ U"alloy" };

inline constexpr StringView Echo{ U"echo" };

inline constexpr StringView Fable{ U"fable" };

inline constexpr StringView Onyx{ U"onyx" };

inline constexpr StringView Nova{ U"nova" };

inline constexpr StringView Shimmer{ U"shimmer" };
}

namespace ResponseFormat
{
inline constexpr StringView MP3{ U"mp3" };

inline constexpr StringView Opus{ U"opus" };

inline constexpr StringView AAC{ U"aac" };

inline constexpr StringView FLAC{ U"flac" };
}

inline constexpr size_t MaxInputLength = 4096;

inline constexpr double MinSpeed = 0.25;

inline constexpr double DefaultSpeed = 1.0;

inline constexpr double MaxSpeed = 4.0;

struct Request
{
String model = U"tts-1";
String model{ OpenAI::Speech::Model::TTS1 };

String input;

String voice = U"alloy";
String voice{ OpenAI::Speech::Voice::Alloy };

String responseFormat = U"mp3";
String responseFormat{ OpenAI::Speech::ResponseFormat::MP3 };

double speed = 1.0;
double speed = OpenAI::Speech::DefaultSpeed;
};

bool Create(const Request& request, FilePathView path);
bool Create(StringView apiKey, const Request& request, FilePathView path);

AsyncTask<bool> CreateAsync(StringView apiKey, const Request& request, FilePathView path);
}
}
}
4 changes: 4 additions & 0 deletions Siv3D/src/Siv3D/OpenAI/OpenAICommon.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

# pragma once
# include <Siv3D/String.hpp>
# include <Siv3D/Duration.hpp>
# include <Siv3D/HashTable.hpp>

namespace s3d
Expand All @@ -20,5 +21,8 @@ namespace s3d
// HTTP ヘッダーを作成する
[[nodiscard]]
HashTable<String, String> MakeHeaders(StringView apiKey);

// 非同期タスクのポーリング間隔
constexpr Milliseconds TaskPollingInterval{ 5 };
}
}
6 changes: 3 additions & 3 deletions Siv3D/src/Siv3D/OpenAI/SivOpenAIChat.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ namespace s3d
namespace detail
{
// OpenAI のチャット API の URL
constexpr URLView ChatV1URL = U"https://api.openai.com/v1/chat/completions";
constexpr URLView ChatCompletionsEndpoint = U"https://api.openai.com/v1/chat/completions";

// チャット API に送信するリクエストを作成する
[[nodiscard]]
Expand Down Expand Up @@ -77,7 +77,7 @@ namespace s3d

MemoryWriter memoryWriter;

if (const auto response = SimpleHTTP::Post(detail::ChatV1URL, headers, data.data(), data.size(), memoryWriter))
if (const auto response = SimpleHTTP::Post(detail::ChatCompletionsEndpoint, headers, data.data(), data.size(), memoryWriter))
{
if (const HTTPStatusCode statusCode = response.getStatusCode();
statusCode == HTTPStatusCode::OK)
Expand Down Expand Up @@ -120,7 +120,7 @@ namespace s3d

const auto headers = detail::MakeHeaders(apiKey);

return SimpleHTTP::PostAsync(detail::ChatV1URL, headers, data.data(), data.size());
return SimpleHTTP::PostAsync(detail::ChatCompletionsEndpoint, headers, data.data(), data.size());
}

String GetContent(const JSON& response)
Expand Down
6 changes: 3 additions & 3 deletions Siv3D/src/Siv3D/OpenAI/SivOpenAIEmbedding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ namespace s3d
namespace detail
{
// OpenAI の Embeddings API の URL
constexpr URLView EmbeddingsV1URL = U"https://api.openai.com/v1/embeddings";
constexpr URLView EmbeddingsEndpoint = U"https://api.openai.com/v1/embeddings";

// Embeddings API に送信するリクエストを作成する
[[nodiscard]]
Expand Down Expand Up @@ -113,7 +113,7 @@ namespace s3d

MemoryWriter memoryWriter;

if (const auto response = SimpleHTTP::Post(detail::EmbeddingsV1URL, headers, data.data(), data.size(), memoryWriter))
if (const auto response = SimpleHTTP::Post(detail::EmbeddingsEndpoint, headers, data.data(), data.size(), memoryWriter))
{
if (const HTTPStatusCode statusCode = response.getStatusCode();
statusCode == HTTPStatusCode::OK)
Expand Down Expand Up @@ -151,7 +151,7 @@ namespace s3d

const auto headers = detail::MakeHeaders(apiKey);

return SimpleHTTP::PostAsync(detail::EmbeddingsV1URL, headers, data.data(), data.size());
return SimpleHTTP::PostAsync(detail::EmbeddingsEndpoint, headers, data.data(), data.size());
}

Array<float> GetVector(const JSON& response)
Expand Down
8 changes: 2 additions & 6 deletions Siv3D/src/Siv3D/OpenAI/SivOpenAIImage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

# include <Siv3D/OpenAI.hpp>
# include <Siv3D/JSON.hpp>
# include <Siv3D/Duration.hpp>
# include <Siv3D/System.hpp>
# include <Siv3D/SimpleHTTP.hpp>
# include <Siv3D/MemoryViewReader.hpp>
Expand All @@ -22,10 +21,7 @@ namespace s3d
namespace detail
{
// OpenAI の画像生成 API の URL
constexpr URLView ImageGenerationV1URL = U"https://api.openai.com/v1/images/generations";

// 非同期タスクのポーリング間隔
constexpr Milliseconds TaskPollingInterval{ 5 };
constexpr URLView ImageGenerationsEndpoint = U"https://api.openai.com/v1/images/generations";

// 画像生成 API に送信するリクエストを作成する
[[nodiscard]]
Expand Down Expand Up @@ -59,7 +55,7 @@ namespace s3d
const auto headers = detail::MakeHeaders(apiKey);

// 画像生成 API に非同期でリクエストを送信する
AsyncHTTPTask task1 = SimpleHTTP::PostAsync(detail::ImageGenerationV1URL, headers, data.data(), data.size());
AsyncHTTPTask task1 = SimpleHTTP::PostAsync(detail::ImageGenerationsEndpoint, headers, data.data(), data.size());

// タスクが完了するまでポーリングする
while (not task1.isReady())
Expand Down
62 changes: 62 additions & 0 deletions Siv3D/src/Siv3D/OpenAI/SivOpenAISpeech.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,70 @@
//-----------------------------------------------

# include <Siv3D/OpenAI.hpp>
# include <Siv3D/JSON.hpp>
# include <Siv3D/System.hpp>
# include "OpenAICommon.hpp"

namespace s3d
{
namespace detail
{
constexpr URLView TextToSpeechEndpoint = U"https://api.openai.com/v1/audio/speech";

[[nodiscard]]
static std::string MakeSpeechRequest(const OpenAI::Speech::Request& request)
{
JSON json;
json[U"model"] = request.model;
json[U"input"] = request.input;
json[U"voice"] = request.voice;
json[U"response_format"] = request.responseFormat;
json[U"speed"] = request.speed;
return json.formatUTF8();
}

static bool CreateSpeechImpl(const String apiKey, const OpenAI::Speech::Request request, const FilePath path)
{
// API キーが空の文字列である場合は失敗
if (apiKey.isEmpty())
{
return false;
}

const auto headers = MakeHeaders(apiKey);

const std::string data = MakeSpeechRequest(request);

AsyncHTTPTask task = SimpleHTTP::PostAsync(TextToSpeechEndpoint, headers, data.data(), data.size(), path);

// タスクが完了するまでポーリングする
while (not task.isReady())
{
System::Sleep(TaskPollingInterval);
}

if (not task.getResponse().isOK())
{
return false;
}

return true;
}
}

namespace OpenAI
{
namespace Speech
{
bool Create(const StringView apiKey, const Request& request, const FilePathView path)
{
return detail::CreateSpeechImpl(String{ apiKey }, request, FilePath{ path });
}

AsyncTask<bool> CreateAsync(const StringView apiKey, const Request& request, const FilePathView path)
{
return Async(detail::CreateSpeechImpl, String{ apiKey }, request, FilePath{ path });
}
}
}
}

0 comments on commit b8c9020

Please sign in to comment.