add simple transcription with adapters
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
package transcriber
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"sync"
|
||||
|
||||
"github.com/leonardotrapani/hyprvoice/internal/recording"
|
||||
)
|
||||
|
||||
// SimpleTranscriber collects all audio and transcribes when stopped
|
||||
type SimpleTranscriber struct {
|
||||
adapter TranscriptionAdapter
|
||||
config Config
|
||||
|
||||
// Audio collection
|
||||
audioBuffer []byte
|
||||
bufferMu sync.Mutex
|
||||
|
||||
// Control
|
||||
running bool
|
||||
wg sync.WaitGroup
|
||||
|
||||
// Transcription result
|
||||
transcriptionMu sync.RWMutex
|
||||
transcriptionText string
|
||||
}
|
||||
|
||||
func NewSimpleTranscriber(config Config, adapter TranscriptionAdapter) *SimpleTranscriber {
|
||||
return &SimpleTranscriber{
|
||||
adapter: adapter,
|
||||
config: config,
|
||||
}
|
||||
}
|
||||
|
||||
func (t *SimpleTranscriber) Start(ctx context.Context, frameCh <-chan recording.AudioFrame) (<-chan error, error) {
|
||||
if t.running {
|
||||
return nil, fmt.Errorf("transcriber already running")
|
||||
}
|
||||
|
||||
t.running = true
|
||||
|
||||
errCh := make(chan error, 1)
|
||||
|
||||
t.wg.Add(1)
|
||||
go t.collectAudio(ctx, frameCh, errCh)
|
||||
|
||||
return errCh, nil
|
||||
}
|
||||
|
||||
func (t *SimpleTranscriber) Stop(ctx context.Context) error {
|
||||
if !t.running {
|
||||
return nil
|
||||
}
|
||||
|
||||
t.wg.Wait()
|
||||
t.running = false
|
||||
|
||||
// Transcribe all collected audio using the passed context
|
||||
return t.transcribeAll(ctx)
|
||||
}
|
||||
|
||||
func (t *SimpleTranscriber) GetTranscription() (string, error) {
|
||||
t.transcriptionMu.RLock()
|
||||
defer t.transcriptionMu.RUnlock()
|
||||
return t.transcriptionText, nil
|
||||
}
|
||||
|
||||
func (t *SimpleTranscriber) collectAudio(ctx context.Context, frameCh <-chan recording.AudioFrame, errCh chan<- error) {
|
||||
defer func() {
|
||||
close(errCh)
|
||||
t.wg.Done()
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
log.Printf("transcriber: stopping audio collection")
|
||||
return
|
||||
|
||||
case frame, ok := <-frameCh:
|
||||
if !ok {
|
||||
log.Printf("transcriber: audio channel closed")
|
||||
return
|
||||
}
|
||||
|
||||
t.bufferMu.Lock()
|
||||
t.audioBuffer = append(t.audioBuffer, frame.Data...)
|
||||
t.bufferMu.Unlock()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (t *SimpleTranscriber) transcribeAll(ctx context.Context) error {
|
||||
t.bufferMu.Lock()
|
||||
audioData := make([]byte, len(t.audioBuffer))
|
||||
copy(audioData, t.audioBuffer)
|
||||
t.bufferMu.Unlock()
|
||||
|
||||
if len(audioData) == 0 {
|
||||
log.Printf("transcriber: no audio data to transcribe")
|
||||
return nil
|
||||
}
|
||||
|
||||
log.Printf("transcriber: transcribing %d bytes of audio", len(audioData))
|
||||
|
||||
// Use the context passed from the pipeline for proper cancellation chain
|
||||
text, err := t.adapter.Transcribe(ctx, audioData)
|
||||
if err != nil {
|
||||
log.Printf("transcriber: transcription failed: %v", err)
|
||||
return fmt.Errorf("transcription failed: %w", err)
|
||||
}
|
||||
|
||||
log.Printf("transcriber: transcription completed: %q", text)
|
||||
|
||||
t.transcriptionMu.Lock()
|
||||
t.transcriptionText = text
|
||||
t.transcriptionMu.Unlock()
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user