cohere-transcribe 0.1.1 → 0.1.2
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 +4 -4
- data/CHANGELOG.md +8 -0
- data/README.md +5 -5
- data/ext/cohere_transcribe_native/CMakeLists.txt +1 -1
- data/ext/cohere_transcribe_native/README.md +1 -1
- data/ext/cohere_transcribe_native/extconf.rb +12 -2
- data/lib/cohere/transcribe/asr/native.rb +72 -8
- data/lib/cohere/transcribe/audio/decoder.rb +130 -82
- data/lib/cohere/transcribe/audio/ffmpeg_native.rb +68 -39
- data/lib/cohere/transcribe/cli.rb +1 -0
- data/lib/cohere/transcribe/configuration.rb +2 -0
- data/lib/cohere/transcribe/dense_converter.rb +29 -4
- data/lib/cohere/transcribe/doctor.rb +2 -2
- data/lib/cohere/transcribe/hub.rb +26 -5
- data/lib/cohere/transcribe/input.rb +4 -4
- data/lib/cohere/transcribe/python_text.rb +21 -3
- data/lib/cohere/transcribe/pytorch_checkpoint.rb +68 -11
- data/lib/cohere/transcribe/runtime/engine.rb +11 -1
- data/lib/cohere/transcribe/runtime/preparation.rb +81 -13
- data/lib/cohere/transcribe/runtime/resources.rb +105 -17
- data/lib/cohere/transcribe/state/io.rb +12 -2
- data/lib/cohere/transcribe/state/manifest.rb +30 -16
- data/lib/cohere/transcribe/version.rb +1 -1
- metadata +1 -1
|
@@ -12,6 +12,47 @@ module Cohere
|
|
|
12
12
|
class ModelResources
|
|
13
13
|
OWNER_GUARD = Monitor.new
|
|
14
14
|
|
|
15
|
+
# The global owner record and the ObjectSpace finalizer retain this
|
|
16
|
+
# state, never the ModelResources instance itself. It also lets a new
|
|
17
|
+
# owner synchronously evict a collected predecessor before loading.
|
|
18
|
+
class SessionOwnership
|
|
19
|
+
def initialize
|
|
20
|
+
@mutex = Mutex.new
|
|
21
|
+
@session = nil
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def session
|
|
25
|
+
@mutex.synchronize { @session }
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def install(session)
|
|
29
|
+
@mutex.synchronize do
|
|
30
|
+
raise TranscriptionRuntimeError, "ASR session ownership is already installed" if @session
|
|
31
|
+
|
|
32
|
+
@session = session
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def close
|
|
37
|
+
session = @mutex.synchronize do
|
|
38
|
+
current = @session
|
|
39
|
+
@session = nil
|
|
40
|
+
current
|
|
41
|
+
end
|
|
42
|
+
return unless session
|
|
43
|
+
|
|
44
|
+
session.close
|
|
45
|
+
nil
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def finalize
|
|
49
|
+
close
|
|
50
|
+
rescue Exception # rubocop:disable Lint/RescueException -- finalizers must not escape during GC or shutdown
|
|
51
|
+
nil
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
private_constant :SessionOwnership
|
|
55
|
+
|
|
15
56
|
class << self
|
|
16
57
|
def evict_current_asr_owner
|
|
17
58
|
OWNER_GUARD.synchronize do
|
|
@@ -33,16 +74,43 @@ module Cohere
|
|
|
33
74
|
|
|
34
75
|
reference.__getobj__
|
|
35
76
|
rescue WeakRef::RefError
|
|
36
|
-
|
|
77
|
+
cleanup_abandoned_owner_locked
|
|
37
78
|
nil
|
|
38
79
|
end
|
|
39
80
|
|
|
40
81
|
def claim_locked(owner)
|
|
41
82
|
@owner_reference = WeakRef.new(owner)
|
|
83
|
+
@owner_ownership = owner.send(:asr_ownership)
|
|
42
84
|
end
|
|
43
85
|
|
|
44
86
|
def release_locked(owner)
|
|
45
|
-
|
|
87
|
+
return unless @owner_ownership.equal?(owner.send(:asr_ownership))
|
|
88
|
+
|
|
89
|
+
@owner_reference = nil
|
|
90
|
+
@owner_ownership = nil
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def cleanup_abandoned_owner_locked
|
|
94
|
+
ownership = @owner_ownership
|
|
95
|
+
@owner_reference = nil
|
|
96
|
+
@owner_ownership = nil
|
|
97
|
+
ownership&.close
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def finalizer_for(ownership)
|
|
101
|
+
proc { |_object_id| finalize_ownership(ownership) }
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def finalize_ownership(ownership)
|
|
105
|
+
OWNER_GUARD.synchronize do
|
|
106
|
+
if @owner_ownership.equal?(ownership)
|
|
107
|
+
@owner_reference = nil
|
|
108
|
+
@owner_ownership = nil
|
|
109
|
+
end
|
|
110
|
+
ownership.finalize
|
|
111
|
+
end
|
|
112
|
+
rescue Exception # rubocop:disable Lint/RescueException -- finalizers must not escape during GC or shutdown
|
|
113
|
+
nil
|
|
46
114
|
end
|
|
47
115
|
end
|
|
48
116
|
|
|
@@ -50,9 +118,13 @@ module Cohere
|
|
|
50
118
|
|
|
51
119
|
def initialize
|
|
52
120
|
@asr_key = nil
|
|
53
|
-
@
|
|
121
|
+
@asr_ownership = SessionOwnership.new
|
|
54
122
|
@batch_controller = nil
|
|
55
123
|
@closed = false
|
|
124
|
+
ObjectSpace.define_finalizer(
|
|
125
|
+
self,
|
|
126
|
+
self.class.send(:finalizer_for, @asr_ownership)
|
|
127
|
+
)
|
|
56
128
|
end
|
|
57
129
|
|
|
58
130
|
# Returns [session, loaded]. A key change evicts this instance's prior
|
|
@@ -62,47 +134,62 @@ module Cohere
|
|
|
62
134
|
|
|
63
135
|
self.class::OWNER_GUARD.synchronize do
|
|
64
136
|
ensure_open!
|
|
65
|
-
|
|
137
|
+
owned_key = immutable_key(key)
|
|
138
|
+
evict_asr_locked if @asr_ownership.session && @asr_key != owned_key
|
|
66
139
|
|
|
67
140
|
owner = self.class.send(:current_owner_locked)
|
|
68
141
|
owner.send(:evict_asr_locked) if owner && !owner.equal?(self)
|
|
69
142
|
self.class.send(:claim_locked, self)
|
|
70
143
|
|
|
71
144
|
loaded = false
|
|
72
|
-
unless @
|
|
145
|
+
unless @asr_ownership.session
|
|
73
146
|
installed = false
|
|
147
|
+
session = nil
|
|
74
148
|
begin
|
|
75
149
|
session = yield
|
|
76
150
|
raise TranscriptionRuntimeError, "ASR loader returned no native session" if session.nil?
|
|
77
151
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
152
|
+
Thread.handle_interrupt(Exception => :never) do
|
|
153
|
+
@asr_ownership.install(session)
|
|
154
|
+
@asr_key = owned_key
|
|
155
|
+
@batch_controller = nil
|
|
156
|
+
loaded = true
|
|
157
|
+
installed = true
|
|
158
|
+
end
|
|
159
|
+
rescue Exception # rubocop:disable Lint/RescueException -- roll back asynchronous loader interruption
|
|
160
|
+
begin
|
|
161
|
+
if @asr_ownership.session.equal?(session)
|
|
162
|
+
evict_asr_locked
|
|
163
|
+
else
|
|
164
|
+
session&.close
|
|
165
|
+
end
|
|
166
|
+
rescue Exception # rubocop:disable Lint/RescueException -- preserve the loader failure
|
|
167
|
+
nil
|
|
168
|
+
end
|
|
169
|
+
raise
|
|
83
170
|
ensure
|
|
84
171
|
self.class.send(:release_locked, self) unless installed
|
|
85
172
|
end
|
|
86
173
|
end
|
|
87
|
-
[@
|
|
174
|
+
[@asr_ownership.session, loaded].freeze
|
|
88
175
|
end
|
|
89
176
|
end
|
|
90
177
|
|
|
91
178
|
def install_batch_controller(controller)
|
|
92
179
|
self.class::OWNER_GUARD.synchronize do
|
|
93
180
|
ensure_open!
|
|
94
|
-
raise TranscriptionRuntimeError, "Cannot install an ASR controller before acquiring ASR" unless @
|
|
181
|
+
raise TranscriptionRuntimeError, "Cannot install an ASR controller before acquiring ASR" unless @asr_ownership.session
|
|
95
182
|
|
|
96
183
|
@batch_controller ||= controller
|
|
97
184
|
end
|
|
98
185
|
end
|
|
99
186
|
|
|
100
187
|
def asr_session
|
|
101
|
-
self.class::OWNER_GUARD.synchronize { @
|
|
188
|
+
self.class::OWNER_GUARD.synchronize { @asr_ownership.session }
|
|
102
189
|
end
|
|
103
190
|
|
|
104
191
|
def asr?
|
|
105
|
-
self.class::OWNER_GUARD.synchronize { !@
|
|
192
|
+
self.class::OWNER_GUARD.synchronize { !@asr_ownership.session.nil? }
|
|
106
193
|
end
|
|
107
194
|
alias has_asr? asr?
|
|
108
195
|
|
|
@@ -123,6 +210,7 @@ module Cohere
|
|
|
123
210
|
|
|
124
211
|
evict_asr_locked
|
|
125
212
|
@closed = true
|
|
213
|
+
ObjectSpace.undefine_finalizer(self)
|
|
126
214
|
end
|
|
127
215
|
nil
|
|
128
216
|
end
|
|
@@ -133,17 +221,17 @@ module Cohere
|
|
|
133
221
|
|
|
134
222
|
private
|
|
135
223
|
|
|
224
|
+
attr_reader :asr_ownership
|
|
225
|
+
|
|
136
226
|
def ensure_open!
|
|
137
227
|
raise TranscriberClosedError, "Model resources have been closed" if @closed
|
|
138
228
|
end
|
|
139
229
|
|
|
140
230
|
def evict_asr_locked
|
|
141
231
|
self.class.send(:release_locked, self)
|
|
142
|
-
session = @asr_session
|
|
143
|
-
@asr_session = nil
|
|
144
232
|
@asr_key = nil
|
|
145
233
|
@batch_controller = nil
|
|
146
|
-
|
|
234
|
+
@asr_ownership.close
|
|
147
235
|
nil
|
|
148
236
|
end
|
|
149
237
|
|
|
@@ -63,7 +63,10 @@ module Cohere
|
|
|
63
63
|
# is performed with the POSIX *at family against that descriptor.
|
|
64
64
|
class BoundDirectory
|
|
65
65
|
AT_FUNCTION_SIGNATURES = {
|
|
66
|
-
openat: [
|
|
66
|
+
openat: [
|
|
67
|
+
[Fiddle::TYPE_INT, Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT, Fiddle::TYPE_VARIADIC],
|
|
68
|
+
Fiddle::TYPE_INT
|
|
69
|
+
],
|
|
67
70
|
renameat: [
|
|
68
71
|
[Fiddle::TYPE_INT, Fiddle::TYPE_VOIDP, Fiddle::TYPE_INT, Fiddle::TYPE_VOIDP],
|
|
69
72
|
Fiddle::TYPE_INT
|
|
@@ -294,7 +297,14 @@ module Cohere
|
|
|
294
297
|
|
|
295
298
|
def open_entry(name, flags, permissions, mode:)
|
|
296
299
|
validate_entry_name!(name)
|
|
297
|
-
file_descriptor = call_at!(
|
|
300
|
+
file_descriptor = call_at!(
|
|
301
|
+
:openat,
|
|
302
|
+
descriptor,
|
|
303
|
+
name,
|
|
304
|
+
flags,
|
|
305
|
+
Fiddle::TYPE_INT,
|
|
306
|
+
permissions
|
|
307
|
+
)
|
|
298
308
|
handle = File.new(file_descriptor, mode, autoclose: true)
|
|
299
309
|
file_descriptor = nil
|
|
300
310
|
handle.close_on_exec = true
|
|
@@ -105,18 +105,21 @@ module Cohere
|
|
|
105
105
|
return "state marker path for #{format} does not match" unless record.is_a?(Hash) && record["name"] == path.basename.to_s
|
|
106
106
|
|
|
107
107
|
begin
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
108
|
+
output_record = if directory_binding
|
|
109
|
+
bound_output_record(
|
|
110
|
+
path,
|
|
111
|
+
directory_binding: directory_binding,
|
|
112
|
+
guard_bindings: guard_bindings
|
|
113
|
+
)
|
|
114
|
+
else
|
|
115
|
+
stat = path.lstat
|
|
116
|
+
return "#{format} output is missing or not regular" unless stat.file? && !stat.symlink?
|
|
117
|
+
|
|
118
|
+
[stat.size, Digest::SHA256.file(path).hexdigest]
|
|
119
|
+
end
|
|
120
|
+
return "#{format} output changed or is not regular" unless output_record
|
|
121
|
+
|
|
122
|
+
size, sha256 = output_record
|
|
120
123
|
return "#{format} output does not match its state marker" if record["size"] != size || record["sha256"] != sha256
|
|
121
124
|
rescue Errno::ENOENT
|
|
122
125
|
return "#{format} output is missing or not regular"
|
|
@@ -133,14 +136,25 @@ module Cohere
|
|
|
133
136
|
) do |bound, basename|
|
|
134
137
|
bound.verify!
|
|
135
138
|
handle = nil
|
|
136
|
-
|
|
137
|
-
|
|
139
|
+
begin
|
|
140
|
+
Thread.handle_interrupt(DEFERRED_PUBLICATION_EXCEPTIONS) do
|
|
141
|
+
handle = bound.open_regular(basename)
|
|
142
|
+
end
|
|
143
|
+
rescue TranscriptionRuntimeError
|
|
144
|
+
bound.verify!
|
|
145
|
+
return nil
|
|
138
146
|
end
|
|
139
147
|
opened = handle.stat
|
|
140
148
|
digest = Digest::SHA256.new
|
|
141
149
|
digest << handle.read(1024 * 1024) until handle.eof?
|
|
142
|
-
|
|
143
|
-
|
|
150
|
+
unchanged = begin
|
|
151
|
+
bound.same_regular_entry?(basename, opened)
|
|
152
|
+
rescue TranscriptionRuntimeError
|
|
153
|
+
false
|
|
154
|
+
end
|
|
155
|
+
unless unchanged
|
|
156
|
+
bound.verify!
|
|
157
|
+
return nil
|
|
144
158
|
end
|
|
145
159
|
|
|
146
160
|
bound.verify!
|