@meistrari/chat-nuxt 4.10.0-rc.0 → 4.10.0-rc.10
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/dist/module.json +1 -1
- package/dist/module.mjs +2 -0
- package/dist/runtime/embed/components/chat-embed-inner.d.vue.ts +9 -9
- package/dist/runtime/embed/components/chat-embed-inner.vue +85 -10
- package/dist/runtime/embed/components/chat-embed-inner.vue.d.ts +9 -9
- package/dist/runtime/files/components/{audio-preview.d.vue.ts → chat-file-audio.d.vue.ts} +8 -7
- package/dist/runtime/files/components/chat-file-audio.vue +94 -0
- package/dist/runtime/files/components/{image-preview.d.vue.ts → chat-file-audio.vue.d.ts} +8 -7
- package/dist/runtime/files/components/chat-file-card.d.vue.ts +31 -0
- package/dist/runtime/files/components/chat-file-card.vue +44 -0
- package/dist/runtime/files/components/chat-file-card.vue.d.ts +31 -0
- package/dist/runtime/files/components/chat-file-preview.vue +90 -196
- package/dist/runtime/files/composables/pdf.d.ts +5 -842
- package/dist/runtime/files/content-detection.js +7 -3
- package/dist/runtime/files/formatting.d.ts +1 -0
- package/dist/runtime/files/formatting.js +4 -0
- package/dist/runtime/files/presentation.d.ts +3 -0
- package/dist/runtime/files/presentation.js +24 -0
- package/dist/runtime/messages/answer.d.ts +0 -5
- package/dist/runtime/messages/answer.js +0 -18
- package/dist/runtime/messages/components/chat-answer.vue +4 -3
- package/dist/runtime/messages/components/chat-message-bubble.vue +12 -0
- package/dist/runtime/messages/components/chat-message-input.d.vue.ts +2 -0
- package/dist/runtime/messages/components/chat-message-input.vue +18 -1
- package/dist/runtime/messages/components/chat-message-input.vue.d.ts +2 -0
- package/dist/runtime/messages/components/widgets/chat-thinking-widget.vue +4 -0
- package/dist/runtime/messages/composables/chat.d.ts +15 -0
- package/dist/runtime/messages/composables/chat.js +49 -5
- package/dist/runtime/messages/composables/use-stick-to-bottom.d.ts +5 -0
- package/dist/runtime/messages/composables/use-stick-to-bottom.js +3 -0
- package/dist/runtime/messages/composer-draft.d.ts +16 -0
- package/dist/runtime/messages/composer-draft.js +61 -0
- package/dist/runtime/messages/composer-pending-send.d.ts +8 -0
- package/dist/runtime/messages/composer-pending-send.js +34 -0
- package/dist/runtime/rendering/components/openui/citation.d.vue.ts +9 -0
- package/dist/runtime/rendering/components/openui/citation.vue +13 -0
- package/dist/runtime/rendering/components/openui/citation.vue.d.ts +9 -0
- package/dist/runtime/rendering/components/openui/file-card.d.vue.ts +9 -0
- package/dist/runtime/rendering/components/openui/file-card.vue +15 -0
- package/dist/runtime/rendering/components/openui/file-card.vue.d.ts +9 -0
- package/dist/runtime/rendering/components/openui/image.d.vue.ts +10 -0
- package/dist/runtime/rendering/components/openui/image.vue +40 -0
- package/dist/runtime/rendering/components/openui/image.vue.d.ts +10 -0
- package/dist/runtime/rendering/components/openui/markdown-prose.d.vue.ts +7 -0
- package/dist/runtime/rendering/components/openui/markdown-prose.vue +14 -0
- package/dist/runtime/rendering/components/openui/markdown-prose.vue.d.ts +7 -0
- package/dist/runtime/rendering/components/openui-block.d.vue.ts +12 -0
- package/dist/runtime/rendering/components/openui-block.vue +47 -0
- package/dist/runtime/rendering/components/openui-block.vue.d.ts +12 -0
- package/dist/runtime/rendering/components/openui-reasoning-placeholder.d.vue.ts +3 -0
- package/dist/runtime/rendering/components/openui-reasoning-placeholder.vue +10 -0
- package/dist/runtime/rendering/components/openui-reasoning-placeholder.vue.d.ts +3 -0
- package/dist/runtime/rendering/components/renderers/artifact-display.vue +1 -1
- package/dist/runtime/rendering/openui/context.d.ts +7 -0
- package/dist/runtime/rendering/openui/context.js +2 -0
- package/dist/runtime/rendering/openui/markdown-link.d.ts +2 -0
- package/dist/runtime/rendering/openui/markdown-link.js +5 -0
- package/dist/runtime/rendering/openui/use-widget-prose.d.ts +2 -0
- package/dist/runtime/rendering/openui/use-widget-prose.js +7 -0
- package/dist/runtime/server/utils/chat-api-proxy.js +3 -2
- package/dist/runtime/shared/composables/polling.d.ts +1 -1
- package/dist/runtime/types/schemas/chat/chat-config.d.ts +6 -2
- package/dist/runtime/types/schemas/chat/chat-config.js +1 -0
- package/dist/runtime/types/schemas/chat/conversation-runtime.d.ts +20 -0
- package/dist/runtime/types/schemas/chat/conversations.d.ts +20 -0
- package/dist/runtime/types/schemas/chat/conversations.js +3 -0
- package/dist/runtime/types/schemas/chat/messages.d.ts +30 -0
- package/dist/runtime/types/schemas/chat/ui-language.d.ts +31 -0
- package/dist/runtime/types/schemas/chat/ui-language.js +13 -0
- package/dist/runtime/types/schemas/chat/v3.d.ts +160 -2
- package/dist/runtime/types/schemas/chat/v3.js +91 -5
- package/dist/runtime/types/schemas/integrations/tela-agent-api.d.ts +40 -0
- package/dist/runtime/types/schemas/integrations/tela-agent-api.js +3 -0
- package/package.json +3 -1
- package/dist/runtime/files/components/audio-preview.vue +0 -52
- package/dist/runtime/files/components/audio-preview.vue.d.ts +0 -14
- package/dist/runtime/files/components/csv-preview.d.vue.ts +0 -20
- package/dist/runtime/files/components/csv-preview.vue +0 -157
- package/dist/runtime/files/components/csv-preview.vue.d.ts +0 -20
- package/dist/runtime/files/components/image-preview.vue +0 -54
- package/dist/runtime/files/components/image-preview.vue.d.ts +0 -14
- package/dist/runtime/files/components/pdf-preview.client.d.vue.ts +0 -20
- package/dist/runtime/files/components/pdf-preview.client.vue +0 -90
- package/dist/runtime/files/components/pdf-preview.client.vue.d.ts +0 -20
- package/dist/runtime/files/components/text-preview.d.vue.ts +0 -19
- package/dist/runtime/files/components/text-preview.vue +0 -105
- package/dist/runtime/files/components/text-preview.vue.d.ts +0 -19
- package/dist/runtime/files/components/video-preview.d.vue.ts +0 -14
- package/dist/runtime/files/components/video-preview.vue +0 -55
- package/dist/runtime/files/components/video-preview.vue.d.ts +0 -14
package/dist/module.json
CHANGED
package/dist/module.mjs
CHANGED
|
@@ -2,6 +2,7 @@ import { existsSync, readFileSync, mkdirSync, symlinkSync } from 'node:fs';
|
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { join, dirname, isAbsolute } from 'node:path';
|
|
4
4
|
import { defineNuxtModule, createResolver, addTemplate, addTypeTemplate, addPlugin, addImportsDir, addComponent, addComponentsDir } from 'nuxt/kit';
|
|
5
|
+
import { registerOpenuiWidget } from '@meistrari/chat-ui-lang/nuxt';
|
|
5
6
|
import { TOOL_ICON_SAFELIST } from '../dist/runtime/messages/tool-registry.js';
|
|
6
7
|
export { ChatMessageStatus } from '../dist/runtime/types/message-status.js';
|
|
7
8
|
|
|
@@ -454,6 +455,7 @@ const module$1 = defineNuxtModule({
|
|
|
454
455
|
const runtimeDirRegExp = new RegExp(runtimeDir.replace(/\\/g, "/").replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
|
|
455
456
|
normalizedImports.transform.include.push(runtimeDirRegExp);
|
|
456
457
|
}
|
|
458
|
+
registerOpenuiWidget(nuxt);
|
|
457
459
|
const rc = nuxt.options.runtimeConfig;
|
|
458
460
|
rc.chatApiUrl = options.chatApiUrl || rc.chatApiUrl || process.env.CHAT_API_URL || "";
|
|
459
461
|
rc.public = rc.public || {};
|
|
@@ -19,27 +19,27 @@ type __VLS_Props = {
|
|
|
19
19
|
user?: EmbedUser | null;
|
|
20
20
|
features?: Partial<ChatFeatureConfig>;
|
|
21
21
|
};
|
|
22
|
-
declare var __VLS_14: {}, __VLS_92: {},
|
|
22
|
+
declare var __VLS_14: {}, __VLS_92: {}, __VLS_107: {
|
|
23
23
|
message: useChatAuth;
|
|
24
|
-
},
|
|
24
|
+
}, __VLS_120: {}, __VLS_129: {}, __VLS_193: {}, __VLS_214: {
|
|
25
25
|
message: useChatAuth;
|
|
26
|
-
},
|
|
26
|
+
}, __VLS_227: {};
|
|
27
27
|
type __VLS_Slots = {} & {
|
|
28
28
|
'sidebar-bottom'?: (props: typeof __VLS_14) => any;
|
|
29
29
|
} & {
|
|
30
30
|
'composer-bottom'?: (props: typeof __VLS_92) => any;
|
|
31
31
|
} & {
|
|
32
|
-
'failed-message-actions'?: (props: typeof
|
|
32
|
+
'failed-message-actions'?: (props: typeof __VLS_107) => any;
|
|
33
33
|
} & {
|
|
34
|
-
'composer-bottom'?: (props: typeof
|
|
34
|
+
'composer-bottom'?: (props: typeof __VLS_120) => any;
|
|
35
35
|
} & {
|
|
36
|
-
'topbar-leading'?: (props: typeof
|
|
36
|
+
'topbar-leading'?: (props: typeof __VLS_129) => any;
|
|
37
37
|
} & {
|
|
38
|
-
'composer-bottom'?: (props: typeof
|
|
38
|
+
'composer-bottom'?: (props: typeof __VLS_193) => any;
|
|
39
39
|
} & {
|
|
40
|
-
'failed-message-actions'?: (props: typeof
|
|
40
|
+
'failed-message-actions'?: (props: typeof __VLS_214) => any;
|
|
41
41
|
} & {
|
|
42
|
-
'composer-bottom'?: (props: typeof
|
|
42
|
+
'composer-bottom'?: (props: typeof __VLS_227) => any;
|
|
43
43
|
};
|
|
44
44
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
45
45
|
"update:conversationId": (value: string | null) => any;
|
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
import { inject, provide, useSlots } from "vue";
|
|
3
3
|
import { useChatHarnessAdapter } from "../composables/harness-adapter";
|
|
4
4
|
import ChatMessageList from "../../messages/components/chat-message-list.vue";
|
|
5
|
+
import { shouldScrollOnComposerResize } from "../../messages/composables/use-stick-to-bottom";
|
|
5
6
|
import { CHAT_COMPOSER_EXTENSION_KEY } from "../../types/composer";
|
|
6
7
|
import { CHAT_MESSAGE_SEND_KEY } from "../../types/messages";
|
|
7
8
|
import { useChatAuth } from "#chat-auth";
|
|
8
|
-
import { useBreakpoints } from "@vueuse/core";
|
|
9
|
+
import { useBreakpoints, useResizeObserver } from "@vueuse/core";
|
|
9
10
|
import { useCitationPanel } from "../../citations/composables/citation-panel";
|
|
10
11
|
import { exportConversationToMarkdown } from "../../conversations/export";
|
|
11
12
|
import { CHAT_MOBILE_BREAKPOINT } from "../../shared/breakpoints";
|
|
@@ -14,6 +15,8 @@ import ChatMobileShell from "./mobile/chat-mobile-shell.vue";
|
|
|
14
15
|
import ChatSidebarToggle from "./chat-sidebar-toggle.vue";
|
|
15
16
|
import ChatDetailsPanel from "./chat-details-panel.vue";
|
|
16
17
|
import ChatMessageInput from "../../messages/components/chat-message-input.vue";
|
|
18
|
+
import { confirmPendingComposerSend, prepareComposerSend, reconcileComposerSend } from "../../messages/composer-pending-send";
|
|
19
|
+
import { composerDraftStorageKey, readComposerDraft, writeComposerDraft } from "../../messages/composer-draft";
|
|
17
20
|
import { normalizeConversationId } from "../../conversations/scope";
|
|
18
21
|
import { resolveChatFeatures } from "../feature-config";
|
|
19
22
|
import { resolveConversationCreator } from "../../conversations/creator";
|
|
@@ -175,6 +178,15 @@ provide("chat-answer-target", answerTarget);
|
|
|
175
178
|
function setAnswerTarget(el) {
|
|
176
179
|
answerTarget.value = el instanceof HTMLElement ? el : null;
|
|
177
180
|
}
|
|
181
|
+
const messageListRef = ref(null);
|
|
182
|
+
const composerRef = ref(null);
|
|
183
|
+
let composerHeights = { composer: 0, dock: 0 };
|
|
184
|
+
useResizeObserver(composerRef, ([entry]) => {
|
|
185
|
+
const next = { composer: entry?.contentRect.height ?? 0, dock: answerTarget.value?.offsetHeight ?? 0 };
|
|
186
|
+
if (shouldScrollOnComposerResize(composerHeights, next, Boolean(messageListRef.value?.isPinned)))
|
|
187
|
+
requestAnimationFrame(() => messageListRef.value?.scrollToBottom());
|
|
188
|
+
composerHeights = next;
|
|
189
|
+
});
|
|
178
190
|
const messageInputRef = ref(null);
|
|
179
191
|
const PROMPT_INPUT_HINTS = [
|
|
180
192
|
{ icon: "i-ph-at-bold", label: "Para mencionar arquivos" },
|
|
@@ -192,8 +204,55 @@ const showTopbarSidebarToggle = computed(() => sidebarCollapsible.value && sideb
|
|
|
192
204
|
const slots = useSlots();
|
|
193
205
|
const hasTopbarLeading = computed(() => showTopbarSidebarToggle.value || !!slots["topbar-leading"]);
|
|
194
206
|
const drawerOpen = ref(false);
|
|
207
|
+
function composerKey(conversationId) {
|
|
208
|
+
return composerDraftStorageKey(
|
|
209
|
+
{ userId: authUser.value?.id, workspaceId: activeOrganization.value?.id, telaAgentId: embedConfig?.telaAgentId.value, conversationScope: embedConfig?.conversationScope?.value },
|
|
210
|
+
conversationId
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
const draftStorageKey = computed(() => composerKey(activeConversationId.value));
|
|
214
|
+
let unconfirmedDraft = null;
|
|
215
|
+
function releaseUnconfirmedDraft(draft) {
|
|
216
|
+
if (readComposerDraft(draft.key) === draft.text)
|
|
217
|
+
writeComposerDraft(draft.key, "");
|
|
218
|
+
}
|
|
219
|
+
function confirmComposerDraft(send) {
|
|
220
|
+
confirmPendingComposerSend(composerKey(send.conversationId), send.messageId);
|
|
221
|
+
if (!unconfirmedDraft || unconfirmedDraft.content !== send.content)
|
|
222
|
+
return;
|
|
223
|
+
if (unconfirmedDraft.conversationId !== null && unconfirmedDraft.conversationId !== send.conversationId)
|
|
224
|
+
return;
|
|
225
|
+
releaseUnconfirmedDraft(unconfirmedDraft);
|
|
226
|
+
unconfirmedDraft = null;
|
|
227
|
+
}
|
|
228
|
+
function prepareComposerRequest(send) {
|
|
229
|
+
if (!unconfirmedDraft || unconfirmedDraft.content !== send.body.content)
|
|
230
|
+
return send.body.messageId;
|
|
231
|
+
return prepareComposerSend(unconfirmedDraft.key, unconfirmedDraft.text, send.body);
|
|
232
|
+
}
|
|
233
|
+
function moveUnconfirmedDraft(conversationId) {
|
|
234
|
+
if (!unconfirmedDraft || unconfirmedDraft.conversationId !== null)
|
|
235
|
+
return;
|
|
236
|
+
const key = draftStorageKey.value;
|
|
237
|
+
if (key === unconfirmedDraft.key || !unconfirmedDraft.text) {
|
|
238
|
+
unconfirmedDraft = { ...unconfirmedDraft, key, conversationId };
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
if (!writeComposerDraft(key, unconfirmedDraft.text)) {
|
|
242
|
+
unconfirmedDraft = { ...unconfirmedDraft, conversationId };
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
releaseUnconfirmedDraft(unconfirmedDraft);
|
|
246
|
+
unconfirmedDraft = { ...unconfirmedDraft, key, conversationId };
|
|
247
|
+
}
|
|
195
248
|
function restoreQueuedSend(send) {
|
|
196
|
-
messageInputRef.value
|
|
249
|
+
const input = messageInputRef.value;
|
|
250
|
+
if (!input)
|
|
251
|
+
return;
|
|
252
|
+
input.restoreDraft(send);
|
|
253
|
+
if (unconfirmedDraft && unconfirmedDraft.key !== draftStorageKey.value && readComposerDraft(draftStorageKey.value))
|
|
254
|
+
releaseUnconfirmedDraft(unconfirmedDraft);
|
|
255
|
+
unconfirmedDraft = null;
|
|
197
256
|
}
|
|
198
257
|
const { isDragging, setupDropZone } = useFileDrop({
|
|
199
258
|
onDrop: (files) => {
|
|
@@ -234,7 +293,10 @@ const {
|
|
|
234
293
|
} = createChat({
|
|
235
294
|
outboundQueueEnabled: computed(() => resolvedFeatures.value.chatOutboundQueue),
|
|
236
295
|
onQueuedSendCancelled: restoreQueuedSend,
|
|
237
|
-
onQueuedSendFailed: restoreQueuedSend
|
|
296
|
+
onQueuedSendFailed: restoreQueuedSend,
|
|
297
|
+
onSendConfirmed: confirmComposerDraft,
|
|
298
|
+
onSendPrepared: prepareComposerRequest,
|
|
299
|
+
onMessagesReceived: ({ conversationId, messages: messages2 }) => reconcileComposerSend(composerKey(conversationId), messages2)
|
|
238
300
|
});
|
|
239
301
|
const agentWake = harnessAdapter?.requiresSandboxWake === false ? null : useAgentWake();
|
|
240
302
|
watch(chatError, (message) => {
|
|
@@ -534,6 +596,12 @@ function claimableWakeSessionId() {
|
|
|
534
596
|
async function handleSend(content, files, agentInputs) {
|
|
535
597
|
const prepared = composerExtension?.prepareSend?.(content);
|
|
536
598
|
const outbound = prepared?.content ?? content;
|
|
599
|
+
unconfirmedDraft = {
|
|
600
|
+
key: draftStorageKey.value,
|
|
601
|
+
conversationId: activeConversationId.value,
|
|
602
|
+
content: outbound,
|
|
603
|
+
text: readComposerDraft(draftStorageKey.value)
|
|
604
|
+
};
|
|
537
605
|
const resolvedAgentInputs = resolveTelaAgentInputs(agentInputs, embedConfig?.telaAgentInputs?.value);
|
|
538
606
|
const sent = await dispatchMessage(outbound, files, resolvedAgentInputs);
|
|
539
607
|
if (sent)
|
|
@@ -559,6 +627,7 @@ async function dispatchMessage(outbound, files, resolvedAgentInputs) {
|
|
|
559
627
|
const grouped = groupId && await moveConversationToGroup(conversation2.id, groupId);
|
|
560
628
|
adoptConversation(grouped ? { ...conversation2, groupId } : conversation2);
|
|
561
629
|
updateConversationId(conversation2.id);
|
|
630
|
+
moveUnconfirmedDraft(conversation2.id);
|
|
562
631
|
}
|
|
563
632
|
const conversation = currentConversation.value;
|
|
564
633
|
if (!conversation)
|
|
@@ -826,7 +895,7 @@ async function handleDelete() {
|
|
|
826
895
|
icon="i-ph-arrow-clockwise"
|
|
827
896
|
@click="reconnect"
|
|
828
897
|
>
|
|
829
|
-
Reconectar
|
|
898
|
+
{{ outboundOccupied ? "Reenviar" : "Reconectar" }}
|
|
830
899
|
</TelaButton>
|
|
831
900
|
</div>
|
|
832
901
|
<!-- Sidebar -->
|
|
@@ -1020,7 +1089,8 @@ async function handleDelete() {
|
|
|
1020
1089
|
ref="messageInputRef"
|
|
1021
1090
|
v-model:selected-model="selectedModel"
|
|
1022
1091
|
v-model:selected-reasoning-effort="selectedReasoningEffort"
|
|
1023
|
-
:
|
|
1092
|
+
:draft-storage-key="draftStorageKey"
|
|
1093
|
+
:loading="loading || composerLocked"
|
|
1024
1094
|
:disabled="composerDisabled"
|
|
1025
1095
|
:send-blocked="sendBlocked"
|
|
1026
1096
|
:creator-name="currentUser?.name ?? void 0"
|
|
@@ -1053,6 +1123,7 @@ async function handleDelete() {
|
|
|
1053
1123
|
|
|
1054
1124
|
<ChatMessageList
|
|
1055
1125
|
:key="currentConversation?.id ?? 'draft'"
|
|
1126
|
+
ref="messageListRef"
|
|
1056
1127
|
:messages="messages"
|
|
1057
1128
|
:events="displayConversationEvents"
|
|
1058
1129
|
:streaming-active-message-id="streamingActiveMessageId"
|
|
@@ -1069,14 +1140,15 @@ async function handleDelete() {
|
|
|
1069
1140
|
<slot name="failed-message-actions" v-bind="slotProps" />
|
|
1070
1141
|
</template>
|
|
1071
1142
|
</ChatMessageList>
|
|
1072
|
-
<div data-chat-composer flex="~ col" gap-12px min-h-0>
|
|
1143
|
+
<div ref="composerRef" data-chat-composer flex="~ col" gap-12px min-h-0>
|
|
1073
1144
|
<div :ref="setAnswerTarget" data-chat-answer-dock class="empty:hidden max-h-[50dvh] overflow-y-auto" />
|
|
1074
1145
|
<ChatMessageInput
|
|
1075
1146
|
ref="messageInputRef"
|
|
1076
1147
|
v-model:selected-model="selectedModel"
|
|
1077
1148
|
v-model:selected-reasoning-effort="selectedReasoningEffort"
|
|
1149
|
+
:draft-storage-key="draftStorageKey"
|
|
1078
1150
|
class="!p-0"
|
|
1079
|
-
:loading="composerLocked"
|
|
1151
|
+
:loading="loading || composerLocked"
|
|
1080
1152
|
:disabled="composerDisabled"
|
|
1081
1153
|
:send-blocked="sendBlocked"
|
|
1082
1154
|
:creator-name="currentUser?.name ?? void 0"
|
|
@@ -1230,7 +1302,8 @@ async function handleDelete() {
|
|
|
1230
1302
|
ref="messageInputRef"
|
|
1231
1303
|
v-model:selected-model="selectedModel"
|
|
1232
1304
|
v-model:selected-reasoning-effort="selectedReasoningEffort"
|
|
1233
|
-
:
|
|
1305
|
+
:draft-storage-key="draftStorageKey"
|
|
1306
|
+
:loading="loading || composerLocked"
|
|
1234
1307
|
:disabled="composerDisabled"
|
|
1235
1308
|
:send-blocked="sendBlocked"
|
|
1236
1309
|
:creator-name="currentUser?.name ?? void 0"
|
|
@@ -1266,6 +1339,7 @@ async function handleDelete() {
|
|
|
1266
1339
|
>
|
|
1267
1340
|
<ChatMessageList
|
|
1268
1341
|
:key="currentConversation?.id ?? 'draft'"
|
|
1342
|
+
ref="messageListRef"
|
|
1269
1343
|
:messages="messages"
|
|
1270
1344
|
:events="displayConversationEvents"
|
|
1271
1345
|
:streaming-active-message-id="streamingActiveMessageId"
|
|
@@ -1282,14 +1356,15 @@ async function handleDelete() {
|
|
|
1282
1356
|
<slot name="failed-message-actions" v-bind="slotProps" />
|
|
1283
1357
|
</template>
|
|
1284
1358
|
</ChatMessageList>
|
|
1285
|
-
<div data-chat-composer flex="~ col" gap-12px min-h-0>
|
|
1359
|
+
<div ref="composerRef" data-chat-composer flex="~ col" gap-12px min-h-0>
|
|
1286
1360
|
<div :ref="setAnswerTarget" data-chat-answer-dock class="empty:hidden max-h-[50dvh] overflow-y-auto" />
|
|
1287
1361
|
<ChatMessageInput
|
|
1288
1362
|
ref="messageInputRef"
|
|
1289
1363
|
v-model:selected-model="selectedModel"
|
|
1290
1364
|
v-model:selected-reasoning-effort="selectedReasoningEffort"
|
|
1365
|
+
:draft-storage-key="draftStorageKey"
|
|
1291
1366
|
class="!p-0"
|
|
1292
|
-
:loading="composerLocked"
|
|
1367
|
+
:loading="loading || composerLocked"
|
|
1293
1368
|
:disabled="composerDisabled"
|
|
1294
1369
|
:send-blocked="sendBlocked"
|
|
1295
1370
|
:creator-name="currentUser?.name ?? void 0"
|
|
@@ -19,27 +19,27 @@ type __VLS_Props = {
|
|
|
19
19
|
user?: EmbedUser | null;
|
|
20
20
|
features?: Partial<ChatFeatureConfig>;
|
|
21
21
|
};
|
|
22
|
-
declare var __VLS_14: {}, __VLS_92: {},
|
|
22
|
+
declare var __VLS_14: {}, __VLS_92: {}, __VLS_107: {
|
|
23
23
|
message: useChatAuth;
|
|
24
|
-
},
|
|
24
|
+
}, __VLS_120: {}, __VLS_129: {}, __VLS_193: {}, __VLS_214: {
|
|
25
25
|
message: useChatAuth;
|
|
26
|
-
},
|
|
26
|
+
}, __VLS_227: {};
|
|
27
27
|
type __VLS_Slots = {} & {
|
|
28
28
|
'sidebar-bottom'?: (props: typeof __VLS_14) => any;
|
|
29
29
|
} & {
|
|
30
30
|
'composer-bottom'?: (props: typeof __VLS_92) => any;
|
|
31
31
|
} & {
|
|
32
|
-
'failed-message-actions'?: (props: typeof
|
|
32
|
+
'failed-message-actions'?: (props: typeof __VLS_107) => any;
|
|
33
33
|
} & {
|
|
34
|
-
'composer-bottom'?: (props: typeof
|
|
34
|
+
'composer-bottom'?: (props: typeof __VLS_120) => any;
|
|
35
35
|
} & {
|
|
36
|
-
'topbar-leading'?: (props: typeof
|
|
36
|
+
'topbar-leading'?: (props: typeof __VLS_129) => any;
|
|
37
37
|
} & {
|
|
38
|
-
'composer-bottom'?: (props: typeof
|
|
38
|
+
'composer-bottom'?: (props: typeof __VLS_193) => any;
|
|
39
39
|
} & {
|
|
40
|
-
'failed-message-actions'?: (props: typeof
|
|
40
|
+
'failed-message-actions'?: (props: typeof __VLS_214) => any;
|
|
41
41
|
} & {
|
|
42
|
-
'composer-bottom'?: (props: typeof
|
|
42
|
+
'composer-bottom'?: (props: typeof __VLS_227) => any;
|
|
43
43
|
};
|
|
44
44
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
45
45
|
"update:conversationId": (value: string | null) => any;
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
+
import type { ChatFileMenuItem } from './chat-file-card.vue.js';
|
|
1
2
|
type __VLS_Props = {
|
|
2
|
-
url
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
url?: string;
|
|
4
|
+
iconSrc: string;
|
|
5
|
+
name: string;
|
|
6
|
+
meta: string;
|
|
7
|
+
menuItems: ChatFileMenuItem[];
|
|
5
8
|
};
|
|
6
9
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
7
|
-
|
|
8
|
-
loaded: () => any;
|
|
10
|
+
open: () => any;
|
|
9
11
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
10
|
-
|
|
11
|
-
onLoaded?: (() => any) | undefined;
|
|
12
|
+
onOpen?: (() => any) | undefined;
|
|
12
13
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
13
14
|
declare const _default: typeof __VLS_export;
|
|
14
15
|
export default _default;
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import ChatFileCard from "./chat-file-card.vue";
|
|
3
|
+
import { formatPlaybackTime } from "../formatting";
|
|
4
|
+
const props = defineProps({
|
|
5
|
+
url: { type: String, required: false },
|
|
6
|
+
iconSrc: { type: String, required: true },
|
|
7
|
+
name: { type: String, required: true },
|
|
8
|
+
meta: { type: String, required: true },
|
|
9
|
+
menuItems: { type: Array, required: true }
|
|
10
|
+
});
|
|
11
|
+
const emit = defineEmits(["open"]);
|
|
12
|
+
const player = ref();
|
|
13
|
+
const playing = ref(false);
|
|
14
|
+
const currentTime = ref(0);
|
|
15
|
+
const duration = ref(0);
|
|
16
|
+
const failed = ref(false);
|
|
17
|
+
const progress = computed(() => duration.value > 0 ? currentTime.value / duration.value * 100 : 0);
|
|
18
|
+
function togglePlayback() {
|
|
19
|
+
const audio = player.value;
|
|
20
|
+
if (!audio)
|
|
21
|
+
return;
|
|
22
|
+
if (audio.paused)
|
|
23
|
+
void audio.play();
|
|
24
|
+
else
|
|
25
|
+
audio.pause();
|
|
26
|
+
}
|
|
27
|
+
function seek(event) {
|
|
28
|
+
const audio = player.value;
|
|
29
|
+
if (!audio || duration.value <= 0)
|
|
30
|
+
return;
|
|
31
|
+
audio.currentTime = Number(event.target.value) / 100 * duration.value;
|
|
32
|
+
}
|
|
33
|
+
watch(() => props.url, () => {
|
|
34
|
+
playing.value = false;
|
|
35
|
+
currentTime.value = 0;
|
|
36
|
+
duration.value = 0;
|
|
37
|
+
failed.value = false;
|
|
38
|
+
});
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<template>
|
|
42
|
+
<ChatFileCard
|
|
43
|
+
:icon-src="iconSrc"
|
|
44
|
+
:name="name"
|
|
45
|
+
:meta="failed ? 'Falha ao carregar \xE1udio' : meta"
|
|
46
|
+
:menu-items="menuItems"
|
|
47
|
+
:disabled="!url"
|
|
48
|
+
@open="emit('open')"
|
|
49
|
+
>
|
|
50
|
+
<template #actions>
|
|
51
|
+
<TelaIconButton
|
|
52
|
+
:icon="playing ? 'i-ph-pause-fill' : 'i-ph-play-fill'"
|
|
53
|
+
color="secondary"
|
|
54
|
+
size="xs"
|
|
55
|
+
:aria-label="playing ? 'Pausar \xE1udio' : 'Reproduzir \xE1udio'"
|
|
56
|
+
:disabled="!url || failed"
|
|
57
|
+
@click="togglePlayback"
|
|
58
|
+
/>
|
|
59
|
+
</template>
|
|
60
|
+
<div flex items-center gap-12px px-12px py-10px border-t-0.5px border>
|
|
61
|
+
<input
|
|
62
|
+
type="range"
|
|
63
|
+
min="0"
|
|
64
|
+
max="100"
|
|
65
|
+
step="0.1"
|
|
66
|
+
:value="progress"
|
|
67
|
+
:disabled="!url || failed || duration <= 0"
|
|
68
|
+
aria-label="Posição do áudio"
|
|
69
|
+
flex-1 cursor-pointer text-primary
|
|
70
|
+
class="chat-file-audio__track"
|
|
71
|
+
@input="seek"
|
|
72
|
+
>
|
|
73
|
+
<span body-12-regular text-secondary tabular-nums shrink-0>
|
|
74
|
+
{{ formatPlaybackTime(currentTime) }} / {{ formatPlaybackTime(duration) }}
|
|
75
|
+
</span>
|
|
76
|
+
</div>
|
|
77
|
+
<audio
|
|
78
|
+
v-if="url"
|
|
79
|
+
ref="player"
|
|
80
|
+
:src="url"
|
|
81
|
+
preload="metadata"
|
|
82
|
+
@play="playing = true"
|
|
83
|
+
@pause="playing = false"
|
|
84
|
+
@ended="playing = false"
|
|
85
|
+
@timeupdate="currentTime = player?.currentTime ?? 0"
|
|
86
|
+
@loadedmetadata="duration = player?.duration ?? 0"
|
|
87
|
+
@error="failed = true"
|
|
88
|
+
/>
|
|
89
|
+
</ChatFileCard>
|
|
90
|
+
</template>
|
|
91
|
+
|
|
92
|
+
<style scoped>
|
|
93
|
+
.chat-file-audio__track{accent-color:currentColor;height:4px}
|
|
94
|
+
</style>
|
|
@@ -1,14 +1,15 @@
|
|
|
1
|
+
import type { ChatFileMenuItem } from './chat-file-card.vue.js';
|
|
1
2
|
type __VLS_Props = {
|
|
2
|
-
url
|
|
3
|
-
|
|
4
|
-
|
|
3
|
+
url?: string;
|
|
4
|
+
iconSrc: string;
|
|
5
|
+
name: string;
|
|
6
|
+
meta: string;
|
|
7
|
+
menuItems: ChatFileMenuItem[];
|
|
5
8
|
};
|
|
6
9
|
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
7
|
-
|
|
8
|
-
loaded: () => any;
|
|
10
|
+
open: () => any;
|
|
9
11
|
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
10
|
-
|
|
11
|
-
onLoaded?: (() => any) | undefined;
|
|
12
|
+
onOpen?: (() => any) | undefined;
|
|
12
13
|
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
13
14
|
declare const _default: typeof __VLS_export;
|
|
14
15
|
export default _default;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface ChatFileMenuItem {
|
|
2
|
+
label: string;
|
|
3
|
+
icon: string;
|
|
4
|
+
click: () => void;
|
|
5
|
+
}
|
|
6
|
+
type __VLS_Props = {
|
|
7
|
+
iconSrc: string;
|
|
8
|
+
name: string;
|
|
9
|
+
meta: string;
|
|
10
|
+
menuItems: ChatFileMenuItem[];
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
};
|
|
13
|
+
declare var __VLS_1: {}, __VLS_14: {};
|
|
14
|
+
type __VLS_Slots = {} & {
|
|
15
|
+
actions?: (props: typeof __VLS_1) => any;
|
|
16
|
+
} & {
|
|
17
|
+
default?: (props: typeof __VLS_14) => any;
|
|
18
|
+
};
|
|
19
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
20
|
+
open: () => any;
|
|
21
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
22
|
+
onOpen?: (() => any) | undefined;
|
|
23
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
24
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
25
|
+
declare const _default: typeof __VLS_export;
|
|
26
|
+
export default _default;
|
|
27
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
28
|
+
new (): {
|
|
29
|
+
$slots: S;
|
|
30
|
+
};
|
|
31
|
+
};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
defineProps({
|
|
3
|
+
iconSrc: { type: String, required: true },
|
|
4
|
+
name: { type: String, required: true },
|
|
5
|
+
meta: { type: String, required: true },
|
|
6
|
+
menuItems: { type: Array, required: true },
|
|
7
|
+
disabled: { type: Boolean, required: false }
|
|
8
|
+
});
|
|
9
|
+
const emit = defineEmits(["open"]);
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<template>
|
|
13
|
+
<div w-full max-w-480px rounded-12px border-0.5px border bg overflow-hidden data-chat-file="card">
|
|
14
|
+
<div flex items-center gap-12px p-12px>
|
|
15
|
+
<button
|
|
16
|
+
type="button"
|
|
17
|
+
flex items-center gap-12px flex-1 min-w-0 text-left
|
|
18
|
+
:class="disabled ? 'cursor-default' : 'cursor-pointer'"
|
|
19
|
+
:disabled="disabled"
|
|
20
|
+
:aria-label="`Abrir ${name}`"
|
|
21
|
+
@click="emit('open')"
|
|
22
|
+
>
|
|
23
|
+
<span size-40px rounded-8px bg-subtle flex items-center justify-center shrink-0>
|
|
24
|
+
<img :src="iconSrc" alt="" size-20px>
|
|
25
|
+
</span>
|
|
26
|
+
<span flex flex-col min-w-0>
|
|
27
|
+
<span body-14-medium text-primary truncate :title="name">{{ name }}</span>
|
|
28
|
+
<span body-12-regular text-secondary truncate>{{ meta }}</span>
|
|
29
|
+
</span>
|
|
30
|
+
</button>
|
|
31
|
+
<slot name="actions" />
|
|
32
|
+
<TelaDropdownMenu :items="menuItems" align="end">
|
|
33
|
+
<TelaIconButton
|
|
34
|
+
icon="i-ph-dots-three"
|
|
35
|
+
color="secondary"
|
|
36
|
+
size="3xs"
|
|
37
|
+
aria-label="Ações do arquivo"
|
|
38
|
+
:disabled="disabled"
|
|
39
|
+
/>
|
|
40
|
+
</TelaDropdownMenu>
|
|
41
|
+
</div>
|
|
42
|
+
<slot />
|
|
43
|
+
</div>
|
|
44
|
+
</template>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
export interface ChatFileMenuItem {
|
|
2
|
+
label: string;
|
|
3
|
+
icon: string;
|
|
4
|
+
click: () => void;
|
|
5
|
+
}
|
|
6
|
+
type __VLS_Props = {
|
|
7
|
+
iconSrc: string;
|
|
8
|
+
name: string;
|
|
9
|
+
meta: string;
|
|
10
|
+
menuItems: ChatFileMenuItem[];
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
};
|
|
13
|
+
declare var __VLS_1: {}, __VLS_14: {};
|
|
14
|
+
type __VLS_Slots = {} & {
|
|
15
|
+
actions?: (props: typeof __VLS_1) => any;
|
|
16
|
+
} & {
|
|
17
|
+
default?: (props: typeof __VLS_14) => any;
|
|
18
|
+
};
|
|
19
|
+
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
|
20
|
+
open: () => any;
|
|
21
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
22
|
+
onOpen?: (() => any) | undefined;
|
|
23
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
24
|
+
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
25
|
+
declare const _default: typeof __VLS_export;
|
|
26
|
+
export default _default;
|
|
27
|
+
type __VLS_WithSlots<T, S> = T & {
|
|
28
|
+
new (): {
|
|
29
|
+
$slots: S;
|
|
30
|
+
};
|
|
31
|
+
};
|