CoolFace
Apppublic

othmane107/ComputerVisionProject

sourceHugging Faceotherupdated 7mo agoView on Hugging Face
0likes
app.py328 linesDownload Raw Back to src
1import streamlit as st2import cv23import numpy as np4from pyzbar.pyzbar import decode5from PIL import Image6from datetime import datetime7import io8 9# Configuration de la page - DOIT ÊTRE LA PREMIÈRE COMMANDE STREAMLIT10st.set_page_config(11    page_title="Scanner QR de Produits",12    page_icon="🛒",13    layout="wide",14    initial_sidebar_state="collapsed"15)16 17# Configuration pour éviter les erreurs CORS sur Hugging Face18st.markdown("""19<style>20    .stApp {21        max-width: 100%;22    }23    .uploadedFile {24        display: block !important;25    }26</style>27""", unsafe_allow_html=True)28 29# Initialisation du session state30if 'produits' not in st.session_state:31    st.session_state.produits = {}32if 'total' not in st.session_state:33    st.session_state.total = 0.034if 'derniere_image' not in st.session_state:35    st.session_state.derniere_image = None36if 'compteur_scan' not in st.session_state:37    st.session_state.compteur_scan = 038 39def ajouter_produit(nom, prix):40    """Ajoute un produit ou incrémente sa quantité"""41    if nom in st.session_state.produits:42        st.session_state.produits[nom]['quantite'] += 143        st.session_state.produits[nom]['total'] = (44            st.session_state.produits[nom]['quantite'] * prix45        )46    else:47        st.session_state.produits[nom] = {48            'prix_unitaire': prix,49            'quantite': 1,50            'total': prix51        }52    53    # Recalculer le total54    st.session_state.total = sum(55        p['total'] for p in st.session_state.produits.values()56    )57 58def supprimer_produit(nom):59    """Supprime un produit de la liste"""60    if nom in st.session_state.produits:61        del st.session_state.produits[nom]62        st.session_state.total = sum(63            p['total'] for p in st.session_state.produits.values()64        )65 66def modifier_quantite(nom, nouvelle_quantite):67    """Modifie la quantité d'un produit"""68    if nom in st.session_state.produits and nouvelle_quantite > 0:69        st.session_state.produits[nom]['quantite'] = nouvelle_quantite70        st.session_state.produits[nom]['total'] = (71            nouvelle_quantite * st.session_state.produits[nom]['prix_unitaire']72        )73        st.session_state.total = sum(74            p['total'] for p in st.session_state.produits.values()75        )76    elif nouvelle_quantite <= 0:77        supprimer_produit(nom)78 79def reinitialiser_caisse():80    """Réinitialise la caisse"""81    st.session_state.produits = {}82    st.session_state.total = 0.083    st.session_state.derniere_image = None84 85def scanner_qr_code(image):86    """Scanne les codes QR dans une image"""87    try:88        # Convertir PIL Image en array numpy89        img_array = np.array(image)90        91        # Convertir RGB en BGR pour OpenCV92        if len(img_array.shape) == 3 and img_array.shape[2] == 3:93            img_bgr = cv2.cvtColor(img_array, cv2.COLOR_RGB2BGR)94        elif len(img_array.shape) == 3 and img_array.shape[2] == 4:95            # Si RGBA, convertir en RGB d'abord96            img_array = cv2.cvtColor(img_array, cv2.COLOR_RGBA2RGB)97            img_bgr = cv2.cvtColor(img_array, cv2.COLOR_RGB2BGR)98        else:99            img_bgr = img_array100        101        # Décoder les codes QR102        codes = decode(img_bgr)103        104        resultats = []105        image_annotee = img_bgr.copy()106        107        for code in codes:108            try:109                data = code.data.decode('utf-8')110            except:111                data = str(code.data)112            113            # Dessiner le contour du QR code114            points = code.polygon115            if len(points) == 4:116                pts = np.array(points, np.int32)117                pts = pts.reshape((-1, 1, 2))118                cv2.polylines(image_annotee, [pts], True, (0, 255, 0), 3)119                120                # Afficher le texte121                x, y = points[0]122                cv2.putText(image_annotee, "QR Detecte", (x, y-10), 123                           cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2)124            125            # Parser les données126            if '|' in data:127                try:128                    nom, prix_str = data.split('|', 1)129                    prix = float(prix_str)130                    resultats.append({131                        'nom': nom.strip(),132                        'prix': prix,133                        'data_brute': data134                    })135                except ValueError:136                    resultats.append({137                        'nom': None,138                        'prix': None,139                        'data_brute': data,140                        'erreur': 'Format invalide - Prix doit être un nombre'141                    })142            else:143                resultats.append({144                    'nom': None,145                    'prix': None,146                    'data_brute': data,147                    'erreur': 'Format attendu: NomProduit|Prix'148                })149        150        # Reconvertir BGR en RGB pour affichage151        image_annotee_rgb = cv2.cvtColor(image_annotee, cv2.COLOR_BGR2RGB)152        153        return resultats, image_annotee_rgb154    155    except Exception as e:156        st.error(f"Erreur lors du scan: {str(e)}")157        return [], np.array(image)158 159# Interface Streamlit160st.title("🛒 Scanner QR de Produits")161st.markdown("### 📸 Uploadez une image contenant un code QR")162 163# Colonnes principales164col1, col2 = st.columns([2, 1])165 166with col1:167    st.subheader("📤 Zone d'Upload")168    169    # Upload d'image avec une clé unique170    uploaded_file = st.file_uploader(171        "Choisissez une image (PNG, JPG, JPEG)",172        type=['png', 'jpg', 'jpeg'],173        help="Uploadez une image contenant un ou plusieurs codes QR au format: NomProduit|Prix",174        key=f"uploader_{st.session_state.compteur_scan}"175    )176    177    # Bouton de réinitialisation178    col_btn1, col_btn2 = st.columns(2)179    with col_btn1:180        if st.button("🔄 Réinitialiser la caisse", use_container_width=True):181            reinitialiser_caisse()182            st.session_state.compteur_scan += 1183            st.rerun()184    185    with col_btn2:186        if st.button("🗑️ Effacer l'image", use_container_width=True):187            st.session_state.compteur_scan += 1188            st.rerun()189    190    # Traitement de l'image uploadée191    if uploaded_file is not None:192        try:193            # Charger l'image194            image = Image.open(uploaded_file)195            196            # Convertir en RGB si nécessaire197            if image.mode != 'RGB':198                image = image.convert('RGB')199            200            # Scanner les codes QR201            with st.spinner("🔍 Scan en cours..."):202                resultats, image_annotee = scanner_qr_code(image)203            204            # Afficher l'image annotée205            st.image(image_annotee, caption="Image scannée", use_container_width=True)206            207            # Afficher les résultats208            if resultats:209                st.success(f"✅ {len(resultats)} code(s) QR détecté(s)")210                211                for i, resultat in enumerate(resultats, 1):212                    if resultat['nom'] and resultat['prix'] is not None:213                        col_res1, col_res2 = st.columns([3, 1])214                        with col_res1:215                            st.write(f"**{i}. {resultat['nom']}** - {resultat['prix']:.2f} DH")216                        with col_res2:217                            # Utiliser une clé unique pour chaque bouton218                            btn_key = f"add_{st.session_state.compteur_scan}_{i}_{resultat['nom']}"219                            if st.button(f"➕ Ajouter", key=btn_key):220                                ajouter_produit(resultat['nom'], resultat['prix'])221                                st.success(f"✅ {resultat['nom']} ajouté au panier!")222                                st.rerun()223                    elif 'erreur' in resultat:224                        st.warning(f"⚠️ {i}. {resultat['erreur']}: `{resultat['data_brute']}`")225                    else:226                        st.info(f"ℹ️ {i}. Code détecté: `{resultat['data_brute']}`")227            else:228                st.warning("⚠️ Aucun code QR détecté dans l'image")229                st.info("💡 **Format attendu:** Le code QR doit contenir: `NomProduit|Prix`\n\nExemple: `Pain|5.50`")230        231        except Exception as e:232            st.error(f"❌ Erreur lors du traitement de l'image: {str(e)}")233    234    else:235        st.info("📷 Uploadez une image pour commencer le scan")236        237        # Instructions238        with st.expander("ℹ️ Instructions d'utilisation"):239            st.markdown("""240            **Comment utiliser le scanner:**241            242            1. 📸 Prenez une photo d'un code QR avec votre téléphone243            2. 📤 Uploadez l'image ci-dessus244            3. ✅ Le système détectera automatiquement les codes QR245            4. ➕ Cliquez sur "Ajouter" pour ajouter le produit au panier246            5. 🛒 Gérez votre panier dans la colonne de droite247            248            **Format du code QR:**249            ```250            NomProduit|Prix251            ```252            253            **Exemples:**254            - `Pain|5.50`255            - `Lait|8.00`256            - `Coca Cola|7.50`257            - `Pommes|12.50`258            259            **Astuces:**260            - Vous pouvez scanner plusieurs produits en une seule image261            - Assurez-vous que l'image est claire et bien éclairée262            - Le code QR doit être bien visible et pas trop petit263            """)264 265with col2:266    st.subheader("🧾 Panier")267    268    # Afficher les produits269    if st.session_state.produits:270        for nom, info in list(st.session_state.produits.items()):271            with st.container():272                st.markdown(f"**{nom}**")273                274                col_qty, col_prix, col_del = st.columns([2, 2, 1])275                276                with col_qty:277                    # Utiliser une clé unique pour chaque input278                    qty_key = f"qty_{nom}_{st.session_state.compteur_scan}"279                    nouvelle_qty = st.number_input(280                        "Qté",281                        min_value=0,282                        value=info['quantite'],283                        key=qty_key,284                        label_visibility="collapsed"285                    )286                    if nouvelle_qty != info['quantite']:287                        modifier_quantite(nom, nouvelle_qty)288                        st.rerun()289                290                with col_prix:291                    st.write(f"{info['prix_unitaire']:.2f} DH × {info['quantite']}")292                    st.write(f"**{info['total']:.2f} DH**")293                294                with col_del:295                    del_key = f"del_{nom}_{st.session_state.compteur_scan}"296                    if st.button("🗑️", key=del_key):297                        supprimer_produit(nom)298                        st.rerun()299                300                st.divider()301        302        # Total303        st.markdown("---")304        st.markdown(f"### 💰 TOTAL: {st.session_state.total:.2f} DH")305        306        # Bouton de paiement307        if st.button("💳 Finaliser le paiement", type="primary", use_container_width=True):308            st.success(f"✅ Paiement de {st.session_state.total:.2f} DH effectué!")309            st.balloons()310            reinitialiser_caisse()311            st.session_state.compteur_scan += 1312            st.rerun()313    else:314        st.info("🛒 Panier vide. Scannez des produits pour commencer.")315        316        # Statistiques du panier317        st.markdown("---")318        st.caption("📊 Statistiques:")319        st.caption(f"• Produits: 0")320        st.caption(f"• Total: 0.00 DH")321 322# Pied de page323st.markdown("---")324col_footer1, col_footer2 = st.columns(2)325with col_footer1:326    st.caption(f"🕒 Dernière mise à jour: {datetime.now().strftime('%H:%M:%S')}")327with col_footer2:328    st.caption("💡 Astuce: Vous pouvez scanner plusieurs produits en une seule image!")