tryonapi / react_native_example.js
sync19's picture
Upload 8 files
98ffc6a verified
raw
history blame
7.72 kB
/**
* React Native Example for Virtual Try-On API
*
* Install required packages:
* npm install expo-image-picker expo-file-system axios
*/
import React, { useState } from 'react';
import {
View,
Text,
Image,
TouchableOpacity,
ActivityIndicator,
StyleSheet,
Alert,
} from 'react-native';
import * as ImagePicker from 'expo-image-picker';
import * as FileSystem from 'expo-file-system';
import axios from 'axios';
// Replace with your Hugging Face Space URL after deployment
const API_URL = 'https://your-username-virtual-tryon-api.hf.space';
const VirtualTryOnApp = () => {
const [personImage, setPersonImage] = useState(null);
const [clothingImage, setClothingImage] = useState(null);
const [resultImage, setResultImage] = useState(null);
const [loading, setLoading] = useState(false);
const [processingTime, setProcessingTime] = useState(null);
// Pick person image
const pickPersonImage = async () => {
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect: [1, 1],
quality: 1,
});
if (!result.canceled) {
setPersonImage(result.assets[0].uri);
}
};
// Pick clothing image
const pickClothingImage = async () => {
const result = await ImagePicker.launchImageLibraryAsync({
mediaTypes: ImagePicker.MediaTypeOptions.Images,
allowsEditing: true,
aspect: [1, 1],
quality: 1,
});
if (!result.canceled) {
setClothingImage(result.assets[0].uri);
}
};
// Method 1: Using Base64 (Recommended for React Native)
const generateTryOnBase64 = async () => {
if (!personImage || !clothingImage) {
Alert.alert('Error', 'Please select both person and clothing images');
return;
}
setLoading(true);
setResultImage(null);
try {
// Convert images to base64
const personBase64 = await FileSystem.readAsStringAsync(personImage, {
encoding: FileSystem.EncodingType.Base64,
});
const clothingBase64 = await FileSystem.readAsStringAsync(clothingImage, {
encoding: FileSystem.EncodingType.Base64,
});
// Create form data
const formData = new FormData();
formData.append('person_image_base64', personBase64);
formData.append('clothing_image_base64', clothingBase64);
formData.append('num_steps', '40'); // Adjust for speed/quality trade-off
// Make API request
const response = await axios.post(`${API_URL}/tryon-base64`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
timeout: 120000, // 2 minutes timeout
});
if (response.data.success) {
const imageUri = `data:image/png;base64,${response.data.image}`;
setResultImage(imageUri);
setProcessingTime(response.data.processing_time);
Alert.alert('Success', `Generated in ${response.data.processing_time.toFixed(1)}s`);
}
} catch (error) {
console.error('Error:', error);
Alert.alert('Error', error.message || 'Failed to generate try-on');
} finally {
setLoading(false);
}
};
// Method 2: Using File Upload
const generateTryOnFiles = async () => {
if (!personImage || !clothingImage) {
Alert.alert('Error', 'Please select both person and clothing images');
return;
}
setLoading(true);
setResultImage(null);
try {
// Create form data
const formData = new FormData();
formData.append('person_image', {
uri: personImage,
type: 'image/jpeg',
name: 'person.jpg',
});
formData.append('clothing_image', {
uri: clothingImage,
type: 'image/jpeg',
name: 'clothing.jpg',
});
formData.append('return_format', 'base64');
formData.append('num_steps', '40');
// Make API request
const response = await axios.post(`${API_URL}/tryon`, formData, {
headers: {
'Content-Type': 'multipart/form-data',
},
timeout: 120000,
});
if (response.data.success) {
const imageUri = `data:image/png;base64,${response.data.image}`;
setResultImage(imageUri);
setProcessingTime(response.data.processing_time);
Alert.alert('Success', `Generated in ${response.data.processing_time.toFixed(1)}s`);
}
} catch (error) {
console.error('Error:', error);
Alert.alert('Error', error.message || 'Failed to generate try-on');
} finally {
setLoading(false);
}
};
return (
<View style={styles.container}>
<Text style={styles.title}>Virtual Try-On</Text>
<View style={styles.imageRow}>
<TouchableOpacity style={styles.imageContainer} onPress={pickPersonImage}>
{personImage ? (
<Image source={{ uri: personImage }} style={styles.image} />
) : (
<View style={styles.placeholder}>
<Text>Select Person Image</Text>
</View>
)}
</TouchableOpacity>
<TouchableOpacity style={styles.imageContainer} onPress={pickClothingImage}>
{clothingImage ? (
<Image source={{ uri: clothingImage }} style={styles.image} />
) : (
<View style={styles.placeholder}>
<Text>Select Clothing Image</Text>
</View>
)}
</TouchableOpacity>
</View>
<TouchableOpacity
style={[styles.button, loading && styles.buttonDisabled]}
onPress={generateTryOnBase64}
disabled={loading}
>
{loading ? (
<ActivityIndicator color="#fff" />
) : (
<Text style={styles.buttonText}>Generate Try-On</Text>
)}
</TouchableOpacity>
{processingTime && (
<Text style={styles.info}>Processing time: {processingTime.toFixed(1)}s</Text>
)}
{resultImage && (
<View style={styles.resultContainer}>
<Text style={styles.subtitle}>Result:</Text>
<Image source={{ uri: resultImage }} style={styles.resultImage} />
</View>
)}
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
padding: 20,
backgroundColor: '#f5f5f5',
},
title: {
fontSize: 24,
fontWeight: 'bold',
textAlign: 'center',
marginVertical: 20,
},
imageRow: {
flexDirection: 'row',
justifyContent: 'space-between',
marginBottom: 20,
},
imageContainer: {
width: '48%',
aspectRatio: 1,
},
image: {
width: '100%',
height: '100%',
borderRadius: 10,
},
placeholder: {
width: '100%',
height: '100%',
backgroundColor: '#ddd',
borderRadius: 10,
justifyContent: 'center',
alignItems: 'center',
},
button: {
backgroundColor: '#007AFF',
padding: 15,
borderRadius: 10,
alignItems: 'center',
marginVertical: 10,
},
buttonDisabled: {
backgroundColor: '#999',
},
buttonText: {
color: '#fff',
fontSize: 16,
fontWeight: 'bold',
},
info: {
textAlign: 'center',
color: '#666',
marginVertical: 10,
},
resultContainer: {
marginTop: 20,
alignItems: 'center',
},
subtitle: {
fontSize: 18,
fontWeight: 'bold',
marginBottom: 10,
},
resultImage: {
width: 300,
height: 300,
borderRadius: 10,
},
});
export default VirtualTryOnApp;