minor changes
This commit is contained in:
parent
4586126536
commit
ab7989d5ab
8 changed files with 0 additions and 88043 deletions
File diff suppressed because one or more lines are too long
227
README.MD
227
README.MD
|
|
@ -1,227 +0,0 @@
|
|||
# Projet de Préparation de Données - OpenFoodFacts
|
||||
|
||||
## 📋 Contexte du projet
|
||||
|
||||
Ce projet a été réalisé pour un organisme de santé publique souhaitant améliorer la **base de données collaborative OpenFoodFacts**. L'objectif est de préparer et d'analyser les données alimentaires pour faciliter la création d'un système d'aide à la saisie de produits par les utilisateurs, tout en respectant les principes du RGPD.
|
||||
|
||||
OpenFoodFacts est une base de données ouverte sur les produits alimentaires du monde entier, contenant des informations nutritionnelles, des ingrédients, des allergènes et des labels. Cependant, ces données nécessitent un nettoyage approfondi et une exploration statistique pour être exploitables.
|
||||
|
||||
## 🎯 Objectifs
|
||||
|
||||
Les objectifs principaux du projet sont :
|
||||
|
||||
1. **Nettoyer et filtrer les données** : Éliminer les doublons, les incohérences et sélectionner les variables pertinentes
|
||||
2. **Traiter les valeurs manquantes et aberrantes** : Identifier et gérer les données manquantes, estimer les valeurs nutritionnelles
|
||||
3. **Réaliser des analyses statistiques** : Analyses univariées, bivariées et multivariées pour comprendre les relations entre variables
|
||||
4. **Créer de nouvelles caractéristiques** : Feature engineering pour enrichir le dataset
|
||||
5. **Produire des visualisations** : Graphiques et analyses pour faciliter la compréhension des données
|
||||
6. **Respecter le RGPD** : Garantir la conformité avec les réglementations sur la protection des données
|
||||
|
||||
## 📊 Données
|
||||
|
||||
Les données proviennent de la base **OpenFoodFacts**, une base collaborative mondiale sur les produits alimentaires contenant :
|
||||
- Des informations nutritionnelles (énergie, lipides, glucides, protéines, etc.)
|
||||
- Des listes d'ingrédients et d'allergènes
|
||||
- Des scores nutritionnels (Nutri-Score)
|
||||
- Des labels et certifications
|
||||
- Des informations géographiques et de packaging
|
||||
|
||||
**⚠️ Note importante** : Le dataset original est volumineux et n'est pas inclus dans ce dépôt. Il est téléchargeable à l'adresse suivante :
|
||||
- **URL** : https://s3-eu-west-1.amazonaws.com/static.oc-static.com/prod/courses/files/parcours-data-scientist/P2/fr.openfoodfacts.org.products.csv.zip
|
||||
|
||||
**Complément** : La librairie [NutriScoreCalculator](https://github.com/MalteIwanicki/NutriScoreCalculator) a été utilisée pour compléter certaines valeurs nutritionnelles et calculer le Nutri-Score manquant.
|
||||
|
||||
## 📁 Structure du projet
|
||||
|
||||
```
|
||||
├── openfoodfacts_analysis_clean.ipynb
|
||||
├── OpenFoodFacts_presentation.pdf
|
||||
├── data_analysis_functions.py
|
||||
├── pandas_df_management.py
|
||||
├── strings_management.py
|
||||
├── translated_allergens.json
|
||||
└── translated_ingredients.json
|
||||
```
|
||||
|
||||
### 1. `openfoodfacts_analysis_clean.ipynb`
|
||||
|
||||
**Notebook Principal d'Analyse et de Préparation des Données**
|
||||
|
||||
Ce notebook constitue le cœur du projet et couvre l'ensemble du processus de data cleaning et d'analyse :
|
||||
|
||||
**Chargement et exploration initiale** :
|
||||
- Importation du dataset OpenFoodFacts
|
||||
- Analyse de la taille, des types de données et des statistiques descriptives
|
||||
- Identification des colonnes pertinentes pour l'analyse
|
||||
|
||||
**Nettoyage et filtrage** :
|
||||
- Sélection des caractéristiques pertinentes pour l'objectif métier
|
||||
- Suppression des doublons (produits identiques)
|
||||
- Filtrage des lignes sans valeurs cibles (notamment les allergènes)
|
||||
- Harmonisation des formats et des unités
|
||||
|
||||
**Gestion des valeurs manquantes et aberrantes** :
|
||||
- Identification des valeurs manquantes par variable
|
||||
- Stratégies d'imputation adaptées à chaque type de variable
|
||||
- Détection et traitement des valeurs nutritionnelles aberrantes
|
||||
- Estimation des valeurs manquantes d'`energy_100g` via des corrélations
|
||||
- Calcul du Nutri-Score manquant avec NutriScoreCalculator
|
||||
|
||||
**Création de nouvelles caractéristiques (Feature Engineering)** :
|
||||
- `allergens_count` : nombre d'allergènes par produit
|
||||
- Caractéristiques dérivées des ingrédients (nombre, présence de certains ingrédients)
|
||||
- Variables binaires pour les additifs
|
||||
- Ratios nutritionnels (lipides/énergie, sucres/glucides, etc.)
|
||||
|
||||
**Analyse exploratoire approfondie** :
|
||||
- **Analyses univariées** : distributions des variables nutritionnelles, Nutri-Score, catégories de produits
|
||||
- **Analyses bivariées** : corrélations entre variables numériques, relations entre Nutri-Score et compositions
|
||||
- **Analyses multivariées** : ACP (Analyse en Composantes Principales) pour visualiser les relations globales
|
||||
- **Tests statistiques** : corrélations de Pearson, ANOVA, tests du Khi², V de Cramer
|
||||
- **Visualisations** : histogrammes, boxplots, heatmaps de corrélation, scatter plots
|
||||
|
||||
**Export des données raffinées** :
|
||||
- Sauvegarde du DataFrame nettoyé et enrichi (`df_refined_allergens_based.csv`)
|
||||
- Documentation des transformations effectuées
|
||||
|
||||
### 2. `OpenFoodFacts_presentation.pdf`
|
||||
|
||||
**Présentation de Soutenance**
|
||||
|
||||
Cette présentation synthétise :
|
||||
- Le contexte et les enjeux du projet
|
||||
- La méthodologie de nettoyage et de préparation des données
|
||||
- Les principales analyses statistiques réalisées
|
||||
- Les insights clés découverts dans les données
|
||||
- Les recommandations pour l'amélioration du système de saisie
|
||||
- Les perspectives d'amélioration et d'exploitation des données
|
||||
|
||||
### 3. `data_analysis_functions.py`
|
||||
|
||||
**Module de Fonctions d'Analyse de Données**
|
||||
|
||||
Ce module Python contient des fonctions réutilisables pour :
|
||||
- Le nettoyage des données (suppression de doublons, filtrage)
|
||||
- L'identification des valeurs aberrantes (méthodes statistiques, IQR)
|
||||
- Le traitement des outliers
|
||||
- La détection d'incohérences dans les données
|
||||
- La génération de rapports de qualité des données
|
||||
|
||||
### 4. `pandas_df_management.py`
|
||||
|
||||
**Module de Gestion des DataFrames Pandas**
|
||||
|
||||
Ce module automatise les tâches courantes de manipulation de DataFrames :
|
||||
- Fonctions d'inspection rapide des DataFrames
|
||||
- Automatisation de la gestion des types de données
|
||||
- Fonctions de transformation et de reshaping
|
||||
- Utilitaires pour l'export et l'import de données
|
||||
- Fonctions de validation de la structure des données
|
||||
|
||||
### 5. `strings_management.py`
|
||||
|
||||
**Module de Nettoyage et Normalisation de Chaînes de Caractères**
|
||||
|
||||
Ce module contient des fonctions spécialisées pour :
|
||||
- Le nettoyage des chaînes de caractères (suppression d'espaces, caractères spéciaux)
|
||||
- La normalisation des textes (majuscules/minuscules, accents)
|
||||
- Le parsing des listes d'ingrédients et d'allergènes
|
||||
- La standardisation des noms de produits et de catégories
|
||||
- La gestion des formats multilingues
|
||||
|
||||
### 6. `translated_allergens.json`
|
||||
|
||||
**Fichier de Correspondance des Allergènes**
|
||||
|
||||
Fichier JSON contenant les traductions et correspondances des allergènes :
|
||||
- Harmonisation des noms d'allergènes en différentes langues
|
||||
- Standardisation des appellations (gluten, lactose, fruits à coque, etc.)
|
||||
- Regroupement des variantes orthographiques
|
||||
- Facilite l'analyse multilingue de la base OpenFoodFacts
|
||||
|
||||
### 7. `translated_ingredients.json`
|
||||
|
||||
**Fichier de Correspondance des Ingrédients**
|
||||
|
||||
Fichier JSON contenant les traductions et correspondances des ingrédients :
|
||||
- Harmonisation des noms d'ingrédients communs
|
||||
- Standardisation des appellations en différentes langues
|
||||
- Regroupement des synonymes et variantes
|
||||
- Support de l'analyse multilingue des compositions
|
||||
|
||||
## 🛠️ Technologies utilisées
|
||||
|
||||
- **Python** : Langage principal pour l'analyse de données
|
||||
- pandas, numpy : manipulation et analyse de données
|
||||
- matplotlib, seaborn, plotly : visualisation de données
|
||||
- scipy, statsmodels : tests statistiques et analyses
|
||||
- scikit-learn : ACP et analyses multivariées
|
||||
- NutriScoreCalculator : calcul du Nutri-Score
|
||||
- **Jupyter Notebook** : développement et documentation
|
||||
- **JSON** : stockage des fichiers de correspondance
|
||||
|
||||
## 📈 Méthodologie
|
||||
|
||||
1. **Exploration initiale** : Compréhension de la structure et du contenu du dataset
|
||||
2. **Nettoyage** : Élimination des doublons, incohérences et données non pertinentes
|
||||
3. **Traitement des valeurs manquantes** : Stratégies d'imputation adaptées à chaque variable
|
||||
4. **Feature Engineering** : Création de variables dérivées pertinentes
|
||||
5. **Analyses statistiques** : Tests et visualisations pour comprendre les relations
|
||||
6. **Validation** : Vérification de la qualité et de la cohérence des données nettoyées
|
||||
7. **Documentation** : Présentation des résultats et recommandations
|
||||
|
||||
## 🎯 Résultats attendus
|
||||
|
||||
- ✅ Dataset nettoyé, enrichi et prêt pour des analyses avancées
|
||||
- ✅ Compréhension approfondie des données OpenFoodFacts
|
||||
- ✅ Identification des variables clés pour la prédiction du Nutri-Score
|
||||
- ✅ Insights sur les relations entre composition nutritionnelle et qualité alimentaire
|
||||
- ✅ Modules Python réutilisables pour le traitement de données similaires
|
||||
- ✅ Documentation complète du processus de préparation
|
||||
|
||||
## 💡 Points clés du projet
|
||||
|
||||
### Qualité des données
|
||||
OpenFoodFacts étant une base collaborative, elle présente de nombreux défis :
|
||||
- **Valeurs manquantes importantes** : certaines colonnes ont plus de 50% de données manquantes
|
||||
- **Incohérences** : variations dans les formats, les unités, les langues
|
||||
- **Doublons** : produits saisis plusieurs fois avec des variations
|
||||
- **Valeurs aberrantes** : erreurs de saisie dans les valeurs nutritionnelles
|
||||
|
||||
### Respect du RGPD
|
||||
Le projet garantit la conformité avec les réglementations :
|
||||
- Anonymisation des données personnelles potentielles
|
||||
- Traitement conforme des données européennes
|
||||
- Documentation des traitements effectués
|
||||
|
||||
### Analyses statistiques approfondies
|
||||
Le projet va au-delà du simple nettoyage en proposant :
|
||||
- Des analyses univariées pour comprendre les distributions
|
||||
- Des analyses bivariées pour identifier les relations entre variables
|
||||
- Des analyses multivariées (ACP) pour une vision globale
|
||||
- Des tests statistiques pour valider les observations
|
||||
|
||||
### Feature Engineering orienté métier
|
||||
Création de variables pertinentes pour la santé publique :
|
||||
- Comptage d'allergènes (aide à l'identification des produits à risque)
|
||||
- Ratios nutritionnels (sucres/glucides, lipides/énergie)
|
||||
- Indicateurs de qualité nutritionnelle
|
||||
|
||||
## 🎓 Compétences développées
|
||||
|
||||
- Nettoyage et préparation de données volumineuses et imparfaites
|
||||
- Gestion des valeurs manquantes et aberrantes avec stratégies adaptées
|
||||
- Analyses statistiques univariées, bivariées et multivariées
|
||||
- Feature engineering orienté métier santé
|
||||
- Visualisation de données pour la communication d'insights
|
||||
- Développement de modules Python réutilisables
|
||||
- Respect des contraintes réglementaires (RGPD)
|
||||
- Documentation et présentation de résultats techniques
|
||||
|
||||
## 👤 Auteur
|
||||
|
||||
**Grégoire Mureau**
|
||||
|
||||
---
|
||||
|
||||
*Ce projet illustre la démarche complète de préparation de données en data science : de l'exploration initiale au dataset raffiné, en passant par le nettoyage, l'enrichissement et l'analyse statistique.*
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
|
|
@ -1,42 +0,0 @@
|
|||
# Find duplicates and only keep the rows with the maximum amount of values for the studied_features
|
||||
# Duplicates finding will be based on the features_for_duplicates list
|
||||
def remove_duplicates(original_dataframe, features_for_duplicates, studied_features):
|
||||
if type(features_for_duplicates)!=list:
|
||||
features_for_duplicates = [features_for_duplicates]
|
||||
|
||||
dataframe_free_duplicates = original_dataframe.copy()
|
||||
# Monitor amount of cleaned rows for each feature
|
||||
removed_values_per_feature = {}
|
||||
for feature in features_for_duplicates :
|
||||
|
||||
# Create a list to store the indices of the rows to keep
|
||||
rows_to_keep = []
|
||||
|
||||
# Iterate over the unique duplicate codes
|
||||
for unique_value in dataframe_free_duplicates[dataframe_free_duplicates.duplicated(subset=[feature], keep=False)][feature].dropna().unique():
|
||||
# Get the subset of rows with the current duplicate code
|
||||
duplicates_subset = dataframe_free_duplicates[dataframe_free_duplicates[feature] == unique_value]
|
||||
|
||||
# Count the number of non-missing values for each row in the subset. 1 or more can be found
|
||||
values_counts = duplicates_subset[studied_features].notna().sum(axis=1)
|
||||
|
||||
# Find the index of the row with the maximum number of non-missing values. If several row are reaching the maximum number of non-missing values,
|
||||
# then the first index will be arbitrarily chosen
|
||||
max_values_index = values_counts.idxmax()
|
||||
|
||||
# Find the index of the row with the maximum number of non-missing values. If several row are reaching the maximum number of non-missing values,
|
||||
# then the first index will be arbitrarily chosen
|
||||
rows_to_keep.append(max_values_index)
|
||||
|
||||
# Get indices of non-duplicate rows
|
||||
non_duplicate_indices = dataframe_free_duplicates[~dataframe_free_duplicates.duplicated(subset=[feature], keep=False)].index
|
||||
|
||||
# Combine indices of non-duplicate rows and rows_to_keep
|
||||
all_indices_to_keep = non_duplicate_indices.union(rows_to_keep)
|
||||
|
||||
removed_values_per_feature[feature] = len(dataframe_free_duplicates) - len(all_indices_to_keep)
|
||||
|
||||
# Create the final DataFrame
|
||||
dataframe_free_duplicates = dataframe_free_duplicates.loc[all_indices_to_keep]
|
||||
|
||||
return dataframe_free_duplicates, removed_values_per_feature
|
||||
|
|
@ -1,219 +0,0 @@
|
|||
import nltk
|
||||
from nltk.corpus import stopwords
|
||||
import re
|
||||
import numpy as np
|
||||
import pandas as pd
|
||||
from deep_translator import GoogleTranslator
|
||||
from googletrans import Translator
|
||||
from concurrent.futures import ThreadPoolExecutor, as_completed
|
||||
|
||||
def select_key_words(
|
||||
text,
|
||||
keep_between_separators=True,
|
||||
regex_pattern=r'[a-zA-Z\u00C0-\u017F]+', # Default regex pattern: keeps words with letters and accents
|
||||
stopword_languages=['english'], # List of languages for stopwords
|
||||
separator=",", # Default separator
|
||||
keep_duplicates = False # Return unique list
|
||||
):
|
||||
if pd.isna(text):
|
||||
return np.nan
|
||||
else:
|
||||
# Compile the custom regex pattern
|
||||
word_pattern = re.compile(regex_pattern, re.UNICODE)
|
||||
|
||||
# Build the stop words set based on the provided languages
|
||||
stop_words = set()
|
||||
for language in stopword_languages:
|
||||
try:
|
||||
stop_words.update(stopwords.words(language))
|
||||
except OSError:
|
||||
print(f"Warning: Could not load stopwords for language '{language}'. "
|
||||
f"Ensure the NLTK stopword corpus is downloaded using 'nltk.download('stopwords')'.")
|
||||
|
||||
# Mode 1: Keep elements separated by the custom separator as single keywords
|
||||
if keep_between_separators:
|
||||
# Split the text using the provided separator while keeping the segments
|
||||
segments = re.split(rf'({re.escape(separator)})', text.lower()) # Split using custom separator
|
||||
segments = [seg.strip() for seg in segments if seg.strip() and seg != separator] # Clean empty segments
|
||||
|
||||
# Apply regex to extract words and clean each segment
|
||||
filtered_segments = [
|
||||
' '.join(word_pattern.findall(seg))
|
||||
for seg in segments
|
||||
]
|
||||
|
||||
if keep_duplicates:
|
||||
# Remove duplicates while preserving order
|
||||
seen = set()
|
||||
ordered_segments = [seg for seg in filtered_segments if seg not in seen and not seen.add(seg) and len(seg)>0]
|
||||
else:
|
||||
ordered_segments = [seg for seg in filtered_segments if len(seg)>0]
|
||||
|
||||
return ordered_segments
|
||||
|
||||
# Mode 2: Extract individual words (ignoring the separator)
|
||||
else:
|
||||
# Extract words using the regex pattern
|
||||
keywords = word_pattern.findall(text.lower())
|
||||
|
||||
if not keep_duplicates:
|
||||
# Remove stop words while preserving the order and remove duplicates
|
||||
seen = set()
|
||||
filtered_words = [word for word in keywords if word not in stop_words and word not in seen and not seen.add(word) and len(word)>0]
|
||||
else:
|
||||
filtered_words = [word for word in keywords if word not in stop_words and len(word)>0]
|
||||
|
||||
|
||||
return filtered_words
|
||||
|
||||
# Function to count occurrences of the first ingredient in a string
|
||||
def count_words_occurrences(text, keep_duplicates=False):
|
||||
if pd.isna(text):
|
||||
result = np.nan
|
||||
else:
|
||||
result = {}
|
||||
for word in select_key_words(text, keep_duplicates=keep_duplicates):
|
||||
count = text.lower().count(word.lower())
|
||||
result[word] = count
|
||||
return result
|
||||
|
||||
|
||||
def translate_word(word, source_language="auto", target_language="en", translator_lib='deep_translator'):
|
||||
"""
|
||||
Traduction d'un mot en utilisant soit `deep_translator`, soit `googletrans`.
|
||||
Args:
|
||||
word (str): Texte à traduire
|
||||
source_language (str): Langue source (auto par défaut)
|
||||
target_language (str): Langue cible (en par défaut)
|
||||
translator_lib (str): Utilise 'deep_translator' ou 'googletrans'.
|
||||
|
||||
Returns:
|
||||
dict: 'original' contient le mot d'origine, 'translated' la traduction ou None en cas d'erreur.
|
||||
"""
|
||||
try:
|
||||
translated = None
|
||||
error_in_text = None
|
||||
|
||||
if translator_lib == 'deep_translator':
|
||||
# Traduction avec deep_translator
|
||||
translated = GoogleTranslator(source=source_language, target=target_language).translate(word)
|
||||
# Vérification si le résultat contient des erreurs textuelles inattendues
|
||||
# Adapté pour détecter les messages comme "Error 500..." ou similaires
|
||||
if "Error" in translated or "error" in translated.lower():
|
||||
error_in_text = f"Erreur détectée dans la réponse traduite : '{translated}'"
|
||||
raise ValueError(error_in_text)
|
||||
|
||||
elif translator_lib == 'googletrans':
|
||||
# Traduction avec googletrans
|
||||
from googletrans import Translator
|
||||
translator = Translator()
|
||||
result = translator.translate(word, src=source_language, dest=target_language)
|
||||
translated = result.text.lower()
|
||||
|
||||
else:
|
||||
raise ValueError("Bibliothèque non supportée. Utilisez 'deep_translator' ou 'googletrans'.")
|
||||
|
||||
return {"original": word, "translated": translated}
|
||||
|
||||
except Exception as e:
|
||||
if e==error_in_text:
|
||||
raise ValueError(error_in_text)
|
||||
# Gestion explicite des erreurs avec diagnostic
|
||||
else:
|
||||
raise ValueError(f"Other Error: {e}")
|
||||
# return {"original": word, "translated": None, "error": str(e)}
|
||||
|
||||
|
||||
|
||||
|
||||
def translate_all_words_parallel(words, source_language="auto", target_language="en", max_workers=5, translator_lib="deep_translator"):
|
||||
"""
|
||||
Translates a list of words in parallel, returning a dictionary where
|
||||
the key is the original word, and the value is the translated word.
|
||||
|
||||
Args:
|
||||
words (list): The list of words to be translated.
|
||||
target_language (str): Target language for translation (default is English "en").
|
||||
max_workers (int): Maximum number of threads for parallel processing.
|
||||
|
||||
Returns:
|
||||
dict: A dictionary with original words as keys and translations as values.
|
||||
"""
|
||||
translations = {} # Dictionary to store the translations
|
||||
with ThreadPoolExecutor(max_workers=max_workers) as executor:
|
||||
# Submit parallel tasks for translation
|
||||
future_to_word = {executor.submit(translate_word, word, source_language, target_language, translator_lib): word for word in words}
|
||||
|
||||
print(future_to_word)
|
||||
# Process the completed tasks
|
||||
for future in as_completed(future_to_word):
|
||||
result = future.result() # Get the result of the translation
|
||||
if result.get("translated"): # If translation is successful
|
||||
translations[result["original"]] = result["translated"]
|
||||
else:
|
||||
# If there's an error, store None or the error message as the translation
|
||||
translations[result["original"]] = None
|
||||
|
||||
return translations # Return all translations
|
||||
|
||||
|
||||
def translate_all_words_batch(words, source_language="auto", target_language="en"):
|
||||
"""
|
||||
Translates a list of words in a batch, returning a dictionary where the key
|
||||
is the original word, and the value is the translated word.
|
||||
This function uses the translate_batch function of deep_translator for better performance
|
||||
on large datasets.
|
||||
|
||||
Args:
|
||||
words (list): The list of words to be translated.
|
||||
source_language (str): Source language for translation (default is "auto").
|
||||
target_language (str): Target language for translation (default is English "en").
|
||||
|
||||
Returns:
|
||||
dict: A dictionary with original words as keys and translations as values.
|
||||
"""
|
||||
translations = {}
|
||||
|
||||
try:
|
||||
# Use GoogleTranslator's translate_batch method from deep_translator
|
||||
translated_batch = GoogleTranslator(source=source_language, target=target_language).translate_batch(words)
|
||||
|
||||
# Match original words with their translations
|
||||
for original, translated in zip(words, translated_batch):
|
||||
translations[original] = translated
|
||||
|
||||
except Exception as e:
|
||||
# Handle exceptions and assign None to the words that failed to translate
|
||||
for word in words:
|
||||
translations[word] = None
|
||||
print(f"An error occurred during batch translation: {e}")
|
||||
|
||||
return translations
|
||||
|
||||
# # other way to translate
|
||||
# from googletrans import Translator
|
||||
# import asyncio
|
||||
|
||||
# async def translate_word_async(word, src_language='auto', target_language='en'):
|
||||
# """
|
||||
# Asynchronously translates a single word or phrase using googletrans.
|
||||
# """
|
||||
# translator = Translator()
|
||||
# try:
|
||||
# # Await translation for the specific word
|
||||
# translation = await translator.translate(word, src=src_language, dest=target_language)
|
||||
# return translation.text
|
||||
# except Exception as e:
|
||||
# print(f"Error while translating '{word}': {e}")
|
||||
# return word # Return the original word in case of an error
|
||||
|
||||
# async def translate_all_words_async(words, src_language='auto', target_language='en'):
|
||||
# """
|
||||
# Asynchronously translates a list of words as fast as possible.
|
||||
# """
|
||||
# # Create a list of translation tasks
|
||||
# tasks = [translate_word_async(word, src_language, target_language) for word in words]
|
||||
|
||||
# # Run all tasks concurrently and wait for their completion
|
||||
# results = await asyncio.gather(*tasks)
|
||||
# return results
|
||||
File diff suppressed because it is too large
Load diff
File diff suppressed because one or more lines are too long
Loading…
Add table
Reference in a new issue