/** * 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 ( Virtual Try-On {personImage ? ( ) : ( Select Person Image )} {clothingImage ? ( ) : ( Select Clothing Image )} {loading ? ( ) : ( Generate Try-On )} {processingTime && ( Processing time: {processingTime.toFixed(1)}s )} {resultImage && ( Result: )} ); }; 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;