<?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: Qingyuan Yang</title>
    <description>The latest articles on DEV Community by Qingyuan Yang (@qingyuan_yang_11c04dc68d8).</description>
    <link>https://dev.to/qingyuan_yang_11c04dc68d8</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%2F3304625%2F78fe32b0-6d60-482e-a280-890cb237df56.png</url>
      <title>DEV Community: Qingyuan Yang</title>
      <link>https://dev.to/qingyuan_yang_11c04dc68d8</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/qingyuan_yang_11c04dc68d8"/>
    <language>en</language>
    <item>
      <title>Open-source AI Interview Platform for chat/voice/video</title>
      <dc:creator>Qingyuan Yang</dc:creator>
      <pubDate>Thu, 16 Jul 2026 02:06:02 +0000</pubDate>
      <link>https://dev.to/qingyuan_yang_11c04dc68d8/open-source-ai-interview-platform-for-chatvoicevideo-4ol5</link>
      <guid>https://dev.to/qingyuan_yang_11c04dc68d8/open-source-ai-interview-platform-for-chatvoicevideo-4ol5</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/qingyuan_yang_11c04dc68d8/building-a-self-hosted-voice-ai-interview-platform-with-nextjs-supabase-and-websockets-23f2" class="crayons-story__hidden-navigation-link"&gt;Building a Self-Hosted Voice AI Interview Platform with Next.js, Supabase, and WebSockets&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/qingyuan_yang_11c04dc68d8" class="crayons-avatar  crayons-avatar--l  "&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3304625%2F78fe32b0-6d60-482e-a280-890cb237df56.png" alt="qingyuan_yang_11c04dc68d8 profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/qingyuan_yang_11c04dc68d8" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Qingyuan Yang
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Qingyuan Yang
                
              
              &lt;div id="story-author-preview-content-4147314" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/qingyuan_yang_11c04dc68d8" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&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.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3304625%2F78fe32b0-6d60-482e-a280-890cb237df56.png" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Qingyuan Yang&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/qingyuan_yang_11c04dc68d8/building-a-self-hosted-voice-ai-interview-platform-with-nextjs-supabase-and-websockets-23f2" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Jul 15&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/qingyuan_yang_11c04dc68d8/building-a-self-hosted-voice-ai-interview-platform-with-nextjs-supabase-and-websockets-23f2" id="article-link-4147314"&gt;
          Building a Self-Hosted Voice AI Interview Platform with Next.js, Supabase, and WebSockets
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/webdev"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;webdev&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/nextjs"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;nextjs&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/qingyuan_yang_11c04dc68d8/building-a-self-hosted-voice-ai-interview-platform-with-nextjs-supabase-and-websockets-23f2" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;5&lt;span class="hidden s:inline"&gt;&amp;nbsp;reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/qingyuan_yang_11c04dc68d8/building-a-self-hosted-voice-ai-interview-platform-with-nextjs-supabase-and-websockets-23f2#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              1&lt;span class="hidden s:inline"&gt;&amp;nbsp;comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            4 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success crayons-icon c-btn__icon"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>ai</category>
      <category>nextjs</category>
      <category>opensource</category>
      <category>showdev</category>
    </item>
    <item>
      <title>Building a Self-Hosted Voice AI Interview Platform with Next.js, Supabase, and WebSockets</title>
      <dc:creator>Qingyuan Yang</dc:creator>
      <pubDate>Wed, 15 Jul 2026 06:45:15 +0000</pubDate>
      <link>https://dev.to/qingyuan_yang_11c04dc68d8/building-a-self-hosted-voice-ai-interview-platform-with-nextjs-supabase-and-websockets-23f2</link>
      <guid>https://dev.to/qingyuan_yang_11c04dc68d8/building-a-self-hosted-voice-ai-interview-platform-with-nextjs-supabase-and-websockets-23f2</guid>
      <description>&lt;p&gt;Aural started with a simple limitation: static question banks and chatbots do not reproduce the rhythm of a real interview. A useful interview system needs to listen, decide when to probe, preserve context, and produce feedback that is consistent enough to act on.&lt;/p&gt;

&lt;p&gt;I built &lt;a href="https://github.com/1146345502/aural-oss" rel="noopener noreferrer"&gt;Aural&lt;/a&gt; as an open-source platform for conducting interviews over voice, chat, and video. Teams can design an interview, share a link, let the AI ask contextual follow-up questions, and receive a structured report. Candidates can also use the same core workflow for practice.&lt;/p&gt;

&lt;p&gt;This post covers the engineering decisions that mattered most when moving from a chat prototype to a self-hostable, real-time product.&lt;/p&gt;

&lt;h2&gt;
  
  
  What the platform needs to do
&lt;/h2&gt;

&lt;p&gt;A single interview touches several subsystems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;interview configuration and question sequencing&lt;/li&gt;
&lt;li&gt;real-time voice, chat, or video interaction&lt;/li&gt;
&lt;li&gt;adaptive follow-up generation&lt;/li&gt;
&lt;li&gt;coding and whiteboard exercises&lt;/li&gt;
&lt;li&gt;transcript storage and cleanup&lt;/li&gt;
&lt;li&gt;structured scoring and report generation&lt;/li&gt;
&lt;li&gt;organization, project, and access controls&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The important design decision was to treat an interview as a stateful workflow, not a series of independent prompts. Every answer changes what the system knows and what it should ask next.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why voice is harder than chat
&lt;/h2&gt;

&lt;p&gt;Chat gives the application a clean turn boundary: the user presses Send. Voice does not. A real-time interview has to infer when a candidate has finished, handle pauses and filler words, and avoid interrupting a thought that is still developing.&lt;/p&gt;

&lt;p&gt;Three problems dominated the implementation.&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Latency is part of the user experience
&lt;/h3&gt;

&lt;p&gt;Every stage adds delay: audio capture, transport, transcription, follow-up generation, speech synthesis, and playback. Optimizing only the model call is not enough. The entire path has to stream wherever possible, and each hop needs timing data so regressions are visible.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Raw transcripts are not reliable application state
&lt;/h3&gt;

&lt;p&gt;Speech recognition output can contain partial phrases, duplicates, false starts, and punctuation changes. Aural keeps the live transcript useful for the interface while normalizing the final answer before it becomes durable interview context. That separation prevents temporary transcription artifacts from polluting later questions and reports.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Follow-ups must feel earned
&lt;/h3&gt;

&lt;p&gt;A generic request to elaborate quickly sounds scripted. The follow-up generator receives the interview goal, current question, normalized answer, previous turns, and remaining depth budget. It must either ask a focused follow-up or explicitly move on. A configurable depth limit keeps the conversation useful without letting one answer consume the whole session.&lt;/p&gt;

&lt;p&gt;Conceptually, the loop looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Capture and normalize the candidate response.&lt;/li&gt;
&lt;li&gt;Persist the turn and update interview state.&lt;/li&gt;
&lt;li&gt;Decide whether the answer needs a follow-up.&lt;/li&gt;
&lt;li&gt;Generate the next prompt under the configured depth and time limits.&lt;/li&gt;
&lt;li&gt;Stream the prompt back through the active communication channel.&lt;/li&gt;
&lt;li&gt;Finalize scoring only after the turn history is stable.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  The architecture
&lt;/h2&gt;

&lt;p&gt;Aural uses Next.js and TypeScript for the application, Supabase/PostgreSQL for durable data, tRPC for typed application APIs, and WebSocket relays for real-time voice events. LLM providers are behind adapters so a self-hosted deployment is not tied to one vendor.&lt;/p&gt;

&lt;p&gt;The data plane and the AI plane are deliberately separated. Product state such as organizations, interviews, sessions, questions, permissions, and reports lives in PostgreSQL. Model calls receive only the scoped context needed for the current operation. This makes authorization easier to reason about and gives operators a clear place to enforce retention policies.&lt;/p&gt;

&lt;p&gt;Long-running operations are also separated from the live turn path. Report generation can be retried without replaying the interview, while the real-time path stays focused on responsiveness.&lt;/p&gt;

&lt;h2&gt;
  
  
  Structured evaluation instead of one opaque score
&lt;/h2&gt;

&lt;p&gt;An overall number is easy to display but hard to trust. Aural evaluates answers against explicit dimensions and keeps the evidence connected to the transcript. The report can therefore show what worked, what was missing, and what to improve next rather than returning a mysterious score.&lt;/p&gt;

&lt;p&gt;The same structure powers candidate practice. Instead of ending with a report alone, the system can turn weaknesses into a revision prompt, a suggested answer outline, or another practice attempt.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-hosting and data ownership
&lt;/h2&gt;

&lt;p&gt;Interview data can include resumes, job descriptions, recordings, transcripts, and internal hiring criteria. For many teams, where that data lives is not a minor deployment detail.&lt;/p&gt;

&lt;p&gt;The open-source release includes Docker-based self-hosting and documented environment configuration. Operators can choose their database, storage, and supported model provider, then place the deployment inside their own network and retention controls. The hosted service remains useful for teams that do not want to operate the stack, but self-hosting is a first-class path rather than an export feature.&lt;/p&gt;

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

&lt;p&gt;The biggest lesson is that a believable AI interview is a systems problem. Prompt quality matters, but so do turn detection, streaming, transcript hygiene, state transitions, authorization, observability, and failure recovery. Improving any one component in isolation has limited value if the full conversation still feels slow or inconsistent.&lt;/p&gt;

&lt;p&gt;A second lesson is to keep model output constrained by product state. Follow-up depth, remaining time, question goals, evaluation rubrics, and permitted tools should be explicit inputs. The model should not silently invent the workflow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try Aural
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Live demo without signup: &lt;a href="https://aural-ai.com" rel="noopener noreferrer"&gt;aural-ai.com&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Source code: &lt;a href="https://github.com/1146345502/aural-oss" rel="noopener noreferrer"&gt;github.com/1146345502/aural-oss&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;License: MIT&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Feedback is especially welcome on the self-hosting workflow, real-time voice experience, and the privacy boundaries you expect around interview data.&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>ai</category>
      <category>webdev</category>
      <category>nextjs</category>
    </item>
  </channel>
</rss>
