Message Attachments

Message Attachments

Overview

This functionality allows users to upload and attach files to chat to get more accurate answers based on the content of the file. The AI can analyze text documents, images, tables, and other formats supported by the platform.

To enable message attachments, pass the enableFileAttachments through the props.

<ChatPage
  enableFileAttachments={true}
  // ...other props
/>

Structure

User message content with attachments are of type: MessageUserContent.

For any attachment types, you can pass data in two ways, via url: string or file: File.

⚠️
If you pass both file and url, file will take priority.
const messages = [{
    id: '1',
    role: 'user',
    content: [{
      type: 'text',
      text: "Describe the files I sent you"
    },
    {
      id: '1',
      type: 'image',
      url: 'your_image_link', // image source
    },
    {
      id: '2',
      type: 'video',
      url: 'your_video_link', // video source
    },
    {
      id: '3',
      type: 'file',
      file: new File(["sample text"], "example.txt", { type: "text/plain" }), // file
    }],
}];

Capabilities

Attach Files

You can pre-load a file on your server to improve the performance of sending a message by passing the onFileAttached method through the props. This feature allows you to retrieve and process the file as you see fit for future use. Please refer to the FileAttachedParams page for more details about parameters.

onFileAttached - Callback function that is triggered when a user attaches a file in the chat interface. This function receives an object with parameters describing the file and a method to update the upload progress. You can use this callback to handle file uploads, simulate progress, handling errors in interface, or perform validation.

Collapse code
Expand code
const onFileAttached = async ({ actions }: FileAttachedParams) => {
  const { setProgress } = actions;

  await fileUploadMock(setProgress);
};
import * as React from "react";
import {
  ChatPage,
  useAssistantAnswerMock,
  Thread,
  FileAttachedParams,
} from "@plteam/chat-ui";
import Box from "@mui/material/Box";

const App: React.FC = () => {
  const [threads] = React.useState<Thread[]>(
    [
      {
        id: "1",
        title: "Attachment Progress",
        messages: [
          {
            id: '1',
            content: 'Hello! May I send files in this chat?',
            role: "user",
          },
          {
            id: '2',
            content: "Hello, yes, you can send files in this chat, and you can also monitor the process of uploading them to the server.",
            role: "assistant",
          },
        ],
        "date": "2024-11-16 08:07:54"
      }
    ]
  );

  const { onUserMessageSent, handleStopMessageStreaming } =
    useAssistantAnswerMock();

  const fileUploadMock = async (callback: (num: number) => void) => {
    for (let i = 0; i < 100; i += 10) {
      await new Promise(resolve => setTimeout(resolve, 500));
      callback(i);
    }
  };

  const onFileAttached = async ({ actions }: FileAttachedParams) => {
    const { setProgress } = actions;

    await fileUploadMock(setProgress);
  };

  return (
    <Box height="100dvh" width="100dvw">
      <ChatPage
        enableFileAttachments
        initialThread={threads[0]}
        threads={threads}
        handleStopMessageStreaming={handleStopMessageStreaming}
        onUserMessageSent={onUserMessageSent}
        onFileAttached={onFileAttached}
      />
    </Box>
  );
}

export default App;

If you want to send a message regardless of whether the file has been uploaded to the server or not, you can use onFinish from FileAttachedParams to prematurely end or skip the upload process in the chat interface.

const onFileAttached = async ({ file, actions }: FileAttachedParams) => {
  const { onFinish } = actions;

  // finishes loading in the interface
  onFinish();

  // file upload on server
  await fileUploadMock(file);
}

If you encounter an error while uploading a file and want to display it in the interface, you need to use setError from FileAttachedParams.

ℹ️
Files with errors will be displayed in the interface but will not be taken into account when sending messages.
Collapse code
Expand code
const onFileAttached = ({ actions }: FileAttachedParams) => {
  const { setError } = actions;

  try {
    await fileUploadMock();
  } catch {
    setError('Server error');
  }
};
import * as React from "react";
import {
  ChatPage,
  useAssistantAnswerMock,
  Thread,
} from "@plteam/chat-ui";
import Box from "@mui/material/Box";
import { FileAttachedParams } from "../../../packages/chat-ui/src/models/FileAttachedParams";

const App: React.FC = () => {
  const [threads] = React.useState<Thread[]>(
    [
      {
        id: "1",
        title: "Attachment Error",
        messages: [
          {
            id: '1',
            content: 'Hello! May I send files in this chat?',
            role: 'user',
          },
          {
            id: '2',
            content: "Hello, you can try, but you will get an error now.",
            role: "assistant",
          },
        ],
        "date": "2024-11-16 08:07:54"
      }
    ]
  );

  const { onUserMessageSent, handleStopMessageStreaming } =
    useAssistantAnswerMock();

  const fileUploadMock = async () => {
    await new Promise((_resolve, reject) => setTimeout(reject, 500));
  };

  const onFileAttached = ({ actions }: FileAttachedParams) => {
    const { setError } = actions;

    try {
      // file upload on server
      await fileUploadMock();
    } catch {
      // set error text in interface
      setError('Server error');
    }
  };

  return (
    <Box height="100dvh" width="100dvw">
      <ChatPage
        enableFileAttachments
        initialThread={threads[0]}
        threads={threads}
        handleStopMessageStreaming={handleStopMessageStreaming}
        onUserMessageSent={onUserMessageSent}
        onFileAttached={onFileAttached}
      />
    </Box>
  );
}

export default App;

Remove Files

If you need to keep track of files that are deleted before a chat message is sent, you can use the onFileDetached method. This feature can be used to clean up resources. It allows you to clean up any temporary storage, server database, UI references, or metadata associated with the deleted file.

onFileDetached - Callback function that is triggered when a user removes (detaches) a file from the chat input before sending the message.

const onFileDetached = async (fileId: string | number) => {
  // delete file from server
  await fileDeleteMock(fileId);
};

Restrictions

You can further control and filter which files can be uploaded to the interface. Various options are presented below.

Collapse code
Expand code
<ChatPage
  enableFileAttachments
  initialThread={threads[0]}
  threads={threads}
  handleStopMessageStreaming={handleStopMessageStreaming}
  acceptableFileFormat={['.png', '.jpg']}
  maxFileCount={3}
  maxFileSize={10 * 1024 * 1024}
  onUserMessageSent={onUserMessageSent}
/>
import * as React from "react";
import {
  ChatPage,
  useAssistantAnswerMock,
  Thread,
} from "@plteam/chat-ui";
import Box from "@mui/material/Box";

const App: React.FC = () => {
  const [threads] = React.useState<Thread[]>(
    [
      {
        id: "1",
        title: "Attachment Restriction",
        messages: [
          {
            id: '1',
            content: 'What are the restrictions on sending files to this chat?',
            role: "user",
          },
          {
            id: '2',
            content: `The following restrictions apply in this chat:
- Maximum number of files in one message: 3

- The size of a single file cannot exceed 10 MB

- Allowed file types: \`.png\`, \`.jpg\``,
            role: "assistant",
          },
        ],
        "date": "2024-11-16 08:07:54"
      }
    ]
  );

  const { onUserMessageSent, handleStopMessageStreaming } =
    useAssistantAnswerMock();

  return (
    <Box height="100dvh" width="100dvw">
      <ChatPage
        enableFileAttachments
        initialThread={threads[0]}
        threads={threads}
        handleStopMessageStreaming={handleStopMessageStreaming}
        acceptableFileFormat={['.png', '.jpg']}
        maxFileCount={3}
        maxFileSize={10 * 1024 * 1024}
        onUserMessageSent={onUserMessageSent}
      />
    </Box>
  );
}

export default App;

Format

You can control the file formats that can be attached to a message using the acceptableFileFormat variable in chat props.

acceptableFileFormat - Specifies the acceptable file types that users are allowed to attach. This can be a single MIME type, an array of MIME types, or file extensions.

By default, there are no restrictions ('*').

<ChatPage
  enableFileAttachments={true}
  acceptableFileFormat='*'
  // ...other props
/>

Size

You can limit the maximum file size that can be transferred via the interface using the maxFileSize variable in chat props.

maxFileSize - Maximum file size in bytes.

The default limit is 20 MB.

<ChatPage
  enableFileAttachments={true}
  maxFileSize={20 * 1024 * 1024} // 20 MB
  // ...other props
/>

Count

You can limit the number of files that can be attached to a single message using the maxFileCount variable in chat props.

maxFileCount - Specifies the maximum number of files.

By default, you can send a maximum of 10 files in a single message.

<ChatPage
  enableFileAttachments={true}
  maxFileCount={10}
  // ...other props
/>

Branching

If the Branching fiche is active you can also delete files in the message editor.

Example

Collapse code
Expand code
<ChatPage
  enableFileAttachments
  enableBranches
  initialThread={threads[0]}
  threads={threads}
  handleStopMessageStreaming={handleStopMessageStreaming}
  onUserMessageSent={onUserMessageSent}
/>
import * as React from "react";
import {
  ChatPage,
  useAssistantAnswerMock,
  Thread,
} from "@plteam/chat-ui";
import Box from "@mui/material/Box";

const text = `
Both images feature anthropomorphic cats.

The first image shows a fluffy white cat with light blue eyes sitting amidst a bed of roses and other flowers, some in shades of purple and pink. To the right of the cat, there's a glass of what appears to be champagne or a similar sparkling beverage, and behind it, a bottle. The background is a vibrant pink and purple, with what looks like floating bubbles or orbs. The cat has a somewhat serious or inquisitive expression.

The second image depicts a fluffy gray cat dressed in a dark green jacket and a brown bow tie, holding a violin as if playing it. The cat has yellow eyes. It is seated at a wooden table next to a lit candle in a glass pitcher, a silver chalice-like object, and an open book. There's also a slice of lime on the table. The background is dark and moody, with a hint of smoke or mist rising from behind the candle.
`;

const App: React.FC = () => {
  const [threads] = React.useState<Thread[]>(
    [
      {
        id: "1",
        title: "Attachment",
        messages: [
          {
            id: '1',
            content: [
              {
                type: 'text',
                text: "Describe what you see in the images",
              },
              {
                id: '1',
                type: 'image',
                url: 'https://examples.cuikit.com/files/exampleImage1.jpg',
              },
              {
                id: '2',
                type: 'image',
                url: 'https://examples.cuikit.com/files/exampleImage2.jpg',
              },
            ],
            role: "user",
          },
          {
            id: '2',
            parentId: '1',
            content: text,
            role: "assistant",
          },
          {
            id: '3',
            parentId: '2',
            content: [
              {
                type: 'text',
                text: "What does this file contain?",
              },
              {
                id: '1',
                type: 'file',
                url: 'https://examples.cuikit.com/files/exampleText.txt',
              },
            ],
            role: "user",
          },
          {
            id: '4',
            parentId: '3',
            content: `The file contains the text "Hello world".`,
            role: "assistant",
          },
        ],
        "date": "2024-11-16 08:07:54"
      }
    ]
  );

  const { onUserMessageSent, handleStopMessageStreaming } =
    useAssistantAnswerMock();

  return (
    <Box height="100dvh" width="100dvw">
      <ChatPage
        enableFileAttachments
        enableBranches
        initialThread={threads[0]}
        threads={threads}
        handleStopMessageStreaming={handleStopMessageStreaming}
        onUserMessageSent={onUserMessageSent}
      />
    </Box>
  );
}

export default App;