<?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: Lê Huy Giang</title>
    <description>The latest articles on DEV Community by Lê Huy Giang (@lehuygiang28).</description>
    <link>https://dev.to/lehuygiang28</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%2F1529231%2F37acb01d-54cf-4f96-ac27-81bd82ff62ea.jpeg</url>
      <title>DEV Community: Lê Huy Giang</title>
      <link>https://dev.to/lehuygiang28</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/lehuygiang28"/>
    <language>en</language>
    <item>
      <title>I Rebuilt My Karaoke App So Everyone's Phone Could Be a Remote</title>
      <dc:creator>Lê Huy Giang</dc:creator>
      <pubDate>Mon, 01 Jun 2026 00:47:27 +0000</pubDate>
      <link>https://dev.to/lehuygiang28/i-rebuilt-my-karaoke-app-so-everyones-phone-could-be-a-remote-4k8b</link>
      <guid>https://dev.to/lehuygiang28/i-rebuilt-my-karaoke-app-so-everyones-phone-could-be-a-remote-4k8b</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/github-2026-05-21"&gt;GitHub Finish-Up-A-Thon Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;VKara&lt;/strong&gt; is a browser-based karaoke room app for singing at home with friends or family.&lt;/p&gt;

&lt;p&gt;It is not trying to replace YouTube.&lt;/p&gt;

&lt;p&gt;YouTube is already great at playing videos. It already has almost every karaoke song we need. But YouTube is not really designed to manage a karaoke night where many people want to choose songs together.&lt;/p&gt;

&lt;p&gt;That is the gap VKara tries to fill.&lt;/p&gt;

&lt;p&gt;You open VKara on a TV or laptop as the main playback screen. Everyone else joins the same room from their phone using a 4-digit room code or QR code. Then anyone can search for songs, add them to the queue, pause, resume, or skip.&lt;/p&gt;

&lt;p&gt;The TV only needs to play the video.&lt;/p&gt;

&lt;p&gt;Everyone's phone becomes their own remote.&lt;/p&gt;

&lt;p&gt;That is the whole idea.&lt;/p&gt;

&lt;p&gt;Simple enough to explain in one sentence. Not simple enough to build in one weekend. I learned that part the hard way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Links:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Live demo: &lt;a href="https://vkara.vercel.app/en" rel="noopener noreferrer"&gt;https://vkara.vercel.app/en&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;GitHub repo: &lt;a href="https://github.com/lehuygiang28/vkara" rel="noopener noreferrer"&gt;https://github.com/lehuygiang28/vkara&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Before branch: &lt;a href="https://github.com/lehuygiang28/vkara/tree/before" rel="noopener noreferrer"&gt;https://github.com/lehuygiang28/vkara/tree/before&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Old backend repo: &lt;a href="https://github.com/lehuygiang28/vkara-api" rel="noopener noreferrer"&gt;https://github.com/lehuygiang28/vkara-api&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Small warning: the demo is running on limited resources, so if it is slow, please give it a moment. My wallet is still a student wallet. lol.&lt;/p&gt;

&lt;p&gt;The flow is:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Open VKara on a TV or laptop.&lt;/li&gt;
&lt;li&gt;Join the room from a phone by code or QR.&lt;/li&gt;
&lt;li&gt;Search for a karaoke video.&lt;/li&gt;
&lt;li&gt;Add it to the shared queue.&lt;/li&gt;
&lt;li&gt;Control playback together.&lt;/li&gt;
&lt;/ol&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%2Fyl1x2rzax072ohmk1pce.jpg" 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%2Fyl1x2rzax072ohmk1pce.jpg" alt="Old VKara version: desktop, mobile search, and mobile controls" width="800" height="300"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Before: the idea worked, but the product still felt like a video app squeezed into a karaoke use case.&lt;/em&gt;&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%2Fzxg3rtr5k8vo8caokxml.jpg" 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%2Fzxg3rtr5k8vo8caokxml.jpg" alt="Current VKara mobile flow" width="800" height="499"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;After: the mobile flow is now focused on joining, searching, choosing an action, and controlling playback.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What Changed
&lt;/h2&gt;

&lt;p&gt;Before:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Frontend and backend lived in separate repos&lt;/li&gt;
&lt;li&gt;Mobile UI was basically a compressed desktop UI&lt;/li&gt;
&lt;li&gt;WebSocket contracts were spread across projects&lt;/li&gt;
&lt;li&gt;The TV screen had too many controls&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;After:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Merged everything into a Bun workspace monorepo&lt;/li&gt;
&lt;li&gt;Moved shared API/WebSocket contracts into packages/shared-types&lt;/li&gt;
&lt;li&gt;Rebuilt the product around two roles: TV as screen, phone as remote&lt;/li&gt;
&lt;li&gt;Simplified the mobile flow around join, search, queue, and controls&lt;/li&gt;
&lt;li&gt;Improved room state, reconnect behavior, playback sync, and deployment&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Comeback Story
&lt;/h2&gt;

&lt;p&gt;I started VKara around early 2025.&lt;/p&gt;

&lt;p&gt;At that time, my goal was very personal. I wanted a better way to sing karaoke at home with friends. The normal setup was: open YouTube on a TV, search for karaoke videos, and pass control around.&lt;/p&gt;

&lt;p&gt;It worked, but it was awkward.&lt;/p&gt;

&lt;p&gt;One person was searching. Another person accidentally played a video immediately. Someone else wanted to know what song was next. The queue was unclear. Casting also usually depended on everyone being on the same Wi-Fi network.&lt;/p&gt;

&lt;p&gt;So I built a prototype.&lt;/p&gt;

&lt;p&gt;The first version technically worked. And by "worked", I mean the dangerous kind of worked: it worked enough to prove the idea, but not enough to confidently bring it to a real karaoke night.&lt;/p&gt;

&lt;p&gt;The product had problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the desktop screen had too many controls around the video&lt;/li&gt;
&lt;li&gt;the mobile UI felt like a compressed desktop app&lt;/li&gt;
&lt;li&gt;search, queue, and controls were too close together&lt;/li&gt;
&lt;li&gt;realtime state was fragile&lt;/li&gt;
&lt;li&gt;the frontend and backend lived in separate repos&lt;/li&gt;
&lt;li&gt;shared types and WebSocket contracts were not cleanly owned by one place&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That last part mattered more than I expected.&lt;/p&gt;

&lt;p&gt;VKara is a realtime app. The frontend and backend have to agree on room state, queue state, video metadata, player commands, and WebSocket messages. When those contracts live in different places, every change feels risky.&lt;/p&gt;

&lt;p&gt;So I stopped working on it.&lt;/p&gt;

&lt;p&gt;Not because the idea was bad.&lt;/p&gt;

&lt;p&gt;Because the project was hard to change.&lt;/p&gt;

&lt;p&gt;When I came back this year, I decided not to start with new features. I started by making the project safe to change.&lt;/p&gt;

&lt;p&gt;The first major step was merging the old frontend repo and old backend repo into one Bun workspace monorepo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;apps/web                # Next.js frontend
apps/api                # Elysia + WebSocket backend
packages/shared-types   # shared API/WebSocket contracts
packages/shared-utils   # shared helper functions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This was not just folder cleanup. It changed how I could work on the project.&lt;/p&gt;

&lt;p&gt;After the monorepo migration, web and API changes could be checked together. Shared contracts could live in &lt;code&gt;packages/shared-types&lt;/code&gt;. I could change a room event or video shape without hunting through two repos and hoping I remembered everything.&lt;/p&gt;

&lt;p&gt;The second major change was UX.&lt;/p&gt;

&lt;p&gt;At first, I treated VKara like a responsive website:&lt;/p&gt;

&lt;p&gt;Desktop layout. Mobile layout. Done.&lt;/p&gt;

&lt;p&gt;That was the wrong mental model.&lt;/p&gt;

&lt;p&gt;A TV is not just a large phone. A phone is not just a small TV.&lt;/p&gt;

&lt;p&gt;They have different jobs.&lt;/p&gt;

&lt;p&gt;So VKara now thinks in two roles:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;TV / laptop:&lt;/strong&gt; the playback screen&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Phone:&lt;/strong&gt; the remote&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That one decision made the product much clearer.&lt;/p&gt;

&lt;p&gt;The TV should stay clean. It should show the video, the room code or QR, and the basic room controls.&lt;/p&gt;

&lt;p&gt;The phone should handle joining, searching, adding to queue, and playback actions.&lt;/p&gt;

&lt;p&gt;The real flow became:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Join a room → search a song → add it to the queue → keep singing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A lot of the comeback work was not glamorous. It was the kind of work users only notice when it fails: WebSocket room state, reconnect behavior, playback sync, queue updates, room cleanup, YouTube metadata shape, Docker builds, GitHub Actions, and Vercel deployment after the monorepo migration.&lt;/p&gt;

&lt;p&gt;Nobody at a karaoke night cares how clever the architecture is.&lt;/p&gt;

&lt;p&gt;They only care that when they tap a button, the room responds.&lt;/p&gt;

&lt;h2&gt;
  
  
  My Experience with GitHub Copilot
&lt;/h2&gt;

&lt;p&gt;The biggest difference between the first version and this comeback was not only GitHub Copilot.&lt;/p&gt;

&lt;p&gt;It was how I used it.&lt;/p&gt;

&lt;p&gt;In the first version, my AI-assisted workflow was too naive. I asked for code, patched bugs by hand, and moved fast. That helped me build a prototype, but it did not always leave behind code I trusted.&lt;/p&gt;

&lt;p&gt;This time, I used GitHub Copilot more like a finishing partner.&lt;/p&gt;

&lt;p&gt;Before changing code, I used Ask Mode to understand the project again. VKara had been sitting for a long time, and honestly, I did not remember every decision I made.&lt;/p&gt;

&lt;p&gt;One of my first questions was basically:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Why am I not using SWR or React Query in this frontend? What am I actually using instead?"&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The answer reminded me that the app was using Zustand stores for client state, direct fetch calls for server data, and WebSocket-driven realtime sync for room/player state.&lt;/p&gt;

&lt;p&gt;That question saved me from changing the wrong layer.&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%2Fnnk97nqpnlul0eeea4lo.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%2Fnnk97nqpnlul0eeea4lo.png" alt="Using Ask Mode in VS Code to understand the old frontend data flow" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Ask Mode helped me understand the old data flow before editing code.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For larger work, I used Plan Mode before execution.&lt;/p&gt;

&lt;p&gt;Instead of saying:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Make these two projects cleaner."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I asked for a real migration plan:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Merge &lt;code&gt;vkara&lt;/code&gt; and &lt;code&gt;vkara-api&lt;/code&gt; into one monorepo, keep history, use Bun workspace, find shared types, and move contracts into shared packages."&lt;/p&gt;
&lt;/blockquote&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%2Fixtml050mv2il2pyp8c9.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%2Fixtml050mv2il2pyp8c9.png" alt="Using Plan Mode in VS Code for the monorepo migration" width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Plan Mode turned a vague refactor into a safer migration path.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;That became my loop:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Think → Ask → Plan → Execute → Verify → Repeat&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;For bugs, I pasted exact TypeScript errors or Docker logs.&lt;/p&gt;

&lt;p&gt;For UI work, I used screenshots and described what felt wrong.&lt;/p&gt;

&lt;p&gt;For architecture questions, I asked for alternatives before touching code.&lt;/p&gt;

&lt;p&gt;That was the real upgrade.&lt;/p&gt;

&lt;p&gt;In the first version, I mostly asked AI to generate code.&lt;/p&gt;

&lt;p&gt;In the comeback, I asked GitHub Copilot to help me investigate, compare, plan, refactor, verify, and explain trade-offs.&lt;/p&gt;

&lt;p&gt;The final result is still not perfect.&lt;/p&gt;

&lt;p&gt;But now I know what actually matters.&lt;/p&gt;

&lt;p&gt;Not “AI lyrics” or some huge feature that sounds cool in a roadmap.&lt;/p&gt;

&lt;p&gt;The real problems are smaller and more human: who is allowed to skip, who added this song, whose turn is next, how to stop one person from filling the whole queue, how to rejoin quickly when someone closes their phone, and how to bring back the same queue for the next karaoke night.&lt;/p&gt;

&lt;p&gt;YouTube already gives us the videos.&lt;/p&gt;

&lt;p&gt;VKara should make the room feel calm.&lt;/p&gt;

&lt;p&gt;But VKara is no longer just a prototype I keep for myself.&lt;/p&gt;

&lt;p&gt;It is something I can open on a TV, hand my phone to a friend, and say:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Pick the next song."&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;And honestly, that already feels like a win.&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>githubchallenge</category>
      <category>githubcopilot</category>
      <category>webdev</category>
    </item>
    <item>
      <title>I Built a Full-Stack Proxy with a Dashboard to Scale the Gemini API. Stop Juggling Keys</title>
      <dc:creator>Lê Huy Giang</dc:creator>
      <pubDate>Tue, 30 Sep 2025 16:22:12 +0000</pubDate>
      <link>https://dev.to/lehuygiang28/i-built-a-full-stack-proxy-with-a-dashboard-to-scale-the-gemini-api-stop-juggling-keys-3a3l</link>
      <guid>https://dev.to/lehuygiang28/i-built-a-full-stack-proxy-with-a-dashboard-to-scale-the-gemini-api-stop-juggling-keys-3a3l</guid>
      <description>&lt;p&gt;Hey Dev Community! 👋&lt;/p&gt;

&lt;p&gt;If you're like me, you love hacking on projects with the Google Gemini API. But you also know that feeling... you're in the zone, code is flowing, and &lt;strong&gt;BAM! Rate limit exceeded.&lt;/strong&gt; 😭&lt;/p&gt;

&lt;p&gt;The free tier is fantastic, but that RPM/RPD limit can be a real creativity killer.&lt;/p&gt;

&lt;p&gt;This exact problem bugged me so much that I decided to build my first major open-source project to solve it. I'm super excited (and a little nervous!) to share it with you all: &lt;a href="https://github.com/lehuygiang28/gemini-proxy" rel="noopener noreferrer"&gt;&lt;strong&gt;Gemini Proxy&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;🚀 This project is fresh off the press and actively being developed!&lt;/strong&gt; I'm constantly adding new features, fixing bugs, and improving the developer experience. Your feedback and contributions are not just welcome—they're essential to making this tool amazing for the entire community.&lt;/p&gt;

&lt;h2&gt;
  
  
  ✨ What's in the Box?
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;🔑 Stop Juggling API Keys&lt;/strong&gt; → Throw all your Google Gemini keys into one secure spot (a Supabase DB). The dashboard lets you add, toggle, or remove them on the fly. No more .env file madness!
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;⚖️ Automatic Load Balancing&lt;/strong&gt; → It smartly spreads your requests across all your active keys. If one key gets tired and hits its limit, the proxy just grabs the next one. Zero downtime for your app.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🛡️ Your Own Secret Handshake&lt;/strong&gt; → Create special &lt;em&gt;proxy&lt;/em&gt; keys for your apps. This means your real Google API keys never leave the backend. Super secure!
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;📊 Know What's Happening&lt;/strong&gt; → A built-in dashboard shows you logs, performance, and usage in real-time. No more flying blind!
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;🌍 Deploy It Your Way&lt;/strong&gt; → The full-stack Next.js app is the easiest way to get everything, but if you just need the core logic, you can deploy it to Vercel Edge, Cloudflare Workers, and more.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  🏗️ How It Works
&lt;/h2&gt;

&lt;p&gt;The concept is simple but powerful. Your application makes requests to your deployed Gemini Proxy instance using a proxy key. The proxy then uses Supabase as its "brain" to fetch an available Google Gemini API key, forward the request, and log the transaction.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Your App → Gemini Proxy → Google Gemini API  
               ↓  
            Supabase (for keys, logs, and metrics)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  🚀 Get Up &amp;amp; Running in 5 Minutes
&lt;/h2&gt;

&lt;p&gt;I wanted the setup to be as painless as possible. You can get the full experience (dashboard included!) up and running in about 5 minutes.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Prep Supabase&lt;/strong&gt; → You'll need a Supabase project to act as the brain. I made an &lt;a href="https://github.com/lehuygiang28/gemini-proxy/blob/main/docs/getting-started.md" rel="noopener noreferrer"&gt;&lt;strong&gt;Illustrated Setup Guide&lt;/strong&gt;&lt;/a&gt; and a &lt;a href="https://github.com/lehuygiang28/gemini-proxy/blob/main/docs/quick-usage.md" rel="noopener noreferrer"&gt;&lt;strong&gt;Quick Usage&lt;/strong&gt;&lt;/a&gt; with pictures and everything to walk you through it.
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;One-Click Deploy to Vercel&lt;/strong&gt; → Just hit this magic button on &lt;a href="https://github.com/lehuygiang28/gemini-proxy/tree/main?tab=readme-ov-file#alternative-deploy-to-vercel-recommended-for-production" rel="noopener noreferrer"&gt;main readme file&lt;/a&gt;. It'll clone the repo and get you ready to go.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connect to Supabase&lt;/strong&gt; → Vercel will ask for your Supabase URL and key. Just paste 'em in.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Launch!&lt;/strong&gt; → You're live! You have a running instance with a dashboard.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Feed It Some Keys&lt;/strong&gt; → Now for the fun part. Use the CLI or the shiny new web UI to add your first proxy key and all your Google Gemini API keys.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  💻 Show Me the Code
&lt;/h2&gt;

&lt;p&gt;Okay, you're deployed. Now what? Just point your favorite AI library to your new proxy URL. Here's how it looks with the Official Google Genai. Check out how clean this is:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;GoogleGenAI&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@google/genai&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;genAI&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;GoogleGenAI&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;YOUR_PROXY_API_KEY&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;httpOptions&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;baseUrl&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;http://localhost:9090/api/gproxy/gemini&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="c1"&gt;// Generate content&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;genAI&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;models&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;generateContent&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;gemini-2.0-flash&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;contents&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Count from 1 to 10&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;And boom! Your app is now supercharged, running through a scalable, managed proxy that you control.&lt;/p&gt;

&lt;h2&gt;
  
  
  🔥 This Project Needs YOUR Help
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;🔥 This project is in active development and I need YOUR help!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Honestly, this is my first big open-source project, and I'm really passionate about making it something the community finds useful. For now, my main collaborator has been AI (it's been an interesting journey, ask me about it sometime!), but I know that the best projects are built with people.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;That's where you come in - and I genuinely appreciate every contribution!&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;🐛 Found a bug?&lt;/strong&gt; → &lt;a href="https://github.com/lehuygiang28/gemini-proxy/issues" rel="noopener noreferrer"&gt;Open an issue&lt;/a&gt; - Please report it! I'm actively fixing issues and your bug reports help me make this tool rock-solid.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;💡 Got an idea?&lt;/strong&gt; → &lt;a href="https://github.com/lehuygiang28/gemini-proxy/discussions" rel="noopener noreferrer"&gt;Start a discussion&lt;/a&gt; - I'm all ears! Feature requests, improvements, or even just suggestions for better UX are incredibly valuable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;👩‍💻 Want to contribute code?&lt;/strong&gt; → &lt;a href="https://github.com/lehuygiang28/gemini-proxy/fork" rel="noopener noreferrer"&gt;Fork the repo&lt;/a&gt; - Pull requests are always welcome! Whether it's fixing a typo, adding a feature, or improving performance - every contribution matters and I'll make sure to acknowledge your hard work.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;📝 Questions about the code?&lt;/strong&gt; → Don't hesitate to ask! I'm here to learn and grow with all of you, and your questions help me improve both the code and the documentation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'm looking for feedback, ideas, and maybe even a few brave souls who want to contribute. If you read my code and have questions or see a better way to do something, please tell me! I'm here to learn and grow with all of you.&lt;/p&gt;




&lt;p&gt;👉 &lt;strong&gt;Check out the Repo: &lt;a href="https://github.com/lehuygiang28/gemini-proxy" rel="noopener noreferrer"&gt;lehuygiang28/gemini-proxy&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you think this is a cool idea, please &lt;strong&gt;give it a ⭐️ on GitHub!&lt;/strong&gt; It would seriously make my day.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This is my first major open-source project, and I'm committed to making it amazing with your help. Let's build something great together!&lt;/em&gt;&lt;/p&gt;

</description>
      <category>gemini</category>
      <category>opensource</category>
      <category>api</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
