Add live translation demo#72
Open
Karolk99 wants to merge 1 commit into
Open
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
Contributor
There was a problem hiding this comment.
Pull request overview
This PR introduces a new live-translation Vite + React application that open-sources a live streaming demo where a publisher streams camera/mic and viewers can watch with selectable AI-translated audio tracks over Media over QUIC (MoQ).
Changes:
- Adds a complete Vite/React app scaffold (Vite config, TS config, Tailwind, PostCSS, routing, assets).
- Implements MoQ publishing + viewing with translation discovery, quality selection, and synced A/V playback when switching translations.
- Adds basic UI components and pages for publishing (QR/link sharing) and watching (play-gated viewer).
Reviewed changes
Copilot reviewed 41 out of 47 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| live-translation/vite.config.ts | Vite dev server + alias configuration |
| live-translation/tsconfig.json | TypeScript compiler configuration |
| live-translation/tailwind.config.cjs | Tailwind theme/content configuration |
| live-translation/src/vite-env.d.ts | Vite env var typings |
| live-translation/src/pages/watch.tsx | Viewer route/page (play-gated) |
| live-translation/src/pages/publish.tsx | Publisher route/page wrapper |
| live-translation/src/main.tsx | App bootstrap, Fishjam provider, routes |
| live-translation/src/lib/utils.ts | Shared cn() utility |
| live-translation/src/layout.tsx | App layout + toaster mount |
| live-translation/src/index.css | Global styles (Tailwind + custom layout CSS) |
| live-translation/src/hooks/useWakeLock.ts | Wake lock hook for viewer/publisher sessions |
| live-translation/src/components/VideoPlayer.tsx | MediaStream-backed <video> helper |
| live-translation/src/components/ui/sonner.tsx | Toast toaster wrapper |
| live-translation/src/components/ui/select.tsx | Radix select wrapper UI |
| live-translation/src/components/ui/label.tsx | Label UI component |
| live-translation/src/components/ui/card.tsx | Card UI components |
| live-translation/src/components/ui/button.tsx | Button UI component |
| live-translation/src/components/ui/badge.tsx | Badge UI component |
| live-translation/src/components/moq/VideoTile.tsx | Tile rendering + quality/translation selectors |
| live-translation/src/components/moq/VideoSurface.tsx | Video/canvas surface + backend attachment |
| live-translation/src/components/moq/utils.ts | URL building, naming, translation parsing, persistence helpers |
| live-translation/src/components/moq/useSyncedPlayback.ts | Hook managing persistent synced playback instance |
| live-translation/src/components/moq/useSignalValue.ts | React hook adapter for MoQ signals |
| live-translation/src/components/moq/usePublisher.ts | Publisher session + device selection + broadcast setup |
| live-translation/src/components/moq/useMoqStreamViewer.ts | Connect-to-single-stream viewer hook |
| live-translation/src/components/moq/useMoqConnection.ts | Core connection + discovery + tile model |
| live-translation/src/components/moq/types.ts | Shared MoQ/publisher/viewer types |
| live-translation/src/components/moq/syncedPlayback.ts | Cross-broadcast A/V clocking for translation audio |
| live-translation/src/components/moq/RoomView.tsx | Main viewer UI frame (single-stream) |
| live-translation/src/components/moq/quality.ts | Quality preference + rendition selection |
| live-translation/src/components/moq/PublisherPanel.tsx | Publisher UI incl. QR/link + start/stop |
| live-translation/src/components/moq/generateStreamName.ts | Stream name generator |
| live-translation/src/components/moq/CallToolbar.tsx | Disconnect toolbar/footer |
| live-translation/src/components/moq/BrandHeader.tsx | Header lockup + tagline |
| live-translation/src/components/DeviceSelect.tsx | Camera/microphone device selector |
| live-translation/README.md | Demo documentation + setup steps |
| live-translation/public/gemini-logo.svg | Public asset |
| live-translation/public/fishjam-logo.svg | Public asset |
| live-translation/public/favicon.svg | Public asset |
| live-translation/public/avatar.svg | Public asset |
| live-translation/postcss.config.cjs | PostCSS configuration |
| live-translation/package.json | App dependencies/scripts |
| live-translation/index.html | Vite HTML entry |
| live-translation/.yarnrc.yml | Yarn config |
| live-translation/.gitignore | Demo-local gitignore |
| live-translation/.env.example | Example env vars |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Comment on lines
+1
to
+3
| /** @type {import('tailwindcss').Config} */ | ||
| export default { | ||
| darkMode: ['class'], |
Comment on lines
+1
to
+11
| import { useTheme } from 'next-themes'; | ||
| import { Toaster as Sonner } from 'sonner'; | ||
|
|
||
| type ToasterProps = React.ComponentProps<typeof Sonner>; | ||
|
|
||
| const Toaster = ({ ...props }: ToasterProps) => { | ||
| const { theme = 'system' } = useTheme(); | ||
|
|
||
| return ( | ||
| <Sonner | ||
| theme={theme as ToasterProps['theme']} |
Comment on lines
+4
to
+14
| useEffect(() => { | ||
| const wakeLockAvailable = 'wakeLock' in navigator; | ||
| if (!wakeLockAvailable) { | ||
| return; | ||
| } | ||
|
|
||
| const wakeLock = navigator.wakeLock.request('screen'); | ||
|
|
||
| return () => { | ||
| wakeLock.then((sentinel) => sentinel.release()); | ||
| }; |
Comment on lines
+159
to
+162
| className={cn( | ||
| 'relative flex items-center justify-center overflow-hidden rounded-lg bg-stone-200', | ||
| isTileWithoutVideo && "bg-[url('./avatar.svg')] bg-center bg-no-repeat bg-[length:33%]", | ||
| isScreenshareTile && 'bg-black', |
Comment on lines
+170
to
+176
| export const prettyPeerName = (path: string) => { | ||
| const lastSegment = | ||
| path | ||
| .split('/') | ||
| .at(-1) | ||
| ?.replace(new RegExp(`${SCREENSHARE_PATH_SUFFIX}$`), '') ?? 'peer'; | ||
| const strippedSuffix = lastSegment.replace(/-[a-f0-9]{8}$/i, ''); |
Comment on lines
+8
to
+11
| server: { | ||
| allowedHosts: true, | ||
| port: 5170, | ||
| }, |
Comment on lines
+71
to
+78
| <Button | ||
| variant="outline" | ||
| size="icon" | ||
| title="Copy link" | ||
| onClick={() => { | ||
| navigator.clipboard.writeText(shareUrl); | ||
| toast('Viewer link copied to clipboard', { position: 'top-center', duration: 1500 }); | ||
| }}> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Open source the live translation demo.
The source code will probably be updated in the near future.