Documentation
¶
Overview ¶
Package dub implements the OrcaDub MCP server internals: the HTTP client and the MCP tool layer. ALL submit/query requests go through the OrcaRouter gateway (https://api.orcarouter.ai) — the officially documented integration surface (see /api-docs): the gateway routes requests to the orca/dub model by the `model` field, wraps billing, and scopes task ids. Direct dub-server routes (native /api/v1/dub/*, GET /v1/videos list, DELETE, cancel) are NOT exposed by the gateway and therefore not offered here. Wire shapes reuse internal/quality/openai
Index ¶
- func RegisterTools(s *mcp.Server, c *Client)
- func RunCLI(args []string) int
- type Client
- func (c *Client) CreateVideo(ctx context.Context, req *CreateVideoRequest) (Video, error)
- func (c *Client) DownloadContent(ctx context.Context, id, dest string) (int64, error)
- func (c *Client) GetVideo(ctx context.Context, id string) (GatewayVideo, error)
- func (c *Client) Health(ctx context.Context) (HealthResult, error)
- func (c *Client) UploadFile(ctx context.Context, path, purpose string) (FileObject, error)
- type CompleteUploadRequest
- type Config
- type CreateInput
- type CreateVideoRequest
- type DownloadInput
- type FileObject
- type GatewayVideo
- type GetInput
- type HealthInput
- type HealthResult
- type Upload
- type UploadInput
- type UploadPart
- type Video
- type VideoError
- type VideoPath
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func RegisterTools ¶
RegisterTools wires every tool onto the server. The surface is exactly the OrcaRouter gateway's documented dub lifecycle (upload → create → poll → download); list/cancel/delete/native-detail are not exposed by the gateway. Annotations follow the MCP spec so hosts can pick approval policies: health/get are read-only; upload/create/download are additive (non-destructive) and non-idempotent; everything talks to an external service (open world).
Types ¶
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client issues authenticated HTTP calls to the OrcaRouter gateway.
func NewClient ¶
NewClient builds a Client. Timeout is generous because uploads and downloads stream video bytes through this process.
func (*Client) CreateVideo ¶
CreateVideo calls POST /v1/videos through the gateway, forcing the model=orca/dub routing field.
func (*Client) DownloadContent ¶
DownloadContent streams the finished mp4 into dest and returns the byte count. It resolves the gateway task id to the underlying job first (the origin content route is the reliable delivery path), then streams from the URL GetVideo derived. Refuses to overwrite an existing file.
func (*Client) GetVideo ¶
GetVideo calls GET /v1/videos/{id} on the gateway. The id must come from a job submitted through the gateway (gateway task ids are its own scope). On completed jobs the response gains content_url pointing at the origin's content route for the underlying job.
func (*Client) Health ¶
func (c *Client) Health(ctx context.Context) (HealthResult, error)
Health probes the gateway → orca/dub route end to end without creating a job: POST /v1/videos with only the model field must come back as the dub service's own "source_lang is required" validation error. Any other reply (gateway "Model name not specified", auth failure, network error) means the chain is broken and is surfaced verbatim.
func (*Client) UploadFile ¶
UploadFile pushes a local file through the gateway and returns the resulting FileObject whose ID feeds dub_create's file_id. Files at or under directUploadLimit go through single-request POST /v1/files; larger files walk the OpenAI Uploads chain (create → parts → complete).
type CompleteUploadRequest ¶
type CompleteUploadRequest struct {
PartIDs []string `json:"part_ids"`
MD5 string `json:"md5,omitempty"`
}
CompleteUploadRequest is the JSON body of POST /v1/uploads/{id}/complete.
type Config ¶
type Config struct {
BaseURL string // OrcaRouter gateway origin; gatewayBaseURL outside tests
APIKey string // REQUIRED Authorization: Bearer credential (OrcaRouter sk-orca key)
}
Config carries the MCP server's runtime configuration. The gateway origin is fixed in code (gatewayBaseURL); the ONLY environment input is the ORCADUB_API_KEY credential. BaseURL stays a struct field solely so tests can point the client at an httptest server.
func LoadConfig ¶
func LoadConfig() Config
LoadConfig reads ORCADUB_API_KEY. A missing key does NOT fail startup — the server comes up and every tool call returns errNotAuthorized instead, so the calling agent can redirect the user to the OrcaRouter console to register; once the key is set (and the session restarted) authentication passes automatically.
type CreateInput ¶
type CreateInput struct {
SourceLang string `` /* 180-byte string literal not displayed */
TargetLang string `json:"target_lang" jsonschema:"REQUIRED — ask the user if not stated. Target language code; auto is not allowed"`
FileID string `` /* 154-byte string literal not displayed */
URL string `` /* 137-byte string literal not displayed */
VideoName string `` /* 127-byte string literal not displayed */
// Content / translation knobs.
Profile string `` /* 138-byte string literal not displayed */
TranslationStyle string `` /* 135-byte string literal not displayed */
Glossary map[string]string `json:"glossary,omitempty" jsonschema:"pinned source→target term renderings, max 64 entries"`
AdaptIdioms *bool `json:"adapt_idioms,omitempty" jsonschema:"render idioms as natural target-language equivalents; empty = deploy default"`
CometEnabled *bool `json:"comet_enabled,omitempty" jsonschema:"COMET translation-quality gate; empty = deploy default"`
// Voice / TTS knobs.
TTSBackend string `json:"tts_backend,omitempty" jsonschema:"TTS backend id (qwen3 | higgs); empty = deploy default"`
SongTranslation *bool `json:"song_translation,omitempty" jsonschema:"dub sung segments instead of passing original audio through; empty = false"`
ProjectID string `json:"project_id,omitempty" jsonschema:"dubbing project id for cross-job character voice memory"`
SpeakerAssignments map[string]string `json:"speaker_assignments,omitempty" jsonschema:"ASR diarization label → character id map; requires project_id"`
VoiceCloneConsent bool `json:"voice_clone_consent,omitempty" jsonschema:"attest the caller holds rights/consent to clone voices in the source"`
// Audio bed / mix knobs.
PreserveBGM *bool `json:"preserve_bgm,omitempty" jsonschema:"keep background music via source separation; empty = deploy default"`
BedLevelMatch *bool `json:"bed_level_match,omitempty" jsonschema:"match bed loudness to broadcast level; empty = deploy default"`
BedDuck *bool `json:"bed_duck,omitempty" jsonschema:"duck the bed under dialog; empty = deploy default"`
BedReverbPreset *string `json:"bed_reverb_preset,omitempty" jsonschema:"bed reverb: none | small_room | hall | outdoor; empty = deploy default"`
LoudnessEnabled *bool `json:"loudness_enabled,omitempty" jsonschema:"EBU R128 loudness-match gate on the final mux; empty = deploy default"`
// Alignment / video output knobs.
AlignPerWord *bool `json:"align_per_word,omitempty" jsonschema:"per-word forced-alignment atempo; empty = deploy default"`
Lipsync *bool `json:"lipsync,omitempty" jsonschema:"enable lipsync; empty = deploy default"`
LipsyncVisemes *bool `json:"lipsync_visemes,omitempty" jsonschema:"viseme-aware lipsync plan; empty = deploy default"`
LipsyncIdentityGuard *bool `json:"lipsync_identity_guard,omitempty" jsonschema:"post-lipsync face-identity guard; empty = deploy default"`
Watermark *bool `json:"watermark,omitempty" jsonschema:"burn watermark; empty = deploy default"`
RemoveWatermark *bool `` /* 147-byte string literal not displayed */
Resolution string `json:"resolution,omitempty" jsonschema:"output height: source | 720p | 1080p | 2k; empty = 720p"`
Ratio string `json:"ratio,omitempty" jsonschema:"output canvas: source | 16:9 | 9:16 | 1:1; empty = source"`
CompactOutput *bool `json:"compact_output,omitempty" jsonschema:"re-encode final mp4 smaller (720p cap, crf 28); empty = false"`
}
CreateInput is the dub_create tool surface — the FULL per-job parameter set of POST /v1/videos. The model=orca/dub gateway routing field is attached automatically. Required fields (source_lang, target_lang, the file_id/url source, video_name with file_id) must come from the USER — the calling agent is instructed (skill + schema descriptions) to ask rather than guess. Only multi-request orchestration fields (batch_id/ batch_total/group_id) and the admin-only bench_run_id stay unexposed.
type CreateVideoRequest ¶
type CreateVideoRequest struct {
Prompt string `json:"prompt,omitempty"`
VideoPath *VideoPath `json:"video_path,omitempty"`
Model string `json:"model,omitempty"`
Seconds string `json:"seconds,omitempty"`
Size string `json:"size,omitempty"`
SourceLang string `json:"source_lang,omitempty"`
TargetLang string `json:"target_lang,omitempty"`
Profile string `json:"profile,omitempty"`
Lipsync *string `json:"lipsync,omitempty"`
LipsyncVisemes *string `json:"lipsync_visemes,omitempty"`
LipsyncIdentityGuard *string `json:"lipsync_identity_guard,omitempty"`
PreserveBGM *string `json:"preserve_bgm,omitempty"`
Watermark *string `json:"watermark,omitempty"`
RemoveWatermark *string `json:"remove_watermark,omitempty"`
BedLevelMatch *string `json:"bed_level_match,omitempty"`
BedDuck *string `json:"bed_duck,omitempty"`
BedReverbPreset *string `json:"bed_reverb_preset,omitempty"`
AlignPerWord *string `json:"align_per_word,omitempty"`
CometEnabled *string `json:"comet_enabled,omitempty"`
LoudnessEnabled *string `json:"loudness_enabled,omitempty"`
AdaptIdiomsEnabled *string `json:"adapt_idioms_enabled,omitempty"`
SongTranslationEnabled *string `json:"song_translation_enabled,omitempty"`
CompactOutput *string `json:"compact_output,omitempty"`
Resolution string `json:"resolution,omitempty"`
Ratio string `json:"ratio,omitempty"`
ProjectID string `json:"project_id,omitempty"`
SpeakerAssignments map[string]string `json:"speaker_assignments,omitempty"`
Glossary map[string]string `json:"glossary,omitempty"`
VoiceCloneConsent bool `json:"voice_clone_consent,omitempty"`
TTSBackend string `json:"tts_backend,omitempty"`
TranslationStyle string `json:"translation_style,omitempty"`
VideoName string `json:"video_name,omitempty"`
}
CreateVideoRequest is the JSON body of POST /videos. Dub-specific knobs ride along as extra_body fields; boolean knobs are *string "true"/"false" on the wire (the server treats nil/empty as "use deploy default").
type DownloadInput ¶
type DownloadInput struct {
VideoID string `json:"video_id" jsonschema:"the completed job/video id"`
Dest string `json:"dest" jsonschema:"absolute local path to write the MP4 (must not already exist)"`
}
DownloadInput saves a completed job's MP4 locally.
type FileObject ¶
type FileObject struct {
ID string `json:"id"`
Bytes int64 `json:"bytes"`
CreatedAt int64 `json:"created_at"`
Filename string `json:"filename"`
Object string `json:"object"`
Purpose string `json:"purpose"`
Status string `json:"status"`
ExpiresAt *int64 `json:"expires_at,omitempty"`
}
FileObject mirrors OpenAI's FileObject (POST /files).
type GatewayVideo ¶
type GatewayVideo struct {
Video
JobID string `json:"job_id,omitempty"`
// ContentURL is the delivery address of the finished video. It requires
// the same Authorization: Bearer header as every other call
// (curl -H "Authorization: Bearer sk-orca-..." <content_url>), or use
// dub_download which sends it automatically.
ContentURL string `json:"content_url,omitempty"`
}
GatewayVideo is Video plus gateway-specific fields: job_id (the underlying dub job uuid the gateway maps the task to) and content_url (the delivery address of the finished mp4 — the gateway retrieve strips output_url by design, so the client derives the origin content route from job_id; the origin re-signs the object freshly on every request).
type GetInput ¶
type GetInput struct {
VideoID string `json:"video_id" jsonschema:"the job id returned by dub_create (gateway task ids are gateway-scoped)"`
}
GetInput identifies one gateway-submitted job.
type HealthResult ¶
type HealthResult struct {
Status string `json:"status"` // ok | degraded
Gateway string `json:"gateway"`
Detail string `json:"detail"`
}
HealthResult is dub_health's report.
type Upload ¶
type Upload struct {
ID string `json:"id"`
Object string `json:"object"`
Bytes int64 `json:"bytes"`
CreatedAt int64 `json:"created_at"`
ExpiresAt int64 `json:"expires_at"`
Filename string `json:"filename"`
Purpose string `json:"purpose"`
Status string `json:"status"`
File *FileObject `json:"file,omitempty"`
}
Upload mirrors OpenAI's Upload object (POST /v1/uploads chain). Once status="completed", File carries the materialised FileObject whose id feeds video_path.file_id.
type UploadInput ¶
type UploadInput struct {
Path string `json:"path" jsonschema:"absolute path of the local video file to upload"`
Purpose string `json:"purpose,omitempty" jsonschema:"OpenAI file purpose; default user_data"`
}
UploadInput selects a local file to push through the gateway.
type UploadPart ¶
type UploadPart struct {
ID string `json:"id"`
Object string `json:"object"`
UploadID string `json:"upload_id"`
CreatedAt int64 `json:"created_at"`
}
UploadPart mirrors OpenAI's UploadPart object (POST /v1/uploads/{id}/parts).
type Video ¶
type Video struct {
ID string `json:"id"`
Name string `json:"name,omitempty"`
Object string `json:"object"`
Status string `json:"status"` // queued|in_progress|completed|failed
Progress int `json:"progress"`
CreatedAt int64 `json:"created_at"`
CompletedAt *int64 `json:"completed_at,omitempty"`
StartedAt *int64 `json:"started_at,omitempty"`
EndedAt *int64 `json:"ended_at,omitempty"`
ExpiresAt *int64 `json:"expires_at,omitempty"`
Model string `json:"model"`
Prompt string `json:"prompt"`
Seconds string `json:"seconds"`
Size string `json:"size"`
SourceLang string `json:"source_lang,omitempty"`
TargetLang string `json:"target_lang,omitempty"`
DurationSeconds *int32 `json:"duration_seconds,omitempty"`
OutputURL string `json:"output_url,omitempty"`
Error *VideoError `json:"error,omitempty"`
}
Video mirrors OpenAI's Video object (POST /videos / GET /videos/{id}) with the OrcaDub extension fields the gateway serves.
type VideoError ¶
VideoError matches OpenAI's VideoCreateError envelope.