<?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.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>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>
