Skip to content

Commit 52cdecd

Browse files
committed
update visualizations, update readme
1 parent 7c5eec1 commit 52cdecd

File tree

4 files changed

+141
-7
lines changed

4 files changed

+141
-7
lines changed

README.md

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,6 @@ basic chat: https://flo-bit.dev/svelte-openai-realtime-api/
1212

1313
chat with visualizations: https://flo-bit.dev/svelte-openai-realtime-api/visualizations-chat
1414

15-
visualizations only: https://flo-bit.dev/svelte-openai-realtime-api/visualizations-input
16-
1715

1816
https://github.com/user-attachments/assets/67d94a6c-ee44-4834-a9dd-a628b4a4e093
1917

@@ -36,7 +34,7 @@ $ npm i openai/openai-realtime-api-beta
3634

3735
```svelte
3836
<script lang="ts">
39-
import Realtime from '$lib/realtime/realtime.svelte';
37+
import Realtime from '$lib/realtime/Realtime.svelte';
4038
import type { ItemType } from '@openai/realtime-api-beta/dist/lib/client';
4139
4240
let startConversation: () => Promise<void>;
@@ -75,7 +73,9 @@ see `src/routes/+page.svelte` for a full example.
7573

7674
## visualization
7775

78-
see `src/routes/visulizations-chat/+page.svelte` for an example of how to visualize the audio input and output.
76+
see `src/routes/visulizations-chat/+page.svelte` for an example of how to visualize the audio input and output. and `src/routes/visulizations-input/+page.svelte` for all currently available visualizations.
77+
78+
demo here: https://flo-bit.dev/svelte-openai-realtime-api/visualizations-input
7979

8080
## relay server
8181

@@ -93,6 +93,10 @@ then you have two options:
9393

9494
### run the relay server with your sveltekit server
9595

96+
> [!WARNING]
97+
> this currently only works in development mode, if you want to use this in production you will need to run the relay server independently.
98+
> if you have any ideas on how to make this work in production, please let me know.
99+
96100
change your `vite.config.ts` to this:
97101

98102
```ts

src/lib/realtime/Realtime.svelte

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -131,11 +131,15 @@
131131
realtimeEvents = [];
132132
items = [];
133133
134-
client?.disconnect();
134+
try {
135+
client?.disconnect();
135136
136-
await wavRecorder.end();
137+
await wavRecorder.end();
137138
138-
await wavStreamPlayer.interrupt();
139+
await wavStreamPlayer.interrupt();
140+
} catch (e) {
141+
console.warn(e);
142+
}
139143
}
140144
141145
/**
Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
<script lang="ts">
2+
import { onDestroy, onMount } from 'svelte';
3+
import { WavRecorder, WavStreamPlayer } from '../wavtools';
4+
import { normalizeArray } from './wav_helper';
5+
6+
let isLoaded = false;
7+
8+
const emptyResult = { values: new Float32Array([0]) };
9+
10+
export let wavInput: WavRecorder | WavStreamPlayer;
11+
12+
export let color: string | undefined = '#f59e0b';
13+
export let backgroundColor: string | undefined = '#78350f';
14+
export let accentColor: string | undefined = undefined;
15+
16+
let volume = 0.5;
17+
18+
const render = () => {
19+
if (!isLoaded) return;
20+
21+
let result = emptyResult;
22+
23+
if (wavInput instanceof WavRecorder && wavInput.recording) {
24+
result = wavInput.getFrequencies('voice');
25+
} else if (wavInput instanceof WavStreamPlayer && wavInput.analyser) {
26+
result = wavInput.getFrequencies('voice');
27+
}
28+
29+
const points = normalizeArray(result.values, 1, true);
30+
volume = points[0];
31+
32+
window.requestAnimationFrame(render);
33+
};
34+
35+
onMount(() => {
36+
isLoaded = true;
37+
38+
render();
39+
});
40+
41+
onDestroy(() => {
42+
isLoaded = false;
43+
});
44+
45+
export let icon: 'microphone' | 'speaker' = 'microphone';
46+
</script>
47+
48+
<div class="w-full h-full flex items-center justify-center">
49+
{#if icon === 'microphone'}
50+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor" class="h-full w-full">
51+
<mask id="microphone-mask-vertical">
52+
<!-- Everything under a white pixel will be visible -->
53+
<rect x="0" y="0" width="24" height="24" fill="white" />
54+
55+
<!-- Everything under a black pixel will be invisible -->
56+
<rect x="0" y="0" width="24" height={(1 - volume) * 24} fill="black" />
57+
</mask>
58+
<path
59+
d="M8.25 4.5a3.75 3.75 0 1 1 7.5 0v8.25a3.75 3.75 0 1 1-7.5 0V4.5Z"
60+
fill={backgroundColor ?? color}
61+
/>
62+
<path
63+
mask="url(#microphone-mask-vertical)"
64+
d="M8.25 4.5a3.75 3.75 0 1 1 7.5 0v8.25a3.75 3.75 0 1 1-7.5 0V4.5Z"
65+
fill={accentColor ?? color}
66+
/>
67+
68+
<path
69+
d="M6 10.5a.75.75 0 0 1 .75.75v1.5a5.25 5.25 0 1 0 10.5 0v-1.5a.75.75 0 0 1 1.5 0v1.5a6.751 6.751 0 0 1-6 6.709v2.291h3a.75.75 0 0 1 0 1.5h-7.5a.75.75 0 0 1 0-1.5h3v-2.291a6.751 6.751 0 0 1-6-6.709v-1.5A.75.75 0 0 1 6 10.5Z"
70+
fill={color}
71+
/>
72+
</svg>
73+
{:else}
74+
<svg
75+
width="24"
76+
height="24"
77+
viewBox="0 0 24 24"
78+
fill="none"
79+
xmlns="http://www.w3.org/2000/svg"
80+
class="h-full w-full"
81+
>
82+
<mask id="speaker-mask-horizontal">
83+
<!-- Everything under a white pixel will be visible -->
84+
<rect x="0" y="0" width="24" height="24" fill="white" />
85+
86+
<!-- Everything under a black pixel will be invisible -->
87+
<rect x={12 + volume * 12} y="0" width={12} height={24} fill="black" />
88+
</mask>
89+
90+
<path
91+
d="M13.5 4.06C13.5 2.724 11.884 2.055 10.94 3L6.44 7.5H4.508C3.367 7.5 2.19 8.164 1.848 9.405C1.61598 10.2504 1.49892 11.1233 1.5 12C1.5 12.898 1.621 13.768 1.85 14.595C2.191 15.835 3.368 16.5 4.509 16.5H6.439L10.939 21C11.884 21.945 13.5 21.276 13.5 19.94V4.06Z"
92+
fill={color}
93+
/>
94+
<path
95+
d="M15.932 7.757C16.0017 7.6873 16.0844 7.63202 16.1754 7.5943C16.2664 7.55657 16.364 7.53716 16.4625 7.53716C16.561 7.53716 16.6586 7.55657 16.7496 7.5943C16.8406 7.63202 16.9233 7.6873 16.993 7.757C17.5503 8.31416 17.9923 8.97564 18.2939 9.70366C18.5955 10.4317 18.7507 11.212 18.7507 12C18.7507 12.788 18.5955 13.5683 18.2939 14.2963C17.9923 15.0244 17.5503 15.6858 16.993 16.243C16.8515 16.3796 16.662 16.4551 16.4653 16.4533C16.2687 16.4515 16.0806 16.3725 15.9416 16.2334C15.8026 16.0942 15.7239 15.9061 15.7222 15.7095C15.7206 15.5128 15.7963 15.3234 15.933 15.182C16.3509 14.7641 16.6823 14.2681 16.9085 13.7221C17.1346 13.1761 17.251 12.591 17.251 12C17.251 11.409 17.1346 10.8239 16.9085 10.2779C16.6823 9.73194 16.3509 9.23586 15.933 8.818C15.7925 8.67737 15.7137 8.48675 15.7137 8.288C15.7137 8.08925 15.7925 7.89862 15.933 7.758L15.932 7.757Z"
96+
fill={backgroundColor ?? color}
97+
/>
98+
<path
99+
d="M19.114 4.88666C18.9152 4.88666 18.7246 4.96555 18.584 5.106C18.4435 5.24663 18.3647 5.43725 18.3647 5.636C18.3647 5.83475 18.4435 6.02538 18.584 6.166C19.3502 6.9321 19.958 7.84162 20.3726 8.84262C20.7873 9.84363 21.0007 10.9165 21.0007 12C21.0007 13.0835 20.7873 14.1564 20.3726 15.1574C19.958 16.1584 19.3502 17.0679 18.584 17.834C18.4515 17.9762 18.3794 18.1642 18.3828 18.3585C18.3863 18.5528 18.465 18.7382 18.6024 18.8756C18.7398 19.013 18.9252 19.0917 19.1195 19.0952C19.3138 19.0986 19.5018 19.0265 19.644 18.894C23.452 15.086 23.452 8.913 19.644 5.106C19.5034 4.96555 19.3128 4.88666 19.114 4.88666Z"
100+
fill={backgroundColor ?? color}
101+
/>
102+
103+
<path
104+
d="M15.932 7.757C16.0017 7.6873 16.0844 7.63202 16.1754 7.5943C16.2664 7.55657 16.364 7.53716 16.4625 7.53716C16.561 7.53716 16.6586 7.55657 16.7496 7.5943C16.8406 7.63202 16.9233 7.6873 16.993 7.757C17.5503 8.31416 17.9923 8.97564 18.2939 9.70366C18.5955 10.4317 18.7507 11.212 18.7507 12C18.7507 12.788 18.5955 13.5683 18.2939 14.2963C17.9923 15.0244 17.5503 15.6858 16.993 16.243C16.8515 16.3796 16.662 16.4551 16.4653 16.4533C16.2687 16.4515 16.0806 16.3725 15.9416 16.2334C15.8026 16.0942 15.7239 15.9061 15.7222 15.7095C15.7206 15.5128 15.7963 15.3234 15.933 15.182C16.3509 14.7641 16.6823 14.2681 16.9085 13.7221C17.1346 13.1761 17.251 12.591 17.251 12C17.251 11.409 17.1346 10.8239 16.9085 10.2779C16.6823 9.73194 16.3509 9.23586 15.933 8.818C15.7925 8.67737 15.7137 8.48675 15.7137 8.288C15.7137 8.08925 15.7925 7.89862 15.933 7.758L15.932 7.757Z"
105+
fill={accentColor ?? color}
106+
mask="url(#speaker-mask-horizontal)"
107+
/>
108+
<path
109+
d="M19.114 4.88666C18.9152 4.88666 18.7246 4.96555 18.584 5.106C18.4435 5.24663 18.3647 5.43725 18.3647 5.636C18.3647 5.83475 18.4435 6.02538 18.584 6.166C19.3502 6.9321 19.958 7.84162 20.3726 8.84262C20.7873 9.84363 21.0007 10.9165 21.0007 12C21.0007 13.0835 20.7873 14.1564 20.3726 15.1574C19.958 16.1584 19.3502 17.0679 18.584 17.834C18.4515 17.9762 18.3794 18.1642 18.3828 18.3585C18.3863 18.5528 18.465 18.7382 18.6024 18.8756C18.7398 19.013 18.9252 19.0917 19.1195 19.0952C19.3138 19.0986 19.5018 19.0265 19.644 18.894C23.452 15.086 23.452 8.913 19.644 5.106C19.5034 4.96555 19.3128 4.88666 19.114 4.88666Z"
110+
fill={accentColor ?? color}
111+
mask="url(#speaker-mask-horizontal)"
112+
/>
113+
</svg>
114+
{/if}
115+
</div>

src/routes/visualizations-input/+page.svelte

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import CircleBarVisualizer from '$lib/realtime/visualizations/CircleBarVisualizer.svelte';
44
import CircleCirclesVisualizer from '$lib/realtime/visualizations/CircleCirclesVisualizer.svelte';
55
import DeformedCircleVisualizer from '$lib/realtime/visualizations/DeformedCircleVisualizer.svelte';
6+
import IconVisualizer from '$lib/realtime/visualizations/IconVisualizer.svelte';
67
import InnerGlowVisualizer from '$lib/realtime/visualizations/InnerGlowVisualizer.svelte';
78
import { WavRecorder } from '$lib/realtime/wavtools';
89
@@ -42,5 +43,15 @@
4243
<div class="h-64 w-full rounded-xl border border-white/15 overflow-hidden">
4344
<InnerGlowVisualizer wavInput={wavRecorder} startHue={0} endHue={50} />
4445
</div>
46+
<div
47+
class="h-64 w-full rounded-xl border border-white/15 overflow-hidden flex items-center justify-center gap-4"
48+
>
49+
<div class="size-12">
50+
<IconVisualizer wavInput={wavRecorder} />
51+
</div>
52+
<div class="size-12">
53+
<IconVisualizer wavInput={wavRecorder} icon="speaker" />
54+
</div>
55+
</div>
4556
</div>
4657
</div>

0 commit comments

Comments
 (0)