<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Melvin Bucio</title>
    <description>The latest articles on DEV Community by Melvin Bucio (@thebuciyo).</description>
    <link>https://dev.to/thebuciyo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3920485%2Fcc5d7c23-d1a0-44d1-8982-8d95fc1c910b.png</url>
      <title>DEV Community: Melvin Bucio</title>
      <link>https://dev.to/thebuciyo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/thebuciyo"/>
    <language>en</language>
    <item>
      <title>I Replaced Whisper with Parakeet on a $55/Month CPU Server. Here Is What Actually Happened</title>
      <dc:creator>Melvin Bucio</dc:creator>
      <pubDate>Thu, 09 Jul 2026 14:13:17 +0000</pubDate>
      <link>https://dev.to/thebuciyo/i-replaced-whisper-with-parakeet-on-a-55month-cpu-server-here-is-what-actually-happened-2a0f</link>
      <guid>https://dev.to/thebuciyo/i-replaced-whisper-with-parakeet-on-a-55month-cpu-server-here-is-what-actually-happened-2a0f</guid>
      <description>&lt;p&gt;Six months ago I launched VidClean with faster-whisper running on a Railway CPU worker. It worked. Accuracy was decent for English, the cost was around $25/month, and users could get a transcription without signing up for anything.&lt;br&gt;
Then NVIDIA released Parakeet TDT 0.6B v3 in August 2025 and I started seeing it in every ASR benchmark thread. The numbers looked almost too good: 6.34% average word error rate on the Open ASR Leaderboard, 3,333x realtime throughput on GPU, 25 European languages with automatic detection. All in a 600-million-parameter model.&lt;br&gt;
I run a free tool that processes real user files. I care about accuracy, speed on CPU (no GPU budget), and a model that does not hallucinate silence into phantom words. So I ran the bakeoff.&lt;br&gt;
Here is what I actually found, including the parts that were harder than expected.&lt;br&gt;
The Setup&lt;br&gt;
VidClean runs on Railway. The transcription worker is a single CPU replica, 2 vCPU, running in a 2GB container. No GPU. The whole backend costs about $55/month across six compute services plus Redis.&lt;br&gt;
On CPU, "3,333x realtime" does not happen. That number is from GPU benchmarks. Parakeet on a 2-vCPU Railway worker is meaningfully faster than Whisper small on the same hardware, but the gap is nothing like the benchmark suggests. If you are reading this expecting sub-minute transcription on cheap CPU hardware, calibrate accordingly.&lt;br&gt;
My previous stack: faster-whisper with the small model for production and large-v2 for quality-sensitive jobs. The tradeoff was painful. Small dropped noticeably on accented English, Spanish, and Portuguese. Large-v2 on CPU was too slow for production on longer files.&lt;br&gt;
For Parakeet I use onnx-asr with an int8-quantized ONNX export of the v3 weights, loaded via ONNX Runtime. Not the NeMo toolkit. The int8 ONNX is significantly smaller than the full-precision checkpoint and stays within the 2GB container budget with careful memory management.&lt;br&gt;
What I Tested&lt;br&gt;
I ran 40 files through both stacks:&lt;/p&gt;

&lt;p&gt;12 English podcast clips (various accents, 2-15 minutes each)&lt;br&gt;
10 Spanish YouTube videos (Mexican, Spanish, Colombian accents)&lt;br&gt;
8 Portuguese files (Brazilian Portuguese, mixed quality)&lt;br&gt;
6 heavily accented English files (Indian, Filipino, French accents)&lt;br&gt;
4 noisy files (background music, cafe noise, wind)&lt;/p&gt;

&lt;p&gt;I measured word error rate against manual transcription on a subset, relative processing time, and hallucination behavior on silence.&lt;br&gt;
Accuracy&lt;br&gt;
English: Parakeet and Whisper small are close on clean native-accent English. Parakeet edges it slightly. On accented English the gap widens: Parakeet handles Indian and Filipino accents noticeably better.&lt;br&gt;
Spanish: Parakeet is clearly better. Whisper small was trained predominantly on English and its Spanish performance drops on non-standard accents. Parakeet v3 was trained on 670,000+ hours of multilingual audio, and the improvement on Mexican and Colombian Spanish is audible when you compare outputs side by side.&lt;br&gt;
Portuguese: Same story as Spanish, maybe more pronounced. Whisper small produces noticeably more errors on Brazilian Portuguese. One caveat from NVIDIA's own model card: their training data uses European Portuguese, so Brazilian Portuguese gets a slight disadvantage. In practice on everyday creator content this has not been a meaningful issue.&lt;br&gt;
Noisy audio: Neither model is great here. Parakeet degrades more gracefully. Whisper hallucinates more on noisy silence.&lt;br&gt;
The Hallucination Problem&lt;br&gt;
This was the primary reason I wanted to switch.&lt;br&gt;
Whisper has a well-documented issue where it hallucinates text during silence or low-signal audio. "Thank you for watching" repeated at the end of a clip. Random phrases inserted during pauses. For a transcription tool used by real people on real content, this is not acceptable.&lt;br&gt;
Parakeet does not do this. On every silent segment I tested, Parakeet returns nothing. The Token-and-Duration Transducer architecture handles silence differently at a fundamental level.&lt;br&gt;
I had a post-processing step in my Whisper pipeline that tried to detect and strip common hallucinations. I removed it entirely after switching to Parakeet.&lt;br&gt;
The Hybrid Architecture&lt;br&gt;
Parakeet covers 25 European languages. A user uploading audio in Arabic, Chinese, Japanese, or Hindi gets routed elsewhere.&lt;br&gt;
The routing works like this: a Whisper pre-pass on the first 30 seconds of audio detects the language. Parakeet does not expose its own detected language externally, so Whisper handles detection for both paths. The detected language is checked against Parakeet's 25-language set. If it matches, Parakeet handles the full transcription. If not, Whisper small takes the job.&lt;br&gt;
The 25 languages include all major EU official languages: English, Spanish, Portuguese, French, German, Italian, Polish, and others including Maltese. Norwegian is notably absent. Russian and Ukrainian are included. Arabic, Chinese, Hindi, and most Asian languages fall to Whisper.&lt;br&gt;
There is also a kill switch: setting TRANSCRIBE_ENGINE=whisper as a Railway service variable routes every job to Whisper instantly, no redeploy required. This was the safety net that made the migration low-risk to ship.&lt;br&gt;
The Hard Part: Fitting Parakeet in 2GB&lt;br&gt;
This is the part most posts skip. Getting Parakeet to run reliably in a 2GB CPU container required real engineering work.&lt;br&gt;
ONNX Runtime memory arena must be disabled. With the default arena enabled, steady-state RSS grows by roughly 520MB over the course of a session and eventually busts the container. The fix is one line:&lt;br&gt;
pythonimport onnxruntime as rt&lt;br&gt;
import onnx_asr&lt;/p&gt;

&lt;p&gt;so = rt.SessionOptions()&lt;br&gt;
so.intra_op_num_threads = 2   # matches 2-vCPU allocation&lt;br&gt;
so.inter_op_num_threads = 1&lt;br&gt;
so.enable_cpu_mem_arena = False  # arena-on costs ~520MB RSS&lt;/p&gt;

&lt;p&gt;model = onnx_asr.load_model(&lt;br&gt;
    "nemo-parakeet-tdt-0.6b-v3",&lt;br&gt;
    quantization="int8",&lt;br&gt;
    sess_options=so,&lt;br&gt;
    providers=["CPUExecutionProvider"],&lt;br&gt;
)&lt;br&gt;
Windowed transcription, not full-file loading. Parakeet's ONNX export rejects inputs longer than roughly 200 seconds due to relative positional attention table limits. Inference buffer memory also scales with window length: a 60-second window peaks at about 1.65GB, a 30-second window at about 1.16GB. I settled on 20-second windows after measuring that 30-second windows hit 1,804MB, which is 4MB over the 1,800MB budget for a 2GB container.&lt;br&gt;
ffmpeg splits the input into overlapping windows before inference. Only one window is ever resident at a time. This is what makes 90-minute files possible in a 2GB container, not RAM headroom.&lt;br&gt;
Additional memory containment: MALLOC_ARENA_MAX=2 caps glibc malloc arenas and OMP_NUM_THREADS=2 caps the OpenMP thread pool. Both are set in the Dockerfile and Procfile.&lt;br&gt;
Weights baked into the Docker image: The model weights are downloaded at build time, not at container startup. A restart loads from local disk in seconds.&lt;br&gt;
The Language Detection Tax&lt;br&gt;
Every auto-language job pays a Whisper pre-pass on the first 30 seconds of audio, even when the file ends up going through Parakeet. This adds 1-2 seconds per job.&lt;br&gt;
If the user explicitly specifies a language at upload time, the pre-pass is skipped entirely and the job routes directly.&lt;br&gt;
One Feature That Only Works on Parakeet&lt;br&gt;
Filler word removal (removing "um," "uh," "you know" from transcripts) only works on the Parakeet path. It reconstructs whole words from Parakeet's token stream. The Whisper path returns empty word boundaries, so filler removal falls back silently. Users on non-European languages who go through Whisper do not get filler word removal.&lt;br&gt;
Results in Production&lt;br&gt;
VidClean has processed over 1,000 transcription jobs since the migration.&lt;br&gt;
Accuracy complaints dropped to near zero. With Whisper small I received occasional complaints about wrong words, particularly from Spanish and Portuguese users. Since switching I have not received a single accuracy complaint.&lt;br&gt;
The hallucination problem is gone. No more phantom phrases appended to transcripts. The post-processing step is deleted.&lt;br&gt;
Processing time improved on longer files. Parakeet is meaningfully faster than Whisper small on CPU. The improvement is most noticeable on files over 10 minutes. Exact numbers vary by audio complexity but the improvement is real.&lt;br&gt;
The 2GB container holds. Hundreds of jobs in production with the arena disabled, windowed inference, and memory-containment env vars. No OOMs since the tuning landed.&lt;br&gt;
Should You Use Parakeet on CPU?&lt;br&gt;
If your users are on European languages and accuracy on non-English matters, yes. The accuracy improvement over Whisper small is real and noticeable on Spanish and Portuguese. The hallucination elimination is practically valuable.&lt;br&gt;
The caveats:&lt;/p&gt;

&lt;p&gt;Use onnx-asr and ONNX Runtime, not the NeMo toolkit (easier for CPU deployment)&lt;br&gt;
Memory management is not optional: arena-off and windowed inference are requirements, not optimizations&lt;br&gt;
The language detection pre-pass adds overhead on every auto-language job&lt;br&gt;
Non-European languages still go through Whisper, so you need both stacks&lt;br&gt;
Speed on CPU is better than Whisper small but nothing like the GPU benchmarks&lt;/p&gt;

&lt;p&gt;The migration took a weekend, most of it on the memory constraints rather than the model swap itself. If you are running a tight CPU container, the 4MB-over-budget window tuning story is probably the most useful thing in this post.&lt;/p&gt;

&lt;p&gt;Melvin Bucio is building VidClean, a free browser-based video and audio tool suite for content creators. No account required, no watermark, no per-minute API bills. vidclean.net&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>python</category>
      <category>ai</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>How I built a free unlimited transcription tool with faster-whisper on CPU for $25/month</title>
      <dc:creator>Melvin Bucio</dc:creator>
      <pubDate>Mon, 01 Jun 2026 19:30:00 +0000</pubDate>
      <link>https://dev.to/thebuciyo/how-i-built-a-free-unlimited-transcription-tool-with-faster-whisper-on-cpu-for-25month-19n7</link>
      <guid>https://dev.to/thebuciyo/how-i-built-a-free-unlimited-transcription-tool-with-faster-whisper-on-cpu-for-25month-19n7</guid>
      <description>&lt;p&gt;Every free transcription tool caps you. Otter caps at 300 minutes per month. Turboscribe at 3 files per day. Notta at 120 minutes per month. They all do this for the same reason: transcription is expensive to run and someone has to pay for it.&lt;br&gt;
I built one with no cap. Here is how it works.&lt;br&gt;
Background&lt;br&gt;
This is the third post in a series about VidClean, a free video and audio tool suite I have been building in public. The first post covered the full stack (FastAPI, ARQ, Railway, Cloudflare R2). The second covered running DeepFilterNet3 background noise removal on CPU. This one covers adding Whisper transcription without breaking the tools that already work.&lt;br&gt;
Why you cannot just add Whisper to your existing worker&lt;br&gt;
My backend already runs two heavy models: DeepFilterNet3 for background noise removal and speech enhancement. Both are gated behind a Redis semaphore that allows only one heavy job at a time per worker. This prevents out-of-memory crashes when multiple users submit files simultaneously.&lt;br&gt;
The naive approach to adding Whisper is to load it alongside DF3 in the same worker. The problem: a 30-minute transcription job would hold the heavy lock for 30 minutes, blocking every silence removal and noise reduction job in the queue. For a free tool where silence removal is the flagship feature, that is unacceptable.&lt;br&gt;
The solution is queue isolation. Whisper gets its own Railway service, its own ARQ queue, and its own Redis namespace. Transcription jobs never touch the DF3 worker. The two systems run completely independently.&lt;br&gt;
The proof is in the timing. I tested this with concurrent jobs: a transcription job and a silence removal job fired within one second of each other. The silence job completed in 6 seconds. The transcription job completed 36 seconds later. No blocking, no waiting.&lt;br&gt;
faster-whisper on CPU&lt;br&gt;
Standard Whisper on CPU is slow. OpenAI's own model runs at roughly 1x realtime on a typical server CPU, meaning a 30-minute file takes 30 minutes to process.&lt;br&gt;
faster-whisper (CTranslate2) changes that. CTranslate2 is an optimized inference engine for Transformer models that runs roughly 4x faster than the standard implementation. On Railway's 2 vCPU allocation, a 10-minute file processes in roughly 3-4 minutes. A 30-minute file finishes in roughly 8-12 minutes.&lt;br&gt;
The configuration that matters:&lt;br&gt;
pythonfrom faster_whisper import WhisperModel&lt;/p&gt;

&lt;p&gt;model = WhisperModel(&lt;br&gt;
    "small",&lt;br&gt;
    device="cpu",&lt;br&gt;
    compute_type="int8",&lt;br&gt;
    cpu_threads=2,&lt;br&gt;
    num_workers=1,&lt;br&gt;
    download_root="/tmp/whisper-models"&lt;br&gt;
)&lt;br&gt;
compute_type="int8" quantizes the model weights to 8-bit integers. This halves the memory footprint and speeds up inference further with minimal accuracy loss on clear speech. cpu_threads=2 matches the 2 vCPU allocation.&lt;br&gt;
The model is 244MB and downloads at worker startup. First boot takes about 30 extra seconds while the model fetches from HuggingFace. Subsequent boots are faster once cached.&lt;br&gt;
VAD — how we handle 90-minute files&lt;br&gt;
A 90-minute recording is not 90 minutes of continuous speech. There are pauses, gaps, filler silence between sentences. Standard Whisper processes all of it. faster-whisper has a VAD filter that skips non-speech segments entirely.&lt;br&gt;
pythonsegments, info = model.transcribe(&lt;br&gt;
    wav_path,&lt;br&gt;
    vad_filter=True,&lt;br&gt;
    language=language,&lt;br&gt;
    beam_size=5&lt;br&gt;
)&lt;br&gt;
vad_filter=True means a 90-minute sermon with natural pauses might only require processing 65-70 minutes of actual speech. The practical effect: long files finish faster and the transcript is cleaner because Whisper is not trying to transcribe ambient room noise between sentences.&lt;br&gt;
The maximum file duration is capped at 90 minutes on the backend. Anything longer fails cleanly with an error before any model work starts.&lt;br&gt;
Three output formats from one job&lt;br&gt;
Whisper returns a list of segments, each with a start time, end time, and transcribed text. From that single segments list three output files are generated:&lt;br&gt;
Plain text (.txt): clean prose, no timestamps, good for reading and copy-pasting.&lt;br&gt;
SRT (.srt): numbered cues with HH:MM:SS,mmm timestamps, the format every video editor and subtitle tool accepts.&lt;br&gt;
VTT (.vtt): WEBVTT format with HH:MM:SS.mmm timestamps, the format browsers use for HTML5 video tracks.&lt;br&gt;
All three are uploaded to Cloudflare R2 as separate objects and returned as individual presigned download URLs. One upload, three downloads.&lt;br&gt;
Real numbers&lt;br&gt;
The dedicated transcription worker adds roughly $8-12 per month to the existing infrastructure. Total cost for the entire suite silence removal, background noise, speech enhancement, transcription, and 14 other tools is around $25-30 per month. No GPU. No paid transcription API. No per-minute billing.&lt;br&gt;
The no-cap positioning&lt;br&gt;
Every competitor caps the free tier because they run GPU infrastructure and need to limit free usage to protect margins. CPU inference is slower but the cost structure is completely different. Running faster-whisper small on a Railway CPU instance costs fractions of a cent per job. There is no economic pressure to cap it.&lt;br&gt;
What is next&lt;br&gt;
Burned-in captions: running the SRT through FFmpeg to render subtitles directly onto the video. One FFmpeg command, no new model, no new infrastructure. That and a dedicated subtitle page at /add-subtitles are next on the roadmap.&lt;br&gt;
Drop a comment if you have questions about the faster-whisper setup, the queue isolation approach, or the VAD configuration.&lt;br&gt;
You can try it at vidclean.net/transcribe. Free, no account, no time limit.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>python</category>
      <category>showdev</category>
      <category>ai</category>
    </item>
    <item>
      <title>How I built a free AI background noise remover that runs on CPU for $20/month</title>
      <dc:creator>Melvin Bucio</dc:creator>
      <pubDate>Thu, 21 May 2026 00:37:52 +0000</pubDate>
      <link>https://dev.to/thebuciyo/how-i-built-a-free-ai-background-noise-remover-that-runs-on-cpu-for-20month-385</link>
      <guid>https://dev.to/thebuciyo/how-i-built-a-free-ai-background-noise-remover-that-runs-on-cpu-for-20month-385</guid>
      <description>&lt;p&gt;Five weeks ago I wrote about the full stack behind VidClean, a free video and audio processing tool suite. That post covered the pipeline, the queue system, and the general architecture. This one goes deep on one specific tool: the background noise remover. It is now the second most used tool on the site. Here is exactly how it works.&lt;br&gt;
FFmpeg cannot do this&lt;br&gt;
FFmpeg has two noise reduction filters worth knowing about: afftdn and anlmdn. Both work fine for consistent background hiss, like tape noise or a steady hum at a fixed frequency. Neither works well for real-world noise, things like air conditioner rumble that shifts in volume, keyboard clicks, street noise, or a fan that speeds up and slows down.&lt;br&gt;
The problem is that FFmpeg's filters are not trained on speech. They do not understand the difference between your voice and the noise behind it. They apply a statistical filter across the whole signal and hope for the best. For simple cases this is fine. For anything real, it falls apart.&lt;br&gt;
DeepFilterNet3 is different. It is a neural network trained specifically on speech enhancement. It understands what speech sounds like and suppresses everything that is not.&lt;br&gt;
Why DeepFilterNet3&lt;br&gt;
There are a few options in this space. RNNoise is lightweight and fast but older and less accurate on complex noise. Whisper is not a noise suppressor, it is a transcription model, though people try to use it this way. DeepFilterNet3 is the current best open-source option for this use case: accurate, actively maintained, and small enough to run without a GPU.&lt;br&gt;
The Python library is deepfilternet. The API is simple:&lt;br&gt;
pythonfrom df.enhance import enhance, init_df, load_audio, save_audio&lt;/p&gt;

&lt;p&gt;model, df_state, _ = init_df()&lt;br&gt;
audio, _ = load_audio(input_path, sr=df_state.sr())&lt;br&gt;
enhanced = enhance(model, df_state, audio)&lt;br&gt;
save_audio(output_path, enhanced, df_state.sr())&lt;br&gt;
That is the core. Four lines of Python. The rest is plumbing.&lt;br&gt;
Running it on CPU&lt;br&gt;
Every DeepFilterNet3 tutorial assumes you have a GPU. The model page recommends CUDA. Most implementations are built around it.&lt;br&gt;
VidClean runs on Railway with no GPU, just CPU. The stack is torch==2.0.1+cpu and torchaudio==2.0.2+cpu. No CUDA, no GPU bill.&lt;br&gt;
The tradeoff is speed. DF3 on CPU runs at roughly [VERIFY: 1-2x realtime on Railway's hardware, check against a real job] so a 3-minute file takes around 3-6 minutes to process. For a free utility tool where users are not watching a progress bar in a meeting, this is an acceptable tradeoff. Nobody is running this live. They upload a file, go do something else, and come back to download.&lt;br&gt;
The cost difference is significant. A Railway CPU instance costs a fraction of any GPU instance. The whole site runs for $16-20/month.&lt;br&gt;
Memory is the real constraint&lt;br&gt;
Speed is not the problem with running DF3 on CPU. Memory is.&lt;br&gt;
When the model loads, it pulls its weights into RAM. That is manageable on its own. The problem is concurrent jobs. If two DF3 jobs start at the same time on the same Railway replica, both model instances are in RAM simultaneously, along with both audio files being processed. On a standard instance this causes an out-of-memory crash.&lt;br&gt;
The fix is a Redis semaphore. Before any heavy job starts, the worker tries to acquire a lock. If the lock is taken, the job waits in the queue. Only one heavy job runs per replica at a time.&lt;br&gt;
pythonasync def acquire_heavy_lock(redis, worker_id, ttl=120):&lt;br&gt;
    key = f"heavy_lock:{worker_id}"&lt;br&gt;
    acquired = await redis.set(key, "1", nx=True, ex=ttl)&lt;br&gt;
    return acquired&lt;br&gt;
The lock has a 120-second TTL with a heartbeat that renews every 60 seconds while the job is running. If the job crashes mid-process, the lock expires on its own and the next job can proceed. No manual cleanup, no stuck locks.&lt;br&gt;
The full repair_audio pipeline&lt;br&gt;
The background noise remover is one surface for DF3. There is a second tool, repair_audio, that uses DF3 as the middle step in a three-stage pipeline.&lt;br&gt;
Stage 1: loudnorm. Normalizes the audio volume before DF3 sees it. DF3 performs better on audio that is already at a consistent level.&lt;br&gt;
Stage 2: DF3. The actual noise removal.&lt;br&gt;
Stage 3: De-hum. A notch filter targeting 60Hz and harmonics (50Hz for non-US content). Some recordings have electrical hum baked in that DF3 does not fully remove. The notch filter handles it as a cleanup pass.&lt;br&gt;
Order matters here. Running de-hum before DF3 can remove frequency content that DF3 would have used to make better decisions. Running loudnorm after DF3 can reintroduce clipping. The sequence loudnorm then DF3 then de-hum gives the cleanest results.&lt;br&gt;
Real numbers&lt;br&gt;
The background noise remover has processed [VERIFY: 24 jobs as of May 20, update to current number on day of posting] since launch. It is the second most used tool on the site behind the silence remover, and it has more than doubled in the last three days.&lt;br&gt;
Total infrastructure cost for all 16 tools: $16-20/month. No GPU. No paid noise removal API. No per-minute billing.&lt;br&gt;
What is next&lt;br&gt;
The next tool in this category is auto captions via Whisper. It is deferred for now because the current bottleneck is distribution, not product. Eight of the sixteen tools have zero completions. Building more before fixing that would be the wrong call.&lt;br&gt;
If you want the full stack breakdown covering FastAPI, ARQ, Cloudflare R2, and Railway deployment, it is in my previous post here on Dev.to. &lt;a href="https://dev.to/thebuciyo/how-i-built-a-free-video-audio-tool-suite-for-20month-2dhe"&gt;https://dev.to/thebuciyo/how-i-built-a-free-video-audio-tool-suite-for-20month-2dhe&lt;/a&gt;&lt;br&gt;
You can try the background noise remover at vidclean.net. Free, no account needed, and no watermark.&lt;br&gt;
If you have questions about the DF3 setup, the semaphore pattern, or the pipeline order, drop a comment.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>python</category>
      <category>showdev</category>
      <category>machinelearning</category>
    </item>
    <item>
      <title>How I Built a Free Video &amp; Audio Tool Suite for $20/Month</title>
      <dc:creator>Melvin Bucio</dc:creator>
      <pubDate>Fri, 08 May 2026 17:27:40 +0000</pubDate>
      <link>https://dev.to/thebuciyo/how-i-built-a-free-video-audio-tool-suite-for-20month-2dhe</link>
      <guid>https://dev.to/thebuciyo/how-i-built-a-free-video-audio-tool-suite-for-20month-2dhe</guid>
      <description>&lt;p&gt;I got tired of video editing tools that either charged money, added watermarks, or made you create an account just to do something simple like remove silence from a recording.&lt;br&gt;
So five weeks ago I built my own. And then kept building. It's now a full video and audio tool suite with 8 tools, getting organic traffic from Google, ChatGPT, and Copilot, all for about $16-20/month in infrastructure costs.&lt;br&gt;
Here's exactly how it's built.&lt;/p&gt;

&lt;p&gt;The stack&lt;/p&gt;

&lt;p&gt;Frontend: Pure static HTML on Vercel. No React, no Next.js, no build step. Just HTML, Tailwind CDN, and vanilla JS. Vercel's free tier handles it.&lt;br&gt;
Backend: FastAPI on Railway with 2 worker replicas&lt;br&gt;
Queue: Redis + ARQ (async job queue for Python)&lt;br&gt;
Storage: Cloudflare R2 with 1-day lifecycle rules&lt;br&gt;
Processing: FFmpeg for everything&lt;/p&gt;

&lt;p&gt;Monthly cost breakdown:&lt;/p&gt;

&lt;p&gt;Railway (2 replicas): ~$10-12&lt;br&gt;
Cloudflare R2: ~$1-2&lt;br&gt;
Redis (Railway): ~$3-5&lt;br&gt;
Vercel: $0&lt;br&gt;
Total: $16-20/month&lt;/p&gt;

&lt;p&gt;How the processing pipeline works&lt;br&gt;
Every tool follows the same pattern:&lt;/p&gt;

&lt;p&gt;User uploads a file to FastAPI via the browser&lt;br&gt;
FastAPI streams it to Cloudflare R2&lt;br&gt;
FastAPI enqueues a job in Redis via ARQ&lt;br&gt;
A worker replica picks up the job, downloads the file from R2, runs FFmpeg, uploads the result back to R2&lt;br&gt;
Frontend polls /status every 500ms until the job is complete&lt;br&gt;
User gets a presigned download URL, file auto-deletes after 15 minutes&lt;/p&gt;

&lt;p&gt;The flow goes: browser uploads to FastAPI, FastAPI streams to R2 and enqueues a job in Redis, a worker picks up the job, downloads from R2, runs FFmpeg, uploads the result back to R2, and writes the status. The frontend polls every 500ms until it gets a presigned download URL back.&lt;br&gt;
The interesting technical decisions&lt;br&gt;
No user accounts, ever&lt;br&gt;
This was a deliberate architectural decision, not just a UX choice. No accounts means no user database, no sessions, no auth system, no password resets, no GDPR compliance headaches, no data breach liability. Every request is stateless. Files are identified by a UUID job ID, not a user ID.&lt;br&gt;
The tradeoff is you can't offer saved history or preferences. That's fine for a free utility tool. People just want to process a file and leave.&lt;br&gt;
15-minute file deletion&lt;br&gt;
Files are deleted from R2 automatically via lifecycle rules after 1 day, but a cleanup job also runs 15 minutes after each job completes. This isn't just a privacy feature. It keeps R2 storage costs near zero since files never accumulate.&lt;br&gt;
max_jobs=1 per worker&lt;br&gt;
ARQ supports concurrent jobs per worker, but FFmpeg is CPU-bound. Running two FFmpeg processes on the same Railway instance causes them to compete for CPU and both slow down. Setting max_jobs=1 means each worker processes one file at a time. With 2 replicas you get 2 simultaneous jobs, enough for current traffic and easy to scale by adding replicas.&lt;br&gt;
The boto3 mistake that caused 504s&lt;br&gt;
This one took me an embarrassingly long time to catch.&lt;br&gt;
boto3 (the AWS/R2 SDK) is synchronous. My first version called it directly inside a FastAPI async endpoint. Under any meaningful upload load, the event loop blocked while the file transferred to R2, requests piled up, and the server started returning 504s.&lt;br&gt;
The fix was one line:&lt;br&gt;
pythonawait asyncio.to_thread(storage.upload_file, tmp_path, key)&lt;br&gt;
This runs the blocking boto3 call in a thread pool, freeing the event loop to handle other requests during the upload. Obvious in hindsight, painful to debug live.&lt;br&gt;
The silence removal pipeline is not one command&lt;br&gt;
A naive implementation uses a single silenceremove filter:&lt;br&gt;
ffmpeg -i input.mp4 -af silenceremove=stop_periods=-1:stop_duration=0.5:stop_threshold=-35dB output.mp4&lt;br&gt;
This works but gives you very little control over cut padding and re-encode behavior. The actual implementation uses a two-pass approach: silencedetect to find the boundaries, then segment-cut and re-stitch with concat. More code but much better results, especially for speech with natural breath gaps you want to preserve.&lt;/p&gt;

&lt;p&gt;What each tool taught me&lt;/p&gt;

&lt;p&gt;Remove silence: Two-pass silence detection beats single-command filters for speech content&lt;br&gt;
Extract audio: libmp3lame at 192k constant bitrate is the right default for spoken audio. VBR (-q:a) is fine for music but creates surprises when input is voice with quiet sections&lt;br&gt;
Compress video: CRF 23 with libx264 veryfast is the sweet spot for quality vs speed on Railway's hardware&lt;br&gt;
Mute video: Stream copy (-c:v copy -an) makes muting essentially instant since no re-encode is needed&lt;br&gt;
Trim video: Re-encoding is worth the extra seconds vs stream copy because keyframe alignment causes noticeable off-by-seconds errors that users notice&lt;br&gt;
Video to GIF: Palette generation in a single FFmpeg invocation matters far more than I expected. Without it, GIF banding is obvious even at small sizes&lt;br&gt;
Resize to 9:16: The blur bars effect requires splitting into two streams in the filter graph. Non-obvious but produces much better results than black bars&lt;br&gt;
MP4 to MP3: Same backend as extract audio, different SEO surface. One FFmpeg function, two landing pages, two different keyword clusters&lt;/p&gt;

&lt;p&gt;The SEO side&lt;br&gt;
Since the goal is organic traffic, I put real effort into the SEO infrastructure from day one: FAQPage, HowTo, and WebApplication JSON-LD schema on every tool page, comparison pages targeting "free Descript alternative" queries, blog posts targeting long-tail keywords, and Spanish versions of all pages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0zlmpwonjiqq19pal3y9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0zlmpwonjiqq19pal3y9.png" alt="Search Console performance after 5 weeks" width="800" height="447"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Five weeks in: 27 clicks in Google Search Console, average position 5.5, and organic referrals already coming in from ChatGPT and Copilot.&lt;br&gt;
The AI referrals were the most surprising thing. ChatGPT and Copilot were recommending the site before Google was sending meaningful traffic. Plain-language description paragraphs on each tool page ("This tool removes silence from video and audio. Upload your file and download a clean version in seconds.") seem to help AI systems understand and cite the tools accurately.&lt;/p&gt;

&lt;p&gt;What surprised me overall&lt;br&gt;
Static HTML is underrated. No build pipeline, no framework updates, no hydration errors, instant Vercel deploys. For a tool suite where each page is mostly the same structure with different copy, it's the right call. I would make the same decision again.&lt;br&gt;
The other surprise was how well the cost scales. Eight tools, all running through the same pipeline, for $16-20/month. FFmpeg does the heavy lifting and Railway scales horizontally by just adding replicas. The unit economics are genuinely good.&lt;/p&gt;

&lt;p&gt;What's next&lt;br&gt;
More tools. Each one is a new keyword cluster, a new internal link target, and a new surface for AI citation. The goal is eventually a comprehensive free video utility suite, the way iLovePDF did it for PDF tools, built one tool at a time.&lt;br&gt;
If you're building something similar or have questions about the FFmpeg pipeline, the ARQ setup, or the R2 lifecycle configuration, drop a comment. Happy to go deeper on any of it.&lt;br&gt;
You can try what I built at vidclean.net.&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>productivity</category>
      <category>showdev</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
