Gradio vs Streamlit : Créer des interfaces IA en Python

tl;dr: Gradio = Interfaces ML rapides (5 lignes de code), idéal demos modèles, intégration HuggingFace native. Streamlit = Apps data science complètes, dashboards, plus flexible mais verbose. Gradio pour MVP ML rapide, Streamlit pour apps métier. Déploiement gratuit sur HF Spaces ou Streamlit Cloud.

Créer une interface web pour votre modèle IA sans JavaScript ? Gradio et Streamlit le permettent en pur Python. Comparaison complète et guide pratique.


Table des Matières

  1. Introduction
  2. Gradio : ML Interfaces en 5 Lignes
  3. Streamlit : Data Apps Complètes
  4. Comparaison Détaillée
  5. Cas d’Usage par Scénario
  6. Exemples Pratiques
  7. Déploiement
  8. Performance et Scalabilité

Illustration détaillée du concept gradio vs streamlit en intelligence artificielle avec exemples pratiques et schémas explicatifs

Le problème

Vous avez :

  • Un modèle ML/IA qui fonctionne en Python
  • Besoin d’une interface web pour démo/production
  • Pas de compétences frontend (React, Vue, etc.)

Solution : Frameworks Python-only. Pour le déploiement en production de ces interfaces, consultez notre guide Déploiement production IA.


Gradio vs Streamlit : Première vue

Gradio (créé par Hugging Face) :

  • 🎯 Focus : Interfaces ML ultra-rapides
  • 📦 Philosophie : Moins de code, plus de magie
  • 🚀 Temps dev : 5-30 minutes

Streamlit :

  • 🎯 Focus : Apps data science complètes
  • 📦 Philosophie : Control total, flexibilité
  • 🚀 Temps dev : 1-4 heures

Exemple Hello World :

Gradio (3 lignes) :

import gradio as gr
gr.Interface(fn=lambda x: x.upper(), inputs="text", outputs="text").launch()
# Interface complète en 3 lignes !

Streamlit (5 lignes) :

import streamlit as st
text = st.text_input("Input")
if text:
    st.write(text.upper())
# Plus verbeux mais plus flexible

Gradio : ML interfaces en 5 lignes

Installation

pip install gradio

Philosophie et design

Gradio = Interface Builder pour ML :

  • Composants prêts : Textbox, Image, Audio, Video, etc.
  • Layout automatique
  • Zero HTML/CSS

Chatbot simple

import gradio as gr
import openai

client = openai.OpenAI(api_key="sk-...")

def chat(message, history):
    """
    Chatbot avec ChatGPT
    history = [(user_msg, bot_msg), ...]
    """
    # Convertir history en format OpenAI
    messages = [{"role": "system", "content": "Tu es un assistant IA."}]

    for user_msg, bot_msg in history:
        messages.append({"role": "user", "content": user_msg})
        messages.append({"role": "assistant", "content": bot_msg})

    messages.append({"role": "user", "content": message})

    # Appel API
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=messages
    )

    return response.choices[0].message.content

# Interface Chatbot en 1 ligne !
gr.ChatInterface(fn=chat).launch()

Résultat : Interface complète avec :

  • ✅ Historique conversationnel
  • ✅ Zone de texte + bouton
  • ✅ Mise en page responsive
  • ✅ Dark mode automatique

Temps : 2 minutes de code.


Classification d’images

import gradio as gr
from transformers import pipeline

# Charger modèle Hugging Face
classifier = pipeline("image-classification", model="google/vit-base-patch16-224")

def classify_image(image):
    """
    Classifie image uploadée
    """
    results = classifier(image)

    # Formater résultats
    return {result['label']: result['score'] for result in results}

# Interface
demo = gr.Interface(
    fn=classify_image,
    inputs=gr.Image(type="pil"),
    outputs=gr.Label(num_top_classes=3),
    title="Classificateur d'Images IA",
    description="Upload une image pour identifier son contenu",
    examples=[
        ["exemple_chat.jpg"],
        ["exemple_chien.jpg"]
    ]
)

demo.launch()

Features automatiques :

  • Upload image (drag & drop)
  • Preview image
  • Résultats avec barre de confiance
  • Exemples cliquables
  • Share link public

Génération d’images (Stable Diffusion)

import gradio as gr
from diffusers import StableDiffusionPipeline
import torch

# Charger modèle
pipe = StableDiffusionPipeline.from_pretrained(
    "stabilityai/stable-diffusion-2-1",
    torch_dtype=torch.float16
).to("cuda")

def generate_image(prompt, negative_prompt, steps, guidance):
    """
    Génère image depuis prompt
    """
    image = pipe(
        prompt=prompt,
        negative_prompt=negative_prompt,
        num_inference_steps=steps,
        guidance_scale=guidance
    ).images[0]

    return image

# Interface avec paramètres avancés
demo = gr.Interface(
    fn=generate_image,
    inputs=[
        gr.Textbox(label="Prompt", placeholder="A sunset over mountains..."),
        gr.Textbox(label="Negative Prompt", placeholder="blurry, low quality..."),
        gr.Slider(10, 100, value=50, label="Steps"),
        gr.Slider(1, 20, value=7.5, label="Guidance Scale")
    ],
    outputs=gr.Image(label="Generated Image"),
    title="Stable Diffusion Generator",
    allow_flagging="never"  # Pas de bouton flag
)

demo.launch(share=True)  # Lien public temporaire

Composants Gradio essentiels

import gradio as gr

# Inputs
gr.Textbox()           # Zone de texte
gr.Number()            # Nombre
gr.Slider()            # Curseur
gr.Checkbox()          # Case à cocher
gr.Radio()             # Boutons radio
gr.Dropdown()          # Menu déroulant
gr.Image()             # Upload image
gr.Audio()             # Upload audio
gr.Video()             # Upload vidéo
gr.File()              # Upload fichier

# Outputs
gr.Textbox()           # Texte
gr.Label()             # Labels avec scores
gr.Image()             # Afficher image
gr.Audio()             # Player audio
gr.Video()             # Player vidéo
gr.JSON()              # Afficher JSON
gr.HTML()              # HTML custom
gr.Plot()              # Graphique Matplotlib/Plotly

# Layouts
gr.Row()               # Ligne horizontale
gr.Column()            # Colonne verticale
gr.Tab()               # Onglets
gr.Accordion()         # Sections pliables

Layout avancé

import gradio as gr

def process(text, temp):
    return f"Processed: {text} (temp={temp})"

with gr.Blocks() as demo:
    gr.Markdown("# Mon Application IA")

    with gr.Tab("Tab 1"):
        with gr.Row():
            with gr.Column(scale=2):
                input_text = gr.Textbox(label="Input")
                temp_slider = gr.Slider(0, 1, value=0.7, label="Temperature")

            with gr.Column(scale=1):
                output = gr.Textbox(label="Output")

        btn = gr.Button("Process")
        btn.click(fn=process, inputs=[input_text, temp_slider], outputs=output)

    with gr.Tab("Tab 2"):
        gr.Markdown("Another tab")

demo.launch()

gr.Blocks() : Control total du layout vs gr.Interface() (automatique).


Intégration Hugging Face native

import gradio as gr

# Charger modèle HF directement
demo = gr.load("openai/whisper-large-v3")  # Transcription audio
demo.launch()

# Ou pour génération texte
demo = gr.load("mistralai/Mistral-7B-Instruct-v0.2")
demo.launch()

Magie : Gradio télécharge et wrappe le modèle automatiquement !


Streamlit : Data apps complètes

Installation

pip install streamlit

Philosophie et design

Streamlit = Script Python → App Web :

  • Réexécution du script à chaque interaction
  • State management intégré
  • Widgets riches

Chatbot ChatGPT

import streamlit as st
import openai

# Config page
st.set_page_config(page_title="ChatGPT Clone", page_icon="💬")

# Titre
st.title("💬 ChatGPT Clone")

# Initialiser session state
if "messages" not in st.session_state:
    st.session_state.messages = []

# Afficher historique
for message in st.session_state.messages:
    with st.chat_message(message["role"]):
        st.markdown(message["content"])

# Input utilisateur
if prompt := st.chat_input("Votre message"):
    # Ajouter message user
    st.session_state.messages.append({"role": "user", "content": prompt})

    with st.chat_message("user"):
        st.markdown(prompt)

    # Générer réponse
    with st.chat_message("assistant"):
        client = openai.OpenAI(api_key=st.secrets["OPENAI_API_KEY"])

        stream = client.chat.completions.create(
            model="gpt-4o-mini",
            messages=st.session_state.messages,
            stream=True
        )

        response = st.write_stream(stream)

    # Sauvegarder réponse
    st.session_state.messages.append({"role": "assistant", "content": response})

Features :

  • ✅ Streaming natif (texte apparaît progressivement)
  • ✅ Session state (mémoire entre interactions)
  • st.chat_message() : Bubbles comme ChatGPT
  • st.secrets : Gestion sécurisée API keys

Lancer :

streamlit run app.py

Dashboard analytics

import streamlit as st
import pandas as pd
import plotly.express as px

st.set_page_config(layout="wide")  # Pleine largeur

st.title("📊 Dashboard Analytics")

# Sidebar
with st.sidebar:
    st.header("Filtres")
    date_range = st.date_input("Date Range", [])
    category = st.multiselect("Catégories", ["A", "B", "C"])

# Upload fichier
uploaded_file = st.file_uploader("Upload CSV", type="csv")

if uploaded_file:
    # Lire données
    df = pd.read_csv(uploaded_file)

    # Métriques
    col1, col2, col3 = st.columns(3)

    with col1:
        st.metric("Total Ventes", f"${df['sales'].sum():,.0f}", delta="+12%")

    with col2:
        st.metric("Clients", df['customer_id'].nunique(), delta="+5%")

    with col3:
        st.metric("Panier Moyen", f"${df['sales'].mean():.2f}", delta="-3%")

    # Graphiques
    st.subheader("Évolution dans le temps")
    fig = px.line(df, x='date', y='sales', title='Ventes Quotidiennes')
    st.plotly_chart(fig, use_container_width=True)

    # Tableau interactif
    st.subheader("Données")
    st.dataframe(df, use_container_width=True)

    # Télécharger résultats
    st.download_button(
        "Télécharger CSV filtré",
        df.to_csv(index=False),
        "filtered_data.csv",
        "text/csv"
    )

Composants Streamlit essentiels

import streamlit as st

# Text
st.title("Titre")
st.header("Header")
st.subheader("Subheader")
st.markdown("**Markdown**")
st.code("print('hello')", language="python")

# Inputs
text = st.text_input("Label")
number = st.number_input("Nombre", min_value=0)
slider = st.slider("Slider", 0, 100)
select = st.selectbox("Select", ["A", "B", "C"])
multi = st.multiselect("Multi", ["A", "B", "C"])
checkbox = st.checkbox("Checkbox")
radio = st.radio("Radio", ["A", "B"])
date = st.date_input("Date")
file = st.file_uploader("Upload")

# Outputs
st.write("N'importe quoi : text, df, chart...")
st.dataframe(df)              # Tableau interactif
st.table(df)                  # Tableau statique
st.json({"key": "value"})     # JSON
st.image("image.jpg")         # Image
st.audio("audio.mp3")         # Audio
st.video("video.mp4")         # Video

# Visualisations
st.line_chart(df)             # Simple
st.bar_chart(df)
st.area_chart(df)
st.plotly_chart(fig)          # Plotly (interactif)
st.pyplot(fig)                # Matplotlib

# Layout
col1, col2 = st.columns(2)    # Colonnes
with st.sidebar:              # Sidebar
    st.write("...")
tab1, tab2 = st.tabs(["Tab1", "Tab2"])
with st.expander("Details"):  # Pliable
    st.write("...")

# Actions
if st.button("Click me"):
    st.write("Clicked!")

# Forms (grouper inputs)
with st.form("my_form"):
    name = st.text_input("Name")
    submitted = st.form_submit_button("Submit")

    if submitted:
        st.write(f"Hello {name}")

Session state (mémoire)

import streamlit as st

# Initialiser state
if "counter" not in st.session_state:
    st.session_state.counter = 0

# Bouton increment
if st.button("Increment"):
    st.session_state.counter += 1

# Afficher
st.write(f"Counter: {st.session_state.counter}")

# Persist entre reruns

Use case : Historique chat, panier, étapes wizard, etc.


Caching (performance)

import streamlit as st
import pandas as pd

@st.cache_data  # Cache résultat
def load_data():
    # Opération lente (CSV 10GB, API, etc.)
    return pd.read_csv("huge_file.csv")

@st.cache_resource  # Cache objet (modèle ML)
def load_model():
    from transformers import pipeline
    return pipeline("sentiment-analysis")

# Utilisations
df = load_data()         # Exécute 1x, puis cache
model = load_model()     # Charge 1x, réutilise

st.write(df)

Différence :

  • @st.cache_data : Données (df, dict, list) - Sérializable
  • @st.cache_resource : Objets (modèles, connexions DB) - Non-sérializable

Comparaison détaillée

Tableau comparatif

CritèreGradioStreamlit
Courbe apprentissage⭐⭐⭐⭐⭐ Facile⭐⭐⭐⭐ Facile
Temps dev MVP5-30 min1-4h
Flexibilité layout⭐⭐⭐ Limitée⭐⭐⭐⭐⭐ Totale
Focus ML/IA⭐⭐⭐⭐⭐ Natif⭐⭐⭐⭐ Bon
Data science⭐⭐⭐ OK⭐⭐⭐⭐⭐ Excellent
Composants20+ basiques50+ riches
Performance⭐⭐⭐⭐ Bon⭐⭐⭐ Rerun lent
DéploiementHF Spaces (gratuit)Streamlit Cloud (gratuit)
Communauté🔥 HuggingFace🔥🔥 Plus large
Customisation CSS❌ Limité✅ Possible
Multi-page⚠️ Tabs✅ Natif

Quand utiliser Gradio

Demos ML rapides :

  • Prototyper interface modèle en 5 min
  • Partager modèle avec collègues
  • Hackathons

Hugging Face workflows :

  • Modèles HF Hub
  • Déployer sur HF Spaces
  • Communauté ML

Interfaces simples :

  • Input → Modèle → Output
  • Pas besoin dashboard complexe

Exemples :

  • Chatbot
  • Classification image/texte
  • Génération (texte, image, audio)
  • OCR
  • Transcription audio

Quand utiliser Streamlit

Apps data science :

  • Dashboards analytics
  • Visualisations interactives
  • Exploration de données

Applications métier :

  • Multi-pages
  • Workflows complexes
  • State management avancé

Intégrations :

  • DBs (SQL, MongoDB)
  • APIs externes
  • Rapports PDF/Excel

Exemples :

  • Dashboard ventes
  • Outil de reporting
  • App de prédiction avec historique
  • Annotateur de données
  • Admin panel

Cas d’usage par scénario

Démo modèle pour client

Besoin : Montrer modèle IA fonctionnel en réunion demain.

Choix : Gradio ⭐⭐⭐⭐⭐

Pourquoi :

  • Développement : 30 minutes
  • Interface propre automatique
  • Partage via lien public (share=True)

Code :

import gradio as gr

def predict(text):
    # Votre modèle
    return model.predict(text)

gr.Interface(
    fn=predict,
    inputs="text",
    outputs="text",
    title="Demo pour Client X"
).launch(share=True)  # Lien public 72h

Dashboard analytics interne

Besoin : Outil interne pour analyser KPIs quotidiens.

Choix : Streamlit ⭐⭐⭐⭐⭐

Pourquoi :

  • Graphiques riches (Plotly)
  • Connexion DB
  • Multi-pages (Overview, Details, Settings)
  • Export CSV/PDF

Chatbot support client

Tie : Les deux fonctionnent.

Gradio :

gr.ChatInterface(fn=chat_function).launch()
# 1 ligne, simple

Streamlit :

# Plus de code mais:
# - Streaming natif
# - Customisation messages
# - Intégration DB tickets

Recommandation :

  • Prototype : Gradio
  • Production : Streamlit (plus de contrôle)

Outil d’annotation de données

Besoin : Labelliser images/textes pour ML.

Choix : Streamlit ⭐⭐⭐⭐⭐

Pourquoi :

  • Navigation entre samples
  • Sauvegarder progressivement (session state)
  • Statistiques en temps réel

Gradio : Possible mais moins adapté.


Exemples pratiques

RAG question-answering (Gradio)

import gradio as gr
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings
from langchain.chat_models import ChatOpenAI
from langchain.chains import RetrievalQA

# Setup RAG
vectorstore = Chroma(
    persist_directory="./chroma_db",
    embedding_function=OpenAIEmbeddings()
)

qa_chain = RetrievalQA.from_chain_type(
    llm=ChatOpenAI(model="gpt-4o-mini"),
    retriever=vectorstore.as_retriever(search_kwargs={"k": 3})
)

def answer_question(question):
    """
    RAG Q&A avec sources
    """
    result = qa_chain({"query": question})
    answer = result['result']

    # Récupérer sources
    docs = vectorstore.similarity_search(question, k=3)
    sources = "\n\n".join([f"**Source {i+1}:**\n{doc.page_content[:200]}..."
                           for i, doc in enumerate(docs)])

    return answer, sources

# Interface
demo = gr.Interface(
    fn=answer_question,
    inputs=gr.Textbox(label="Question", placeholder="Posez votre question..."),
    outputs=[
        gr.Textbox(label="Réponse"),
        gr.Markdown(label="Sources")
    ],
    title="RAG Question-Answering",
    description="Posez des questions sur nos documents",
    examples=[
        ["Qu'est-ce que le RAG ?"],
        ["Comment fonctionne LangChain ?"]
    ]
)

demo.launch()

Comparateur de modèles (Streamlit)

import streamlit as st
import openai
import anthropic

st.title("🤖 Comparateur de Modèles LLM")

# Sidebar : Config
with st.sidebar:
    st.header("Configuration")
    models = st.multiselect(
        "Modèles à comparer",
        ["GPT-4o", "GPT-4o mini", "Claude 3 Opus", "Claude 3 Sonnet"],
        default=["GPT-4o mini", "Claude 3 Sonnet"]
    )
    temperature = st.slider("Temperature", 0.0, 1.0, 0.7)

# Input
prompt = st.text_area("Prompt", height=150)

if st.button("Comparer"):
    cols = st.columns(len(models))

    for i, model in enumerate(models):
        with cols[i]:
            st.subheader(model)

            with st.spinner(f"Génération {model}..."):
                if "GPT" in model:
                    client = openai.OpenAI()
                    response = client.chat.completions.create(
                        model="gpt-4o" if "4o" in model else "gpt-4o-mini",
                        messages=[{"role": "user", "content": prompt}],
                        temperature=temperature
                    )
                    output = response.choices[0].message.content
                    tokens = response.usage.total_tokens
                    cost = tokens * 0.00001  # Approximation

                elif "Claude" in model:
                    client = anthropic.Anthropic()
                    response = client.messages.create(
                        model="claude-3-opus-20240229" if "Opus" in model else "claude-3-sonnet-20240229",
                        max_tokens=1024,
                        messages=[{"role": "user", "content": prompt}],
                        temperature=temperature
                    )
                    output = response.content[0].text
                    tokens = response.usage.input_tokens + response.usage.output_tokens
                    cost = tokens * 0.000015

                # Afficher
                st.markdown(output)
                st.caption(f"Tokens: {tokens} | Coût: ${cost:.4f}")

Déploiement

Hugging Face Spaces (Gradio)

1. Créer Space

# Sur huggingface.co/new-space
Name: my-gradio-app
SDK: Gradio

2. Structure fichiers

my-gradio-app/
├── app.py          # Code Gradio
├── requirements.txt
└── README.md

3. app.py

import gradio as gr

def greet(name):
    return f"Hello {name}!"

demo = gr.Interface(fn=greet, inputs="text", outputs="text")
demo.launch()

4. requirements.txt

gradio
openai
transformers

5. Push

git clone https://huggingface.co/spaces/username/my-gradio-app
cd my-gradio-app
# Ajouter fichiers
git add .
git commit -m "Initial commit"
git push

Résultat : App live sur https://huggingface.co/spaces/username/my-gradio-app

Gratuit : CPU, GPU payant ($0.60/h).


Streamlit Cloud (Streamlit)

1. Repository GitHub

my-streamlit-app/
├── streamlit_app.py   # DOIT s'appeler streamlit_app.py
├── requirements.txt
└── .streamlit/
    └── secrets.toml    # API keys (local seulement)

2. Déployer

  • Aller sur streamlit.io/cloud
  • Connect GitHub repo
  • Deploy

3. Secrets (API keys)

  • Dashboard Streamlit Cloud → App Settings → Secrets
  • Ajouter:
OPENAI_API_KEY = "sk-..."

Accès dans code :

import streamlit as st
api_key = st.secrets["OPENAI_API_KEY"]

Gratuit : 1 app, ressources limitées.


Alternatives déploiement

Docker :

FROM python:3.11

WORKDIR /app
COPY requirements.txt .
RUN pip install -r requirements.txt

COPY . .

# Gradio
CMD ["python", "app.py"]

# OU Streamlit
# CMD ["streamlit", "run", "streamlit_app.py", "--server.port=8501"]

Cloud Providers :

  • Railway : Gratuit (limité)
  • Render : Gratuit (sleep après inactivité)
  • AWS/GCP/Azure : Payant, scalable

Performance et scalabilité

Gradio : Performance

Avantages :

  • ✅ Léger (FastAPI backend)
  • ✅ Websockets pour streaming
  • ✅ Queue automatique (file d’attente)

Limites :

  • ⚠️ 1 worker par défaut
  • ⚠️ Pas de load balancing natif

Optimisations :

demo.queue(max_size=10)  # File attente
demo.launch(
    server_port=7860,
    server_name="0.0.0.0",
    share=False,
    inbrowser=False
)

Production : Déployer derrière nginx + gunicorn.


Streamlit : Performance

Problème : Réexécute tout le script à chaque interaction.

Solutions :

1. Caching agressif

@st.cache_data
def expensive_computation(param):
    # Calcul 10s
    return result

# Exécute 1x, puis cache par param

2. Session state minimal

# Éviter
if "huge_df" not in st.session_state:
    st.session_state.huge_df = load_huge_df()  # Chargé chaque rerun

# Préférer
@st.cache_data
def get_df():
    return load_huge_df()

df = get_df()  # Cache global

3. Fragments (Streamlit 1.30+)

@st.fragment
def expensive_chart():
    # Seulement ce fragment rerun quand update
    fig = create_complex_plot()
    st.plotly_chart(fig)

Scalabilité

Gradio :

  • Multi-instances (k8s, Docker Swarm)
  • Load balancer devant

Streamlit :

  • Streamlit Cloud : Auto-scale payant
  • Self-hosted : Plusieurs instances + LB

Recommandation production :

  • Trafic faible (<100 users/jour) : Gratuit (HF Spaces, Streamlit Cloud)
  • Trafic moyen : VPS ($10-50/mois)
  • Trafic élevé : Cluster k8s, cloud scaling

Conclusion

Résumé choix

Gradio si :

  • ✅ Démo ML rapide
  • ✅ Prototype en minutes
  • ✅ Intégration HuggingFace
  • ✅ Interface simple input→output

Streamlit si :

  • ✅ App data science complète
  • ✅ Dashboard analytics
  • ✅ Multi-pages
  • ✅ Besoin flexibilité layout

Les deux :

  • ✅ Pas de JavaScript requis
  • ✅ Déploiement gratuit
  • ✅ Communautés actives
  • ✅ Open source

Combinaison possible

Oui ! Utiliser les deux dans même projet :

# gradio_tab.py
import gradio as gr

def ml_inference(input):
    return model.predict(input)

gradio_app = gr.Interface(fn=ml_inference, inputs="text", outputs="text")

# streamlit_app.py
import streamlit as st
from gradio_tab import gradio_app

tab1, tab2 = st.tabs(["Dashboard", "ML Demo"])

with tab1:
    st.write("Streamlit dashboard...")

with tab2:
    # Embed Gradio dans Streamlit !
    st.components.v1.html(gradio_app.launch(inline=True), height=600)

Ressources

Documentation :

Galeries d’exemples :

Communautés :

  • Discord Gradio
  • Forum Streamlit

Articles connexes :