Skip to content

Feat ai images #61

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 8 commits into
base: main
Choose a base branch
from
8 changes: 7 additions & 1 deletion src/components/Chat/Chat.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, memo } from 'react';
import React, { useEffect, memo, useState } from 'react';
import cx from 'classnames';
import {
DialogState,
Expand Down Expand Up @@ -126,6 +126,8 @@ const Chat: React.FC<Props> = ({
experts,
useMathFormatting = false,
}) => {

const [previewFiles, setPreviewFiles] = useState<{ name: string; id: string; content: string; mediumID: string | undefined }[]>([]);
const scrollToBottom = () => {
setTimeout(() => {
let userMsgs = document.querySelectorAll(
Expand Down Expand Up @@ -230,6 +232,7 @@ const Chat: React.FC<Props> = ({
experts={experts}
showCopyButton={showCopyButton}
useMathFormatting={useMathFormatting}
previewFiles={previewFiles}
/>

{showDates && !!message.timestamp && (
Expand Down Expand Up @@ -340,6 +343,7 @@ const Chat: React.FC<Props> = ({

{showInputs && (
<ChatInputs
apiURL={apiUrl || ''}
resetTranscript={resetTranscript}
userMessage={userMessage}
onChangeUserMessage={onChangeUserMessage}
Expand All @@ -350,6 +354,7 @@ const Chat: React.FC<Props> = ({
microphoneMode={microphoneMode}
sendOnEnter={sendOnEnter}
setSendOnEnter={setSendOnEnter}
sessionID={sessionID}
showUpload={showUpload}
attachmentsMenuOpen={attachmentsMenuOpen}
setAttachmentsMenuOpen={setAttachmentsMenuOpen}
Expand All @@ -361,6 +366,7 @@ const Chat: React.FC<Props> = ({
listening={listening}
isPlayingAudio={isPlayingAudio}
showMicrophone={showMicrophone}
setPreviewFiles={setPreviewFiles}
/>
)}
</div>
Expand Down
11 changes: 5 additions & 6 deletions src/components/ChatBubble/ChatBubble.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import { stripHTML, stripOutputTags } from '../../helpers/utils';
import FilePreview from '../FilePreview/FilePreview';
import { renderMsg, truncateMessage } from '../../helpers/message';
import Expandable from '../ui/Expandable';

// Always import and load MathJax
import { installMathJax } from '../../helpers/utils';

Expand Down Expand Up @@ -56,6 +55,7 @@ export interface Props {
userAvatar?: MemoriProps['userAvatar'];
user?: User;
experts?: ExpertReference[];
previewFiles?: { name: string; id: string; content: string; mediumID: string | undefined }[];
}

const ChatBubble: React.FC<Props> = ({
Expand All @@ -76,6 +76,7 @@ const ChatBubble: React.FC<Props> = ({
user,
userAvatar,
experts,
previewFiles,
}) => {
const { t, i18n } = useTranslation();
const lang = i18n.language || 'en';
Expand Down Expand Up @@ -121,6 +122,8 @@ const ChatBubble: React.FC<Props> = ({
}
}, [message.text, message.fromUser, renderedText]);

console.log('previewFiles', previewFiles);

return (
<>
{(message.initial || isFirst) && (
Expand Down Expand Up @@ -361,11 +364,7 @@ const ChatBubble: React.FC<Props> = ({
message.media?.length > 0 &&
message.media[0].properties?.isAttachedFile && (
<FilePreview
previewFiles={message.media.map(m => ({
name: m.title ?? '',
id: m.mediumID,
content: m.content ?? '',
}))}
previewFiles={previewFiles}
removeFile={() => {}}
allowRemove={false}
isMessagePreview={true}
Expand Down
6 changes: 6 additions & 0 deletions src/components/ChatInputs/ChatInputs.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ it('renders ChatInputs unchanged', () => {
stopListening={jest.fn()}
resetTranscript={jest.fn()}
showMicrophone={true}
setPreviewFiles={jest.fn()}
/>
);
expect(container).toMatchSnapshot();
Expand All @@ -44,6 +45,7 @@ it('renders ChatInputs with user message unchanged', () => {
stopListening={jest.fn()}
resetTranscript={jest.fn()}
showMicrophone={true}
setPreviewFiles={jest.fn()}
/>
);
expect(container).toMatchSnapshot();
Expand Down Expand Up @@ -71,6 +73,7 @@ it('renders ChatInputs on instruct unchanged', () => {
stopListening={jest.fn()}
resetTranscript={jest.fn()}
showMicrophone={true}
setPreviewFiles={jest.fn()}
/>
);
expect(container).toMatchSnapshot();
Expand All @@ -94,6 +97,7 @@ it('renders ChatInputs listening unchanged', () => {
stopListening={jest.fn()}
resetTranscript={jest.fn()}
showMicrophone={true}
setPreviewFiles={jest.fn()}
/>
);
expect(container).toMatchSnapshot();
Expand All @@ -117,6 +121,7 @@ it('renders ChatInputs without microphone button unchanged', () => {
stopListening={jest.fn()}
resetTranscript={jest.fn()}
showMicrophone={false}
setPreviewFiles={jest.fn()}
/>
);
expect(container).toMatchSnapshot();
Expand All @@ -143,6 +148,7 @@ it('renders ChatInputs disabled unchanged', () => {
stopListening={jest.fn()}
resetTranscript={jest.fn()}
showMicrophone={true}
setPreviewFiles={jest.fn()}
/>
);
expect(container).toMatchSnapshot();
Expand Down
68 changes: 51 additions & 17 deletions src/components/ChatInputs/ChatInputs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import cx from 'classnames';
import Microphone from '../icons/Microphone';
import UploadButton from '../UploadButton/UploadButton';
import FilePreview from '../FilePreview/FilePreview';

import memoriApiClient from '@memori.ai/memori-api-client';
export interface Props {
dialogState?: DialogState;
instruct?: boolean;
Expand Down Expand Up @@ -41,6 +41,9 @@ export interface Props {
microphoneMode?: 'CONTINUOUS' | 'HOLD_TO_TALK';
authToken?: string;
showUpload?: boolean;
sessionID?: string;
apiURL?: string;
setPreviewFiles: (files: { name: string; id: string; content: string; mediumID: string | undefined }[]) => void;
}

const ChatInputs: React.FC<Props> = ({
Expand All @@ -52,33 +55,45 @@ const ChatInputs: React.FC<Props> = ({
onTextareaFocus,
onTextareaBlur,
resetTranscript,
setPreviewFiles,
showMicrophone = false,
microphoneMode = 'HOLD_TO_TALK',
listening = false,
stopAudio,
startListening,
stopListening,
showUpload = false,
sessionID,
authToken,
apiURL,
}) => {
const { t } = useTranslation();

// State for file preview list
const [previewFiles, setPreviewFiles] = useState<
{ name: string; id: string; content: string }[]
// State for document preview files
const [documentPreviewFiles, setDocumentPreviewFiles] = useState<
{ name: string; id: string; content: string; mediumID: string | undefined }[]
>([]);

// Client
const client = apiURL ? memoriApiClient(apiURL) : null;
const { dialog } = client || {
dialog: { postMediumDeselectedEvent: null },
};

/**
* Handles sending a message, including any attached files
*/
const onSendMessage = () => {
const fileToSend = documentPreviewFiles.find(file => !file.mediumID);
setPreviewFiles(documentPreviewFiles);
sendMessage(
userMessage,
previewFiles[0]
fileToSend
? {
mediumID: '',
mimeType: 'text/plain',
content: previewFiles[0].content,
title: previewFiles[0].name,
content: fileToSend.content,
title: fileToSend.name,
properties: {
isAttachedFile: true,
},
Expand All @@ -87,7 +102,7 @@ const ChatInputs: React.FC<Props> = ({
);

// Reset states after sending
setPreviewFiles([]);
setDocumentPreviewFiles([]);
stopAudio();
speechSynthesis.speak(new SpeechSynthesisUtterance(''));
};
Expand All @@ -100,20 +115,20 @@ const ChatInputs: React.FC<Props> = ({
stopListening();
sendMessage(
userMessage,
previewFiles[0]
documentPreviewFiles[0]
? {
mediumID: '',
mimeType: 'text/plain',
content: previewFiles[0].content,
title: previewFiles[0].name,
content: documentPreviewFiles[0].content,
title: documentPreviewFiles[0].name,
properties: {
isAttachedFile: true,
},
}
: undefined
);

setPreviewFiles([]);
setDocumentPreviewFiles([]);
onChangeUserMessage('');
resetTranscript();
}
Expand All @@ -122,9 +137,15 @@ const ChatInputs: React.FC<Props> = ({
/**
* Removes a file from the preview list
*/
const removeFile = (fileId: string) => {
setPreviewFiles((prev: { name: string; id: string; content: string }[]) =>
prev.filter((file: { id: string }) => file.id !== fileId)
const removeFile = async (fileId: string, mediumID: string | undefined) => {
console.log('removeFile', fileId);
// Call the MediumDeselected event if dialog API is available
if (dialog.postMediumDeselectedEvent && sessionID && mediumID) {
await dialog.postMediumDeselectedEvent(sessionID, mediumID);
}
setDocumentPreviewFiles(
(prev: { name: string; id: string; content: string; mediumID: string | undefined }[]) =>
prev.filter((file: { id: string }) => file.id !== fileId)
);
};

Expand All @@ -144,10 +165,23 @@ const ChatInputs: React.FC<Props> = ({
dialogState?.state || ''
)}
/>
{/* Preview for document files */}
{showUpload && (
<>
<FilePreview previewFiles={previewFiles} removeFile={removeFile} />
<UploadButton setPreviewFiles={setPreviewFiles} />
<FilePreview
previewFiles={documentPreviewFiles}
removeFile={removeFile}
/>

{/* Replace the individual buttons with our unified upload component */}
<UploadButton
authToken={authToken}
apiUrl={apiURL}
sessionID={sessionID}
isMediaAccepted={dialogState?.acceptsMedia || false}
setDocumentPreviewFiles={setDocumentPreviewFiles}
documentPreviewFiles={documentPreviewFiles}
/>
</>
)}
<Button
Expand Down
Loading