Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .woodpecker/build-amd64.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ steps:
image: bash
commands:
- attic login lounge-rocks https://cache.lounge.rocks $ATTIC_KEY --set-default
secrets: [attic_key]
environment:
ATTIC_KEY:
from_secret: attic_key

- name: build whisper_api
image: bash
Expand Down
17 changes: 7 additions & 10 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
# newest version:
# https://hub.docker.com/r/nvidia/cuda/tags?page=1&name=-base-ubuntu22.04&ordering=name

ARG CUDA_VERSION=12.4.1
FROM nvidia/cuda:${CUDA_VERSION}-base-ubuntu22.04

ARG PYTHON_VERSION=3.10
ARG CUDA_VERSION=12.6.2
FROM nvidia/cuda:${CUDA_VERSION}-base-ubuntu24.04

WORKDIR /workspace

RUN export DEBIAN_FRONTEND=noninteractive && \
apt-get -qq update && \
apt-get -qq install --no-install-recommends \
ffmpeg \
python${PYTHON_VERSION} \
python${PYTHON_VERSION}-venv \
python3 \
python3-venv \
python3-pip && \
rm -rf /var/lib/apt/lists/* && \
pip3 install --upgrade pip
rm -rf /var/lib/apt/lists/*

COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt
RUN pip3 install -r requirements.txt --break-system-packages

# disabled by default since GitHub Actions do not have enough space
ARG PREFETCH_MODEL=0
Expand All @@ -32,7 +29,7 @@ RUN if [ "$PREFETCH_MODEL" != 0 ]; then \
COPY . /workspace/code

RUN cd /workspace/code && \
pip3 install .
pip3 install . --break-system-packages

ENV PORT=3001 \
LISTEN=0.0.0.0 \
Expand Down
6 changes: 3 additions & 3 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@
(system: nixpkgsFor.${system}.nixpkgs-fmt);

overlays.default = final: prev: {
devShell = final.callPackage nixos/devShell { inherit self; };
whisper_api = final.callPackage nixos/pkgs/whisper_api { inherit self; };
devShell = final.python3Packages.callPackage nixos/devShell { inherit self; };
whisper_api = final.python3Packages.callPackage nixos/pkgs/whisper_api { inherit self; };
# Our code is not compatible with pydantic version 2 yet.
python3 = prev.python3.override {
packageOverrides = python-self: python-super: {
Expand Down
31 changes: 23 additions & 8 deletions nixos/pkgs/whisper_api/default.nix
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
{ self
, lib
, python3
,
{
self,
lib,
buildPythonApplication,

# build-system
setuptools,
pythonRelaxDepsHook,

# dependencies
fastapi,
ffmpeg-python,
openai-whisper,
python-multipart,
uvicorn,

# tests
unittestCheckHook,
httpx,
}:
python3.pkgs.buildPythonApplication {
buildPythonApplication {

pname = "whisper_api";

Expand All @@ -18,20 +33,20 @@ python3.pkgs.buildPythonApplication {

pythonRelaxDeps = [ ];

nativeBuildInputs = with python3.pkgs; [
nativeBuildInputs = [
setuptools
pythonRelaxDepsHook
];

propagatedBuildInputs = with python3.pkgs; [
propagatedBuildInputs = [
fastapi
ffmpeg-python
openai-whisper
python-multipart
uvicorn
];

nativeCheckInputs = with python3.pkgs; [
nativeCheckInputs = [
unittestCheckHook
httpx
];
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ name = "whisper_api"
dynamic = ["dependencies", "version"]
description = "A simple API for whisper"
readme = "README.md"
requires-python = ">=3.10"
requires-python = "~=3.12"
license = { text = "" }
authors = [
{ name = "MayNiklas", email = "info@niklas-steffen.de" },
Expand Down
10 changes: 5 additions & 5 deletions requirements.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
fastapi==0.112.0
fastapi==0.121.1
ffmpeg-python==0.2.0
openai-whisper==20240930
pydantic==2.8.2
python-multipart==0.0.9
uvicorn==0.29.0
openai-whisper==20250625
pydantic==2.12.4
python-multipart==0.0.20
uvicorn==0.38.0
16 changes: 13 additions & 3 deletions src/whisper_api/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import multiprocessing
import os
import sys

Expand All @@ -6,10 +7,19 @@
path = os.path.realpath(os.path.abspath(__file__))
sys.path.insert(0, os.path.dirname(os.path.dirname(path)))

__version__ = "20241105"
__version__ = "20251214"

from whisper_api.main import app # isort: skip
from whisper_api.main import start

from whisper_api.main import am_i_main_process
def start():
"""Mock Version of start() that is overwritten in the main process by the import below."""
name = multiprocessing.current_process().name
raise ImportError(f"You're trying to run start() from another process than Main "
f"(you are: '{name}'). This is currently not supported.")

if am_i_main_process():
from whisper_api.main import app # isort: skip
from whisper_api.main import start

if __name__ == "__main__":
start()
32 changes: 19 additions & 13 deletions src/whisper_api/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,20 +47,25 @@
from whisper_api.log_setup import logger
from whisper_api.log_setup import uuid_log_format

IS_MAIN_PROCESS = multiprocessing.current_process().name == "MainProcess"

def am_i_process(name: str) -> bool:
return multiprocessing.current_process().name == name

def am_i_main_process() -> bool:
return am_i_process("MainProcess")

description = """
Whisper API transcribes audio files.
"""

if IS_MAIN_PROCESS:
if am_i_main_process():
print(description)


"""
init global variables
"""
if IS_MAIN_PROCESS:
if am_i_main_process():
# TODO: can tasks get GCed before they finish if queue is too long?
task_dict: TempDict[uuid_hex_t, Task] = TempDict(
expiration_time_m=DELETE_RESULTS_AFTER_M,
Expand Down Expand Up @@ -284,7 +289,7 @@ async def lifespan(_app: FastAPI):
"""
Init API
"""
if IS_MAIN_PROCESS:
if am_i_main_process():
app = FastAPI(
title="Whisper API",
description=description,
Expand Down Expand Up @@ -346,18 +351,19 @@ async def log_requests(req: Request, call_next):
return resp


"""
Hook for uvicorn
"""
"""
Hook for uvicorn
"""


def start():
import uvicorn
def start():
"""Entrypoint to start the API (note: this version is only imported on the MainProcess (see __init.py__)"""
import uvicorn

# TODO:
# forwarded_allow_ips= should be set via env var
# proxy_headers=True only when needed
uvicorn.run(app, host=API_LISTEN, port=API_PORT, proxy_headers=True, forwarded_allow_ips="*", log_level="warning")
# TODO:
# forwarded_allow_ips= should be set via env var
# proxy_headers=True only when needed
uvicorn.run(app, host=API_LISTEN, port=API_PORT, proxy_headers=True, forwarded_allow_ips="*", log_level="warning")


if __name__ == "__main__":
Expand Down
27 changes: 26 additions & 1 deletion test/test_import.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,29 @@ def test_import_whisper_api(self):

assert whisper_api
except ImportError:
unittest.fail("Failed to import whisper_api")
unittest.fail("Failed to 'import whisper_api'")

def test_from_import_app(self):
try:
from whisper_api import app

assert app

except ImportError:
unittest.fail("Failed to 'from whisper_api import app'")


def test_from_import_start(self):
try:
from whisper_api import start

assert start

assert "Mock Version" not in start.__doc__

except ImportError:
unittest.fail("Failed to 'from whisper_api import real implementation of start()' on main process")



# TODO: write a test that attempt to import from a a mp.Process and assert that app does not exist
Loading