@myned-ai/avatar-chat-widget 0.4.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -23,8 +23,7 @@ Add directly to any HTML page or website builder:
|
|
|
23
23
|
AvatarChat.init({
|
|
24
24
|
container: '#avatar-chat',
|
|
25
25
|
serverUrl: 'wss://your-backend-server.com/ws',
|
|
26
|
-
position: 'bottom-right'
|
|
27
|
-
theme: 'light'
|
|
26
|
+
position: 'bottom-right'
|
|
28
27
|
});
|
|
29
28
|
</script>
|
|
30
29
|
```
|
|
@@ -63,7 +62,6 @@ chat.destroy(); // Cleanup
|
|
|
63
62
|
| `container` | `string \| HTMLElement` | **required** | CSS selector or DOM element |
|
|
64
63
|
| `serverUrl` | `string` | **required** | WebSocket server URL (ws:// or wss://) |
|
|
65
64
|
| `position` | `string` | `'bottom-right'` | `bottom-right`, `bottom-left`, `top-right`, `top-left`, `inline` |
|
|
66
|
-
| `theme` | `string` | `'light'` | `light`, `dark`, `auto` (follows system preference) |
|
|
67
65
|
| `startCollapsed` | `boolean` | `true` | Start minimized as bubble |
|
|
68
66
|
| `width` | `number` | `380` | Widget width (200-2000px) |
|
|
69
67
|
| `height` | `number` | `550` | Widget height (300-2000px) |
|
|
@@ -1180,6 +1180,10 @@ class AudioInput {
|
|
|
1180
1180
|
// 100ms at 24kHz
|
|
1181
1181
|
async requestPermission() {
|
|
1182
1182
|
try {
|
|
1183
|
+
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
|
|
1184
|
+
log$e.error("MediaDevices API not available. Microphone requires HTTPS.");
|
|
1185
|
+
throw new Error("Microphone requires a secure connection (HTTPS)");
|
|
1186
|
+
}
|
|
1183
1187
|
const stream = await navigator.mediaDevices.getUserMedia({
|
|
1184
1188
|
audio: {
|
|
1185
1189
|
sampleRate: CONFIG.audio.input.sampleRate,
|
|
@@ -1225,6 +1229,9 @@ class AudioInput {
|
|
|
1225
1229
|
*/
|
|
1226
1230
|
async startPCM16Recording(onData) {
|
|
1227
1231
|
try {
|
|
1232
|
+
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
|
|
1233
|
+
throw new Error("Microphone requires a secure connection (HTTPS)");
|
|
1234
|
+
}
|
|
1228
1235
|
this.mediaStream = await navigator.mediaDevices.getUserMedia({
|
|
1229
1236
|
audio: {
|
|
1230
1237
|
channelCount: 1,
|
|
@@ -3551,6 +3558,12 @@ class VoiceInputController {
|
|
|
3551
3558
|
* Start voice recording
|
|
3552
3559
|
*/
|
|
3553
3560
|
async start() {
|
|
3561
|
+
if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
|
|
3562
|
+
const message = "Voice input requires a secure connection (HTTPS). Please use text input instead.";
|
|
3563
|
+
log$5.warn(message);
|
|
3564
|
+
alert(message);
|
|
3565
|
+
return;
|
|
3566
|
+
}
|
|
3554
3567
|
try {
|
|
3555
3568
|
log$5.info("Starting recording (PCM16 24kHz)");
|
|
3556
3569
|
this.protocolClient.sendAudioStreamStart();
|
|
@@ -3569,7 +3582,10 @@ class VoiceInputController {
|
|
|
3569
3582
|
log$5.error("Failed to start recording:", error2);
|
|
3570
3583
|
errorBoundary.handleError(error2, "audio-input");
|
|
3571
3584
|
this.options.onError?.(error2);
|
|
3572
|
-
|
|
3585
|
+
const errorMsg = error2.message || "";
|
|
3586
|
+
if (errorMsg.includes("Permission denied") || errorMsg.includes("NotAllowedError")) {
|
|
3587
|
+
alert("Microphone access was denied. Please allow microphone access in your browser settings to use voice input.");
|
|
3588
|
+
}
|
|
3573
3589
|
}
|
|
3574
3590
|
}
|
|
3575
3591
|
/**
|
|
@@ -3696,7 +3712,6 @@ class ChatManager {
|
|
|
3696
3712
|
await this.protocolClient.connect();
|
|
3697
3713
|
log$4.info("WebSocket connected");
|
|
3698
3714
|
this.avatar.setChatState("Idle");
|
|
3699
|
-
await this.audioInput.requestPermission();
|
|
3700
3715
|
} catch (error2) {
|
|
3701
3716
|
errorBoundary.handleError(error2, "chat-manager");
|
|
3702
3717
|
log$4.error("Connection failed");
|
|
@@ -3788,6 +3803,9 @@ class ChatManager {
|
|
|
3788
3803
|
this.useSyncPlayback = false;
|
|
3789
3804
|
this.subtitleController.showRemaining();
|
|
3790
3805
|
this.transcriptManager.finalizeAssistantTurn();
|
|
3806
|
+
setTimeout(() => {
|
|
3807
|
+
this.subtitleController.clear();
|
|
3808
|
+
}, 1500);
|
|
3791
3809
|
});
|
|
3792
3810
|
}
|
|
3793
3811
|
setupAutoScroll() {
|
|
@@ -4286,8 +4304,10 @@ const WIDGET_STYLES = `
|
|
|
4286
4304
|
@media (max-width: 480px) {
|
|
4287
4305
|
.widget-root {
|
|
4288
4306
|
width: 100vw;
|
|
4289
|
-
height: 100vh;
|
|
4307
|
+
height: 100vh; /* Fallback for older browsers */
|
|
4308
|
+
height: 100dvh; /* Dynamic viewport height - accounts for mobile browser UI */
|
|
4290
4309
|
max-height: 100vh;
|
|
4310
|
+
max-height: 100dvh;
|
|
4291
4311
|
border-radius: 0;
|
|
4292
4312
|
/* Let the mobile media query at the bottom handle the rest */
|
|
4293
4313
|
padding-bottom: 90px; /* Ensure input layer space is preserved */
|
|
@@ -5207,6 +5227,16 @@ const WIDGET_STYLES = `
|
|
|
5207
5227
|
object-fit: cover;
|
|
5208
5228
|
}
|
|
5209
5229
|
|
|
5230
|
+
.avatar-fallback-icon {
|
|
5231
|
+
width: 100%;
|
|
5232
|
+
height: 100%;
|
|
5233
|
+
display: flex;
|
|
5234
|
+
align-items: center;
|
|
5235
|
+
justify-content: center;
|
|
5236
|
+
background: linear-gradient(135deg, #4B4ACF 0%, #2E3A87 100%);
|
|
5237
|
+
color: white;
|
|
5238
|
+
}
|
|
5239
|
+
|
|
5210
5240
|
.bubble-avatar-preview .status-dot {
|
|
5211
5241
|
position: absolute;
|
|
5212
5242
|
bottom: 0;
|
|
@@ -5326,7 +5356,8 @@ const WIDGET_STYLES = `
|
|
|
5326
5356
|
|
|
5327
5357
|
/* Avatar-focus mode on mobile: avatar takes most of the space */
|
|
5328
5358
|
:host(:not(.collapsed)) [data-drawer-state="avatar-focus"] {
|
|
5329
|
-
--avatar-height: calc(100vh - 56px - 90px) !important; /*
|
|
5359
|
+
--avatar-height: calc(100vh - 56px - 90px) !important; /* Fallback */
|
|
5360
|
+
--avatar-height: calc(100dvh - 56px - 90px) !important; /* Full height minus header and input */
|
|
5330
5361
|
background: transparent !important; /* Let avatar stage show through */
|
|
5331
5362
|
}
|
|
5332
5363
|
|
|
@@ -5371,11 +5402,13 @@ const WIDGET_STYLES = `
|
|
|
5371
5402
|
|
|
5372
5403
|
/* Text-focus mode on mobile: chat takes most of the space, avatar in corner */
|
|
5373
5404
|
:host(:not(.collapsed)) [data-drawer-state="text-focus"] {
|
|
5374
|
-
--chat-height: calc(100vh - 70px - 90px) !important; /*
|
|
5405
|
+
--chat-height: calc(100vh - 70px - 90px) !important; /* Fallback */
|
|
5406
|
+
--chat-height: calc(100dvh - 70px - 90px) !important; /* Full height minus header and input */
|
|
5375
5407
|
}
|
|
5376
5408
|
|
|
5377
5409
|
:host(:not(.collapsed)) [data-drawer-state="text-focus"] .chat-section {
|
|
5378
|
-
height: calc(100vh - 70px - 90px) !important;
|
|
5410
|
+
height: calc(100vh - 70px - 90px) !important; /* Fallback */
|
|
5411
|
+
height: calc(100dvh - 70px - 90px) !important;
|
|
5379
5412
|
flex: 1;
|
|
5380
5413
|
}
|
|
5381
5414
|
|
|
@@ -5424,14 +5457,14 @@ const WIDGET_STYLES = `
|
|
|
5424
5457
|
bottom: 110px; /* Similar position to subtitles, above input */
|
|
5425
5458
|
width: 95%;
|
|
5426
5459
|
max-width: none;
|
|
5427
|
-
gap:
|
|
5428
|
-
padding:
|
|
5460
|
+
gap: 6px;
|
|
5461
|
+
padding: 4px;
|
|
5429
5462
|
}
|
|
5430
5463
|
|
|
5431
5464
|
:host(:not(.collapsed)) [data-drawer-state="avatar-focus"] .avatar-suggestions .suggestion-chip {
|
|
5432
|
-
padding: 12px
|
|
5433
|
-
font-size:
|
|
5434
|
-
border-radius:
|
|
5465
|
+
padding: 8px 12px;
|
|
5466
|
+
font-size: 13px;
|
|
5467
|
+
border-radius: 16px;
|
|
5435
5468
|
}
|
|
5436
5469
|
|
|
5437
5470
|
/* Mist overlay on mobile - covers lower portion without reaching avatar's face */
|
|
@@ -5699,7 +5732,13 @@ const BUBBLE_TEMPLATE = `
|
|
|
5699
5732
|
</div>
|
|
5700
5733
|
<div class="chat-bubble" id="chatBubble" role="button" aria-label="Open chat" tabindex="0">
|
|
5701
5734
|
<div class="bubble-avatar-preview">
|
|
5702
|
-
<img src="./asset/avatar.gif" class="avatar-face-img" alt="Nyx Avatar" />
|
|
5735
|
+
<img src="./asset/avatar.gif" class="avatar-face-img" alt="Nyx Avatar" onerror="this.style.display='none';this.nextElementSibling.style.display='flex';" />
|
|
5736
|
+
<div class="avatar-fallback-icon" style="display:none;">
|
|
5737
|
+
<svg width="32" height="32" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
5738
|
+
<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"></path>
|
|
5739
|
+
<circle cx="12" cy="7" r="4"></circle>
|
|
5740
|
+
</svg>
|
|
5741
|
+
</div>
|
|
5703
5742
|
<div class="status-dot"></div>
|
|
5704
5743
|
</div>
|
|
5705
5744
|
</div>
|