This commit is contained in:
Ladebeze66 2025-04-03 11:11:13 +02:00
parent db180b340f
commit ea257c737e
11 changed files with 149 additions and 769 deletions

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

View File

@ -1,4 +0,0 @@
Extraction du ticket 11046 le 2025-04-03 10:22:59
Nom du ticket: changement nom centrale d'enrobage
Nombre de messages: 9
Nombre de pièces jointes: 3

File diff suppressed because one or more lines are too long

View File

@ -1,5 +1,5 @@
{ {
"date_extraction": "2025-04-03T10:44:16.768543", "date_extraction": "2025-04-03T11:09:41.473063",
"ticket_dir": "output/ticket_T11067", "ticket_dir": "output/ticket_T11067",
"fichiers_json": [ "fichiers_json": [
"ticket_info.json", "ticket_info.json",

File diff suppressed because one or more lines are too long

View File

@ -1 +1,6 @@
{} {
"id": 11046,
"name": "changement nom centrale d'enrobage",
"description": "<p><br></p>",
"stage_id": "Clôturé"
}

View File

@ -4,6 +4,8 @@ import base64
import requests import requests
from typing import Dict, List, Any, Optional from typing import Dict, List, Any, Optional
from datetime import datetime from datetime import datetime
import re
from html import unescape
class TicketManager: class TicketManager:
def __init__(self, url: str, db: str, username: str, api_key: str): def __init__(self, url: str, db: str, username: str, api_key: str):
@ -49,9 +51,20 @@ class TicketManager:
"model": self.model_name, "model": self.model_name,
"method": "read", "method": "read",
"args": [[ticket_id]], "args": [[ticket_id]],
"kwargs": {} "kwargs": {"fields": ["id", "name", "description", "stage_id", "user_id", "partner_id",
"create_date", "write_date", "date_deadline", "priority",
"tag_ids", "code", "project_id"]}
} }
return self._rpc_call("/web/dataset/call_kw", params) result = self._rpc_call("/web/dataset/call_kw", params)
# Afficher le résultat brut pour le débogage
print(f"Réponse brute de l'appel RPC pour le ticket ID {ticket_id} : {result}")
if isinstance(result, list) and len(result) > 0:
return result[0]
else:
print(f"Aucun ticket trouvé avec l'ID {ticket_id} ou une erreur est survenue.")
return {}
def get_ticket_messages(self, ticket_id: int) -> List[Dict[str, Any]]: def get_ticket_messages(self, ticket_id: int) -> List[Dict[str, Any]]:
messages = self._rpc_call("/web/dataset/call_kw", { messages = self._rpc_call("/web/dataset/call_kw", {
@ -63,32 +76,24 @@ class TicketManager:
return messages return messages
def get_ticket_by_code(self, ticket_code: str) -> Dict[str, Any]: def get_ticket_by_code(self, ticket_code: str) -> Dict[str, Any]:
"""
Récupère un ticket par son code unique.
Args:
ticket_code: Code du ticket à récupérer (par exemple, T11067)
Returns:
Dictionnaire contenant les informations du ticket ou une erreur si non trouvé
"""
# Recherche du ticket par code
params = { params = {
"model": self.model_name, "model": self.model_name,
"method": "search_read", "method": "search_read",
"args": [[["code", "=", ticket_code]], ["id", "name", "description", "stage_id"]], "args": [[["code", "=", ticket_code]]],
"kwargs": {"limit": 1} "kwargs": {"fields": ["id", "name", "description", "stage_id", "user_id",
"partner_id", "create_date", "write_date"], "limit": 1}
} }
print(f"Recherche du ticket avec code: {ticket_code}")
result = self._rpc_call("/web/dataset/call_kw", params) result = self._rpc_call("/web/dataset/call_kw", params)
if not result: if result and len(result) > 0:
print(f"Ticket trouvé avec le code {ticket_code}: ID={result[0]['id']}")
return result[0]
else:
print(f"Aucun ticket trouvé avec le code {ticket_code}") print(f"Aucun ticket trouvé avec le code {ticket_code}")
return {} return {}
# Retourne le premier ticket trouvé
return result[0] if isinstance(result, list) and len(result) > 0 else {}
def save_json(self, data: Any, path: str): def save_json(self, data: Any, path: str):
with open(path, "w", encoding="utf-8") as f: with open(path, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2, ensure_ascii=False) json.dump(data, f, indent=2, ensure_ascii=False)
@ -97,25 +102,31 @@ class TicketManager:
os.makedirs(output_dir, exist_ok=True) os.makedirs(output_dir, exist_ok=True)
ticket_data = self.get_ticket(ticket_id) ticket_data = self.get_ticket(ticket_id)
self.save_json(ticket_data, os.path.join(output_dir, "ticket_info.json"))
# Vérifier si le ticket a bien été trouvé
if not ticket_data or "id" not in ticket_data:
print(f"Impossible d'extraire les données pour le ticket ID {ticket_id}")
return {"error": "Ticket non trouvé", "ticket_info": None, "messages_file": None, "ticket_data_file": None, "attachments": []}
ticket_info = {
"id": ticket_data["id"],
"name": ticket_data["name"],
"description": ticket_data.get("description", ""),
"stage_id": ticket_data.get("stage_id", ["", ""])[1] if ticket_data.get("stage_id") else "Non défini"
}
self.save_json(ticket_info, os.path.join(output_dir, "ticket_info.json"))
messages = self.get_ticket_messages(ticket_id) messages = self.get_ticket_messages(ticket_id)
# Save messages in raw and cleaned formats # Sauvegarde brute des messages
self.save_json(messages, os.path.join(output_dir, "messages_raw.json")) self.save_json(messages, os.path.join(output_dir, "messages_raw.json"))
cleaned_messages = [] # Nettoyage des messages
for msg in messages: cleaned_messages = self._clean_messages(messages)
cleaned_messages.append({
"message_id": msg["id"],
"sender": msg["author_id"][1] if msg["author_id"] else "Unknown",
"timestamp": msg["date"],
"content": self.clean_html(msg["body"])
})
self.save_json(cleaned_messages, os.path.join(output_dir, "all_messages.json")) self.save_json(cleaned_messages, os.path.join(output_dir, "all_messages.json"))
# Generate structure.json # Génération de structure.json
structure = { structure = {
"date_extraction": datetime.now().isoformat(), "date_extraction": datetime.now().isoformat(),
"ticket_dir": output_dir, "ticket_dir": output_dir,
@ -127,38 +138,40 @@ class TicketManager:
} }
self.save_json(structure, os.path.join(output_dir, "structure.json")) self.save_json(structure, os.path.join(output_dir, "structure.json"))
def clean_html(self, html_content: str) -> str: return {
import re "ticket_info": os.path.join(output_dir, "ticket_info.json"),
from html import unescape "messages_file": os.path.join(output_dir, "all_messages.json"),
"ticket_data_file": os.path.join(output_dir, "structure.json"),
"attachments": [] # Si vous implémentez la gestion des pièces jointes
}
text = re.sub(r'<.*?>', '', html_content) def _clean_messages(self, messages: List[Dict[str, Any]]) -> List[Dict[str, Any]]:
text = unescape(text) signatures = [
text = re.sub(r'\s+', ' ', text).strip() r'Droit à la déconnexion.*',
r'Ce message électronique et tous les fichiers attachés.*',
r'Direction des Infrastructures.*',
r'Service d\'Appui aux Politiques d\'Aménagement.*',
r'tél :.*',
r'mobile :.*',
r'email :.*',
r'Cordialement,.*',
r'Bonne réception.*',
r'---.*'
]
return text cleaned_messages = []
for msg in messages:
body = msg.get("body", "")
body = re.sub(r'<.*?>', '', body)
body = unescape(body)
body = re.sub(r'\s+', ' ', body).strip()
if __name__ == "__main__": # Supprime les signatures courantes
import sys for signature in signatures:
body = re.sub(signature, '', body, flags=re.IGNORECASE | re.DOTALL)
if len(sys.argv) < 2: msg["body"] = body
print("Usage: python ticket_manager2.py <ticket_id>") cleaned_messages.append(msg)
sys.exit(1)
ticket_id = int(sys.argv[1]) return cleaned_messages
# Configuration Odoo
url = "https://odoo.cbao.fr"
db = "database_name"
username = "username"
api_key = "api_key"
manager = TicketManager(url, db, username, api_key)
if not manager.login():
print("Échec de connexion à Odoo")
sys.exit(1)
output_dir = f"T11067_analysis/ticket_structure"
manager.extract_ticket_data(ticket_id, output_dir)
print("Extraction terminée avec succès.")