Files
llink/go/internal/speech/service.go
T
talksik 986a389606 feat: generate transcript and event-driven particle processing
This generates the transcript and shows the caption experience on the
client side for media particles. It also simplifies other side effects
that we must perform such as updating the `last_child_created_at` field
for stream and container particles.
2026-03-25 14:43:47 -07:00

100 lines
2.2 KiB
Go

package speech
import (
"context"
"log/slog"
dgapi "github.com/deepgram/deepgram-go-sdk/v3/pkg/api/listen/v1/rest"
interfaces "github.com/deepgram/deepgram-go-sdk/v3/pkg/client/interfaces"
client "github.com/deepgram/deepgram-go-sdk/v3/pkg/client/listen"
)
type TranscriptWord struct {
Word string
Start float64
End float64
}
type TranscriptSentence struct {
Text string
Start float64
End float64
}
type TranscriptParagraph struct {
Sentences []TranscriptSentence
Start float64
End float64
}
type TranscriptResult struct {
Transcript string
Words []TranscriptWord
Paragraphs []TranscriptParagraph
}
type SpeechService interface {
Transcribe(ctx context.Context, mediaUrl string) (*TranscriptResult, error)
}
type speechServiceImpl struct {
deepgramClient *dgapi.Client
}
func NewSpeechService(ctx context.Context) SpeechService {
return &speechServiceImpl{
deepgramClient: dgapi.New(client.NewRESTWithDefaults()),
}
}
func (s *speechServiceImpl) Transcribe(ctx context.Context, mediaUrl string) (*TranscriptResult, error) {
options := &interfaces.PreRecordedTranscriptionOptions{
Model: "nova-3",
SmartFormat: true,
Paragraphs: true,
}
response, err := s.deepgramClient.FromURL(ctx, mediaUrl, options)
if err != nil {
slog.Error("failed to transcribe prerecorded media", "error", err)
return nil, err
}
alt := response.Results.Channels[0].Alternatives[0]
words := make([]TranscriptWord, len(alt.Words))
for i, w := range alt.Words {
words[i] = TranscriptWord{
Word: w.PunctuatedWord,
Start: w.Start,
End: w.End,
}
}
var paragraphs []TranscriptParagraph
if alt.Paragraphs != nil {
paragraphs = make([]TranscriptParagraph, len(alt.Paragraphs.Paragraphs))
for i, p := range alt.Paragraphs.Paragraphs {
sentences := make([]TranscriptSentence, len(p.Sentences))
for j, s := range p.Sentences {
sentences[j] = TranscriptSentence{
Text: s.Text,
Start: s.Start,
End: s.End,
}
}
paragraphs[i] = TranscriptParagraph{
Sentences: sentences,
Start: p.Start,
End: p.End,
}
}
}
return &TranscriptResult{
Transcript: alt.Transcript,
Words: words,
Paragraphs: paragraphs,
}, nil
}