Skip to content

Commit 1b656cf

Browse files
committed
chore: Add basic statistics to demo apps
1 parent 6c1dea0 commit 1b656cf

File tree

17 files changed

+271
-4
lines changed

17 files changed

+271
-4
lines changed

apps/computer-vision/app/classification/index.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,14 @@ import { BottomBar } from '../../components/BottomBar';
99
import React, { useContext, useEffect, useState } from 'react';
1010
import { GeneratingContext } from '../../context';
1111
import ScreenWrapper from '../../ScreenWrapper';
12+
import { StatsBar } from '../../components/StatsBar';
1213

1314
export default function ClassificationScreen() {
1415
const [results, setResults] = useState<{ label: string; score: number }[]>(
1516
[]
1617
);
1718
const [imageUri, setImageUri] = useState('');
19+
const [inferenceTime, setInferenceTime] = useState<number | null>(null);
1820

1921
const model = useClassification({ model: EFFICIENTNET_V2_S_QUANTIZED });
2022
const { setGlobalGenerating } = useContext(GeneratingContext);
@@ -34,7 +36,9 @@ export default function ClassificationScreen() {
3436
const runForward = async () => {
3537
if (imageUri) {
3638
try {
39+
const start = Date.now();
3740
const output = await model.forward(imageUri);
41+
setInferenceTime(Date.now() - start);
3842
const top10 = Object.entries(output)
3943
.sort(([, a], [, b]) => (b as number) - (a as number))
4044
.slice(0, 10)
@@ -80,6 +84,7 @@ export default function ClassificationScreen() {
8084
</View>
8185
)}
8286
</View>
87+
<StatsBar inferenceTime={inferenceTime} />
8388
<BottomBar
8489
handleCameraPress={handleCameraPress}
8590
runForward={runForward}

apps/computer-vision/app/object_detection/index.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import ImageWithBboxes from '../../components/ImageWithBboxes';
1414
import React, { useContext, useEffect, useState } from 'react';
1515
import { GeneratingContext } from '../../context';
1616
import ScreenWrapper from '../../ScreenWrapper';
17+
import { StatsBar } from '../../components/StatsBar';
1718

1819
const MODELS: ModelOption<ObjectDetectionModelSources>[] = [
1920
{ label: 'RF-DeTR Nano', value: RF_DETR_NANO },
@@ -29,6 +30,7 @@ export default function ObjectDetectionScreen() {
2930
}>();
3031
const [selectedModel, setSelectedModel] =
3132
useState<ObjectDetectionModelSources>(RF_DETR_NANO);
33+
const [inferenceTime, setInferenceTime] = useState<number | null>(null);
3234

3335
const model = useObjectDetection({ model: selectedModel });
3436
const { setGlobalGenerating } = useContext(GeneratingContext);
@@ -52,7 +54,9 @@ export default function ObjectDetectionScreen() {
5254
const runForward = async () => {
5355
if (imageUri) {
5456
try {
57+
const start = Date.now();
5558
const output = await model.forward(imageUri);
59+
setInferenceTime(Date.now() - start);
5660
setResults(output);
5761
} catch (e) {
5862
console.error(e);
@@ -100,6 +104,10 @@ export default function ObjectDetectionScreen() {
100104
setResults([]);
101105
}}
102106
/>
107+
<StatsBar
108+
inferenceTime={inferenceTime}
109+
detectionCount={results.length > 0 ? results.length : null}
110+
/>
103111
<BottomBar
104112
handleCameraPress={handleCameraPress}
105113
runForward={runForward}

apps/computer-vision/app/ocr/index.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import ImageWithBboxes2 from '../../components/ImageWithOCRBboxes';
1818
import React, { useContext, useEffect, useState } from 'react';
1919
import { GeneratingContext } from '../../context';
2020
import ScreenWrapper from '../../ScreenWrapper';
21+
import { StatsBar } from '../../components/StatsBar';
2122

2223
type OCRModelSources = OCRProps['model'];
2324

@@ -40,6 +41,7 @@ export default function OCRScreen() {
4041
}>();
4142
const [selectedModel, setSelectedModel] =
4243
useState<OCRModelSources>(OCR_ENGLISH);
44+
const [inferenceTime, setInferenceTime] = useState<number | null>(null);
4345

4446
const model = useOCR({
4547
model: selectedModel,
@@ -63,7 +65,9 @@ export default function OCRScreen() {
6365

6466
const runForward = async () => {
6567
try {
68+
const start = Date.now();
6669
const output = await model.forward(imageUri);
70+
setInferenceTime(Date.now() - start);
6771
setResults(output);
6872
} catch (e) {
6973
console.error(e);
@@ -123,6 +127,10 @@ export default function OCRScreen() {
123127
setResults([]);
124128
}}
125129
/>
130+
<StatsBar
131+
inferenceTime={inferenceTime}
132+
detectionCount={results.length > 0 ? results.length : null}
133+
/>
126134
<BottomBar
127135
handleCameraPress={handleCameraPress}
128136
runForward={runForward}

apps/computer-vision/app/ocr_vertical/index.tsx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import ImageWithBboxes2 from '../../components/ImageWithOCRBboxes';
77
import React, { useContext, useEffect, useState } from 'react';
88
import { GeneratingContext } from '../../context';
99
import ScreenWrapper from '../../ScreenWrapper';
10+
import { StatsBar } from '../../components/StatsBar';
1011

1112
export default function VerticalOCRScree() {
1213
const [imageUri, setImageUri] = useState('');
@@ -15,6 +16,7 @@ export default function VerticalOCRScree() {
1516
width: number;
1617
height: number;
1718
}>();
19+
const [inferenceTime, setInferenceTime] = useState<number | null>(null);
1820
const model = useVerticalOCR({
1921
model: OCR_ENGLISH,
2022
independentCharacters: true,
@@ -38,7 +40,9 @@ export default function VerticalOCRScree() {
3840

3941
const runForward = async () => {
4042
try {
43+
const start = Date.now();
4144
const output = await model.forward(imageUri);
45+
setInferenceTime(Date.now() - start);
4246
setResults(output);
4347
} catch (e) {
4448
console.error(e);
@@ -89,6 +93,10 @@ export default function VerticalOCRScree() {
8993
</View>
9094
)}
9195
</View>
96+
<StatsBar
97+
inferenceTime={inferenceTime}
98+
detectionCount={results.length > 0 ? results.length : null}
99+
/>
92100
<BottomBar
93101
handleCameraPress={handleCameraPress}
94102
runForward={runForward}

apps/computer-vision/app/semantic_segmentation/index.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { View, StyleSheet, Image } from 'react-native';
2424
import React, { useContext, useEffect, useState } from 'react';
2525
import { GeneratingContext } from '../../context';
2626
import ScreenWrapper from '../../ScreenWrapper';
27+
import { StatsBar } from '../../components/StatsBar';
2728

2829
const numberToColor: number[][] = [
2930
[255, 87, 51], // 0 Red
@@ -75,6 +76,7 @@ export default function SemanticSegmentationScreen() {
7576
const [imageSize, setImageSize] = useState({ width: 0, height: 0 });
7677
const [segImage, setSegImage] = useState<SkImage | null>(null);
7778
const [canvasSize, setCanvasSize] = useState({ width: 0, height: 0 });
79+
const [inferenceTime, setInferenceTime] = useState<number | null>(null);
7880

7981
useEffect(() => {
8082
setGlobalGenerating(isGenerating);
@@ -91,6 +93,7 @@ export default function SemanticSegmentationScreen() {
9193
const runForward = async () => {
9294
if (!imageUri || imageSize.width === 0 || imageSize.height === 0) return;
9395
try {
96+
const start = Date.now();
9497
const { width, height } = imageSize;
9598
const output = await forward(imageUri, [], true);
9699
const argmax = output.ARGMAX || [];
@@ -119,6 +122,7 @@ export default function SemanticSegmentationScreen() {
119122
width * 4
120123
);
121124
setSegImage(img);
125+
setInferenceTime(Date.now() - start);
122126
} catch (e) {
123127
console.error(e);
124128
}
@@ -179,6 +183,7 @@ export default function SemanticSegmentationScreen() {
179183
setSegImage(null);
180184
}}
181185
/>
186+
<StatsBar inferenceTime={inferenceTime} />
182187
<BottomBar
183188
handleCameraPress={handleCameraPress}
184189
runForward={runForward}

apps/computer-vision/app/style_transfer/index.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import { View, StyleSheet, Image } from 'react-native';
1616
import React, { useContext, useEffect, useState } from 'react';
1717
import { GeneratingContext } from '../../context';
1818
import ScreenWrapper from '../../ScreenWrapper';
19+
import { StatsBar } from '../../components/StatsBar';
1920

2021
type StyleTransferModelSources = {
2122
modelName: StyleTransferModelName;
@@ -42,6 +43,7 @@ export default function StyleTransferScreen() {
4243

4344
const [imageUri, setImageUri] = useState('');
4445
const [styledUri, setStyledUri] = useState('');
46+
const [inferenceTime, setInferenceTime] = useState<number | null>(null);
4547

4648
const handleCameraPress = async (isCamera: boolean) => {
4749
const image = await getImage(isCamera);
@@ -55,7 +57,9 @@ export default function StyleTransferScreen() {
5557
const runForward = async () => {
5658
if (imageUri) {
5759
try {
60+
const start = Date.now();
5861
const uri = await model.forward(imageUri, 'url');
62+
setInferenceTime(Date.now() - start);
5963
setStyledUri(uri);
6064
} catch (e) {
6165
console.error(e);
@@ -96,6 +100,7 @@ export default function StyleTransferScreen() {
96100
setStyledUri('');
97101
}}
98102
/>
103+
<StatsBar inferenceTime={inferenceTime} />
99104
<BottomBar
100105
handleCameraPress={handleCameraPress}
101106
runForward={runForward}

apps/computer-vision/app/text_to_image/index.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ const MODELS: ModelOption<TextToImageModelSources>[] = [
3030
{ label: 'BK-SDM 256', value: BK_SDM_TINY_VPRED_256 },
3131
{ label: 'BK-SDM 512', value: BK_SDM_TINY_VPRED_512 },
3232
];
33+
import { BottomBarWithTextInput } from '../../components/BottomBarWithTextInput';
34+
import { StatsBar } from '../../components/StatsBar';
3335

3436
export default function TextToImageScreen() {
3537
const [inferenceStepIdx, setInferenceStepIdx] = useState<number>(0);
@@ -39,6 +41,9 @@ export default function TextToImageScreen() {
3941
const [selectedModel, setSelectedModel] = useState<TextToImageModelSources>(
4042
BK_SDM_TINY_VPRED_256
4143
);
44+
const [generationTime, setGenerationTime] = useState<number | null>(null);
45+
const [showTextInput, setShowTextInput] = useState(false);
46+
const [keyboardVisible, setKeyboardVisible] = useState(false);
4247

4348
const imageSize = 224;
4449
const model = useTextToImage({
@@ -55,8 +60,15 @@ export default function TextToImageScreen() {
5560
const runForward = async () => {
5661
if (!input.trim()) return;
5762
try {
63+
const start = Date.now();
5864
const output = await model.generate(input, imageSize, steps);
5965
if (output.length) setImage(output);
66+
else {
67+
setImageTitle(prevImageTitle);
68+
return;
69+
}
70+
setGenerationTime(Date.now() - start);
71+
setImage(output);
6072
} catch (e) {
6173
console.error(e);
6274
} finally {
@@ -134,6 +146,20 @@ export default function TextToImageScreen() {
134146
onSubmitEditing={runForward}
135147
returnKeyType="send"
136148
/>
149+
</View>
150+
<StatsBar inferenceTime={generationTime} />
151+
<View style={styles.bottomContainer}>
152+
<BottomBarWithTextInput
153+
runModel={runForward}
154+
numSteps={steps}
155+
setSteps={setSteps}
156+
stopModel={model.interrupt}
157+
isGenerating={model.isGenerating}
158+
isReady={model.isReady}
159+
showTextInput={showTextInput}
160+
setShowTextInput={setShowTextInput}
161+
keyboardVisible={keyboardVisible}
162+
/>
137163
{model.isGenerating ? (
138164
<TouchableOpacity
139165
style={styles.sendButton}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import React from 'react';
2+
import { View, Text, StyleSheet } from 'react-native';
3+
4+
interface Props {
5+
inferenceTime: number | null;
6+
detectionCount?: number | null;
7+
}
8+
9+
export function StatsBar({ inferenceTime, detectionCount }: Props) {
10+
if (inferenceTime === null) return null;
11+
12+
return (
13+
<View style={styles.container}>
14+
<Text style={styles.stat}>Inference: {inferenceTime} ms</Text>
15+
{detectionCount != null && (
16+
<>
17+
<Text style={styles.separator}>·</Text>
18+
<Text style={styles.stat}>
19+
{detectionCount} detection{detectionCount !== 1 ? 's' : ''}
20+
</Text>
21+
</>
22+
)}
23+
</View>
24+
);
25+
}
26+
27+
const styles = StyleSheet.create({
28+
container: {
29+
flexDirection: 'row',
30+
justifyContent: 'center',
31+
alignItems: 'center',
32+
gap: 8,
33+
paddingVertical: 6,
34+
},
35+
stat: {
36+
fontSize: 13,
37+
color: '#334155',
38+
fontWeight: '500',
39+
},
40+
separator: {
41+
fontSize: 13,
42+
color: '#94A3B8',
43+
},
44+
});

apps/llm/app/llm/index.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ const SUGGESTED_PROMPTS = [
2828
'What are the benefits of on-device AI?',
2929
'Give me 3 fun facts about space',
3030
];
31+
import { useLLMStats } from '../../hooks/useLLMStats';
32+
import { StatsBar } from '../../components/StatsBar';
3133

3234
export default function LLMScreenWrapper() {
3335
const isFocused = useIsFocused();
@@ -44,6 +46,7 @@ function LLMScreen() {
4446
const { setGlobalGenerating } = useContext(GeneratingContext);
4547

4648
const llm = useLLM({ model: selectedModel });
49+
const { stats, onMessageSend } = useLLMStats(llm.response, llm.isGenerating);
4750

4851
useEffect(() => {
4952
if (llm.error) {
@@ -56,6 +59,7 @@ function LLMScreen() {
5659
}, [llm.isGenerating, setGlobalGenerating]);
5760

5861
const sendMessage = async () => {
62+
onMessageSend();
5963
setUserInput('');
6064
textInputRef.current?.clear();
6165
try {
@@ -109,7 +113,7 @@ function LLMScreen() {
109113
onSelect={(m) => setSelectedModel(m)}
110114
disabled={llm.isGenerating}
111115
/>
112-
116+
<StatsBar stats={stats} />
113117
<View style={styles.bottomContainer}>
114118
<TextInput
115119
autoCorrect={false}

apps/llm/app/llm_structured_output/index.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ const SUGGESTED_PROMPTS = [
2020
"I'm Bob. Does it have warranty? I'll pay €50.",
2121
"Name's Sara. What condition? My bid is $75.",
2222
];
23+
import { useLLMStats } from '../../hooks/useLLMStats';
24+
import { StatsBar } from '../../components/StatsBar';
2325
import {
2426
useLLM,
2527
fixAndValidateStructuredOutput,
@@ -85,7 +87,8 @@ function LLMScreen() {
8587
const textInputRef = useRef<TextInput>(null);
8688
const { setGlobalGenerating } = useContext(GeneratingContext);
8789

88-
const llm = useLLM({ model: selectedModel }); // try out 4B model if 1.7B struggles with following structured output
90+
const llm = useLLM({ model: selectedModel });
91+
const { stats, onMessageSend } = useLLMStats(llm.response, llm.isGenerating);
8992

9093
useEffect(() => {
9194
setGlobalGenerating(llm.isGenerating);
@@ -136,6 +139,7 @@ function LLMScreen() {
136139
}, [llm.error]);
137140

138141
const sendMessage = async () => {
142+
onMessageSend();
139143
setUserInput('');
140144
textInputRef.current?.clear();
141145
try {
@@ -190,7 +194,7 @@ function LLMScreen() {
190194
onSelect={(m) => setSelectedModel(m)}
191195
disabled={llm.isGenerating}
192196
/>
193-
197+
<StatsBar stats={stats} />
194198
<View style={styles.bottomContainer}>
195199
<TextInput
196200
autoCorrect={false}

0 commit comments

Comments
 (0)