diff --git a/Photo_heure.py b/Photo_heure.py new file mode 100644 index 0000000..c7fd427 --- /dev/null +++ b/Photo_heure.py @@ -0,0 +1,108 @@ +import os +import shutil +from datetime import datetime +import google.generativeai as genai +import PIL.Image + +# --------------------- +# CONFIGURATION +# --------------------- +photo_folder = "C:\\Users\\Antoine\\PycharmProjects\\PHOTO\\photo a organiser" +dossier_folder = "C:\\Users\\Antoine\\PycharmProjects\\PHOTO\\dossier" +genai.configure(api_key="VOTRE_CLE_API") +model = genai.GenerativeModel('gemini-1.5-flash') + +# Créer le dossier de sortie s'il n'existe pas +if not os.path.exists(dossier_folder): + os.makedirs(dossier_folder) + +# --------------------- +# FONCTION POUR EXTRAIRE L'HEURE DEPUIS LE NOM DE FICHIER +# --------------------- +def get_time_from_filename(filename): + try: + base = os.path.splitext(filename)[0] # on met les filename dans la base + parts = base.split("_") + time_part = parts[1] + time_obj = datetime.strptime(time_part, "%H%M%S") # on traite l'infor en temps + return time_obj + except Exception as e: + print(f"Impossible d'extraire l'heure de {filename}: {e}") + return None + +# --------------------- +# LISTER ET TRIER LES PHOTOS PAR HEURE +# --------------------- +photos_raw = [f for f in os.listdir(photo_folder) if f.lower().endswith(".jpg")] + +photo_times = [] +for photo in photos_raw: + time_obj = get_time_from_filename(photo) + if time_obj: + photo_times.append((photo, time_obj)) + else: + print(f"Photo ignorée (nom invalide) : {photo}") + +photo_times.sort(key=lambda x: x[1]) # faire un sort pour mettre l'heure du plus jeune au plus vieux. + +# --------------------- +# GROUPEMENT PAR MINUTE +# --------------------- +groups = [] + +for photo, time_obj in photo_times: + heure_lisible = time_obj.strftime("%H:%M:%S") # met le texte lisible + print(f" {photo} → {heure_lisible}") + + if not groups: + groups.append({"photos": [photo], "reference": time_obj}) + img = PIL.Image.open("photos") + response = model.generate_content(["Retourne moi unqiuement les lettres et les chiffres de cette image, uniquement sur le code barre",img + groups.append({"photos": [photo], "reference": time_obj}) + ]) + print(f" → Nouveau groupe 1 (référence : {heure_lisible})") + else: + current_group = groups[-1] + reference_time = current_group["reference"] + difference = abs((time_obj - reference_time).total_seconds()) # on soustrait la reference of temps de référence + + if difference <= 60: + current_group["photos"].append(photo) + print(f" → Ajouté au groupe {len(groups)} (écart : {difference:.0f}s)") + else: + groups.append({"photos": [photo], "reference": time_obj}) + print(f" → Nouveau groupe {len(groups)} (référence : {heure_lisible})") + +# --------------------- +# FUSIONNER LES GROUPES AVEC UNE SEULE PHOTO +# --------------------- +merged_groups = [] + +for i, group in enumerate(groups): + if len(group["photos"]) == 1 and merged_groups: + # Une seule photo → on la fusionne dans le groupe précédent + photo = group["photos"][0] + merged_groups[-1]["photos"].append(photo) + print(f" Photo seule '{photo}' fusionnée dans le groupe précédent") + else: + merged_groups.append(group) + +groups = merged_groups + +# --------------------- +# CRÉER LES DOSSIERS NUMÉROTÉS ET DÉPLACER LES PHOTOS +# --------------------- +for i, group in enumerate(groups, start=1): + group_folder = os.path.join(dossier_folder, str(i)) + os.makedirs(group_folder, exist_ok=True) + + ref_time = group["reference"].strftime("%H:%M:%S") + print(f"\nGroupe {i} (référence : {ref_time}) → dossier '{i}'") + + for photo in group["photos"]: + src = os.path.join(photo_folder, photo) + dst = os.path.join(group_folder, photo) + shutil.move(src, dst) + print(f" Déplacé : {photo}") + +print("\nRegroupement terminé !") \ No newline at end of file diff --git a/Photo_heure_dossier_dans_dossier.py b/Photo_heure_dossier_dans_dossier.py new file mode 100644 index 0000000..1b6ecfa --- /dev/null +++ b/Photo_heure_dossier_dans_dossier.py @@ -0,0 +1,109 @@ +import os +import shutil +from datetime import datetime +import google.generativeai as genai +import PIL.Image + +# --------------------- CONFIGURATION --------------------- +photo_folder = r"C:\Users\Antoine\PycharmProjects\PHOTO\photo a organiser" +dossier_folder = r"C:\Users\Antoine\PycharmProjects\PHOTO\dossier" + +# REMPLACER PAR VOTRE CLÉ +genai.configure(api_key="AIzaSyDq2LmX_fwKGAwxGAtmBfX940vT2wDQzBU") + +# Gemini 1.5 Flash is excellent for OCR/Barcodes +model = genai.GenerativeModel('models/gemini-2.5-flash') + +if not os.path.exists(dossier_folder): + os.makedirs(dossier_folder) + +# --------------------- FONCTIONS --------------------- +def get_time_from_filename(filename): + try: + # Supposant un format : QuelqueChose_123045.jpg (HHMMSS) + base = os.path.splitext(filename)[0] + parts = base.split("_") + time_part = parts[-1] # On prend la dernière partie avant l'extension + return datetime.strptime(time_part, "%H%M%S") + except Exception: + return None + +def read_barcode(photo_path): + """ + Détecte le contenu d'un code-barre. + Retourne la valeur ou 'inconnu' s'il n'y en a pas. + """ + try: + with PIL.Image.open(photo_path) as img: + response = model.generate_content([ + "Retourne uniquement le texte ou les chiffres du code-barre présent sur l'image. " + "Si aucun code-barre n'est visible, répond 'inconnu'.", + img + ]) + res = response.text.strip().lower() + if "inconnu" in res or len(res) > 50: # Sécurité si le modèle divague + return "inconnu" + return response.text.strip().replace(" ", "") + except Exception as e: + print(f"Erreur lors de la lecture de {photo_path} : {e}") + return "inconnu" + +# --------------------- TRAITEMENT --------------------- +photos_raw = [f for f in os.listdir(photo_folder) if f.lower().endswith((".jpg", ".jpeg", ".png"))] +photo_times = [] + +for photo in photos_raw: + time_obj = get_time_from_filename(photo) + if time_obj: + photo_times.append((photo, time_obj)) + +# Trier par heure +photo_times.sort(key=lambda x: x[1]) + +groups = [] +for photo, time_obj in photo_times: + if not groups: + groups.append({"photos": [photo], "reference_time": time_obj}) + else: + current_group = groups[-1] + # On compare avec la dernière photo du groupe actuel + difference = abs((time_obj - current_group["reference_time"]).total_seconds()) + + if difference <= 60: + current_group["photos"].append(photo) + current_group["reference_time"] = time_obj # Update reference to the latest photo + else: + groups.append({"photos": [photo], "reference_time": time_obj}) + +# --------------------- DÉPLACEMENT ET SOUS-DOSSIERS --------------------- +for i, group in enumerate(groups, start=1): + # Dossier principal pour le groupe (ex: Dossier_1) + group_folder_name = f"{i}" + group_folder_path = os.path.join(dossier_folder, group_folder_name) + os.makedirs(group_folder_path, exist_ok=True) + + print(f"Traitement du groupe {i} ({len(group['photos'])} photos)...") + + for photo_name in group["photos"]: + src_path = os.path.join(photo_folder, photo_name) + + # Vérifier si CETTE photo est un code-barre + barcode_value = read_barcode(src_path) + + if barcode_value != "inconnu": + # Nettoyage du nom pour Windows + barcode_clean = "".join(c for c in barcode_value if c.isalnum() or c in "-_").strip() + + # Création du SOUS-DOSSIER dans le dossier du groupe + subfolder_path = os.path.join(group_folder_path, barcode_clean) + os.makedirs(subfolder_path, exist_ok=True) + + dst_path = os.path.join(subfolder_path, photo_name) + print(f" -> Code-barre détecté ({barcode_clean}), déplacé dans sous-dossier.") + else: + # Photo normale, reste à la racine du dossier groupe + dst_path = os.path.join(group_folder_path, photo_name) + + shutil.move(src_path, dst_path) + +print("\nOpération terminée avec succès !") \ No newline at end of file diff --git a/Photo_heure_dossier_nommer.py b/Photo_heure_dossier_nommer.py new file mode 100644 index 0000000..79989c1 --- /dev/null +++ b/Photo_heure_dossier_nommer.py @@ -0,0 +1,92 @@ +import os +import shutil +from datetime import datetime +import google.generativeai as genai +import PIL.Image + +# --------------------- CONFIGURATION --------------------- +# Utilisation de r"" pour les chemins Windows +photo_folder = r"C:\Users\Antoine\PycharmProjects\PHOTO\photo a organiser" +dossier_folder = r"C:\Users\Antoine\PycharmProjects\PHOTO\dossier" + +# REMPLACER PAR VOTRE NOUVELLE CLÉ +genai.configure(api_key="AIzaSyDq2LmX_fwKGAwxGAtmBfX940vT2wDQzBU") +for m in genai.list_models(): + if 'generateContent' in m.supported_generation_methods: + print(m.name) +model = genai.GenerativeModel('models/gemini-2.5-flash') # 1.5 est plus stable pour l'OCR + +if not os.path.exists(dossier_folder): + os.makedirs(dossier_folder) + +# --------------------- FONCTIONS --------------------- +def get_time_from_filename(filename): + try: + # Supposant un format : QuelqueChose_123045.jpg (HHMMSS) + base = os.path.splitext(filename)[0] + parts = base.split("_") + time_part = parts[1] + return datetime.strptime(time_part, "%H%M%S") + except Exception as e: + return None + +def read_barcode(photo_path): + try: + # Utiliser 'with' permet de fermer l'image AUTOMATIQUEMENT après la lecture + with PIL.Image.open(photo_path) as img: + response = model.generate_content([ + "Retourne uniquement le texte ou les chiffres du code-barre. " + "Si aucun code-barre n'est visible, répond 'inconnu'.", + img + ]) + return response.text.strip().replace(" ", "") + except Exception as e: + print(f"Erreur lors de la lecture : {e}") + return "erreur_lecture" +# --------------------- TRAITEMENT --------------------- +photos_raw = [f for f in os.listdir(photo_folder) if f.lower().endswith(".jpg")] +photo_times = [] + +for photo in photos_raw: + time_obj = get_time_from_filename(photo) + if time_obj: + photo_times.append((photo, time_obj)) + +photo_times.sort(key=lambda x: x[1]) + +groups = [] +for photo, time_obj in photo_times: + full_path = os.path.join(photo_folder, photo) + + if not groups: + barcode = read_barcode(full_path) + groups.append({"photos": [photo], "reference_time": time_obj, "barcode": barcode}) + else: + current_group = groups[-1] + # Comparaison avec la dernière photo ajoutée pour plus de souplesse + difference = abs((time_obj - current_group["reference_time"]).total_seconds()) + + if difference <= 60: + current_group["photos"].append(photo) + else: + barcode = read_barcode(full_path) + groups.append({"photos": [photo], "reference_time": time_obj, "barcode": barcode}) + +# --------------------- DÉPLACEMENT --------------------- +for i, group in enumerate(groups, start=1): + barcode = group["barcode"] + # Nettoyage pour nom de dossier Windows valide + barcode_clean = "".join(c for c in barcode if c.isalnum() or c in "-_").strip() + + # Format demandé : 1_CodeBarre + folder_name = f"{i}_{barcode_clean}" if barcode_clean else str(i) + group_folder = os.path.join(dossier_folder, folder_name) + + os.makedirs(group_folder, exist_ok=True) + + for photo in group["photos"]: + src = os.path.join(photo_folder, photo) + dst = os.path.join(group_folder, photo) + shutil.move(src, dst) + +print("\nRegroupement et déplacement terminés !") \ No newline at end of file diff --git a/Photo_heure_photo_nommer.py b/Photo_heure_photo_nommer.py new file mode 100644 index 0000000..186012f --- /dev/null +++ b/Photo_heure_photo_nommer.py @@ -0,0 +1,135 @@ +import os +import shutil +from datetime import datetime +import google.generativeai as genai +import PIL.Image +import time + +# --------------------- CONFIGURATION --------------------- +photo_folder = r"C:\Users\Antoine\PycharmProjects\PHOTO\photo a organiser" +dossier_folder = r"C:\Users\Antoine\PycharmProjects\PHOTO\dossier" + +genai.configure(api_key="AIzaSyDq2LmX_fwKGAwxGAtmBfX940vT2wDQzBU") +model = genai.GenerativeModel('models/gemini-2.5-flash') + +if not os.path.exists(dossier_folder): + os.makedirs(dossier_folder) + +# --------------------- FONCTIONS --------------------- +def get_time_from_filename(filename): + try: + base = os.path.splitext(filename)[0] + parts = base.split("_") + time_part = parts[-1] + return datetime.strptime(time_part, "%H%M%S") + except Exception: + return None + +def analyze_group_photos(group_paths): + """ + Envoie les images et demande de lier les valeurs aux noms de fichiers. + """ + prompt = ( + "Analyze these images one by one. For each image, if you see a 6-character Barcode " + "or a 5-character LCLC, identify it.\n" + "Return the results in this exact format for each relevant file:\n" + "FILENAME: [filename], TYPE: [BARCODE or LCLC], VALUE: [value]\n" + "If a file has nothing, don't list it." + ) + + content = [prompt] + + # On ouvre les images (avec gestion de fermeture automatique) + images_to_close = [] + for path in group_paths: + img = PIL.Image.open(path) + content.append(f"Filename: {os.path.basename(path)}") + content.append(img) + images_to_close.append(img) + + try: + # Note: Utilisez 'gemini-1.5-flash' car 2.5 n'existe pas encore + response = model.generate_content(content) + res_text = response.text + print(f"--- Gemini Analysis ---\n{res_text}\n-----------------------") + + # Fermeture des images pour libérer les fichiers + for i in images_to_close: i.close() + + return res_text + except Exception as e: + print(f"Error calling Gemini: {e}") + return "" + +# --------------------- TRAITEMENT --------------------- +photos_raw = [f for f in os.listdir(photo_folder) if f.lower().endswith((".jpg", ".jpeg", ".png"))] +photo_times = [] + +for photo in photos_raw: + time_obj = get_time_from_filename(photo) + if time_obj: + photo_times.append((photo, time_obj)) + +photo_times.sort(key=lambda x: x[1]) + +groups = [] +for photo, time_obj in photo_times: + if not groups: + groups.append({"photos": [photo], "reference_time": time_obj}) + else: + current_group = groups[-1] + difference = abs((time_obj - current_group["reference_time"]).total_seconds()) + if difference <= 60: + current_group["photos"].append(photo) + current_group["reference_time"] = time_obj + else: + groups.append({"photos": [photo], "reference_time": time_obj}) + +# --------------------- ANALYSE ET RENOMMAGE --------------------- +for i, group in enumerate(groups, start=1): + print(f"Analyzing Group {i}...") + group_paths = [os.path.join(photo_folder, p) for p in group["photos"]] + analysis_result = analyze_group_photos(group_paths) + + group_folder_path = os.path.join(dossier_folder, str(i)) + os.makedirs(group_folder_path, exist_ok=True) + + # Créer un dictionnaire pour mapper Filename -> NouveauNom + # Exemple: {"IMG_123.jpg": "ABC123.jpg"} + filename_mapping = {} + + # Parsing de la réponse de Gemini + for line in analysis_result.splitlines(): + if "FILENAME:" in line and "VALUE:" in line: + try: + fname = line.split("FILENAME:")[1].split(",")[0].strip() + vtype = line.split("TYPE:")[1].split(",")[0].strip() + val = line.split("VALUE:")[1].strip() + + # On vérifie la validité des données + if (vtype == "BARCODE" and len(val) == 6) or (vtype == "LCLC" and len(val) == 5): + filename_mapping[fname] = val + except: + continue + + for photo_name in group["photos"]: + src_path = os.path.join(photo_folder, photo_name) + extension = os.path.splitext(photo_name)[1] + + # On vérifie si Gemini a trouvé une valeur spécifique pour CE fichier + if photo_name in filename_mapping: + new_name = f"{filename_mapping[photo_name]}{extension}" + else: + # Sinon on garde le nom original + new_name = photo_name + + dst_path = os.path.join(group_folder_path, new_name) + + # Gestion des doublons (si deux photos ont le même code) + counter = 1 + base_name = os.path.splitext(new_name)[0] + while os.path.exists(dst_path): + dst_path = os.path.join(group_folder_path, f"{base_name}_{counter}{extension}") + counter += 1 + + shutil.move(src_path, dst_path) \ No newline at end of file diff --git a/delete_dossier.py b/delete_dossier.py new file mode 100644 index 0000000..82042cc --- /dev/null +++ b/delete_dossier.py @@ -0,0 +1,54 @@ +import os +import shutil + +# --------------------- +# CONFIGURATION +# --------------------- +dossier_folder = "C:\\Users\\Antoine\\PycharmProjects\\PHOTO\\dossier" + +# --------------------- +# INPUT +# --------------------- +user_input = input("Entrez le(s) numéro(s) de dossier à supprimer (ex: 2 ou 2,4,5) : ") +to_delete = set(int(x.strip()) for x in user_input.split(",")) + +# --------------------- +# LISTER LES DOSSIERS EXISTANTS TRIÉS +# --------------------- +existing = sorted( + int(f) for f in os.listdir(dossier_folder) + if os.path.isdir(os.path.join(dossier_folder, f)) and f.isdigit() +) + +# --------------------- +# SUPPRIMER LES DOSSIERS DEMANDÉS +# --------------------- +for num in to_delete: + folder_path = os.path.join(dossier_folder, str(num)) + if os.path.exists(folder_path): + shutil.rmtree(folder_path) + print(f"Dossier {num} supprimé.") + else: + print(f"Dossier {num} introuvable, ignoré.") + +# --------------------- +# RENOMMER LES DOSSIERS RESTANTS EN ORDRE +# --------------------- +remaining = sorted( + int(f) for f in os.listdir(dossier_folder) + if os.path.isdir(os.path.join(dossier_folder, f)) and f.isdigit() +) + +# Renommage en deux passes pour éviter les conflits (ex: 2→1 alors que 1 existe encore) +temp_names = [] +for i, num in enumerate(remaining, start=1): + old_path = os.path.join(dossier_folder, str(num)) + temp_path = os.path.join(dossier_folder, f"temp_{i}") + os.rename(old_path, temp_path) + temp_names.append((temp_path, os.path.join(dossier_folder, str(i)))) + +for temp_path, final_path in temp_names: + os.rename(temp_path, final_path) + print(f"Renommé : {os.path.basename(temp_path).replace('temp_', '')} → {os.path.basename(final_path)}") + +print("\nSuppression et renumérotation terminées !") \ No newline at end of file