MingruiZhang commited on
Commit
2fc64b7
1 Parent(s): a031dc6

feat: tips and new example (#119)

Browse files

![image](https://github.com/landing-ai/vision-agent-ui/assets/5669963/25f73843-422c-4186-b5b3-08462dc0468f)

app/globals.css CHANGED
@@ -108,3 +108,31 @@ h1 {
108
  drop-shadow(0 0 20px transparent);
109
  }
110
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
108
  drop-shadow(0 0 20px transparent);
109
  }
110
  }
111
+
112
+ .CollapsibleContent {
113
+ overflow: hidden;
114
+ }
115
+ .CollapsibleContent[data-state='open'] {
116
+ animation: slideDown 300ms ease-out;
117
+ }
118
+ .CollapsibleContent[data-state='closed'] {
119
+ animation: slideUp 300ms ease-out;
120
+ }
121
+
122
+ @keyframes slideDown {
123
+ from {
124
+ height: 0;
125
+ }
126
+ to {
127
+ height: var(--radix-collapsible-content-height);
128
+ }
129
+ }
130
+
131
+ @keyframes slideUp {
132
+ from {
133
+ height: var(--radix-collapsible-content-height);
134
+ }
135
+ to {
136
+ height: 0;
137
+ }
138
+ }
app/page.tsx CHANGED
@@ -7,15 +7,28 @@ import Composer, { ComposerRef } from '@/components/chat/Composer';
7
  import { dbPostCreateChat } from '@/lib/db/functions';
8
  import { nanoid } from '@/lib/utils';
9
  import Chip from '@/components/ui/Chip';
10
- import { IconArrowUpRight } from '@/components/ui/Icons';
 
 
 
 
 
11
  import { EXAMPLES } from '@/lib/constants';
 
 
 
 
 
 
 
 
12
 
13
  export default function Page() {
14
  const router = useRouter();
15
  const composerRef = useRef<ComposerRef>(null);
16
  return (
17
  <div className="h-screen w-screen homepage">
18
- <div className="mx-auto w-[42rem] max-w-full px-4 mt-[200px]">
19
  <h1 className="mb-4 text-center relative">
20
  Vision Agent
21
  <Chip className="absolute bg-green-100 text-green-500">BETA</Chip>
@@ -47,7 +60,7 @@ export default function Page() {
47
  return (
48
  <Chip
49
  key={index}
50
- className="bg-transparent border border-zinc-500 cursor-pointer px-4"
51
  onClick={() => {
52
  composerRef.current?.setInput(example.prompt);
53
  composerRef.current?.setMediaUrl(example.mediaUrl);
@@ -60,6 +73,65 @@ export default function Page() {
60
  </Chip>
61
  );
62
  })}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  </div>
64
  </div>
65
  );
 
7
  import { dbPostCreateChat } from '@/lib/db/functions';
8
  import { nanoid } from '@/lib/utils';
9
  import Chip from '@/components/ui/Chip';
10
+ import {
11
+ IconArrowDown,
12
+ IconArrowUpRight,
13
+ IconCaretDown,
14
+ IconSpark,
15
+ } from '@/components/ui/Icons';
16
  import { EXAMPLES } from '@/lib/constants';
17
+ import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
18
+ import { ThumbsDown, ThumbsUp } from 'lucide-react';
19
+ import {
20
+ Collapsible,
21
+ CollapsibleContent,
22
+ CollapsibleTrigger,
23
+ } from '@/components/ui/collapsible';
24
+ import { CodeBlock } from '@/components/ui/CodeBlock';
25
 
26
  export default function Page() {
27
  const router = useRouter();
28
  const composerRef = useRef<ComposerRef>(null);
29
  return (
30
  <div className="h-screen w-screen homepage">
31
+ <div className="mx-auto w-[42rem] max-w-full px-4 mt-24">
32
  <h1 className="mb-4 text-center relative">
33
  Vision Agent
34
  <Chip className="absolute bg-green-100 text-green-500">BETA</Chip>
 
60
  return (
61
  <Chip
62
  key={index}
63
+ className="bg-transparent border border-zinc-500 cursor-pointer px-2 py-0.5"
64
  onClick={() => {
65
  composerRef.current?.setInput(example.prompt);
66
  composerRef.current?.setMediaUrl(example.mediaUrl);
 
73
  </Chip>
74
  );
75
  })}
76
+ <Collapsible className="mt-8 bg-zinc-800 relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7">
77
+ <CollapsibleTrigger className="flex flex-row items-center space-x-4 w-full">
78
+ <IconSpark />
79
+ <h4 className="font-bold grow text-left">
80
+ Vision Agent prompting tips
81
+ </h4>
82
+ <IconCaretDown />
83
+ </CollapsibleTrigger>
84
+ <CollapsibleContent className="mt-4 CollapsibleContent text-sm space-y-2 [&_p]:leading-relaxed">
85
+ <p>
86
+ <span className="font-bold">Be specific:</span> Give concrete
87
+ instructions to what you desire as output, avoid vague questions.
88
+ </p>
89
+ <div className="flex flex-row space-x-2 justify-start items-center w-full">
90
+ <div className="w-1/8">
91
+ <ThumbsUp className="text-green-500 size-5" />
92
+ </div>
93
+ <p className="italic w-7/8">
94
+ Detect people wearing helmet by detecting people, then detecting
95
+ helmets, a person is wearing a helmet if the helmet is detected
96
+ near the person.
97
+ </p>
98
+ </div>
99
+ <div className="flex flex-row space-x-2 justify-start items-center w-full">
100
+ <div className="w-1/8">
101
+ <ThumbsDown className="text-red-500 size-5" />
102
+ </div>
103
+ <p className="italic w-7/8">Detect people wearing helmet</p>
104
+ </div>
105
+ <p>
106
+ <span className="font-bold">Start simple:</span> Start with simple
107
+ prompt to understand underlying tool performance first
108
+ </p>
109
+ <div className="flex flex-row space-x-2 justify-start items-center w-full">
110
+ <div className="w-1/8"> - </div>
111
+ <p className="italic w-7/8">
112
+ Can you run OCR on this image and plot the detected text?
113
+ </p>
114
+ </div>
115
+ <div className="flex flex-row space-x-2 justify-start items-center w-full">
116
+ <div className="w-1/8"> - </div>
117
+ <p className="italic w-7/8">
118
+ Can you detect the people in this image and visualize the
119
+ result?
120
+ </p>
121
+ </div>
122
+ <p>
123
+ <span className="font-bold">Focus on single problem:</span> Each
124
+ conversation should focus on solving single problem, start new
125
+ conversations when switching task
126
+ </p>
127
+ <p>
128
+ <span className="font-bold">Ask for visualization:</span> You can
129
+ simply add{' '}
130
+ <span className="font-bold font-sans">Visualize the result</span>{' '}
131
+ at the end of your prompt to visualize the result
132
+ </p>
133
+ </CollapsibleContent>
134
+ </Collapsible>
135
  </div>
136
  </div>
137
  );
components/ui/Icons.tsx CHANGED
@@ -775,6 +775,70 @@ function IconGlowingDot({ className, ...props }: React.ComponentProps<'div'>) {
775
  return <div className={cn('size-3 svg-shadow', className)} {...props} />;
776
  }
777
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
778
  export {
779
  IconEdit,
780
  IconLandingAI,
@@ -818,4 +882,8 @@ export {
818
  IconLog,
819
  IconOutput,
820
  IconGlowingDot,
 
 
 
 
821
  };
 
775
  return <div className={cn('size-3 svg-shadow', className)} {...props} />;
776
  }
777
 
778
+ function IconSpark({ className, ...props }: React.ComponentProps<'svg'>) {
779
+ return (
780
+ <svg
781
+ xmlns="http://www.w3.org/2000/svg"
782
+ viewBox="0 0 256 256"
783
+ className={cn('size-4', className)}
784
+ {...props}
785
+ >
786
+ <path
787
+ fill="currentColor"
788
+ d="M197.58,129.06,146,110l-19-51.62a15.92,15.92,0,0,0-29.88,0L78,110l-51.62,19a15.92,15.92,0,0,0,0,29.88L78,178l19,51.62a15.92,15.92,0,0,0,29.88,0L146,178l51.62-19a15.92,15.92,0,0,0,0-29.88ZM137,164.22a8,8,0,0,0-4.74,4.74L112,223.85,91.78,169A8,8,0,0,0,87,164.22L32.15,144,87,123.78A8,8,0,0,0,91.78,119L112,64.15,132.22,119a8,8,0,0,0,4.74,4.74L191.85,144ZM144,40a8,8,0,0,1,8-8h16V16a8,8,0,0,1,16,0V32h16a8,8,0,0,1,0,16H184V64a8,8,0,0,1-16,0V48H152A8,8,0,0,1,144,40ZM248,88a8,8,0,0,1-8,8h-8v8a8,8,0,0,1-16,0V96h-8a8,8,0,0,1,0-16h8V72a8,8,0,0,1,16,0v8h8A8,8,0,0,1,248,88Z"
789
+ ></path>
790
+ </svg>
791
+ );
792
+ }
793
+
794
+ function IconThumbsUp({ className, ...props }: React.ComponentProps<'svg'>) {
795
+ return (
796
+ <svg
797
+ xmlns="http://www.w3.org/2000/svg"
798
+ viewBox="0 0 256 256"
799
+ className={cn('size-4', className)}
800
+ {...props}
801
+ >
802
+ <path
803
+ fill="currentColor"
804
+ d="M234,80.12A24,24,0,0,0,216,72H160V56a40,40,0,0,0-40-40,8,8,0,0,0-7.16,4.42L75.06,96H32a16,16,0,0,0-16,16v88a16,16,0,0,0,16,16H204a24,24,0,0,0,23.82-21l12-96A24,24,0,0,0,234,80.12ZM32,112H72v88H32ZM223.94,97l-12,96a8,8,0,0,1-7.94,7H88V105.89l36.71-73.43A24,24,0,0,1,144,56V80a8,8,0,0,0,8,8h64a8,8,0,0,1,7.94,9Z"
805
+ ></path>
806
+ </svg>
807
+ );
808
+ }
809
+
810
+ function IconThumbsDown({ className, ...props }: React.ComponentProps<'svg'>) {
811
+ return (
812
+ <svg
813
+ xmlns="http://www.w3.org/2000/svg"
814
+ viewBox="0 0 256 256"
815
+ className={cn('size-4', className)}
816
+ {...props}
817
+ >
818
+ <path
819
+ fill="currentColor"
820
+ d="M239.82,157l-12-96A24,24,0,0,0,204,40H32A16,16,0,0,0,16,56v88a16,16,0,0,0,16,16H75.06l37.78,75.58A8,8,0,0,0,120,240a40,40,0,0,0,40-40V184h56a24,24,0,0,0,23.82-27ZM72,144H32V56H72Zm150,21.29a7.88,7.88,0,0,1-6,2.71H152a8,8,0,0,0-8,8v24a24,24,0,0,1-19.29,23.54L88,150.11V56H204a8,8,0,0,1,7.94,7l12,96A7.87,7.87,0,0,1,222,165.29Z"
821
+ ></path>
822
+ </svg>
823
+ );
824
+ }
825
+
826
+ function IconCaretDown({ className, ...props }: React.ComponentProps<'svg'>) {
827
+ return (
828
+ <svg
829
+ xmlns="http://www.w3.org/2000/svg"
830
+ viewBox="0 0 256 256"
831
+ className={cn('size-4', className)}
832
+ {...props}
833
+ >
834
+ <path
835
+ fill="currentColor"
836
+ d="M213.66,101.66l-80,80a8,8,0,0,1-11.32,0l-80-80A8,8,0,0,1,53.66,90.34L128,164.69l74.34-74.35a8,8,0,0,1,11.32,11.32Z"
837
+ ></path>
838
+ </svg>
839
+ );
840
+ }
841
+
842
  export {
843
  IconEdit,
844
  IconLandingAI,
 
882
  IconLog,
883
  IconOutput,
884
  IconGlowingDot,
885
+ IconSpark,
886
+ IconThumbsUp,
887
+ IconThumbsDown,
888
+ IconCaretDown,
889
  };
components/ui/alert.tsx ADDED
@@ -0,0 +1,62 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import * as React from 'react';
2
+ import { cva, type VariantProps } from 'class-variance-authority';
3
+
4
+ import { cn } from '@/lib/utils';
5
+
6
+ const alertVariants = cva(
7
+ 'relative w-full rounded-lg border px-4 py-3 text-sm [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground [&>svg~*]:pl-7',
8
+ {
9
+ variants: {
10
+ variant: {
11
+ default: 'text-foreground',
12
+ destructive:
13
+ 'border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive',
14
+ },
15
+ },
16
+ defaultVariants: {
17
+ variant: 'default',
18
+ },
19
+ },
20
+ );
21
+
22
+ const Alert = React.forwardRef<
23
+ HTMLDivElement,
24
+ React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
25
+ >(({ className, variant, ...props }, ref) => (
26
+ <div
27
+ ref={ref}
28
+ role="alert"
29
+ className={cn(alertVariants({ variant }), className)}
30
+ {...props}
31
+ />
32
+ ));
33
+ Alert.displayName = 'Alert';
34
+
35
+ const AlertTitle = React.forwardRef<
36
+ HTMLParagraphElement,
37
+ React.HTMLAttributes<HTMLHeadingElement>
38
+ >(({ className, ...props }, ref) => (
39
+ <h5
40
+ ref={ref}
41
+ className={cn(
42
+ 'mb-3 mt-1 font-medium leading-none tracking-tight',
43
+ className,
44
+ )}
45
+ {...props}
46
+ />
47
+ ));
48
+ AlertTitle.displayName = 'AlertTitle';
49
+
50
+ const AlertDescription = React.forwardRef<
51
+ HTMLParagraphElement,
52
+ React.HTMLAttributes<HTMLParagraphElement>
53
+ >(({ className, ...props }, ref) => (
54
+ <div
55
+ ref={ref}
56
+ className={cn('text-sm space-y-2 [&_p]:leading-relaxed', className)}
57
+ {...props}
58
+ />
59
+ ));
60
+ AlertDescription.displayName = 'AlertDescription';
61
+
62
+ export { Alert, AlertTitle, AlertDescription };
components/ui/collapsible.tsx ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client"
2
+
3
+ import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"
4
+
5
+ const Collapsible = CollapsiblePrimitive.Root
6
+
7
+ const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger
8
+
9
+ const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent
10
+
11
+ export { Collapsible, CollapsibleTrigger, CollapsibleContent }
lib/constants.ts CHANGED
@@ -1,10 +1,10 @@
1
  export const EXAMPLES = [
2
  {
3
- title: 'Counting flowers in image',
4
  mediaUrl:
5
- 'https://vision-agent-dev.s3.us-east-2.amazonaws.com/examples/flower.png',
6
  prompt:
7
- 'Detect flowers in this image, draw boxes and output the image, also return total number of flowers',
8
  },
9
  {
10
  title: 'Detecting sharks in video',
 
1
  export const EXAMPLES = [
2
  {
3
+ title: 'Counting workers hearing helmets',
4
  mediaUrl:
5
+ 'https://vision-agent-dev.s3.us-east-2.amazonaws.com/examples/workers.png',
6
  prompt:
7
+ 'Can you write a program to check if each person is wearing a helmet? First detect all the people in the image, then detect the helmets, check whether or not a person is wearing a helmet if the helmet is on the worker. Return a dictionary with the count of people with helmets and people without helmets. Visualize the result',
8
  },
9
  {
10
  title: 'Detecting sharks in video',
package.json CHANGED
@@ -20,6 +20,7 @@
20
  "@aws-sdk/s3-presigned-post": "^3.556.0",
21
  "@prisma/client": "5.14.0",
22
  "@radix-ui/react-checkbox": "^1.1.0",
 
23
  "@radix-ui/react-dialog": "^1.0.5",
24
  "@radix-ui/react-dropdown-menu": "^2.0.6",
25
  "@radix-ui/react-icons": "^1.3.0",
 
20
  "@aws-sdk/s3-presigned-post": "^3.556.0",
21
  "@prisma/client": "5.14.0",
22
  "@radix-ui/react-checkbox": "^1.1.0",
23
+ "@radix-ui/react-collapsible": "^1.1.0",
24
  "@radix-ui/react-dialog": "^1.0.5",
25
  "@radix-ui/react-dropdown-menu": "^2.0.6",
26
  "@radix-ui/react-icons": "^1.3.0",
pnpm-lock.yaml CHANGED
@@ -23,6 +23,9 @@ importers:
23
  '@radix-ui/react-checkbox':
24
  specifier: ^1.1.0
25
  version: 1.1.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
 
 
 
26
  '@radix-ui/react-dialog':
27
  specifier: ^1.0.5
28
  version: 1.0.5(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
@@ -825,6 +828,19 @@ packages:
825
  '@types/react-dom':
826
  optional: true
827
 
 
 
 
 
 
 
 
 
 
 
 
 
 
828
  '@radix-ui/react-collection@1.0.3':
829
  resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==}
830
  peerDependencies:
@@ -5153,6 +5169,22 @@ snapshots:
5153
  '@types/react': 18.2.79
5154
  '@types/react-dom': 18.2.25
5155
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
5156
  '@radix-ui/react-collection@1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
5157
  dependencies:
5158
  '@babel/runtime': 7.24.4
 
23
  '@radix-ui/react-checkbox':
24
  specifier: ^1.1.0
25
  version: 1.1.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
26
+ '@radix-ui/react-collapsible':
27
+ specifier: ^1.1.0
28
+ version: 1.1.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
29
  '@radix-ui/react-dialog':
30
  specifier: ^1.0.5
31
  version: 1.0.5(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
 
828
  '@types/react-dom':
829
  optional: true
830
 
831
+ '@radix-ui/react-collapsible@1.1.0':
832
+ resolution: {integrity: sha512-zQY7Epa8sTL0mq4ajSJpjgn2YmCgyrG7RsQgLp3C0LQVkG7+Tf6Pv1CeNWZLyqMjhdPkBa5Lx7wYBeSu7uCSTA==}
833
+ peerDependencies:
834
+ '@types/react': '*'
835
+ '@types/react-dom': '*'
836
+ react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
837
+ react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc
838
+ peerDependenciesMeta:
839
+ '@types/react':
840
+ optional: true
841
+ '@types/react-dom':
842
+ optional: true
843
+
844
  '@radix-ui/react-collection@1.0.3':
845
  resolution: {integrity: sha512-3SzW+0PW7yBBoQlT8wNcGtaxaD0XSu0uLUFgrtHY08Acx05TaHaOmVLR73c0j/cqpDy53KBMO7s0dx2wmOIDIA==}
846
  peerDependencies:
 
5169
  '@types/react': 18.2.79
5170
  '@types/react-dom': 18.2.25
5171
 
5172
+ '@radix-ui/react-collapsible@1.1.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
5173
+ dependencies:
5174
+ '@radix-ui/primitive': 1.1.0
5175
+ '@radix-ui/react-compose-refs': 1.1.0(@types/react@18.2.79)(react@18.2.0)
5176
+ '@radix-ui/react-context': 1.1.0(@types/react@18.2.79)(react@18.2.0)
5177
+ '@radix-ui/react-id': 1.1.0(@types/react@18.2.79)(react@18.2.0)
5178
+ '@radix-ui/react-presence': 1.1.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
5179
+ '@radix-ui/react-primitive': 2.0.0(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)
5180
+ '@radix-ui/react-use-controllable-state': 1.1.0(@types/react@18.2.79)(react@18.2.0)
5181
+ '@radix-ui/react-use-layout-effect': 1.1.0(@types/react@18.2.79)(react@18.2.0)
5182
+ react: 18.2.0
5183
+ react-dom: 18.2.0(react@18.2.0)
5184
+ optionalDependencies:
5185
+ '@types/react': 18.2.79
5186
+ '@types/react-dom': 18.2.25
5187
+
5188
  '@radix-ui/react-collection@1.0.3(@types/react-dom@18.2.25)(@types/react@18.2.79)(react-dom@18.2.0(react@18.2.0))(react@18.2.0)':
5189
  dependencies:
5190
  '@babel/runtime': 7.24.4