Skip to content

Migrate the simple-chatbot React client from voice-ui-kit to Pipecat UI - #256

Merged
markbackman merged 7 commits into
mainfrom
mb/simple-chatbot-pipecat-ui
Sep 14, 2026
Merged

markbackman merged 7 commits into
mainfrom
mb/simple-chatbot-pipecat-ui

Conversation

@markbackman

@markbackman markbackman commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Replaces @pipecat-ai/voice-ui-kit in simple-chatbot/client/react with components from the Pipecat UI shadcn registry, keeping the original look of the app.

  • Registry components copied in via npx shadcn@latest registry add @pipecat and shadcn add: connect-button, user-audio-control, conversation, text-input, device-select, audio-visualizer-bar, the usePipecatApp / usePipecatEventStream hooks, and the base-nova ui primitives they compose.
  • App shell: PipecatAppBase → usePipecatApp with a lazy transport factory (Daily / SmallWebRTC), an app-owned PipecatClientProvider + PipecatClientAudio, shadcn spinner and alert for loading and error states.
  • Local panels for the pieces the registry doesn't ship: bot video (gated on transport state, since SmallWebRTC exposes a placeholder track before connecting), conversation (with text render mode select and text input), and an events log with one-line descriptions and a filter, on top of the event stream hook.
  • Styling: Tailwind v4 base-nova stylesheet carrying the kit's dark palette, Geist / Geist Mono, uppercase mono panel titles and the registry's active/inactive/agent/client tokens.
  • Docs: READMEs cover registry setup and the diff-and-re-add update flow; fixes the stale port and two typos.
  • Gitignore: the repo-root Python lib/ rule was hiding src/lib/; the client's .gitignore now un-ignores it.

Not carried over: the conversation panel's Metrics tab (the registry metrics block pulls in recharts).

Upstream issues found while reviewing (not patched locally)

The vendored registry files are kept byte-identical to upstream so shadcn add can re-sync them. Two issues belong in the registry and are worked around from app code here:

  • use-pipecat-app on Daily: a failed startBot after a previous session calls client.disconnect(), Daily moves to disconnecting and awaits daily.leave(), but daily-js resolves without emitting left-meeting when already left, so the transport stays stuck and the connect button remains disabled until reload.
  • use-pipecat-event-stream capture list: only localAudioLevel is excluded from capture, so remoteAudioLevel, per-word botTtsText / botLlmText, and botOutput progress re-emits fill the shared 500-event cap within a minute. The events panel here raises maxEvents and groups botOutput by segment and status instead.

Test plan

  • npm run lint, tsc --noEmit, next build
  • Live against uv run bot-openai.py on Daily and SmallWebRTC: connect, bot video, transcript, text input, events, disconnect, transport switching
  • Compared side by side with the pre-migration client from main

🤖 Generated with Claude Code

https://claude.ai/code/session_01XyWgTC5nJ21if2nyEcfyv6

Register the @pipecat shadcn registry and copy in the components the
client needs: connect-button, user-audio-control, conversation,
text-input, device-select, audio-visualizer-bar, plus the usePipecatApp
and usePipecatEventStream hooks and the base-nova ui primitives they
compose. Un-ignore src/lib, which the repo-root Python rule for lib/
would otherwise hide.

Claude-Session: https://claude.ai/code/session_01XyWgTC5nJ21if2nyEcfyv6
Replace @pipecat-ai/voice-ui-kit with the Pipecat UI shadcn registry.
PipecatAppBase becomes usePipecatApp with a lazy transport factory and
an app-owned PipecatClientProvider; the kit's loader, error card, bot
video, conversation and events panels become small local components on
top of the registry pieces. The stylesheet is a Tailwind v4 base-nova
theme carrying the kit's dark palette, Geist Mono labels and the
registry tokens, so the app keeps its original look. READMEs cover the
registry setup and update flow.

Claude-Session: https://claude.ai/code/session_01XyWgTC5nJ21if2nyEcfyv6
@vercel

vercel Bot commented Sep 14, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
pipecat-examples Ready Ready Preview Sep 14, 2026 4:33pm UTC

Request Review

Register the Daily and SmallWebRTC loaders with registerTransport instead
of a local factory switch, so transportOptions are honoured and only the
selected package is loaded. Initialize devices from an effect inside the
provider tree rather than with initDevicesOnMount, which ran before the
provider's state listener was attached and left the connect button
enabled during the mic prompt. Style the disconnect states through the
inactive tokens instead of a variant override, fix the transport picker
height so the header controls align, and declare color-scheme so native
form chrome follows the forced dark theme.

Claude-Session: https://claude.ai/code/session_01XyWgTC5nJ21if2nyEcfyv6
The shared event store trims to its cap before per-subscriber filters
run, so Daily's audio-level and per-word text events evicted the rows
worth reading within a minute; raise the cap and collapse botOutput
progress re-emits into one row per segment and spoken status. Match the
filter against the rendered description as well as the type, clear the
log when the transport is switched, label SmallWebRTC's participant-less
remote tracks as the bot's, read the current will_be_spoken and
spoken_status fields, show the error message from error envelopes, and
derive each row once instead of on every store flush.

Claude-Session: https://claude.ai/code/session_01XyWgTC5nJ21if2nyEcfyv6
The media track hook keeps the previous session's ended track across a
disconnect, so a reconnect painted a black box before the new track
started. Require a live track as well as a connected transport.

Claude-Session: https://claude.ai/code/session_01XyWgTC5nJ21if2nyEcfyv6
Inline the one-off mono-upper utility into PanelTitle, drop the unused
data-slot attributes, and stop repeating font-sans on the html element
since the stylesheet already applies it.

Claude-Session: https://claude.ai/code/session_01XyWgTC5nJ21if2nyEcfyv6
The class-based fill override fought the registry's token tint through
the class merger and lost, so drop it and keep the documented default.

Claude-Session: https://claude.ai/code/session_01XyWgTC5nJ21if2nyEcfyv6
@markbackman
markbackman merged commit a627ed5 into main Sep 14, 2026
47 checks passed

This branch was successfully deployed

1 active deployment
Preview — 23df4916 Deployed Sep 14, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant