wave-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE +21 -0
- data/README.md +44 -0
- data/lib/wave/captions.rb +46 -0
- data/lib/wave/chapters.rb +26 -0
- data/lib/wave/client.rb +118 -0
- data/lib/wave/clips.rb +48 -0
- data/lib/wave/collab.rb +36 -0
- data/lib/wave/editor.rb +46 -0
- data/lib/wave/errors.rb +35 -0
- data/lib/wave/phone.rb +41 -0
- data/lib/wave/podcast.rb +39 -0
- data/lib/wave/search.rb +39 -0
- data/lib/wave/sentiment.rb +31 -0
- data/lib/wave/studio_ai.rb +32 -0
- data/lib/wave/transcribe.rb +36 -0
- data/lib/wave/version.rb +5 -0
- data/lib/wave/voice.rb +30 -0
- data/lib/wave.rb +85 -0
- metadata +65 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 51569e29966120978d4c3b21eafbea0f5e8d259269d2866039225a1183e7e8cb
|
|
4
|
+
data.tar.gz: 8e00b241e35f45d21fee085627cd6c63b7752be372f204ef972615b2f2e13d2a
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 04002e1d7c9e521a88ea79a0bf600ab12dea9d4d9d72d6c93d0ccebda8ee10b80970cb48562601a08f6dcf73760346ce72d1439e318fc9a3407ea36ca5541e7a
|
|
7
|
+
data.tar.gz: a8cf81ac371ec3b9886f075004a90e7ba01fdc6dda47f32733a75327aac18955be9e137c12b58fde116a028022300788c909736dc0e48985e2f19652538714bc
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 WAVE Online, LLC
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# WAVE SDK for Ruby
|
|
2
|
+
|
|
3
|
+
Official Ruby client for the [WAVE](https://wave.online) API. Generated from the gateway OpenAPI
|
|
4
|
+
contract. One gem, no runtime dependencies (stdlib `net/http`).
|
|
5
|
+
|
|
6
|
+
```ruby
|
|
7
|
+
gem "wave-sdk"
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Usage
|
|
11
|
+
|
|
12
|
+
```ruby
|
|
13
|
+
require "wave"
|
|
14
|
+
|
|
15
|
+
client = Wave::Client.new("wave_live_...")
|
|
16
|
+
|
|
17
|
+
clip = client.clips.get("clip_123")
|
|
18
|
+
puts clip["title"]
|
|
19
|
+
|
|
20
|
+
page = client.clips.list(video_id: "vid_1", per_page: 50)
|
|
21
|
+
puts "#{page['data'].length} of #{page['pagination']['total']}"
|
|
22
|
+
|
|
23
|
+
begin
|
|
24
|
+
client.clips.get("missing")
|
|
25
|
+
rescue Wave::Error => e
|
|
26
|
+
warn "[#{e.code}] #{e.message} (status #{e.status_code})"
|
|
27
|
+
end
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Notes
|
|
31
|
+
|
|
32
|
+
- **Auth + entitlement** are enforced server-side at the gateway (`401`/`402`/`403`).
|
|
33
|
+
- **Responses** are parsed JSON (`Hash` with string keys). Path params are positional, query params
|
|
34
|
+
are keyword args, request bodies are a `Hash`.
|
|
35
|
+
- **Configuration:** `Wave::Client.new(key, base_url:, max_retries:, timeout:)`. Defaults: base
|
|
36
|
+
`https://api.wave.online/v1`, 3 retries, 30s timeout.
|
|
37
|
+
- **Errors:** non-2xx → `Wave::Error`; `429` (after retries) → `Wave::RateLimitError`. Retries apply
|
|
38
|
+
to `429`/`5xx`/network with backoff + `Retry-After`.
|
|
39
|
+
- **Generated** by `codegen/`; do not edit `lib/**` by hand.
|
|
40
|
+
|
|
41
|
+
## Status
|
|
42
|
+
|
|
43
|
+
`v0.1.0` — all 12 contract-frozen products (49 operations). New; not yet exercised against the live
|
|
44
|
+
gateway end-to-end. Requires Ruby ≥ 3.0. License: MIT.
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wave
|
|
4
|
+
# Captions — Auto-captioning and multi-language translation
|
|
5
|
+
class Captions
|
|
6
|
+
def initialize(client)
|
|
7
|
+
@client = client
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# List caption jobs (operationId: listCaptions, GET /captions).
|
|
11
|
+
def list(page: nil, per_page: nil, video_id: nil, status: nil)
|
|
12
|
+
query = {
|
|
13
|
+
"page" => page,
|
|
14
|
+
"perPage" => per_page,
|
|
15
|
+
"videoId" => video_id,
|
|
16
|
+
"status" => status,
|
|
17
|
+
}
|
|
18
|
+
@client.request("GET", "/captions", query: query)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Create a caption job (operationId: createCaptionJob, POST /captions).
|
|
22
|
+
def create_job(body)
|
|
23
|
+
@client.request("POST", "/captions", body: body)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Get a caption job (operationId: getCaptionJob, GET /captions/{jobId}).
|
|
27
|
+
def get_job(job_id)
|
|
28
|
+
@client.request("GET", "/captions/#{job_id}")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Delete a caption job (operationId: deleteCaptionJob, DELETE /captions/{jobId}).
|
|
32
|
+
def delete_job(job_id)
|
|
33
|
+
@client.request("DELETE", "/captions/#{job_id}")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Download captions (operationId: downloadCaptions, GET /captions/{jobId}/download).
|
|
37
|
+
def download(job_id, language, format: nil)
|
|
38
|
+
query = {
|
|
39
|
+
"language" => language,
|
|
40
|
+
"format" => format,
|
|
41
|
+
}
|
|
42
|
+
@client.request("GET", "/captions/#{job_id}/download", query: query)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wave
|
|
4
|
+
# Chapters — AI chapter detection and video segmentation
|
|
5
|
+
class Chapters
|
|
6
|
+
def initialize(client)
|
|
7
|
+
@client = client
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# List chapters for a video (operationId: listChapters, GET /videos/{videoId}/chapters).
|
|
11
|
+
def list(video_id)
|
|
12
|
+
@client.request("GET", "/videos/#{video_id}/chapters")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Create a chapter (operationId: createChapter, POST /videos/{videoId}/chapters).
|
|
16
|
+
def create(video_id, body)
|
|
17
|
+
@client.request("POST", "/videos/#{video_id}/chapters", body: body)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Start AI chapter detection (operationId: detectChapters, POST /videos/{videoId}/chapters/detect).
|
|
21
|
+
def detect(video_id, body)
|
|
22
|
+
@client.request("POST", "/videos/#{video_id}/chapters/detect", body: body)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
end
|
|
26
|
+
end
|
data/lib/wave/client.rb
ADDED
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "net/http"
|
|
4
|
+
require "json"
|
|
5
|
+
require "uri"
|
|
6
|
+
|
|
7
|
+
module Wave
|
|
8
|
+
# HTTP client for the WAVE gateway. Handles auth, retries, and error parsing.
|
|
9
|
+
class Client
|
|
10
|
+
DEFAULT_BASE_URL = "https://api.wave.online/v1"
|
|
11
|
+
USER_AGENT = "wave-sdk-ruby/0.1.0"
|
|
12
|
+
|
|
13
|
+
def initialize(api_key, base_url: DEFAULT_BASE_URL, max_retries: 3, timeout: 30)
|
|
14
|
+
raise ArgumentError, "api_key is required" if api_key.nil? || api_key.to_s.empty?
|
|
15
|
+
|
|
16
|
+
@api_key = api_key
|
|
17
|
+
@base_url = base_url.to_s.chomp("/")
|
|
18
|
+
@max_retries = max_retries
|
|
19
|
+
@timeout = timeout
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Perform a request. Returns parsed JSON (Hash) or nil for 204/no body.
|
|
23
|
+
# Raises Wave::Error / Wave::RateLimitError on failure.
|
|
24
|
+
def request(method, path, query: nil, body: nil)
|
|
25
|
+
uri = URI("#{@base_url}#{path}")
|
|
26
|
+
uri.query = URI.encode_www_form(compact(query)) if query && !compact(query).empty?
|
|
27
|
+
|
|
28
|
+
attempt = 0
|
|
29
|
+
loop do
|
|
30
|
+
response = perform(method, uri, body)
|
|
31
|
+
status = response.code.to_i
|
|
32
|
+
request_id = response["x-request-id"]
|
|
33
|
+
|
|
34
|
+
if status == 429
|
|
35
|
+
retry_after = (response["Retry-After"] || "1").to_f
|
|
36
|
+
if attempt < @max_retries
|
|
37
|
+
sleep(retry_after)
|
|
38
|
+
attempt += 1
|
|
39
|
+
next
|
|
40
|
+
end
|
|
41
|
+
raise RateLimitError.new("rate limit exceeded", retry_after: retry_after, request_id: request_id)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
if status >= 400
|
|
45
|
+
err = parse_error(response, status, request_id)
|
|
46
|
+
if err.retryable && attempt < @max_retries
|
|
47
|
+
sleep(backoff(attempt))
|
|
48
|
+
attempt += 1
|
|
49
|
+
next
|
|
50
|
+
end
|
|
51
|
+
raise err
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
return nil if status == 204 || response.body.nil? || response.body.empty?
|
|
55
|
+
|
|
56
|
+
content_type = response["Content-Type"].to_s
|
|
57
|
+
return JSON.parse(response.body) if content_type.start_with?("application/json")
|
|
58
|
+
|
|
59
|
+
return nil
|
|
60
|
+
rescue Errno::ECONNREFUSED, Errno::ETIMEDOUT, Net::OpenTimeout, Net::ReadTimeout, SocketError => e
|
|
61
|
+
if attempt < @max_retries
|
|
62
|
+
sleep(backoff(attempt))
|
|
63
|
+
attempt += 1
|
|
64
|
+
retry
|
|
65
|
+
end
|
|
66
|
+
raise Error.new(e.message, code: "NETWORK_ERROR", status_code: 0)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
def perform(method, uri, body)
|
|
73
|
+
klass = {
|
|
74
|
+
"GET" => Net::HTTP::Get, "POST" => Net::HTTP::Post,
|
|
75
|
+
"PUT" => Net::HTTP::Put, "PATCH" => Net::HTTP::Patch,
|
|
76
|
+
"DELETE" => Net::HTTP::Delete
|
|
77
|
+
}.fetch(method)
|
|
78
|
+
req = klass.new(uri)
|
|
79
|
+
req["Authorization"] = "Bearer #{@api_key}"
|
|
80
|
+
req["Accept"] = "application/json"
|
|
81
|
+
req["User-Agent"] = USER_AGENT
|
|
82
|
+
unless body.nil?
|
|
83
|
+
req["Content-Type"] = "application/json"
|
|
84
|
+
req.body = JSON.generate(body)
|
|
85
|
+
end
|
|
86
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
87
|
+
http.use_ssl = uri.scheme == "https"
|
|
88
|
+
http.open_timeout = @timeout
|
|
89
|
+
http.read_timeout = @timeout
|
|
90
|
+
http.request(req)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def parse_error(response, status, request_id)
|
|
94
|
+
body = begin
|
|
95
|
+
JSON.parse(response.body.to_s)
|
|
96
|
+
rescue JSON::ParserError
|
|
97
|
+
{}
|
|
98
|
+
end
|
|
99
|
+
err = body["error"] || {}
|
|
100
|
+
Error.new(
|
|
101
|
+
err["message"] || "HTTP #{status}",
|
|
102
|
+
code: err["code"] || "HTTP_#{status}",
|
|
103
|
+
status_code: status,
|
|
104
|
+
request_id: request_id || body["request_id"],
|
|
105
|
+
details: err["details"]
|
|
106
|
+
)
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
def compact(hash)
|
|
110
|
+
(hash || {}).reject { |_, v| v.nil? }
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
def backoff(attempt)
|
|
114
|
+
delay = [2.0**attempt, 30.0].min
|
|
115
|
+
delay + (rand * delay * 0.25)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|
data/lib/wave/clips.rb
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wave
|
|
4
|
+
# Clips — AI-powered highlight detection and clip management
|
|
5
|
+
class Clips
|
|
6
|
+
def initialize(client)
|
|
7
|
+
@client = client
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# List clips (operationId: listClips, GET /clips).
|
|
11
|
+
def list(page: nil, per_page: nil, video_id: nil, status: nil, category: nil)
|
|
12
|
+
query = {
|
|
13
|
+
"page" => page,
|
|
14
|
+
"perPage" => per_page,
|
|
15
|
+
"videoId" => video_id,
|
|
16
|
+
"status" => status,
|
|
17
|
+
"category" => category,
|
|
18
|
+
}
|
|
19
|
+
@client.request("GET", "/clips", query: query)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Create a clip (operationId: createClip, POST /clips).
|
|
23
|
+
def create(body)
|
|
24
|
+
@client.request("POST", "/clips", body: body)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Get a clip (operationId: getClip, GET /clips/{clipId}).
|
|
28
|
+
def get(clip_id)
|
|
29
|
+
@client.request("GET", "/clips/#{clip_id}")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
# Update a clip (operationId: updateClip, PATCH /clips/{clipId}).
|
|
33
|
+
def update(clip_id, body)
|
|
34
|
+
@client.request("PATCH", "/clips/#{clip_id}", body: body)
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
# Delete a clip (operationId: deleteClip, DELETE /clips/{clipId}).
|
|
38
|
+
def delete(clip_id)
|
|
39
|
+
@client.request("DELETE", "/clips/#{clip_id}")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Start AI clip detection (operationId: detectClips, POST /clips/detect).
|
|
43
|
+
def detect(body)
|
|
44
|
+
@client.request("POST", "/clips/detect", body: body)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
end
|
|
48
|
+
end
|
data/lib/wave/collab.rb
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wave
|
|
4
|
+
# Collab — Real-time collaboration rooms
|
|
5
|
+
class Collab
|
|
6
|
+
def initialize(client)
|
|
7
|
+
@client = client
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# List collaboration rooms (operationId: listCollabRooms, GET /collab/rooms).
|
|
11
|
+
def list_rooms(page: nil, per_page: nil, status: nil)
|
|
12
|
+
query = {
|
|
13
|
+
"page" => page,
|
|
14
|
+
"perPage" => per_page,
|
|
15
|
+
"status" => status,
|
|
16
|
+
}
|
|
17
|
+
@client.request("GET", "/collab/rooms", query: query)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Create a collaboration room (operationId: createCollabRoom, POST /collab/rooms).
|
|
21
|
+
def create_room(body)
|
|
22
|
+
@client.request("POST", "/collab/rooms", body: body)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Get a room (operationId: getCollabRoom, GET /collab/rooms/{roomId}).
|
|
26
|
+
def get_room(room_id)
|
|
27
|
+
@client.request("GET", "/collab/rooms/#{room_id}")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Delete a room (operationId: deleteCollabRoom, DELETE /collab/rooms/{roomId}).
|
|
31
|
+
def delete_room(room_id)
|
|
32
|
+
@client.request("DELETE", "/collab/rooms/#{room_id}")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
end
|
data/lib/wave/editor.rb
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wave
|
|
4
|
+
# Editor — Cloud video editing projects
|
|
5
|
+
class Editor
|
|
6
|
+
def initialize(client)
|
|
7
|
+
@client = client
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# List editor projects (operationId: listProjects, GET /editor/projects).
|
|
11
|
+
def list_projects(page: nil, per_page: nil, status: nil)
|
|
12
|
+
query = {
|
|
13
|
+
"page" => page,
|
|
14
|
+
"perPage" => per_page,
|
|
15
|
+
"status" => status,
|
|
16
|
+
}
|
|
17
|
+
@client.request("GET", "/editor/projects", query: query)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Create an editor project (operationId: createProject, POST /editor/projects).
|
|
21
|
+
def create_project(body)
|
|
22
|
+
@client.request("POST", "/editor/projects", body: body)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Get a project (operationId: getProject, GET /editor/projects/{projectId}).
|
|
26
|
+
def get_project(project_id)
|
|
27
|
+
@client.request("GET", "/editor/projects/#{project_id}")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Update a project (operationId: updateProject, PATCH /editor/projects/{projectId}).
|
|
31
|
+
def update_project(project_id, body)
|
|
32
|
+
@client.request("PATCH", "/editor/projects/#{project_id}", body: body)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Delete a project (operationId: deleteProject, DELETE /editor/projects/{projectId}).
|
|
36
|
+
def delete_project(project_id)
|
|
37
|
+
@client.request("DELETE", "/editor/projects/#{project_id}")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Export a project (operationId: exportProject, POST /editor/projects/{projectId}/export).
|
|
41
|
+
def export_project(project_id, body)
|
|
42
|
+
@client.request("POST", "/editor/projects/#{project_id}/export", body: body)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
end
|
data/lib/wave/errors.rb
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wave
|
|
4
|
+
# Canonical WAVE API error. The gateway emits a nested envelope
|
|
5
|
+
# {"error":{"code","message"}}; code/message are lifted from it.
|
|
6
|
+
class Error < StandardError
|
|
7
|
+
attr_reader :code, :status_code, :request_id, :details, :retryable
|
|
8
|
+
|
|
9
|
+
def initialize(message, code:, status_code:, request_id: nil, details: nil)
|
|
10
|
+
super(message)
|
|
11
|
+
@code = code
|
|
12
|
+
@status_code = status_code
|
|
13
|
+
@request_id = request_id
|
|
14
|
+
@details = details
|
|
15
|
+
@retryable = self.class.retryable?(status_code, code)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def self.retryable?(status_code, code)
|
|
19
|
+
return true if status_code == 429
|
|
20
|
+
return true if status_code >= 500 && status_code < 600
|
|
21
|
+
|
|
22
|
+
%w[TIMEOUT NETWORK_ERROR SERVICE_UNAVAILABLE].include?(code)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Raised on HTTP 429 once the retry budget is exhausted.
|
|
27
|
+
class RateLimitError < Error
|
|
28
|
+
attr_reader :retry_after
|
|
29
|
+
|
|
30
|
+
def initialize(message, retry_after:, request_id: nil)
|
|
31
|
+
super(message, code: "RATE_LIMITED", status_code: 429, request_id: request_id)
|
|
32
|
+
@retry_after = retry_after
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
data/lib/wave/phone.rb
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wave
|
|
4
|
+
# Phone — VoIP phone lines and call management
|
|
5
|
+
class Phone
|
|
6
|
+
def initialize(client)
|
|
7
|
+
@client = client
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# List phone lines (operationId: listPhoneLines, GET /phone/lines).
|
|
11
|
+
def list_lines(page: nil, per_page: nil)
|
|
12
|
+
query = {
|
|
13
|
+
"page" => page,
|
|
14
|
+
"perPage" => per_page,
|
|
15
|
+
}
|
|
16
|
+
@client.request("GET", "/phone/lines", query: query)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Provision a phone line (operationId: provisionPhoneLine, POST /phone/lines).
|
|
20
|
+
def provision_line(body)
|
|
21
|
+
@client.request("POST", "/phone/lines", body: body)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# List calls (operationId: listCalls, GET /phone/calls).
|
|
25
|
+
def list_calls(page: nil, per_page: nil, line_id: nil, direction: nil)
|
|
26
|
+
query = {
|
|
27
|
+
"page" => page,
|
|
28
|
+
"perPage" => per_page,
|
|
29
|
+
"lineId" => line_id,
|
|
30
|
+
"direction" => direction,
|
|
31
|
+
}
|
|
32
|
+
@client.request("GET", "/phone/calls", query: query)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Make a call (operationId: makeCall, POST /phone/calls).
|
|
36
|
+
def make_call(body)
|
|
37
|
+
@client.request("POST", "/phone/calls", body: body)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
end
|
|
41
|
+
end
|
data/lib/wave/podcast.rb
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wave
|
|
4
|
+
# Podcast — Podcast show and episode management
|
|
5
|
+
class Podcast
|
|
6
|
+
def initialize(client)
|
|
7
|
+
@client = client
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# List podcast shows (operationId: listPodcastShows, GET /podcast/shows).
|
|
11
|
+
def list_shows(page: nil, per_page: nil)
|
|
12
|
+
query = {
|
|
13
|
+
"page" => page,
|
|
14
|
+
"perPage" => per_page,
|
|
15
|
+
}
|
|
16
|
+
@client.request("GET", "/podcast/shows", query: query)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Create a podcast show (operationId: createPodcastShow, POST /podcast/shows).
|
|
20
|
+
def create_show(body)
|
|
21
|
+
@client.request("POST", "/podcast/shows", body: body)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# List episodes for a show (operationId: listPodcastEpisodes, GET /podcast/shows/{showId}/episodes).
|
|
25
|
+
def list_episodes(show_id, page: nil, per_page: nil)
|
|
26
|
+
query = {
|
|
27
|
+
"page" => page,
|
|
28
|
+
"perPage" => per_page,
|
|
29
|
+
}
|
|
30
|
+
@client.request("GET", "/podcast/shows/#{show_id}/episodes", query: query)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Create an episode (operationId: createPodcastEpisode, POST /podcast/shows/{showId}/episodes).
|
|
34
|
+
def create_episode(show_id, body)
|
|
35
|
+
@client.request("POST", "/podcast/shows/#{show_id}/episodes", body: body)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
end
|
data/lib/wave/search.rb
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wave
|
|
4
|
+
# Search — Semantic content search
|
|
5
|
+
class Search
|
|
6
|
+
def initialize(client)
|
|
7
|
+
@client = client
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# Search content (operationId: search, POST /search).
|
|
11
|
+
def search(body)
|
|
12
|
+
@client.request("POST", "/search", body: body)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# Quick search (operationId: quickSearch, GET /search/quick).
|
|
16
|
+
def quick(q, limit: nil)
|
|
17
|
+
query = {
|
|
18
|
+
"q" => q,
|
|
19
|
+
"limit" => limit,
|
|
20
|
+
}
|
|
21
|
+
@client.request("GET", "/search/quick", query: query)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Get search suggestions (operationId: searchSuggest, GET /search/suggest).
|
|
25
|
+
def suggest(q, limit: nil)
|
|
26
|
+
query = {
|
|
27
|
+
"q" => q,
|
|
28
|
+
"limit" => limit,
|
|
29
|
+
}
|
|
30
|
+
@client.request("GET", "/search/suggest", query: query)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Semantic search (operationId: semanticSearch, POST /search/semantic).
|
|
34
|
+
def semantic(body)
|
|
35
|
+
@client.request("POST", "/search/semantic", body: body)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wave
|
|
4
|
+
# Sentiment — Sentiment and emotion analysis
|
|
5
|
+
class Sentiment
|
|
6
|
+
def initialize(client)
|
|
7
|
+
@client = client
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# List sentiment analyses (operationId: listSentimentAnalyses, GET /sentiment).
|
|
11
|
+
def list_analyses(page: nil, per_page: nil, status: nil)
|
|
12
|
+
query = {
|
|
13
|
+
"page" => page,
|
|
14
|
+
"perPage" => per_page,
|
|
15
|
+
"status" => status,
|
|
16
|
+
}
|
|
17
|
+
@client.request("GET", "/sentiment", query: query)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Create a sentiment analysis (operationId: createSentimentAnalysis, POST /sentiment).
|
|
21
|
+
def create_analysis(body)
|
|
22
|
+
@client.request("POST", "/sentiment", body: body)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Analyze text directly (operationId: analyzeText, POST /sentiment/analyze).
|
|
26
|
+
def analyze_text(body)
|
|
27
|
+
@client.request("POST", "/sentiment/analyze", body: body)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wave
|
|
4
|
+
# Studio AI — Video enhancement and AI processing
|
|
5
|
+
class StudioAi
|
|
6
|
+
def initialize(client)
|
|
7
|
+
@client = client
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# List enhancement jobs (operationId: listEnhancements, GET /studio-ai/enhancements).
|
|
11
|
+
def list_enhancements(page: nil, per_page: nil, type: nil, status: nil)
|
|
12
|
+
query = {
|
|
13
|
+
"page" => page,
|
|
14
|
+
"perPage" => per_page,
|
|
15
|
+
"type" => type,
|
|
16
|
+
"status" => status,
|
|
17
|
+
}
|
|
18
|
+
@client.request("GET", "/studio-ai/enhancements", query: query)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# Create an enhancement job (operationId: createEnhancement, POST /studio-ai/enhancements).
|
|
22
|
+
def create_enhancement(body)
|
|
23
|
+
@client.request("POST", "/studio-ai/enhancements", body: body)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
# Generate enhancement preview (operationId: previewEnhancement, POST /studio-ai/preview).
|
|
27
|
+
def preview_enhancement(body)
|
|
28
|
+
@client.request("POST", "/studio-ai/preview", body: body)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wave
|
|
4
|
+
# Transcribe — Speech-to-text transcription
|
|
5
|
+
class Transcribe
|
|
6
|
+
def initialize(client)
|
|
7
|
+
@client = client
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# List transcriptions (operationId: listTranscriptions, GET /transcribe).
|
|
11
|
+
def list_transcriptions(page: nil, per_page: nil, status: nil)
|
|
12
|
+
query = {
|
|
13
|
+
"page" => page,
|
|
14
|
+
"perPage" => per_page,
|
|
15
|
+
"status" => status,
|
|
16
|
+
}
|
|
17
|
+
@client.request("GET", "/transcribe", query: query)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Create a transcription (operationId: createTranscription, POST /transcribe).
|
|
21
|
+
def create_transcription(body)
|
|
22
|
+
@client.request("POST", "/transcribe", body: body)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Get a transcription (operationId: getTranscription, GET /transcribe/{transcriptionId}).
|
|
26
|
+
def get_transcription(transcription_id)
|
|
27
|
+
@client.request("GET", "/transcribe/#{transcription_id}")
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Delete a transcription (operationId: deleteTranscription, DELETE /transcribe/{transcriptionId}).
|
|
31
|
+
def delete_transcription(transcription_id)
|
|
32
|
+
@client.request("DELETE", "/transcribe/#{transcription_id}")
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end
|
|
36
|
+
end
|
data/lib/wave/version.rb
ADDED
data/lib/wave/voice.rb
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Wave
|
|
4
|
+
# Voice — Text-to-speech synthesis and voice cloning
|
|
5
|
+
class Voice
|
|
6
|
+
def initialize(client)
|
|
7
|
+
@client = client
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# List available voices (operationId: listVoices, GET /voice/voices).
|
|
11
|
+
def list(category: nil, language: nil)
|
|
12
|
+
query = {
|
|
13
|
+
"category" => category,
|
|
14
|
+
"language" => language,
|
|
15
|
+
}
|
|
16
|
+
@client.request("GET", "/voice/voices", query: query)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
# Generate speech from text (operationId: generateSpeech, POST /voice/generate).
|
|
20
|
+
def generate_speech(body)
|
|
21
|
+
@client.request("POST", "/voice/generate", body: body)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# Clone a voice from audio samples (operationId: cloneVoice, POST /voice/clone).
|
|
25
|
+
def clone(body)
|
|
26
|
+
@client.request("POST", "/voice/clone", body: body)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
end
|
data/lib/wave.rb
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "wave/version"
|
|
4
|
+
require_relative "wave/errors"
|
|
5
|
+
require_relative "wave/client"
|
|
6
|
+
require_relative "wave/clips"
|
|
7
|
+
require_relative "wave/voice"
|
|
8
|
+
require_relative "wave/captions"
|
|
9
|
+
require_relative "wave/chapters"
|
|
10
|
+
require_relative "wave/editor"
|
|
11
|
+
require_relative "wave/phone"
|
|
12
|
+
require_relative "wave/collab"
|
|
13
|
+
require_relative "wave/podcast"
|
|
14
|
+
require_relative "wave/studio_ai"
|
|
15
|
+
require_relative "wave/transcribe"
|
|
16
|
+
require_relative "wave/sentiment"
|
|
17
|
+
require_relative "wave/search"
|
|
18
|
+
|
|
19
|
+
# Official WAVE API SDK for Ruby. Generated from the gateway OpenAPI contract.
|
|
20
|
+
#
|
|
21
|
+
# client = Wave::Client.new("wave_live_...")
|
|
22
|
+
# clip = client.clips.get("clip_123")
|
|
23
|
+
module Wave
|
|
24
|
+
class Client
|
|
25
|
+
# Access the Clips product.
|
|
26
|
+
def clips
|
|
27
|
+
Wave::Clips.new(self)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
# Access the Voice product.
|
|
31
|
+
def voice
|
|
32
|
+
Wave::Voice.new(self)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# Access the Captions product.
|
|
36
|
+
def captions
|
|
37
|
+
Wave::Captions.new(self)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Access the Chapters product.
|
|
41
|
+
def chapters
|
|
42
|
+
Wave::Chapters.new(self)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Access the Editor product.
|
|
46
|
+
def editor
|
|
47
|
+
Wave::Editor.new(self)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Access the Phone product.
|
|
51
|
+
def phone
|
|
52
|
+
Wave::Phone.new(self)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Access the Collab product.
|
|
56
|
+
def collab
|
|
57
|
+
Wave::Collab.new(self)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Access the Podcast product.
|
|
61
|
+
def podcast
|
|
62
|
+
Wave::Podcast.new(self)
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Access the Studio AI product.
|
|
66
|
+
def studio_ai
|
|
67
|
+
Wave::StudioAi.new(self)
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Access the Transcribe product.
|
|
71
|
+
def transcribe
|
|
72
|
+
Wave::Transcribe.new(self)
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# Access the Sentiment product.
|
|
76
|
+
def sentiment
|
|
77
|
+
Wave::Sentiment.new(self)
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Access the Search product.
|
|
81
|
+
def search
|
|
82
|
+
Wave::Search.new(self)
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: wave-sdk
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- WAVE Inc.
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-06-01 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
13
|
+
description: Typed-ergonomic Ruby client for the WAVE API, generated from the gateway
|
|
14
|
+
OpenAPI contract.
|
|
15
|
+
email:
|
|
16
|
+
- sdk@wave.online
|
|
17
|
+
executables: []
|
|
18
|
+
extensions: []
|
|
19
|
+
extra_rdoc_files: []
|
|
20
|
+
files:
|
|
21
|
+
- LICENSE
|
|
22
|
+
- README.md
|
|
23
|
+
- lib/wave.rb
|
|
24
|
+
- lib/wave/captions.rb
|
|
25
|
+
- lib/wave/chapters.rb
|
|
26
|
+
- lib/wave/client.rb
|
|
27
|
+
- lib/wave/clips.rb
|
|
28
|
+
- lib/wave/collab.rb
|
|
29
|
+
- lib/wave/editor.rb
|
|
30
|
+
- lib/wave/errors.rb
|
|
31
|
+
- lib/wave/phone.rb
|
|
32
|
+
- lib/wave/podcast.rb
|
|
33
|
+
- lib/wave/search.rb
|
|
34
|
+
- lib/wave/sentiment.rb
|
|
35
|
+
- lib/wave/studio_ai.rb
|
|
36
|
+
- lib/wave/transcribe.rb
|
|
37
|
+
- lib/wave/version.rb
|
|
38
|
+
- lib/wave/voice.rb
|
|
39
|
+
homepage: https://wave.online
|
|
40
|
+
licenses:
|
|
41
|
+
- MIT
|
|
42
|
+
metadata:
|
|
43
|
+
source_code_uri: https://github.com/wave-av/sdks
|
|
44
|
+
homepage_uri: https://wave.online
|
|
45
|
+
rubygems_mfa_required: 'true'
|
|
46
|
+
post_install_message:
|
|
47
|
+
rdoc_options: []
|
|
48
|
+
require_paths:
|
|
49
|
+
- lib
|
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - ">="
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '3.0'
|
|
55
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
56
|
+
requirements:
|
|
57
|
+
- - ">="
|
|
58
|
+
- !ruby/object:Gem::Version
|
|
59
|
+
version: '0'
|
|
60
|
+
requirements: []
|
|
61
|
+
rubygems_version: 3.5.22
|
|
62
|
+
signing_key:
|
|
63
|
+
specification_version: 4
|
|
64
|
+
summary: Official WAVE API SDK for Ruby
|
|
65
|
+
test_files: []
|