Files
pipeline_backend/workers/transcribe/internal/nexara/nexara.go
2026-06-10 17:12:58 +03:00

118 lines
2.6 KiB
Go

package nexara
import (
"bytes"
"context"
"encoding/json"
"fmt"
"io"
"mime/multipart"
"net/http"
"os"
"path/filepath"
"strings"
"time"
"github.com/yourorg/transcribe/internal/models"
)
type Client struct {
apiURL string
apiKey string
model string
httpClient *http.Client
}
func New(baseURL, apiKey, model string, timeout time.Duration) *Client {
baseURL = strings.TrimRight(baseURL, "/")
return &Client{
apiURL: baseURL + "/api/v1/audio/transcriptions",
apiKey: apiKey,
model: model,
httpClient: &http.Client{
Timeout: timeout,
},
}
}
func (c *Client) TranscribeFile(ctx context.Context, path string) (text, language string, segments []models.Segment, err error) {
f, err := os.Open(path)
if err != nil {
return "", "", nil, fmt.Errorf("open file: %w", err)
}
defer f.Close()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile("file", filepath.Base(path))
if err != nil {
return "", "", nil, err
}
if _, err := io.Copy(part, f); err != nil {
return "", "", nil, err
}
if c.model != "" {
if err := writer.WriteField("model", c.model); err != nil {
return "", "", nil, err
}
}
if err := writer.WriteField("response_format", "json"); err != nil {
return "", "", nil, err
}
if err := writer.Close(); err != nil {
return "", "", nil, err
}
req, err := http.NewRequestWithContext(ctx, http.MethodPost, c.apiURL, body)
if err != nil {
return "", "", nil, err
}
req.Header.Set("Content-Type", writer.FormDataContentType())
req.Header.Set("Authorization", "Bearer "+c.apiKey)
resp, err := c.httpClient.Do(req)
if err != nil {
return "", "", nil, fmt.Errorf("request: %w", err)
}
defer resp.Body.Close()
respBody, err := io.ReadAll(resp.Body)
if err != nil {
return "", "", nil, err
}
if resp.StatusCode != http.StatusOK {
return "", "", nil, fmt.Errorf("status %d: %s", resp.StatusCode, string(respBody))
}
var raw map[string]any
if err := json.Unmarshal(respBody, &raw); err != nil {
return "", "", nil, fmt.Errorf("parse: %w", err)
}
if t, ok := raw["text"].(string); ok {
text = t
}
if lang, ok := raw["language"].(string); ok {
language = lang
}
if segs, ok := raw["segments"].([]any); ok {
for _, s := range segs {
m, ok := s.(map[string]any)
if !ok {
continue
}
var seg models.Segment
if v, ok := m["start"].(float64); ok {
seg.Start = v
}
if v, ok := m["end"].(float64); ok {
seg.End = v
}
if v, ok := m["text"].(string); ok {
seg.Text = v
}
segments = append(segments, seg)
}
}
return text, language, segments, nil
}