Code Monkey home page Code Monkey logo

go-subgen's Introduction

go-subgen

Automatic subtitle generation for your media using whisper.cpp.

Runs a webserver that upon receiving a webhook/post with a file path will use whisper.cpp to generate subtitles for your media and output them as srt files. Supports webhooks from Radarr & Sonarr.

Whisper.cpp is resource intensive, and go-subgen stores the stripped audio in memory instead of saving it to the filesystem. If you have large media files and/or use large models you will need lots of ram.

Note

I am in the process of substantially rewritting go-subgen to provide support for many of the below TODO features and improve code quality. This work is being done in the v1-dev and v1-dev-web branches, which are mostly functional.

Features

  • Sonarr & Radarr webhook support
  • basic Tautulli webhook support
  • Subtitle filename templating (see subfile-name-templating)
  • File queueing

Todo/Future

Create an issue or Discussion if you have other feature requests or comments.

  • Further software integrations
  • Persistent Queue
  • Translation and more advanced media checking (don't run if file already has subs, for example)
  • A basic web ui to queue transcription and view queued/in progress tasks.
  • Filesystem watching support
  • Integration into Bazarr as a provider (Not sure how to go about this, please open an issue if you have any ideas)
  • CLBLAST & CUBLAS support for GPU acceleration #39
  • Track ggerganov/whisper.cpp#1261
  • Track ggerganov/whisper.cpp#1060 (Not present in Go binding yet)
  • Distributed ASR?

Docker

Docker Compose

Pre-built image

Important

If you encounter illegal instruction errors when the model attempts to run, you may need to build the image locally. See Locally built image. The image currently requires your CPU support avx2, avx, and sse3.

version: "3.8"
services:
  subgen:
    image: ghcr.io/khakers/go-subgen:latest
    restart: unless-stopped
    ports:
      - "8095:8095"
    volumes:
      # Path must be identical to the path in your other services
      - /path/to/your/media:/media
      # Models will be downloaded to this directory
      - models:/models
    environment:
      - MODEL_TYPE=base_en
volumes:
  models:

Locally built image

In many cases you may want or even need to build the image locally. Building locally can give you better optimizations for your specific hardware. Unfortunately, this means you will need to manually trigger rebuilds (docker compose build) and change versions yourself instead of letting a service like watchtower pull newer images for you.

version: "3.8"
services:
  subgen:
    build:
      context: https://github.com/khakers/go-subgen.git#v0.1.0
    restart: unless-stopped
    ports:
      - "8095:8095"
    volumes:
      # Path must be identical to the path in your other services
      - /path/to/your/media:/media
      # Models will be downloaded to this directory
      - models:/models
    environment:
      - MODEL_TYPE=base_en
volumes:
  models:

Web API Endpoints

Healthcheck

GET

/healthcheck

Returns 200 if the server is running

Tautulli

POST

/webhooks/tautulli

Designed around being compatible with subgens Tautulli webhook and accepts the same json payload

However, go-subgen currently only uses 'file' and ignores the rest of the json data.

{
  "event": "",
  "file": "{file}",
  "filename": "{filename}",
  "mediatype": "{media_type}"
}

Generic

POST

/webhooks/generic

A very basic post endpoint that accepts a json array of file paths

{
  "files": [
    "/path/to/file.mp4",
    "/path/to/other/file.mkv"
  ]
}

Radarr

POST

/webhooks/radarr

Accepts Radarr formatted webhooks

Example webhook configuration

img_1.png

This example only sends the notification on series that have the 'whisper' tag, allowing you to only transcribe series that need it.

Sonarr

POST

/webhooks/sonarr

Accepts Sonarr formatted webhooks

Example webhook configuration

Sonarr webhook connection example image

This example only sends the notification on series that have the 'whisper' tag, allowing you to only transcribe series that need it.

Configuration

Subfile name templating

Go-Subgen allows you to configure how subtitle files are name using Go templates.

The default filename templates is as follows: {{.FileName}}.subgen.{{.Lang}}.{{.FileType}}

You can set your own template by setting the environment variable SUBTITLE_NAME_TEMPLATE. The template is created using the struct below. You can use any of the variables provided and any features of the Go templating system, but keep in mind no escaping is applied to the result. Additionally, FileHash is not a SHA hash. It is a hash generated using imohash which hashes only portions of the file using murmur3

type SubtitleTemplateData struct {
  FilePath  string
  FileName  string
  Lang      string
  FileHash  string
  FileType  string
  ModelType string
}

Options

Environment Variable Type Default Description
MODEL_TYPE Model base_en Whisper.cpp Model version tiny_en, tiny base_en, base, small_en, small, medium_en, medium, large_v1, large_v2, large_v3 large
TARGET_LANG string en
IGNORE_IF_EXISTING bool true
MAX_CONCURRENCY uint 1
MODEL_DIR string /models/
LOG_LEVEL log.Level info
VERIFY_MODEL_HASH bool true Verify that the downloaded model mashes the expected hash
PORT uint8 8095 Web server port
SUBTITLE_NAME_TEMPLATE string "{{.FileName}}.subgen.{{.Lang}}.{{.FileType}}" See Subfile-name-templating
WHISPER_CONF_THREADS uint Number of threads to run Whisper.cpp on
WHISPER_CONF_WHISPER_SPEEDUP bool
WHISPER_CONF_TOKEN_THRESHOLD float32
WHISPER_CONF_TOKEN_SUM_THRESHOLD float32
WHISPER_CONF_MAX_SEGMENT_LENGTH uint
WHISPER_CONF_MAX_TOKENS_PER_SEGMENT uint
FILE_PERMISSIONS_UID uint 0 UID of the saved subtitle file
FILE_PERMISSIONS_GID uint 0 GID of the saved subtitle file

Acknowledgements

Inspired by McCloudS/subgen but written in Go and for more service agnostic (not designed around plex) usage.

go-subgen's People

Contributors

dependabot[bot] avatar khakers avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

go-subgen's Issues

Incorrect MODEL_TYPE options listed on the README.md

First of all, let me thank for the project. It is greatly useful!

The options for MODEL_TYPE should be in lower case. The subject case used on the description of README.md results in error:
time="2023-05-26T19:55:53Z" level=fatal msg="load config: load environment: Small does not belong to Model values"

Please update them.

[Question] Change filepath with template?

I'm not very good at this stuff, but I know how to tinker a bit... I got the original Subgen docker running on my NAS, but that was way too slow. Can I make this work running the docker on my Windows PC, while everything else (Tautulli, mediafiles etc) are on the NAS?

[feature request] SRT file translate

I like your project :) thanks
I have a feature request could you create a webhook for translate srt file from eng to (selected lang?)

Example:
webhooks/generic

{
    "srt": ["/foo/bar/file.eng.srt", "/xxx/yyy/file.eng.srt"]
}

Every eng.srt will be translated to selected languages

Generic webhook failed no message

When i`ll try to create a subfile trough the generic webhook it doesn't start.

{
    "files": [
        "/mnt/nfs/05-TV/Ghosts (US) (2021) [imdb-tt11379026]/Season 02/Ghosts 2021 S02E01 Spies 720p AMZN WEBRip DDP5 1 x264-NTb.mkv"
    ]
}

When creating a invalid json i`ll get a error message. It seems that works just fine.

time="2023-03-21T13:08:15Z" level=info msg="using model type base_en for language nl"
time="2023-03-21T13:08:15Z" level=error msg="Model check failed (this is likely normal and can be ignored)" error="stat /models/ggml-base_en.bin: no such file or directory"
time="2023-03-21T13:08:15Z" level=info msg="downloading model to /models/ggml-base_en.bin"
time="2023-03-21T13:08:19Z" level=info msg="model downloaded"
time="2023-03-21T13:08:48Z" level=info msg="Queueing file /subgen"
time="2023-03-21T13:08:48Z" level=info msg="failed to generate file hash" error="read /subgen: is a directory"
time="2023-03-21T13:09:06Z" level=info msg="Queueing file /subgen"
time="2023-03-21T13:09:06Z" level=info msg="failed to generate file hash" error="read /subgen: is a directory"
time="2023-03-21T13:15:25Z" level=error msg="invalid character ' ' in string escape code"

using this path to post this json: http://192.168.1.21:32012/webhooks/generic

Error encountered: "SIGILL: illegal instruction"

I have encountered an error while posting a Tautulli json to go-subgen.

Environment:

  • Hadrware: Synology DS918+
  • CPU: INTEL Celeron J3455
  • RAM: 16GB
  • Host OS: DSM 7.1.1-42962 Update 5
uname -a
Linux DS918Plus 4.4.180+ #42962 SMP Sat Apr 8 00:14:26 CST 2023 x86_64 GNU/Linux synology_apollolake_918+
$ docker -v
Docker version 20.10.3, build 55f0773

command executed:

$ curl -X POST -H "Content-Type: application/json" -d '{"event": "created", "file": "/volume2/Shared/TV Shows/[omitted].mkv", "filename": "[omitted].mkv", "mediatype": "episode"}'  http://10.27.0.40:8095/webhooks/tautulli

Log:

$ docker logs subgen
time="2023-05-26T20:01:07Z" level=info msg="using model type small for language en"
time="2023-05-26T20:01:07Z" level=error msg="Model check failed (this is likely normal and can be ignored)" error="stat /models/ggml-small.bin: no such file or directory"
time="2023-05-26T20:01:07Z" level=info msg="downloading model to /models/ggml-small.bin"
time="2023-05-26T20:01:18Z" level=info msg="model downloaded"
time="2023-05-26T20:14:01Z" level=error msg=EOF
time="2023-05-26T20:21:17Z" level=error msg=EOF
time="2023-05-26T22:57:28Z" level=info msg="Queueing file /volume2/Shared/TV Shows/[omitted].mkv"
time="2023-05-26T22:57:28Z" level=info msg="Job Queued"
time="2023-05-26T22:57:28Z" level=info msg="Processing job for file /volume2/Shared/TV Shows/[omitted].mkv"
2023/05/26 22:57:28 compiled command: ffmpeg -i  -ac 1 -ar 16000 -c:a pcm_s16le -f s16le pipe:
time="2023-05-26T22:58:17Z" level=info msg="completed audio stripping in 49.632246007 seconds."
time="2023-05-26T22:58:17Z" level=info msg="created srt file /volume2/Shared/TV Shows/[omitted].mkv.subgen.en."
whisper_model_load: n_vocab       = 51865
whisper_model_load: n_audio_ctx   = 1500
whisper_model_load: n_text_ctx    = 448
whisper_model_load: n_text_state  = 768
whisper_model_load: adding 1608 extra tokens
SIGILL: illegal instruction
PC=0xa6a459 m=0 sigcode=2
runtime.gopark(0x200000003?, 0xc0000061a0?, 0x0?, 0x0?, 0xc0001dfa58?)
	/usr/local/go/src/runtime/proc.go:363 +0xd6 fp=0xc0000bb9e8 sp=0xc0000bb9c8 pc=0x451936
	/usr/local/go/src/internal/poll/fd_poll_runtime.go:84 +0x32 fp=0xc0000bba68 sp=0xc0000bba40 pc=0x4f2c92
internal/poll.(*pollDesc).waitRead(...)
	/usr/local/go/src/internal/poll/fd_poll_runtime.go:89
internal/poll.(*FD).Accept(0xc000380000)
	/usr/local/go/src/internal/poll/fd_unix.go:614 +0x234 fp=0xc0000bbb00 sp=0xc0000bba68 pc=0x4f7f14
net.(*netFD).accept(0xc000380000)
rdx    0x27f4
rdi    0x0
rsi    0xc
rbp    0x7fff30c10c20
rsp    0x7fff30c10aa8
r8     0x27f49f0
r9     0x282f550
r10    0x282f530
r11    0x45f7f06197052eb1
r12    0x50
r13    0x1
r14    0xc

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.