| import streamlit as st |
| from PIL import Image |
| import torch |
| import tempfile |
| import os |
| import io |
| import base64 |
|
|
| |
| st.set_page_config( |
| page_title="Video AI Generator", |
| page_icon="🎥", |
| layout="wide", |
| initial_sidebar_state="expanded" |
| ) |
|
|
| |
| if 'HF_SPACE' in os.environ: |
| |
| st.set_option('server.enableCORS', True) |
| st.set_option('server.enableXsrfProtection', False) |
|
|
| |
| @st.cache_resource |
| def load_pipeline(): |
| """Charge le pipeline avec optimisations mémoire""" |
| try: |
| from diffusers import StableDiffusionImg2ImgPipeline |
| |
| |
| model_id = "runwayml/stable-diffusion-v1-5" |
| |
| pipeline = StableDiffusionImg2ImgPipeline.from_pretrained( |
| model_id, |
| torch_dtype=torch.float16 if torch.cuda.is_available() else torch.float32, |
| use_safetensors=True, |
| ) |
| |
| |
| if torch.cuda.is_available(): |
| pipeline = pipeline.to("cuda") |
| pipeline.enable_memory_efficient_attention() |
| pipeline.enable_attention_slicing() |
| else: |
| pipeline = pipeline.to("cpu") |
| |
| return pipeline |
| except Exception as e: |
| st.error(f"Erreur lors du chargement du modèle : {e}") |
| return None |
|
|
| def safe_file_upload(): |
| """Upload de fichier sécurisé avec gestion d'erreurs""" |
| try: |
| |
| uploaded_file = st.file_uploader( |
| "Choisissez une image", |
| type=['png', 'jpg', 'jpeg'], |
| accept_multiple_files=False, |
| key="image_uploader", |
| help="Formats supportés: PNG, JPG, JPEG (max 10MB recommandé)" |
| ) |
| |
| if uploaded_file is not None: |
| |
| file_size = len(uploaded_file.getvalue()) |
| if file_size > 10 * 1024 * 1024: |
| st.warning(f"⚠️ Fichier volumineux ({file_size/1024/1024:.1f}MB). Réduisez la taille pour de meilleures performances.") |
| |
| |
| try: |
| image = Image.open(uploaded_file) |
| st.success(f"✅ Image chargée: {image.size[0]}x{image.size[1]} pixels") |
| return image, uploaded_file |
| except Exception as img_error: |
| st.error(f"❌ Erreur lors du chargement de l'image: {img_error}") |
| return None, None |
| |
| except Exception as upload_error: |
| st.error(f"❌ Erreur d'upload: {upload_error}") |
| st.info("💡 Essayez de rafraîchir la page ou utilisez un fichier plus petit") |
| return None, None |
| |
| return None, None |
|
|
| def process_image(image, prompt, strength=0.75, guidance_scale=7.5): |
| """Traite l'image avec le pipeline""" |
| try: |
| pipeline = load_pipeline() |
| if pipeline is None: |
| return None |
| |
| |
| max_size = 512 |
| if image.width > max_size or image.height > max_size: |
| image.thumbnail((max_size, max_size), Image.Resampling.LANCZOS) |
| |
| |
| if image.mode != "RGB": |
| image = image.convert("RGB") |
| |
| |
| with torch.autocast("cuda" if torch.cuda.is_available() else "cpu"): |
| result = pipeline( |
| prompt=prompt, |
| image=image, |
| strength=strength, |
| guidance_scale=guidance_scale, |
| num_inference_steps=20, |
| height=image.height, |
| width=image.width |
| ) |
| |
| return result.images[0] |
| except Exception as e: |
| st.error(f"Erreur lors de la génération : {e}") |
| return None |
|
|
| |
| def main(): |
| st.title("🎥 Générateur Video AI") |
| st.markdown("Transformez vos images avec l'IA") |
| |
| |
| if 'HF_SPACE' in os.environ: |
| st.info("🚀 Application déployée sur Hugging Face Spaces") |
| |
| |
| with st.sidebar: |
| st.header("⚙️ Paramètres") |
| |
| strength = st.slider( |
| "Force de transformation", |
| min_value=0.1, |
| max_value=1.0, |
| value=0.75, |
| step=0.05, |
| help="Plus élevé = plus de changements" |
| ) |
| |
| guidance_scale = st.slider( |
| "Échelle de guidance", |
| min_value=1.0, |
| max_value=20.0, |
| value=7.5, |
| step=0.5, |
| help="Plus élevé = plus fidèle au prompt" |
| ) |
| |
| st.markdown("---") |
| st.markdown("💡 **Conseils:**") |
| st.markdown("- Utilisez des images < 10MB") |
| st.markdown("- Format recommandé: PNG, JPG") |
| st.markdown("- Résolution max: 512x512") |
| |
| |
| col1, col2 = st.columns([1, 1]) |
| |
| with col1: |
| st.header("📤 Image d'entrée") |
| |
| |
| input_image, uploaded_file = safe_file_upload() |
| |
| if input_image is not None: |
| |
| display_image = input_image.copy() |
| if display_image.width > 400: |
| display_image.thumbnail((400, 400), Image.Resampling.LANCZOS) |
| |
| st.image(display_image, caption="Image d'origine", use_column_width=True) |
| |
| |
| prompt = st.text_area( |
| "🎨 Décrivez la transformation souhaitée:", |
| placeholder="Ex: transformer en anime style, ajouter des couleurs vives, style cyberpunk...", |
| height=100, |
| key="prompt_input" |
| ) |
| |
| |
| if st.button("🚀 Générer", type="primary", use_container_width=True): |
| if prompt.strip(): |
| with st.spinner("Génération en cours... Cela peut prendre quelques minutes."): |
| result_image = process_image( |
| input_image, |
| prompt, |
| strength, |
| guidance_scale |
| ) |
| |
| if result_image: |
| |
| st.session_state['result_image'] = result_image |
| st.success("✅ Génération terminée!") |
| st.rerun() |
| else: |
| st.error("❌ Erreur lors de la génération") |
| else: |
| st.warning("⚠️ Veuillez entrer une description") |
| |
| with col2: |
| st.header("🎨 Résultat") |
| |
| |
| if 'result_image' in st.session_state: |
| result_image = st.session_state['result_image'] |
| |
| |
| display_result = result_image.copy() |
| if display_result.width > 400: |
| display_result.thumbnail((400, 400), Image.Resampling.LANCZOS) |
| |
| st.image(display_result, caption="Image transformée", use_column_width=True) |
| |
| |
| try: |
| buffered = io.BytesIO() |
| result_image.save(buffered, format="PNG") |
| |
| st.download_button( |
| label="💾 Télécharger le résultat", |
| data=buffered.getvalue(), |
| file_name="result_ai.png", |
| mime="image/png", |
| use_container_width=True |
| ) |
| except Exception as e: |
| st.error(f"Erreur lors de la préparation du téléchargement: {e}") |
| else: |
| st.info("👈 Uploadez une image et entrez un prompt pour commencer") |
| |
| |
| with st.expander("🔧 Problèmes d'upload?"): |
| st.markdown(""" |
| **Si vous ne pouvez pas charger d'images:** |
| |
| 1. **Rafraîchissez** la page (F5) |
| 2. **Réduisez** la taille de votre image (< 5MB) |
| 3. **Changez** le format (essayez JPG au lieu de PNG) |
| 4. **Utilisez** un autre navigateur |
| 5. **Attendez** quelques secondes et réessayez |
| |
| **Formats supportés:** PNG, JPG, JPEG |
| **Taille recommandée:** < 10MB |
| """) |
| |
| |
| with st.expander("📖 Instructions d'utilisation"): |
| st.markdown(""" |
| ### Comment utiliser cette application: |
| |
| 1. **Uploadez une image** dans la section de gauche |
| 2. **Décrivez la transformation** que vous souhaitez |
| 3. **Ajustez les paramètres** dans la sidebar si nécessaire |
| 4. **Cliquez sur Générer** et patientez |
| 5. **Téléchargez le résultat** une fois terminé |
| |
| ### Exemples de prompts: |
| - "transformer en style anime" |
| - "ajouter des couleurs arc-en-ciel" |
| - "style cyberpunk néon" |
| - "portrait artistique à l'aquarelle" |
| - "paysage fantastique avec des dragons" |
| """) |
|
|
| if __name__ == "__main__": |
| main() |