change template panel left, create dashboard

This commit is contained in:
Tykayn 2025-09-08 18:40:08 +02:00 committed by tykayn
parent 381f378db4
commit 539b4c094f
24 changed files with 1367 additions and 166 deletions

View file

@ -0,0 +1,199 @@
# Ajout de la fonctionnalité de suivi des pages "France" sans catégorie
## Description
Cette fonctionnalité permet de suivre les pages du wiki OpenStreetMap commençant par "France" qui n'ont pas de catégorie (pages sans issues). Ces pages sont identifiées à partir de la liste des "DeadendPages" du wiki OSM. La fonctionnalité suggère également des catégories pour ces pages et suit leur évolution lorsqu'elles sont catégorisées.
## Modifications apportées
### 1. Ajout de constantes dans `wiki_compare.py`
```python
WIKI_DEADEND_PAGES_URL = "https://wiki.openstreetmap.org/w/index.php?title=Special:DeadendPages&limit=500&offset=1000"
DEADEND_PAGES_FILE = "deadend_pages.json"
```
### 2. Ajout de la fonction `suggest_categories` dans `wiki_compare.py`
Cette fonction analyse le titre et le contenu d'une page pour suggérer des catégories pertinentes :
```python
def suggest_categories(page_title, page_url):
"""
Suggest categories for an uncategorized page based on its title and content
Args:
page_title (str): Title of the page
page_url (str): URL of the page
Returns:
list: List of suggested categories
"""
# Logique de suggestion de catégories basée sur le titre et le contenu de la page
```
### 3. Ajout de la fonction `fetch_deadend_pages` dans `wiki_compare.py`
Cette fonction récupère les pages commençant par "France" depuis la liste des DeadendPages :
```python
def fetch_deadend_pages():
"""
Fetch pages starting with "France" from the DeadendPages list
Returns:
list: List of dictionaries containing page information
"""
# Logique de récupération des pages depuis la liste des DeadendPages
# Filtrage des pages commençant par "France"
# Suggestion de catégories pour chaque page
```
### 4. Modification de la fonction `main` dans `wiki_compare.py`
Ajout d'une section pour traiter les pages sans catégorie et suivre leur évolution :
```python
# Fetch pages starting with "France" from the DeadendPages list
deadend_pages = fetch_deadend_pages()
if deadend_pages:
# Load existing deadend pages data to compare with history
existing_data = load_json_data(DEADEND_PAGES_FILE)
# Initialize history if it doesn't exist
if 'history' not in existing_data:
existing_data['history'] = {}
# Get the most recent history entry
sorted_timestamps = sorted(existing_data.get('history', {}).keys())
previous_pages = []
if sorted_timestamps:
latest_timestamp = sorted_timestamps[-1]
previous_pages = existing_data['history'][latest_timestamp].get('pages', [])
# Find pages that were in the previous list but are no longer in the current list
previous_urls = [page['url'] for page in previous_pages]
current_urls = [page['url'] for page in deadend_pages]
categorized_pages = []
for url in previous_urls:
if url not in current_urls:
# Find the page in previous_pages
for page in previous_pages:
if page['url'] == url:
# This page is no longer in the DeadendPages list, which means it has been categorized
categorized_pages.append(page)
break
# Create a timestamp for the current data
current_timestamp = datetime.now().isoformat()
# Create the history entry
history_entry = {
'pages': deadend_pages,
'categorized_pages': categorized_pages
}
# Add the entry to history with timestamp as key
existing_data['history'][current_timestamp] = history_entry
# Update the current data
existing_data['pages'] = deadend_pages
existing_data['categorized_pages'] = categorized_pages
existing_data['last_updated'] = current_timestamp
# Save the updated data
save_to_json(existing_data, DEADEND_PAGES_FILE)
```
### 5. Modification du contrôleur `WikiController.php`
Ajout du chargement des données des pages sans catégorie :
```php
// Load deadend pages (pages starting with "France" from the DeadendPages list)
$deadendPages = [];
$categorizedPages = [];
$deadendPagesFile = $this->getParameter('kernel.project_dir') . '/wiki_compare/deadend_pages.json';
if (file_exists($deadendPagesFile)) {
$deadendPagesData = json_decode(file_get_contents($deadendPagesFile), true);
if (isset($deadendPagesData['pages']) && is_array($deadendPagesData['pages'])) {
$deadendPages = $deadendPagesData['pages'];
}
if (isset($deadendPagesData['categorized_pages']) && is_array($deadendPagesData['categorized_pages'])) {
$categorizedPages = $deadendPagesData['categorized_pages'];
}
}
```
Ajout des données à la vue :
```php
return $this->render('admin/wiki.html.twig', [
// Autres données...
'deadend_pages' => $deadendPages,
'categorized_pages' => $categorizedPages
]);
```
### 6. Ajout de sections dans le template `admin/wiki.html.twig`
Ajout d'une section pour afficher les pages sans catégorie :
```twig
{% if deadend_pages is defined and deadend_pages|length > 0 %}
<div class="card mb-4">
<div class="card-header bg-danger text-white">
<h2>Pages "France" sans catégorie ({{ deadend_pages|length }})</h2>
</div>
<div class="card-body">
<p>Ces pages wiki commençant par "France" n'ont pas de catégorie. Vous pouvez contribuer en ajoutant des catégories à ces pages.</p>
<div class="table-responsive">
<table class="table table-striped table-hover">
<!-- Contenu de la table -->
</table>
</div>
</div>
</div>
{% endif %}
```
Ajout d'une section pour afficher les pages récemment catégorisées :
```twig
{% if categorized_pages is defined and categorized_pages|length > 0 %}
<div class="card mb-4">
<div class="card-header bg-success text-white">
<h2>Pages "France" récemment catégorisées ({{ categorized_pages|length }})</h2>
</div>
<div class="card-body">
<p>Ces pages wiki commençant par "France" ont été récemment catégorisées et ne sont plus dans la liste des pages sans catégorie.</p>
<div class="table-responsive">
<table class="table table-striped table-hover">
<!-- Contenu de la table -->
</table>
</div>
</div>
</div>
{% endif %}
```
## Fonctionnalités
1. **Scraping des pages sans catégorie** : Récupération des pages commençant par "France" depuis la liste des DeadendPages du wiki OSM.
2. **Suggestion de catégories** : Analyse du titre et du contenu des pages pour suggérer des catégories pertinentes.
3. **Suivi des pages catégorisées** : Détection des pages qui ont été catégorisées depuis le dernier scraping.
4. **Affichage dans l'interface** : Affichage des pages sans catégorie et des pages récemment catégorisées dans l'interface utilisateur.
## Utilisation
1. Le script `wiki_compare.py` est exécuté périodiquement pour mettre à jour les données.
2. Les utilisateurs peuvent consulter les pages sans catégorie et les pages récemment catégorisées dans l'interface.
3. Les utilisateurs peuvent cliquer sur les boutons d'action pour voir les pages et ajouter des catégories.
## Avantages
1. **Amélioration de la qualité du wiki** : Aide à identifier et à catégoriser les pages qui devraient avoir des catégories.
2. **Suivi des progrès** : Permet de suivre les progrès dans la catégorisation des pages.
3. **Suggestion de catégories** : Facilite le travail des contributeurs en suggérant des catégories pertinentes.

View file

@ -0,0 +1,94 @@
# Corrections apportées à QualiWiki
Ce document décrit les corrections apportées pour résoudre les problèmes mentionnés dans la description des issues.
## 1. Correction de l'erreur dans wiki_archived_proposals.html.twig
### Problème
```
Key "total_proposals" for sequence/mapping with keys "0, 1, 2, 3, ..." does not exist in admin/wiki_archived_proposals.html.twig at line 193.
```
### Solution
Ajout d'une valeur par défaut pour `total_proposals` dans le template :
```twig
<div class="stats-value">{{ statistics.total_proposals|default(proposals|length) }}</div>
```
Cette modification permet d'utiliser le nombre de propositions dans le tableau `proposals` comme valeur par défaut si `statistics.total_proposals` n'est pas défini.
## 2. Implémentation d'un panneau latéral sombre pour la navigation
### Modifications
- Ajout d'un panneau latéral sombre dans `templates/base.html.twig`
- Ajout de styles CSS dans `public/css/main.css` pour le panneau latéral
- Réorganisation de la structure HTML pour intégrer le panneau latéral
- Ajout de liens vers toutes les sections principales de l'application
### Avantages
- Navigation plus claire et plus accessible
- Meilleure organisation visuelle de l'application
- Accès rapide à toutes les fonctionnalités principales
## 3. Création d'une page dashboard avec graphiques
### Fonctionnalités
- Ajout d'une méthode `dashboard` dans `WikiController.php`
- Création d'un template `admin/wiki_dashboard.html.twig`
- Implémentation de graphiques montrant :
- L'évolution du score moyen de décrépitude
- L'évolution du nombre de pages suivies
- L'évolution du nombre de pages sans catégorie
### Données suivies
- Score moyen de décrépitude des pages
- Nombre de pages suivies
- Nombre de pages sans catégorie (pages orphelines)
## 4. Correction de l'erreur dans wiki_random_suggestion.html.twig
### Problème
```
Key "en_page" for sequence/mapping with keys "title, level" does not exist in admin/wiki_random_suggestion.html.twig at line 28.
```
### Solution
- Ajout de vérifications pour l'existence de `en_page` dans le template
- Ajout de valeurs par défaut pour les propriétés de `en_page`
- Filtrage des pages pour s'assurer qu'elles ont une clé `en_page` dans le contrôleur
## 5. Ajout d'avatars utilisateurs dans la page des changements récents
### Fonctionnalités
- Ajout d'une fonction `fetchUserAvatar` dans `WikiController.php` pour récupérer et mettre en cache les avatars des utilisateurs
- Mise à jour des templates `admin/wiki_recent_changes.html.twig` et `public/wiki_recent_changes.html.twig` pour afficher les avatars
- Mise en cache des avatars pour éviter de les récupérer à chaque fois
## 6. Correction de l'erreur de mémoire dans la page des suppressions suspectes
### Problème
```
Error: Allowed memory size of 134217728 bytes exhausted (tried to allocate 175260864 bytes)
```
### Solution
- Modification de la méthode `suspiciousDeletions` dans `WikiController.php` pour utiliser une approche plus efficace en mémoire
- Utilisation de la méthode `extractJsonArrayByKey` au lieu de `json_decode(file_get_contents())` pour traiter le fichier JSON
- Limitation du nombre d'éléments extraits à 50 avec le paramètre `$maxItems`
- Ajout d'une limite pour arrêter le traitement après avoir trouvé 20 pages suspectes
## 7. Implémentation du suivi des pages "France" sans catégorie
### Fonctionnalités
- Ajout de constantes pour l'URL des DeadendPages et le fichier de sortie dans `wiki_compare.py`
- Création d'une fonction `fetch_deadend_pages` pour récupérer les pages commençant par "France" depuis la liste des DeadendPages
- Création d'une fonction `suggest_categories` pour suggérer des catégories pour les pages sans catégorie
- Modification de la fonction `main` pour traiter et sauvegarder les données des DeadendPages
- Mise à jour du contrôleur pour charger et afficher les données des DeadendPages
- Ajout de sections dans le template pour afficher les pages sans catégorie et les pages récemment catégorisées
### Avantages
- Suivi des pages qui devraient avoir des catégories
- Suggestion de catégories pour faciliter le travail des contributeurs
- Suivi des progrès dans la catégorisation des pages

View file

@ -61,10 +61,12 @@ WIKI_BASE_URL_EN = "https://wiki.openstreetmap.org/wiki/Key:"
WIKI_BASE_URL_FR = "https://wiki.openstreetmap.org/wiki/FR:Key:"
WIKI_BASE_URL = "https://wiki.openstreetmap.org/wiki/"
WIKI_CATEGORY_URL = "https://wiki.openstreetmap.org/wiki/Category:FR:Traductions_d%C3%A9synchronis%C3%A9es"
WIKI_DEADEND_PAGES_URL = "https://wiki.openstreetmap.org/w/index.php?title=Special:DeadendPages&limit=500&offset=1000"
TOP_KEYS_FILE = "top_keys.json"
KEYS_WITHOUT_WIKI_FILE = "keys_without_wiki.json"
WIKI_PAGES_CSV = "wiki_pages.csv"
OUTDATED_PAGES_FILE = "outdated_pages.json"
DEADEND_PAGES_FILE = "deadend_pages.json"
STALENESS_HISTOGRAM_FILE = "staleness_histogram.png"
# Number of wiki pages to examine
NUM_WIKI_PAGES = 2
@ -154,6 +156,161 @@ def fetch_desynchronized_pages():
logger.error(f"Error fetching category page: {e}")
return []
def suggest_categories(page_title, page_url):
"""
Suggest categories for an uncategorized page based on its title and content
Args:
page_title (str): Title of the page
page_url (str): URL of the page
Returns:
list: List of suggested categories
"""
logger.info(f"Suggesting categories for page: {page_title}")
suggested_categories = []
# Common categories for French OSM wiki pages
common_categories = [
"Documentation OSM en français",
"Cartographie",
"Contributeurs",
"Développeurs",
"Éléments cartographiés",
"Imports",
"Logiciels",
"Projets",
"Rencontres",
"Utilisateurs"
]
# Add geography-related categories for pages about France
if "France" in page_title:
suggested_categories.append("France")
# Check for specific regions or departments
regions = [
"Auvergne-Rhône-Alpes", "Bourgogne-Franche-Comté", "Bretagne",
"Centre-Val de Loire", "Corse", "Grand Est", "Hauts-de-France",
"Île-de-France", "Normandie", "Nouvelle-Aquitaine",
"Occitanie", "Pays de la Loire", "Provence-Alpes-Côte d'Azur"
]
for region in regions:
if region in page_title:
suggested_categories.append(region)
# Try to fetch the page content to make better suggestions
try:
response = requests.get(page_url)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser')
# Get the main content
content = soup.select_one('#mw-content-text')
if content:
text = content.get_text(separator=' ', strip=True).lower()
# Check for keywords related to common categories
if any(keyword in text for keyword in ["carte", "cartographie", "mapper"]):
suggested_categories.append("Cartographie")
if any(keyword in text for keyword in ["contribuer", "contributeur", "éditer"]):
suggested_categories.append("Contributeurs")
if any(keyword in text for keyword in ["développeur", "programmer", "code", "api"]):
suggested_categories.append("Développeurs")
if any(keyword in text for keyword in ["tag", "clé", "valeur", "élément", "nœud", "way", "relation"]):
suggested_categories.append("Éléments cartographiés")
if any(keyword in text for keyword in ["import", "données", "dataset"]):
suggested_categories.append("Imports")
if any(keyword in text for keyword in ["logiciel", "application", "outil"]):
suggested_categories.append("Logiciels")
if any(keyword in text for keyword in ["projet", "initiative"]):
suggested_categories.append("Projets")
if any(keyword in text for keyword in ["rencontre", "réunion", "événement", "conférence"]):
suggested_categories.append("Rencontres")
if any(keyword in text for keyword in ["utiliser", "utilisateur", "usage"]):
suggested_categories.append("Utilisateurs")
except requests.exceptions.RequestException as e:
logger.warning(f"Error fetching page content for category suggestions: {e}")
# If we can't fetch the content, suggest common categories based on title only
if "projet" in page_title.lower():
suggested_categories.append("Projets")
elif "logiciel" in page_title.lower() or "application" in page_title.lower():
suggested_categories.append("Logiciels")
elif "rencontre" in page_title.lower() or "réunion" in page_title.lower():
suggested_categories.append("Rencontres")
# Always suggest the general French documentation category
suggested_categories.append("Documentation OSM en français")
# Remove duplicates while preserving order
seen = set()
unique_categories = []
for cat in suggested_categories:
if cat not in seen:
seen.add(cat)
unique_categories.append(cat)
logger.info(f"Suggested {len(unique_categories)} categories for {page_title}: {', '.join(unique_categories)}")
return unique_categories
def fetch_deadend_pages():
"""
Fetch pages starting with "France" from the DeadendPages list
Returns:
list: List of dictionaries containing page information
"""
logger.info(f"Fetching pages from DeadendPages list: {WIKI_DEADEND_PAGES_URL}")
try:
response = requests.get(WIKI_DEADEND_PAGES_URL)
response.raise_for_status()
soup = BeautifulSoup(response.text, 'html.parser')
# Find all links in the DeadendPages list
page_links = []
for link in soup.select('.mw-spcontent li a'):
href = link.get('href', '')
title = link.get_text(strip=True)
# Skip if it's not a wiki page or if it's a special page
if not href.startswith('/wiki/') or 'Special:' in href:
continue
# Filter pages that start with "France"
if title.startswith('France'):
# Get the full URL
full_url = 'https://wiki.openstreetmap.org' + href
# Suggest categories for this page
suggested_categories = suggest_categories(title, full_url)
page_links.append({
'title': title,
'url': full_url,
'suggested_categories': suggested_categories
})
logger.info(f"Found {len(page_links)} pages starting with 'France' in the DeadendPages list")
return page_links
except requests.exceptions.RequestException as e:
logger.error(f"Error fetching DeadendPages list: {e}")
return []
def fetch_top_keys(limit=NUM_WIKI_PAGES):
"""
Fetch the most used OSM keys from TagInfo API
@ -1365,10 +1522,11 @@ def main():
3. Fetches and processes wiki pages for these keys
4. Processes specific wiki pages listed in SPECIFIC_PAGES
5. Processes pages from the FR:Traductions_désynchronisées category
6. Calculates staleness scores for all pages
7. Generates a histogram of staleness scores
8. Saves the results to CSV and JSON files
9. Prints a list of pages that need updating
6. Processes pages starting with "France" from the DeadendPages list
7. Calculates staleness scores for all pages
8. Generates a histogram of staleness scores
9. Saves the results to CSV and JSON files
10. Prints a list of pages that need updating
"""
# Parse command-line arguments
parser = argparse.ArgumentParser(description='Compare OpenStreetMap wiki pages in English and French.')
@ -1404,6 +1562,62 @@ def main():
logger.info(f"Saved {len(keys_without_wiki)} keys without wiki pages to {KEYS_WITHOUT_WIKI_FILE}")
else:
logger.warning("No keys without wiki pages were fetched.")
# Fetch pages starting with "France" from the DeadendPages list
deadend_pages = fetch_deadend_pages()
if deadend_pages:
# Load existing deadend pages data to compare with history
existing_data = load_json_data(DEADEND_PAGES_FILE)
# Initialize history if it doesn't exist
if 'history' not in existing_data:
existing_data['history'] = {}
# Get the most recent history entry
sorted_timestamps = sorted(existing_data.get('history', {}).keys())
previous_pages = []
if sorted_timestamps:
latest_timestamp = sorted_timestamps[-1]
previous_pages = existing_data['history'][latest_timestamp].get('pages', [])
# Find pages that were in the previous list but are no longer in the current list
previous_urls = [page['url'] for page in previous_pages]
current_urls = [page['url'] for page in deadend_pages]
categorized_pages = []
for url in previous_urls:
if url not in current_urls:
# Find the page in previous_pages
for page in previous_pages:
if page['url'] == url:
# This page is no longer in the DeadendPages list, which means it has been categorized
categorized_pages.append(page)
break
# Create a timestamp for the current data
current_timestamp = datetime.now().isoformat()
# Create the history entry
history_entry = {
'pages': deadend_pages,
'categorized_pages': categorized_pages
}
# Add the entry to history with timestamp as key
existing_data['history'][current_timestamp] = history_entry
# Update the current data
existing_data['pages'] = deadend_pages
existing_data['categorized_pages'] = categorized_pages
existing_data['last_updated'] = current_timestamp
# Save the updated data
save_to_json(existing_data, DEADEND_PAGES_FILE)
logger.info(f"Saved {len(deadend_pages)} deadend pages to {DEADEND_PAGES_FILE}")
logger.info(f"Found {len(categorized_pages)} pages that have been categorized since the last run")
else:
logger.warning("No deadend pages were fetched.")
# Fetch wiki pages for each key
wiki_pages = []