wuyiqunLu commited on
Commit
3a22cf3
β€’
1 Parent(s): 5d7d435

feat: adjust image to use next/image (#20)

Browse files

Ignore the image size from the video, it was using the unoptimized
property which renders the origin image


https://github.com/landing-ai/vision-agent-ui/assets/132986242/e90977b6-4ced-4ee7-bf02-df599e506631

<img width="970" alt="image"
src="https://github.com/landing-ai/vision-agent-ui/assets/132986242/531e5d7e-dca1-4f74-ad2c-8e60cdf1b178">

<img width="903" alt="image"
src="https://github.com/landing-ai/vision-agent-ui/assets/132986242/49456cf1-efc2-4383-a12b-7cd156caa660">

components/chat-sidebar/ChatCard.tsx CHANGED
@@ -44,7 +44,7 @@ const ChatCard: React.FC<ChatCardProps> = ({ chat }) => {
44
  classNames={chatIdFromParam === id && 'border-gray-500'}
45
  >
46
  <div className="overflow-hidden flex items-center size-full">
47
- <Img src={url} className="w-1/4 " />
48
  <div className="flex items-start h-full">
49
  <p className="text-sm w-3/4 ml-3">{title}</p>
50
  </div>
 
44
  classNames={chatIdFromParam === id && 'border-gray-500'}
45
  >
46
  <div className="overflow-hidden flex items-center size-full">
47
+ <Img src={url} alt={`chat-${id}-card-image`} className="w-1/4 " />
48
  <div className="flex items-start h-full">
49
  <p className="text-sm w-3/4 ml-3">{title}</p>
50
  </div>
components/chat/ChatList.tsx CHANGED
@@ -10,7 +10,7 @@ export interface ChatList {
10
 
11
  export function ChatList({ messages }: ChatList) {
12
  return (
13
- <div className="relative mx-auto max-w-5xl px-8 pr-12">
14
  {messages
15
  // .filter(message => message.role !== 'system')
16
  .map((message, index) => (
 
10
 
11
  export function ChatList({ messages }: ChatList) {
12
  return (
13
+ <div className="relative mx-auto max-w-5xl px-8 pr-12 pb-[100px]">
14
  {messages
15
  // .filter(message => message.role !== 'system')
16
  .map((message, index) => (
components/chat/ChatMessage.tsx CHANGED
@@ -11,6 +11,7 @@ import { IconOpenAI, IconUser } from '@/components/ui/Icons';
11
  import { ChatMessageActions } from '@/components/chat/ChatMessageActions';
12
  import { MessageBase } from '../../lib/types';
13
  import { useCleanedUpMessages } from '@/lib/hooks/useCleanedUpMessages';
 
14
 
15
  export interface ChatMessageProps {
16
  message: MessageBase;
@@ -60,11 +61,32 @@ export function ChatMessage({ message, ...props }: ChatMessageProps) {
60
  className="break-words"
61
  remarkPlugins={[remarkGfm, remarkMath]}
62
  components={{
63
- p({ children }) {
 
 
 
 
 
 
 
 
 
64
  return (
65
  <p className="my-2 last:mb-0 whitespace-pre-line">{children}</p>
66
  );
67
  },
 
 
 
 
 
 
 
 
 
 
 
 
68
  code({ node, inline, className, children, ...props }) {
69
  if (children.length) {
70
  if (children[0] == '▍') {
 
11
  import { ChatMessageActions } from '@/components/chat/ChatMessageActions';
12
  import { MessageBase } from '../../lib/types';
13
  import { useCleanedUpMessages } from '@/lib/hooks/useCleanedUpMessages';
14
+ import Img from '../ui/Img';
15
 
16
  export interface ChatMessageProps {
17
  message: MessageBase;
 
61
  className="break-words"
62
  remarkPlugins={[remarkGfm, remarkMath]}
63
  components={{
64
+ p({ children, ...props }) {
65
+ if (
66
+ props.node.children.some(
67
+ child => child.type === 'element' && child.tagName === 'img',
68
+ )
69
+ ) {
70
+ return (
71
+ <p className="flex flex-wrap gap-2 items-start">{children}</p>
72
+ );
73
+ }
74
  return (
75
  <p className="my-2 last:mb-0 whitespace-pre-line">{children}</p>
76
  );
77
  },
78
+ img(props) {
79
+ return (
80
+ <Img
81
+ src={props.src ?? '/landing.png'}
82
+ alt={props.alt ?? 'answer-image'}
83
+ quality={100}
84
+ sizes="(min-width: 66em) 40vw,
85
+ (min-width: 44em) 66vw,
86
+ 100vw"
87
+ />
88
+ );
89
+ },
90
  code({ node, inline, className, children, ...props }) {
91
  if (children.length) {
92
  if (children[0] == '▍') {
components/chat/PromptForm.tsx CHANGED
@@ -60,10 +60,14 @@ export function PromptForm({
60
  {url && (
61
  <Tooltip>
62
  <TooltipTrigger asChild>
63
- <Img src={url} className="w-1/5 my-4 mx-2 cursor-zoom-in" />
 
 
 
 
64
  </TooltipTrigger>
65
  <TooltipContent>
66
- <Img src={url} className="m-2" />
67
  </TooltipContent>
68
  </Tooltip>
69
  )}
 
60
  {url && (
61
  <Tooltip>
62
  <TooltipTrigger asChild>
63
+ <Img
64
+ alt="prompt-image"
65
+ src={url}
66
+ className="w-1/5 my-4 mx-2 cursor-zoom-in"
67
+ />
68
  </TooltipTrigger>
69
  <TooltipContent>
70
+ <Img alt="prompt-hovered-image" src={url} className="m-2" />
71
  </TooltipContent>
72
  </Tooltip>
73
  )}
components/ui/Img.tsx CHANGED
@@ -10,8 +10,8 @@ const placeholder =
10
  // const Props = Omit<React.ComponentPropsWithoutRef<typeof Image>, 'alt'>;
11
  const Img = React.forwardRef<
12
  React.ElementRef<typeof Image>,
13
- Omit<React.ComponentPropsWithoutRef<typeof Image>, 'alt'>
14
- >(({ src, onLoad, width, height, className, ...props }, ref) => {
15
  const [dimensions, setDimensions] = React.useState({
16
  width: width ?? 200,
17
  height: height ?? 200,
@@ -24,7 +24,7 @@ const Img = React.forwardRef<
24
  placeholder={placeholder}
25
  width={dimensions.width}
26
  height={dimensions.height}
27
- alt="image"
28
  ref={ref}
29
  className={cn('rounded-md', className)}
30
  onLoad={e => {
 
10
  // const Props = Omit<React.ComponentPropsWithoutRef<typeof Image>, 'alt'>;
11
  const Img = React.forwardRef<
12
  React.ElementRef<typeof Image>,
13
+ React.ComponentPropsWithoutRef<typeof Image>
14
+ >(({ src, alt, onLoad, width, height, className, ...props }, ref) => {
15
  const [dimensions, setDimensions] = React.useState({
16
  width: width ?? 200,
17
  height: height ?? 200,
 
24
  placeholder={placeholder}
25
  width={dimensions.width}
26
  height={dimensions.height}
27
+ alt={alt ?? 'image'}
28
  ref={ref}
29
  className={cn('rounded-md', className)}
30
  onLoad={e => {
lib/hooks/useCleanedUpMessages.ts CHANGED
@@ -62,11 +62,18 @@ export const getCleanedUpMessages = ({
62
  }
63
  cleanedLogs.push(content.substring(left, right));
64
  const [answerText, imagesStr = ''] = answer.split('<VIZ>');
65
- const images = imagesStr.split('</IMG>').map(str => str.replace('<IMG>', ''));
 
 
 
 
66
  return {
67
  logs: cleanedLogs.join('').replace(/β”‚/g, '|').split('|\n\n|').join('|\n|'),
68
- content: answerText.replace('</</ANSWER>', '').replace('</ANSWER>', ''),
69
- images: images.slice(0, -1),
 
 
 
70
  };
71
  };
72
 
 
62
  }
63
  cleanedLogs.push(content.substring(left, right));
64
  const [answerText, imagesStr = ''] = answer.split('<VIZ>');
65
+ const [imagesArrayStr, ...rest] = imagesStr.split('</VIZ>');
66
+ const images = imagesArrayStr
67
+ .split('</IMG>')
68
+ .map(str => str.replace('<IMG>', ''))
69
+ .slice(0, -1);
70
  return {
71
  logs: cleanedLogs.join('').replace(/β”‚/g, '|').split('|\n\n|').join('|\n|'),
72
+ content:
73
+ answerText.replace('</</ANSWER>', '').replace('</ANSWER>', '') +
74
+ images.map((_, index) => `![answers-${index}](/loading.gif)`).join('') +
75
+ rest.join(''),
76
+ images: images,
77
  };
78
  };
79
 
lib/hooks/useVisionAgent.tsx CHANGED
@@ -72,17 +72,18 @@ const useVisionAgent = (chat: ChatEntity) => {
72
  uploadBase64(image, message.id, id, index),
73
  ),
74
  );
 
 
 
 
 
 
75
  const newMessage = {
76
  ...message,
77
- content:
78
- logs +
79
- CLEANED_SEPARATOR +
80
- content +
81
- '\n' +
82
- publicUrls
83
- .map((url, index) => `![image-${index}](${url})`)
84
- .join('\n'),
85
  };
 
 
86
  saveKVChatMessage(id, newMessage);
87
  } else {
88
  saveKVChatMessage(id, {
 
72
  uploadBase64(image, message.id, id, index),
73
  ),
74
  );
75
+ const newContent = publicUrls.reduce((accum, url, index) => {
76
+ return accum.replace(
77
+ `![answers-${index}](/loading.gif)`,
78
+ `![answers-${index}](${url})`,
79
+ );
80
+ }, content);
81
  const newMessage = {
82
  ...message,
83
+ content: logs + CLEANED_SEPARATOR + newContent,
 
 
 
 
 
 
 
84
  };
85
+ console.log(messages);
86
+ setMessages([...messages, newMessage]);
87
  saveKVChatMessage(id, newMessage);
88
  } else {
89
  saveKVChatMessage(id, {
public/loading.gif ADDED