Self-hosted service
LoredCast/filewizard avatar
LoredCast/filewizard

FileWizard: a self-hosted conversion, OCR and transcription box

File Converter, OCR, Transcription & TTS WebUI

1,120 stars74 forksPythonMIT

At a glance

What is it?
FileWizard is a self-hosted web application that wraps the usual command line converters, LibreOffice, Pandoc, ImageMagick, FFmpeg, Tesseract and faster-whisper, behind a FastAPI service with a job queue and a history table. It runs without a login by default, and the README says so plainly in its security section.
Who is it for?
FileWizard fits a homelab or a small team that wants one browser address for document conversion, OCR and transcription instead of a directory of shell scripts, and it fits a Raspberry Pi or an arm64 host that would rather pull a container than install LibreOffice and Pandoc. It does not fit a public deployment without authentication, because LOCAL_ONLY mode has no login at all, and it does not fit a workflow that must not run converters over untrusted uploads.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 26 days ago.
What is it written in?
Mainly Python, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.

Editorial analysis

One address for the tools you already run by hand

FileWizard is a self-hosted, browser-based utility for file conversion, OCR and audio transcription. What it wraps is not its own invention: it wraps common CLI and Python converters, FFmpeg, LibreOffice, Pandoc and ImageMagick among them, plus faster-whisper and Tesseract OCR.

The pitch is breadth of formats. It supports 180+ formats out of the box, 700+ formats theoretically, and much more can be configured and extended.

The value is therefore not the converters. Anyone who has run soffice to convert a spreadsheet to PDF, or ffmpeg to pull a track out of a video, has the raw capability already. What FileWizard adds is a place to run those commands from a browser, a queue that survives the browser tab closing, a history of what was produced, and a settings page where the commands are configured.

For a home server or a small studio that is a real saving. The alternative is a folder of shell scripts, a naming convention for outputs, and no record of what ran. The trade is that the same tools now sit behind a network service, which is where the security story begins.

The stack is deliberately plain: FastAPI with a vanilla HTML, JS and CSS frontend, and the repository holds main.py, run.sh, a settings.default.yml, a templates and static directory, and the docker directory. The application language is Python and the licence is MIT.

The tool table is configuration, not code

The interesting extension mechanism is that the set of converters is a configuration file. The features list says you can convert between many file formats, extendable via settings.yml to add any CLI tool.

The tools table in the README makes the shape of that configuration concrete, and each row is one external program with its inputs, its outputs and a caveat. LibreOffice, invoked as soffice, handles the office and document formats and is described as good for office and document conversions with fidelity varying with complex layouts. Pandoc handles the markup and document formats, is described as highly configurable via templates and filters, and requires LaTeX for PDF output. Ghostscript, as gs, covers PostScript and PDF work including producing PDF/A and rasterising. Calibre's ebook-convert handles the ebook formats.

Two of those caveats are the kind of thing a README usually omits. Fidelity varies with complex layouts, and PDF output needs a LaTeX engine. Both are properties of the underlying tools, and both are the kind of thing that turns into a support question if nobody says it.

The security consequence is more interesting, and the README is deliberate about it. Conversion command templates are read-only on the settings page: you edit config/settings.yml, or you set ALLOW_COMMAND_EDITS=true to edit them in the browser. In other words, the people who can use the app cannot normally change what the app runs, which matters because the app runs command line tools on files that anybody can upload.

That single design decision is the difference between a self-hosted convenience and a remote code execution service, and it is why the ALLOW_COMMAND_EDITS flag defaults to false.

LOCAL_ONLY means no login, and the README says so first

The Security section opens with a warning rather than a reassurance, and it is worth reading before you deploy.

In LOCAL_ONLY mode there is no login: everyone who can reach the port can use the app and change its settings. The instruction is to keep it on a trusted network or to enable OIDC authentication by setting LOCAL_ONLY=False. And a second sentence names the real risk: the converters process untrusted files, so run the container with only the volumes it needs.

That second sentence is the one that matters. The app's whole purpose is to accept a file and hand it to a program that parses it, and the programs in question are LibreOffice, Pandoc, Ghostscript, Tesseract, FFmpeg and a set of Python parsers, which is a large attack surface for document and media parsers. The application is only as safe as the least hardened converter it can be made to run.

The built-in protections are a sensible set. Requests that change state, uploads, settings and deletions, are only accepted from the app's own origin, so other websites you visit cannot drive your instance. Secrets such as the OIDC client secret and the webhook token are never sent to the browser, and leaving the field empty keeps the stored value. And auth_settings.allowed_users and allowed_domains restrict which accounts of your identity provider may log in, with both empty meaning everyone the provider accepts.

The environment variable table is worth reading as a security checklist. ALLOWED_HOSTS, a comma-separated list of host names the app answers to, is described as protecting LOCAL_ONLY instances against DNS rebinding, and SESSION_COOKIE_SECURE should be true when served over HTTPS. CSRF_TRUSTED_ORIGINS is needed when a reverse proxy rewrites the Host header, and setting app_public_url is offered as an alternative. FRAME_ANCESTORS defaults to 'self' and decides who may embed the interface in a frame.

Docker first, with three image variants

The recommended install is Docker, and the image is published with three variants.

loredcast/filewizard:latest is the full image, loredcast/filewizard:small is the same without TeX, Inkscape and Docling, and loredcast/filewizard:cuda is for transcription on NVIDIA GPUs. The images exist for linux/amd64 and linux/arm64, which covers a Raspberry Pi 4 or 5 and Apple Silicon, and the cuda variant is amd64 only.

The procedure is to copy docker-compose.yml from the repo, adjust as needed, and run:

bash
docker compose up -d

FileWizard is then available at localhost:6969, because the container listens on 8000 and the compose file maps 6969 to it. The app runs as an unprivileged user, and you set PUID and PGID to the owner of the mounted folders, with 99 and 100 given as the Unraid values and templates in the unraid directory of the repository.

The compose file itself is the better documentation than the README, because it shows the shape of the deployment. There are five volumes: config for settings.yml, created from the defaults on first start; data for the job history database; models for the downloaded Whisper and TTS models, so they survive updates; and uploads_data and processed_data for the working directories. The environment block shows LOCAL_ONLY=True, an optional SECRET_KEY that is generated and stored in ./config if empty, PUID and PGID, DOWNLOAD_KOKORO_ON_STARTUP, and a commented set of the security variables from the table above.

There is also a GPU path, commented out in the compose file, which asks for a resource reservation for the NVIDIA Container Toolkit. The build command inside the Dockerfile makes the variant explicit: docker buildx build --build-arg VARIANT=small -t filewizard:small .

The manual install is a virtualenv and a shell script

If you would rather not run a container, the manual path needs Python 3.12 and the converters you want to use on the PATH, LibreOffice, Pandoc, Ghostscript, Tesseract and FFmpeg among them, with the Dockerfile carrying the full list.

bash
git clone https://github.com/LoredCast/filewizard.git
cd filewizard
python3 -m venv venv
source venv/bin/activate   # Windows: venv\Scripts\activate
pip install -r requirements.txt   # or requirements_small.txt
./run.sh

The smaller requirements file is the same idea as the small Docker image, and the same reasoning applies: the converters you do not install are the ones you cannot use.

Updating is described as git pull, run the pip install line again and restart, and the README says settings and job history are kept. The user interface is at http://127.0.0.1:8000 in this mode, since the port mapping in the compose file is what moves it to 6969 in the container. The usage is four steps: open the page, drag and drop or choose files, select an action of Convert, OCR or Transcribe, and watch the History table update automatically.

The Python dependency list explains most of the features. faster-whisper and the piper-tts and kokoro-tts packages are the transcription and speech side, tesseract through pytesseract and ocrmypdf are the OCR side, SQLAlchemy with huey gives the persistent history and the background job queue, and authlib with httpx covers the OIDC login. markitdown with the pdf, docx, pptx, xlsx and outlook extras is a document parser, and docling is what the small variant leaves out.

Job history, model downloads and cleanup are the operational details

Three small features decide whether the application is pleasant to live with, and none of them are about conversion.

The first is persistent history. Background job processing comes with real-time status updates and a persistent history, and the History table in the interface is where a job is watched and where finished jobs are found. There is also a cleanup path: you can delete selected jobs, or remove finished jobs automatically after a number of days, which matters because a self-hosted box fills up with half-finished conversions otherwise.

The second is the models volume. Whisper and TTS models are downloaded on demand, and the compose file mounts./models to /app/models specifically so the downloaded models survive updates. The DOWNLOAD_KOKORO_ON_STARTUP variable in the compose file controls whether the Kokoro TTS model is fetched at startup. Without a volume, every container restart means the models are downloaded again.

The third is the upload cleanup. STALE_UPLOAD_HOURS, defaulting to 6, removes abandoned chunked uploads after that time, which is a sensible default for a drag and drop uploader where a user can abandon a large file halfway.

Converter processes are also bounded. CHILD_CPU_LIMIT_SECONDS and CHILD_MEMORY_LIMIT_MB, with defaults of 6000 and 4096, cap what a conversion can consume, and a memory limit of 0 disables that limit. On a small host with a runaway converter, that is the difference between a slow job and a dead box.

OCR language selection is per job rather than global, and the Tesseract language packs are chosen at build time, with the Dockerfile's default set covering English, German, French, Spanish, Italian, Portuguese, Dutch and Polish.

Reproducible builds, a dated snapshot, and a version 0.5

The Dockerfile's header is unusually explicit about reproducibility, and it is the part of the repository that speaks to a deployment team.

The comment says that builds are reproducible because the base images are pinned by digest, the Ubuntu packages come from a dated snapshot of the archive, and the Python packages come from the hash-pinned lock files in the locks directory. The base image arguments show that in practice: an Ubuntu 24.04 image pinned to a sha256 digest, a bootstrap Alpine image pinned to a digest that supplies a CA bundle for the first HTTPS apt update, and a UBUNTU_SNAPSHOT argument set to a specific timestamp. The comment also notes the asymmetry that the arm64 ports archive has no public snapshots, so the snapshot pinning applies to amd64.

Two more build arguments matter for operators. SOURCE_DATE_EPOCH is set to 0, which fixes timestamps written during the build for TeX formats, .pyc files and /etc/shadow, and VERSION is an argument so a release image can be tagged. There is also a documented escape hatch for corporate networks: behind a TLS-inspecting proxy, pass its CA certificate as a build secret, with docker buildx build --secret id=build_ca,src=/path/to/ca.crt, and the comment notes it is not stored in the image.

The licensing is MIT with the LICENSE file at the root of the repository. The release history is short: v0.4 on 2025-10-25, then v0.5 and v0.5.1 both on 2026-09-27, and the last push to the repository on that same day. The upgrade note for 0.4 is in docs/docker.md and says that docker compose pull && docker compose up -d works with an existing setup, that the app no longer runs as root, and that you can keep your job history.

That last point is a real behaviour change rather than a cosmetic one, since the unprivileged user and the PUID and PGID settings are what make the mounted folders safe to write to.

Editorial conclusion

FileWizard fits a homelab or a small team that wants one browser address for document conversion, OCR and transcription instead of a directory of shell scripts, and it fits a Raspberry Pi or an arm64 host that would rather pull a container than install LibreOffice and Pandoc. It does not fit a public deployment without authentication, because LOCAL_ONLY mode has no login at all, and it does not fit a workflow that must not run converters over untrusted uploads. Before you expose it, read the security section, set ALLOWED_HOSTS, and decide whether the container gets only the volumes it needs.

Frequently asked questions

What is FileWizard and what does it wrap?

It is a self-hosted, browser-based utility for file conversion, OCR and audio transcription that wraps common CLI and Python converters such as FFmpeg, LibreOffice, Pandoc and ImageMagick, plus faster-whisper and Tesseract OCR. It supports 180+ formats out of the box and can be extended with settings.yml to add any CLI tool.

How do I install FileWizard?

The recommended route is Docker: copy docker-compose.yml from the repository, adjust it, and run docker compose up -d, after which the app is on localhost:6969. Manually it needs Python 3.12 and the converters on the PATH, then a virtualenv, pip install -r requirements.txt and ./run.sh.

Does FileWizard need a login?

Not in LOCAL_ONLY mode, where the README warns that everyone who can reach the port can use the app and change its settings, so it should stay on a trusted network. Setting LOCAL_ONLY=False enables OIDC authentication, and auth_settings.allowed_users or allowed_domains can restrict which accounts may log in.

Which Docker image variants does FileWizard publish?

loredcast/filewizard:latest with all tools, loredcast/filewizard:small without TeX, Inkscape and Docling, and loredcast/filewizard:cuda for NVIDIA GPU transcription. The images exist for linux/amd64 and linux/arm64, with the cuda variant on amd64 only.

Can I edit the conversion commands from the settings page?

Not by default. Conversion command templates are read-only on the settings page, and you edit config/settings.yml instead, or set ALLOW_COMMAND_EDITS=true to enable browser editing. The README also notes that secrets are never sent to the browser, so leaving a secret field empty keeps the stored value.

Official sources

  1. Issues
  2. License: MIT
  3. LoredCast/filewizard on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/loredcast-filewizard.svg)](https://hysenlabs.com/projects/loredcast-filewizard)

Was this useful?