Model or dataset
souzatharsis/podcastfy avatar
souzatharsis/podcastfy

podcastfy: turning URLs, PDFs and images into two-host audio with Python

An Open Source Python alternative to NotebookLM's podcast feature: Transforming Multimodal Content into Captivating Multilingual Audio Conversations with GenAI

6,555 stars761 forksPythonApache-2.0

At a glance

What is it?
podcastfy is an Apache-2.0 Python package that turns websites, PDFs, images, YouTube videos and plain topics into multi-lingual two-speaker audio conversations. The code path is short and the configuration surface is wide, which is the whole trade-off.
Who is it for?
Adopt podcastfy if you need audio generation inside a Python program or a batch job and you accept that the output is a two-speaker conversation rather than a narration, because the package ships conversation_config.yaml as part of its design. Do not adopt it if you need a guaranteed offline pipeline: the default path calls hosted model and speech providers, and the README states the FastAPI service for URLs is beta.
Can I use it commercially?
Yes. Apache-2.0 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 134 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 September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

What problem podcastfy solves, and for whom

NotebookLM's audio overview is a closed UI: you upload sources, press a button, and you get a conversation between two synthetic hosts. You cannot call it from a script, you cannot run it over two thousand documents, and you cannot change how the hosts talk to each other beyond what the UI exposes. podcastfy is aimed squarely at that gap. The README describes it as an "Open Source API alternative to NotebookLM's podcast feature", and the framing is programmatic and bespoke generation rather than research synthesis.

The intended user is a developer who already has content in some machine-readable form (a URL list, a PDF directory, a YouTube link) and wants audio out of it as one step in a larger pipeline. That includes people building internal briefing feeds, course material generators, or accessibility layers over documentation. It is not aimed at someone who wants to click a button once a week; the CLI is thin and the real control lives in YAML files you are expected to edit.

The input surface is the part worth noting. The README lists websites, PDFs, images, YouTube videos and user-provided topics. Images are handled by feeding them to a vision-capable model, not by OCR, which is why the sample gallery pairs paintings rather than scanned pages.

The pipeline: extract, generate a transcript, synthesize speech

The architecture implied by the repository layout is a three-stage pipeline with a config file at each seam. The first stage pulls raw content: BeautifulSoup for HTML, PyMuPDF for PDFs, youtube-transcript-api for YouTube captions. Those dependencies appear in pyproject.toml, and they map one-to-one onto the advertised source types.

The second stage is transcript generation through LangChain, which is why langchain, langchain-google-genai and langchain-google-vertexai are all listed as dependencies. A language model turns the extracted text into a dialogue between two named speakers. The shape of that dialogue is not invented per run: the package ships conversation_config.yaml and config.yaml, both explicitly included in the wheel via the include list in pyproject.toml.

The third stage is text-to-speech. The dependency list carries three separate speech paths: elevenlabs, edge-tts and google-cloud-texttospeech. That is more than redundancy; it is the mechanism by which you trade cost against voice quality. edge-tts is the only one of the three that does not require a paid key, which matters if you are generating long-form audio and paying per character.

Long-form handling is a real branch in the code, not a flag that quietly does nothing. The README's sample table labels two entries with longform=True, one being a five-hour interview and the other an entire autobiography from Project Gutenberg. That tells you the pipeline chunks input rather than truncating it, though the README does not document the chunk size or how speakers are kept consistent across chunks.

Installing podcastfy and generating your first audio file

The README lists two prerequisites: Python 3.11 or higher, and ffmpeg for audio processing. Note that the README writes the ffmpeg step as a pip install, which is unusual since ffmpeg is normally a system package. The project's own Dockerfile resolves this the conventional way, installing ffmpeg through apt on an Ubuntu 24.04 base. If you are not using Docker, install ffmpeg through your system package manager and confirm it is on PATH before going further.

With that in place, the package itself comes from PyPI:

bash
pip install podcastfy

Before any generation call works you need provider keys. The README points to usage/config.md for this, and docker-compose.yml shows the two names the container expects to receive from the environment, GEMINI_API_KEY and OPENAI_API_KEY. Both are passed through to the podcastfy service and the dev service. Set whichever ones match the models and voices you configure.

The shortest working example is the Python client. This is the exact call the README gives, with two URLs:

python
from podcastfy.client import generate_podcast

audio_file = generate_podcast(urls=["<url1>", "<url2>"])

The return value is a path to the generated audio file, not an audio buffer, so you read it from disk or hand it to your own upload step. If you would rather not write Python at all, the CLI wraps the same function:

bash
python -m podcastfy.client --url <url1> --url <url2>

That is the CLI line as the README writes it, with the same flag repeated for each source. Treat the flag name as something to confirm against usage/cli.md rather than assuming, since the README's Python example passes a list while the CLI repeats the flag.

If you want the container instead, docker-compose.yml exposes the service on port 8000 and a development variant on port 8001 mapped to container port 8000. The healthcheck simply runs python3 -c "import podcastfy", so a green container means the package imports, not that your API keys work. The first real request is where key problems surface.

Where podcastfy breaks down

The most consequential limitation is that the output format is fixed to a conversation. The package ships conversation_config.yaml, and the entire premise is two speakers trading turns. If you want a single-narrator reading of a document, you are fighting the design rather than using it. There is no documented narration mode.

Cost and latency are the second constraint, and they compound. Every run makes at least one model call for the transcript and then one speech call per segment. Long inputs multiply both. The longform=True path exists precisely because a five-hour source cannot go through in a single pass, and the README does not document how many chunks that produces or what it costs. Anyone planning a nightly batch job over a large corpus should measure this on their own content before committing.

Third, the hosted dependency is unavoidable on the default path. The README's config documentation is the place to look for a fully local setup, and it is not described in the README itself. If your constraint is that source documents must never leave your infrastructure, the README as given does not establish that podcastfy can meet it.

Fourth, the FastAPI service is labeled beta in the README, and specifically beta for URLs. The README points at Dockerfile_api and a notebook for the request shape rather than documenting the endpoints inline. Treat that surface as unstable. Finally, YouTube input depends on youtube-transcript-api, which means it works on videos that have captions and fails on those that do not; the README does not describe a fallback to audio transcription.

podcastfy compared with a general TTS library

The natural alternative is not another podcast generator; it is a speech synthesis library such as Coqui TTS or a cloud TTS SDK, driven by your own prompt code. The difference in approach is where the intelligence sits.

With a TTS library, you write the script. You decide the structure, you decide whether it is one voice or two, and you decide how the source material is compressed into something speakable. That is more work, and it is the work podcastfy automates. podcastfy's contribution is the middle stage: taking unstructured multimodal input and producing a dialogue that sounds like two people who read the material. The speech layer underneath is a detail it delegates to elevenlabs, edge-tts or google-cloud-texttospeech.

So the choice is about whether you want to own the transcript logic. If your content already has a natural spoken structure, a TTS library plus a short prompt gets you there with fewer moving parts and one fewer API key. If your content is a pile of PDFs and links with no structure at all, the transcript generation is the expensive part and podcastfy is doing the thing you would otherwise have to build. The configuration files are the seam where you can influence that generation without rewriting the pipeline, which is the practical reason to prefer it over assembling LangChain and a TTS client yourself.

Maintenance, releases and what Apache-2.0 means here

The repository is not archived, and the last push was on 2026-05-04. The most recent tagged release in the list is v0.4.0 from 2024-11-16, while pyproject.toml declares version 0.4.3. That gap between the newest tag and the declared package version is worth knowing before you pin a dependency: the PyPI artifact and the GitHub release list are not in step, so pin the version you actually install rather than the version you see tagged.

The licence is Apache-2.0, which is permissive and includes an explicit patent grant. There is a NOTICE file at the repository root, and Apache-2.0 expects that notice to be preserved in redistributions. If you vendor podcastfy into a product, keep LICENSE and NOTICE intact. That is a description of what the licence requires, not legal advice; your counsel decides how it applies to your distribution.

Upgrade cost is dominated by the dependency graph rather than by podcastfy's own code. pyproject.toml pins numpy to >=1,<2, which will conflict with any project already on NumPy 2.x. It also pulls in the whole LangChain stack plus three separate speech SDKs. A monthly upgrade cadence means tracking LangChain's release notes as much as podcastfy's. The Makefile, make.sh and build_docs.py at the root suggest the maintainers script their own builds, so building from a clone is a supported path if you need to patch something.

Editorial conclusion

Adopt podcastfy if you need audio generation inside a Python program or a batch job and you accept that the output is a two-speaker conversation rather than a narration, because the package ships conversation_config.yaml as part of its design. Do not adopt it if you need a guaranteed offline pipeline: the default path calls hosted model and speech providers, and the README states the FastAPI service for URLs is beta. Before building on it, verify two things in your own environment: that ffmpeg is present on PATH, since the README lists it as a prerequisite, and that your chosen speech provider's key is one the config actually reads. Then run the two-URL example and listen to the result before you wire it into anything scheduled.

Frequently asked questions

Is podcastfy free to use?

The package itself is Apache-2.0 licensed and installs from PyPI at no cost. The generation pipeline calls hosted model and speech providers, so your real cost is whatever those APIs charge for the transcript and audio, unless you configure a provider that does not need a paid key.

What Python version does podcastfy require?

The README lists Python 3.11 or higher as a prerequisite, and pyproject.toml declares python = "^3.11". It also lists ffmpeg for audio processing, which the project's Dockerfile installs as a system package rather than through pip.

Which content types can podcastfy turn into audio?

The README lists websites, PDFs, images, YouTube videos and user-provided topics. The dependency list matches those source types, with BeautifulSoup for HTML, PyMuPDF for PDFs and youtube-transcript-api for YouTube captions.

Does podcastfy support languages other than English?

Yes. The README includes a multi-lingual sample table with French and Portuguese-BR outputs generated from a website and a news article, and describes the package as multi-lingual.

What API keys does podcastfy need?

The README points to usage/config.md for key setup, and docker-compose.yml passes GEMINI_API_KEY and OPENAI_API_KEY into the container. Which keys you actually need depends on the model and speech providers you configure.

Can podcastfy run as an API service?

The README includes a FastAPI section labeled beta for URLs, built with Dockerfile_api, and points to a notebook for the request example. It does not document the endpoints inline, so treat that interface as unstable.

Official sources

  1. License: Apache-2.0
  2. Project website
  3. README
  4. Releases
  5. souzatharsis/podcastfy on GitHub
Community notes

Community notes