wuyiqunLu commited on
Commit
34afd2e
1 Parent(s): bc0330e

feat: add switch to toggle self reflection (#44)

Browse files

<img width="904" alt="image"
src="https://github.com/landing-ai/vision-agent-ui/assets/132986242/5b2fd8ee-1ade-41d7-a59f-57c323cd5036">
<img width="884" alt="image"
src="https://github.com/landing-ai/vision-agent-ui/assets/132986242/c3373cfc-f8c3-49d9-8415-e40492328303">

app/api/vision-agent/route.ts CHANGED
@@ -17,10 +17,11 @@ export const POST = withLogging(
17
  messages: MessageBase[];
18
  id: string;
19
  url: string;
 
20
  },
21
  request,
22
  ) => {
23
- const { messages, url } = json;
24
 
25
  // const session = await auth();
26
  // if (!session?.user?.email) {
@@ -55,7 +56,7 @@ export const POST = withLogging(
55
  formData.append('image', url);
56
 
57
  const fetchResponse = await fetch(
58
- 'https://api.dev.landing.ai/v1/agent/chat?agent_class=vision_agent&visualize_output=true',
59
  // 'http://localhost:5050/v1/agent/chat?agent_class=vision_agent',
60
  {
61
  method: 'POST',
 
17
  messages: MessageBase[];
18
  id: string;
19
  url: string;
20
+ enableSelfReflection: boolean;
21
  },
22
  request,
23
  ) => {
24
+ const { messages, url, enableSelfReflection } = json;
25
 
26
  // const session = await auth();
27
  // if (!session?.user?.email) {
 
56
  formData.append('image', url);
57
 
58
  const fetchResponse = await fetch(
59
+ `https://api.dev.landing.ai/v1/agent/chat?agent_class=vision_agent&visualize_output=true&self_reflection=${enableSelfReflection}`,
60
  // 'http://localhost:5050/v1/agent/chat?agent_class=vision_agent',
61
  {
62
  method: 'POST',
components/chat/Composer.tsx CHANGED
@@ -21,6 +21,7 @@ import {
21
  } from '@/components/ui/Icons';
22
  import { cn } from '@/lib/utils';
23
  import { generateInputImageMarkdown } from '@/lib/messageUtils';
 
24
 
25
  export interface ComposerProps
26
  extends Pick<
@@ -33,6 +34,8 @@ export interface ComposerProps
33
  url?: string;
34
  isAtBottom: boolean;
35
  scrollToBottom: () => void;
 
 
36
  }
37
 
38
  export function Composer({
@@ -47,6 +50,8 @@ export function Composer({
47
  messages,
48
  isAtBottom,
49
  scrollToBottom,
 
 
50
  url,
51
  }: ComposerProps) {
52
  const { formRef, onKeyDown } = useEnterSubmit();
@@ -102,22 +107,33 @@ export function Composer({
102
  </Tooltip>
103
  </div>
104
  )}
105
- <Textarea
106
- ref={inputRef}
107
- tabIndex={0}
108
- onKeyDown={onKeyDown}
109
- rows={1}
110
- value={input}
111
- disabled={isLoading}
112
- onChange={e => setInput(e.target.value)}
113
- placeholder={
114
- isLoading
115
- ? 'Vision Agent is thinking...'
116
- : 'Ask question about the image.'
117
- }
118
- spellCheck={false}
119
- className="min-h-[60px] w-4/5 resize-none bg-transparent px-4 py-[1.3em] focus-within:outline-none sm:text-sm"
120
- />
 
 
 
 
 
 
 
 
 
 
 
121
  {/* Scroll to bottom Icon */}
122
  <div
123
  className={cn(
 
21
  } from '@/components/ui/Icons';
22
  import { cn } from '@/lib/utils';
23
  import { generateInputImageMarkdown } from '@/lib/messageUtils';
24
+ import { Switch } from '../ui/Switch';
25
 
26
  export interface ComposerProps
27
  extends Pick<
 
34
  url?: string;
35
  isAtBottom: boolean;
36
  scrollToBottom: () => void;
37
+ enableSelfReflection: boolean;
38
+ setEnableSelfReflection: (value: boolean) => void;
39
  }
40
 
41
  export function Composer({
 
50
  messages,
51
  isAtBottom,
52
  scrollToBottom,
53
+ enableSelfReflection,
54
+ setEnableSelfReflection,
55
  url,
56
  }: ComposerProps) {
57
  const { formRef, onKeyDown } = useEnterSubmit();
 
107
  </Tooltip>
108
  </div>
109
  )}
110
+ <div className="flex flex-col gap-2 w-4/5 px-4">
111
+ <Textarea
112
+ ref={inputRef}
113
+ tabIndex={0}
114
+ onKeyDown={onKeyDown}
115
+ rows={1}
116
+ value={input}
117
+ disabled={isLoading}
118
+ onChange={e => setInput(e.target.value)}
119
+ placeholder={
120
+ isLoading
121
+ ? 'Vision Agent is thinking...'
122
+ : 'Ask question about the image.'
123
+ }
124
+ spellCheck={false}
125
+ className="min-h-[60px] resize-none bg-transparent py-[1.3em] focus-within:outline-none sm:text-sm"
126
+ />
127
+ <div className="flex items-center gap-2 mt-4">
128
+ <Switch
129
+ checked={enableSelfReflection}
130
+ onCheckedChange={checked => {
131
+ setEnableSelfReflection(checked);
132
+ }}
133
+ />
134
+ <p className="text-sm">Self Reflection</p>
135
+ </div>
136
+ </div>
137
  {/* Scroll to bottom Icon */}
138
  <div
139
  className={cn(
components/chat/index.tsx CHANGED
@@ -6,6 +6,7 @@ import { ChatEntity } from '@/lib/types';
6
  import useVisionAgent from '@/lib/hooks/useVisionAgent';
7
  import { useScrollAnchor } from '@/lib/hooks/useScrollAnchor';
8
  import { Session } from 'next-auth';
 
9
 
10
  export interface ChatProps extends React.ComponentProps<'div'> {
11
  chat: ChatEntity;
@@ -14,8 +15,10 @@ export interface ChatProps extends React.ComponentProps<'div'> {
14
 
15
  export function Chat({ chat, session }: ChatProps) {
16
  const { url, id } = chat;
 
 
17
  const { messages, append, reload, stop, isLoading, input, setInput } =
18
- useVisionAgent(chat);
19
 
20
  const { messagesRef, scrollRef, visibilityRef, isAtBottom, scrollToBottom } =
21
  useScrollAnchor();
@@ -45,6 +48,8 @@ export function Chat({ chat, session }: ChatProps) {
45
  setInput={setInput}
46
  isAtBottom={isAtBottom}
47
  scrollToBottom={scrollToBottom}
 
 
48
  />
49
  </div>
50
  </>
 
6
  import useVisionAgent from '@/lib/hooks/useVisionAgent';
7
  import { useScrollAnchor } from '@/lib/hooks/useScrollAnchor';
8
  import { Session } from 'next-auth';
9
+ import { useState } from 'react';
10
 
11
  export interface ChatProps extends React.ComponentProps<'div'> {
12
  chat: ChatEntity;
 
15
 
16
  export function Chat({ chat, session }: ChatProps) {
17
  const { url, id } = chat;
18
+ const [enableSelfReflection, setEnableSelfReflection] =
19
+ useState<boolean>(true);
20
  const { messages, append, reload, stop, isLoading, input, setInput } =
21
+ useVisionAgent(chat, enableSelfReflection);
22
 
23
  const { messagesRef, scrollRef, visibilityRef, isAtBottom, scrollToBottom } =
24
  useScrollAnchor();
 
48
  setInput={setInput}
49
  isAtBottom={isAtBottom}
50
  scrollToBottom={scrollToBottom}
51
+ enableSelfReflection={enableSelfReflection}
52
+ setEnableSelfReflection={setEnableSelfReflection}
53
  />
54
  </div>
55
  </>
components/project/ProjectChat.tsx CHANGED
@@ -1,7 +1,7 @@
1
  'use client';
2
 
3
  import { MediaDetails } from '@/lib/fetch';
4
- import React from 'react';
5
  import { ChatList } from '../chat/ChatList';
6
  import useVisionAgent from '@/lib/hooks/useVisionAgent';
7
  import { nanoid } from '@/lib/utils';
@@ -19,13 +19,18 @@ const ProjectChat: React.FC<ChatProps> = ({ mediaList }) => {
19
  // fallback to the first media
20
  const selectedMedia =
21
  mediaList.find(media => media.id === selectedMediaId) ?? mediaList[0];
 
 
22
  const { messages, append, reload, stop, isLoading, input, setInput } =
23
- useVisionAgent({
24
- url: selectedMedia.url,
25
- messages: [],
26
- user: 'does-not-matter@landing.ai',
27
- updatedAt: Date.now(),
28
- });
 
 
 
29
 
30
  const { messagesRef, scrollRef, visibilityRef, isAtBottom, scrollToBottom } =
31
  useScrollAnchor();
@@ -50,6 +55,8 @@ const ProjectChat: React.FC<ChatProps> = ({ mediaList }) => {
50
  setInput={setInput}
51
  isAtBottom={isAtBottom}
52
  scrollToBottom={scrollToBottom}
 
 
53
  />
54
  </div>
55
  </>
 
1
  'use client';
2
 
3
  import { MediaDetails } from '@/lib/fetch';
4
+ import React, { useState } from 'react';
5
  import { ChatList } from '../chat/ChatList';
6
  import useVisionAgent from '@/lib/hooks/useVisionAgent';
7
  import { nanoid } from '@/lib/utils';
 
19
  // fallback to the first media
20
  const selectedMedia =
21
  mediaList.find(media => media.id === selectedMediaId) ?? mediaList[0];
22
+ const [enableSelfReflection, setEnableSelfReflection] =
23
+ useState<boolean>(true);
24
  const { messages, append, reload, stop, isLoading, input, setInput } =
25
+ useVisionAgent(
26
+ {
27
+ url: selectedMedia.url,
28
+ messages: [],
29
+ user: 'does-not-matter@landing.ai',
30
+ updatedAt: Date.now(),
31
+ },
32
+ enableSelfReflection,
33
+ );
34
 
35
  const { messagesRef, scrollRef, visibilityRef, isAtBottom, scrollToBottom } =
36
  useScrollAnchor();
 
55
  setInput={setInput}
56
  isAtBottom={isAtBottom}
57
  scrollToBottom={scrollToBottom}
58
+ enableSelfReflection={enableSelfReflection}
59
+ setEnableSelfReflection={setEnableSelfReflection}
60
  />
61
  </div>
62
  </>
components/ui/Switch.tsx ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 'use client';
2
+
3
+ import * as React from 'react';
4
+ import * as SwitchPrimitive from '@radix-ui/react-switch';
5
+
6
+ import { cn } from '@/lib/utils';
7
+
8
+ const Switch = React.forwardRef<
9
+ React.ElementRef<typeof SwitchPrimitive.Root>,
10
+ React.ComponentPropsWithoutRef<typeof SwitchPrimitive.Root>
11
+ >(({ className, ...props }, ref) => (
12
+ <SwitchPrimitive.Root
13
+ className={cn(
14
+ 'h-[20px] w-[36px] cursor-pointer rounded-full bg-slate-500 data-[state=checked]:bg-sky-600 ',
15
+ className,
16
+ )}
17
+ {...props}
18
+ ref={ref}
19
+ >
20
+ <SwitchPrimitive.Thumb className="w-[18px] h-[18px] block rounded-full bg-white shadow-sm data-[state=checked]:translate-x-[18px] transition-transform" />
21
+ </SwitchPrimitive.Root>
22
+ ));
23
+
24
+ Switch.displayName = SwitchPrimitive.Root.displayName;
25
+
26
+ export { Switch };
lib/hooks/useVisionAgent.ts CHANGED
@@ -49,7 +49,7 @@ const uploadBase64 = async (
49
  }
50
  };
51
 
52
- const useVisionAgent = (chat: ChatEntity) => {
53
  const { messages: initialMessages, id, url } = chat;
54
  const {
55
  messages,
@@ -120,6 +120,7 @@ const useVisionAgent = (chat: ChatEntity) => {
120
  body: {
121
  url,
122
  id,
 
123
  },
124
  });
125
 
 
49
  }
50
  };
51
 
52
+ const useVisionAgent = (chat: ChatEntity, enableSelfReflection = true) => {
53
  const { messages: initialMessages, id, url } = chat;
54
  const {
55
  messages,
 
120
  body: {
121
  url,
122
  id,
123
+ enableSelfReflection,
124
  },
125
  });
126