API résumé et gestion
تم الإنشاء في: ١٧ يناير ٢٠٢٥
تم الإنشاء في: ١٧ يناير ٢٠٢٥
ce code peux ajouter une api import sys
import json
import requests
from groq import Groq
apis_configurees = []
MAX_CHARS_DIRECT_ANALYSIS = 3000
def summarizer_groq(long_text, groq_api_key="gsk_XXXXXXXXXXXXXXX"):
"""
Découpe la documentation en chunks et génère un résumé global en langage naturel.
Ceci n'utilise pas le mode JSON : on veut juste un résumé texte.
"""
client = Groq(api_key=groq_api_key)
textchunk_size = 3000 chunks = [] start = 0 while start < len(long_text): end = start + chunk_size chunks.append(long_text[start:end]) start = end summaries = [] for i, chunk_text in enumerate(chunks, start=1): print(f"[INFO] Résumé du chunk {i}/{len(chunks)}...") messages = [ { "role": "system", "content": ( "Tu es un assistant chargé de résumer la documentation d'API. " "Retourne un résumé concis (en langage courant) du texte fourni. " "Ne génère pas de JSON, pas de code, juste un texte résumé clair." ) }, { "role": "user", "content": chunk_text } ] try: completion = client.chat.completions.create( messages=messages, # Mixtral est conseillé pour la génération de JSON, # mais convient également pour la génération de texte court. model="llama-3.3-70b-versatile", temperature=0.2, max_completion_tokens=1024, top_p=1, stream=False ) summary_text = completion.choices[0].message.content.strip() summaries.append(summary_text) except Exception as e: print(f"[ERREUR] Impossible de résumer le chunk {i} : {e}") # On concatène juste une chaîne vide si échec summaries.append("") combined_summary = "\n".join(summaries) print(f"[INFO] Résumé global généré. Longueur du résumé : {len(combined_summary)} caractères.") return combined_summary
def analyser_api_avec_groq(input_text, groq_api_key="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"):
"""
1) Si le texte est trop long, on génère un résumé texte via summarizer_groq.
2) On passe ensuite (ou directement) le texte final dans un prompt
qui demande un JSON strict, en utilisant la 'response_format={"type": "json_object"}'
pour forcer Groq à renvoyer un JSON valide.
"""
# 1) Résume si trop volumineux
text_for_analysis = input_text
if len(input_text) > MAX_CHARS_DIRECT_ANALYSIS:
print("[INFO] La documentation est trop volumineuse, on génère un résumé d’abord.")
text_for_analysis = summarizer_groq(input_text, groq_api_key=groq_api_key)
text# 2) Appel Chat Completion en mode JSON client = Groq(api_key=groq_api_key) # Prompt : nous exigeons un JSON strict messages = [ { "role": "system", "content": ( "Tu es un assistant d'analyse d'API, tu dois répondre UNIQUEMENT en JSON valide, sans code superflu. " "Respecte le schéma JSON suivant (toutes les clés doivent exister) :\n\n" "{\n" " \"api_type\": \"REST | GraphQL | SOAP\",\n" " \"base_url\": \"string\",\n" " \"auth_info\": {\n" " \"type\": \"string (Bearer, Basic, etc.)\",\n" " \"key_name\": \"string\",\n" " \"required\": true/false\n" " },\n" " \"common_headers\": {\n" " \"Header-Name\": \"Header-Value\"\n" " },\n" " \"endpoints\": [\n" " {\n" " \"name\": \"string\",\n" " \"path\": \"string\",\n" " \"method\": \"GET | POST | ...\",\n" " \"required_params\": [\"param1\", \"param2\"],\n" " \"optional_params\": [\"param1\", \"param2\"],\n" " \"description\": \"string\"\n" " }\n" " ],\n" " \"suggested_name\": \"string\",\n" " \"rate_limit\": \"string\",\n" " \"confidence_score\": 0.0\n" "}\n\n" "Analyse le texte ci-après et renvoie STRICTEMENT un JSON conforme, sans texte additionnel." ) }, { "role": "user", "content": text_for_analysis } ] try: chat_completion = client.chat.completions.create( messages=messages, model="llama-3.3-70b-versatile", # Meilleur pour JSON d'après la doc temperature=0.0, max_completion_tokens=1024, top_p=1, stream=False, # Activation du mode JSON : Groq renverra un JSON strict ou renverra une erreur response_format={"type": "json_object"} ) # Puisque response_format={"type":"json_object"} est activé, # le contenu renvoyé EST (en principe) déjà du JSON strict. # On l'obtient via : content = chat_completion.choices[0].message.content # content est déjà une chaîne JSON validée par Groq, on peut la charger directement data = json.loads(content) return data except Exception as e: print(f"[ERREUR] Échec de la conversion en JSON : {e}") print("[INFO] Nous allons retourner un squelette par défaut.") return { "api_type": None, "base_url": None, "auth_info": { "type": None, "key_name": None, "required": False }, "common_headers": {}, "endpoints": [], "suggested_name": "API_Inconnue", "rate_limit": None, "confidence_score": 0.0 }
def ajouter_api():
print("=== Ajout d’une nouvelle API ===")
textcoller_doc = input("Voulez-vous coller la documentation de l’API ? (o/n) : ") doc_api = "" print("Collez la documentation ci-dessous (finissez par un skibidi vide) :") lignes_doc = "" while True: ligne = input() if ligne == "skibidi": break lignes_doc += ligne + "\n" doc_api = lignes_doc url_ou_description = doc_api texte_complet = "" if doc_api.strip(): texte_complet += doc_api.strip() if url_ou_description.strip(): texte_complet += "\n\n" + url_ou_description.strip() if not texte_complet: texte_complet = "Pas d'information sur l'API." # Appel Groq pour analyse resultats_analyse = analyser_api_avec_groq(texte_complet, groq_api_key="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") confidence_score = resultats_analyse.get("confidence_score", 0.0) if confidence_score < 0.5: print( "Le score de confiance de l’analyse est faible. " "Les informations retournées peuvent être partielles ou incorrectes.\n" ) # On lit les champs api_type = resultats_analyse.get("api_type") base_url = resultats_analyse.get("base_url") auth_info = resultats_analyse.get("auth_info", {}) common_headers = resultats_analyse.get("common_headers", {}) endpoints = resultats_analyse.get("endpoints", []) suggested_name = resultats_analyse.get("suggested_name", "NouvelleAPI") rate_limit = resultats_analyse.get("rate_limit") print(f"Nom suggéré pour l’API : {suggested_name}") nom_api = input(f"Entrez le nom de l’API ({suggested_name}) : ") if not nom_api.strip(): nom_api = suggested_name # Si auth_info.required == True, on demande la clé api_key_value = None if auth_info.get("required", False): api_key_value = input("Entrez la valeur de la clé API ou du token : ") # Construction de la config nouvelle_api = { "name": nom_api, "type": api_type, "base_url": base_url, "auth_info": auth_info, "api_key_value": api_key_value, "common_headers": common_headers, "endpoints": endpoints, "rate_limit": rate_limit } apis_configurees.append(nouvelle_api) print(f"\n[OK] L’API '{nom_api}' a été ajoutée.") print(f" - Type : {api_type}") print(f" - URL de base : {base_url}\n")
def lister_apis():
print("=== Liste des API configurées ===")
if not apis_configurees:
print("Aucune API n’est configurée.\n")
return
textfor i, api in enumerate(apis_configurees, start=1): print(f"{i}. Nom : {api['name']}") print(f" URL de base : {api['base_url'] or 'Non renseignée'}") print(f" Type : {api['type'] or 'Inconnu'}") if api["rate_limit"]: print(f" Limitation de débit : {api['rate_limit']}") if api["endpoints"]: print(" Endpoints :") for ep in api["endpoints"]: print(f" - {ep['name']} ({ep['method']} {ep['path']})") else: print(" Aucun endpoint configuré.") print() print()
def modifier_api():
print("=== Modification d’une API ===")
if not apis_configurees:
print("Aucune API n’est configurée.\n")
return
textfor i, api in enumerate(apis_configurees, start=1): print(f"{i}. {api['name']}") choix = input("Quelle API souhaitez-vous modifier ? (nom ou numéro) : ") api_choisie = None try: idx = int(choix) - 1 if 0 <= idx < len(apis_configurees): api_choisie = apis_configurees[idx] except ValueError: for a in apis_configurees: if a["name"].lower() == choix.lower(): api_choisie = a break if not api_choisie: print("API introuvable.\n") return print(f"\nAPI sélectionnée : {api_choisie['name']}") print("Que voulez-vous modifier ? (ex: 'changer l'URL de base', 'changer la clé API', " "'ajouter un endpoint', 'modifier un endpoint', 'supprimer un endpoint')") action = input("> ").lower() if "url" in action: new_url = input("Nouvelle URL de base : ") api_choisie["base_url"] = new_url print("URL de base modifiée.\n") if "clé" in action or "key" in action: new_key = input("Nouvelle clé API : ") api_choisie["api_key_value"] = new_key print("Clé API modifiée.\n") if "ajouter un endpoint" in action: print("=== Ajout d'un endpoint ===") nom_ep = input("Nom du nouvel endpoint : ") path_ep = input("Chemin (ex: /playlists/{playlist_id}/tracks) : ") methode = input("Méthode HTTP (GET, POST, etc.) : ") params_req = [p.strip() for p in input("Paramètres requis (séparés par des virgules) : ").split(",") if p.strip()] params_opt = [p.strip() for p in input("Paramètres optionnels (séparés par des virgules) : ").split(",") if p.strip()] new_ep = { "name": nom_ep, "path": path_ep, "method": methode.upper(), "required_params": params_req, "optional_params": params_opt, "description": "" } api_choisie["endpoints"].append(new_ep) print(f"Endpoint '{nom_ep}' ajouté.\n") if "modifier un endpoint" in action: print("=== Modification d'un endpoint ===") for i, ep in enumerate(api_choisie["endpoints"], start=1): print(f"{i}. {ep['name']} ({ep['method']} {ep['path']})") choix_ep = input("Quel endpoint ? (numéro ou nom) : ") ep_choisi = None try: eidx = int(choix_ep) - 1 if 0 <= eidx < len(api_choisie["endpoints"]): ep_choisi = api_choisie["endpoints"][eidx] except: for ep in api_choisie["endpoints"]: if ep["name"].lower() == choix_ep.lower(): ep_choisi = ep break if not ep_choisi: print("Endpoint introuvable.") return print(f"Endpoint sélectionné : {ep_choisi['name']}") modif_ep = input("Que voulez-vous faire ? (ex: 'ajouter un paramètre', 'changer la méthode', etc.) : ").lower() if "ajouter un paramètre" in modif_ep: nom_p = input("Nom du paramètre : ") r_o = input("Paramètre requis ou optionnel ? (r/o) : ") if r_o.lower() == 'r': ep_choisi["required_params"].append(nom_p) else: ep_choisi["optional_params"].append(nom_p) print(f"Paramètre '{nom_p}' ajouté.\n") # Vous pouvez ajouter d’autres modifications au besoin (méthode, path, etc.) if "supprimer un endpoint" in action: print("=== Suppression d'un endpoint ===") for i, ep in enumerate(api_choisie["endpoints"], start=1): print(f"{i}. {ep['name']} ({ep['method']} {ep['path']})") choix_ep = input("Quel endpoint supprimer ? (numéro ou nom) : ") ep_asup = None try: eidx = int(choix_ep) - 1 if 0 <= eidx < len(api_choisie["endpoints"]): ep_asup = api_choisie["endpoints"][eidx] except: for ep in api_choisie["endpoints"]: if ep["name"].lower() == choix_ep.lower(): ep_asup = ep break if ep_asup: api_choisie["endpoints"].remove(ep_asup) print(f"Endpoint '{ep_asup['name']}' supprimé.") else: print("Endpoint introuvable.") print("Modification(s) terminée(s).\n")
def supprimer_api():
print("=== Suppression d’une API ===")
if not apis_configurees:
print("Aucune API n’est configurée.\n")
return
textfor i, api in enumerate(apis_configurees, start=1): print(f"{i}. {api['name']}") choix = input("Quelle API supprimer ? (nom ou numéro) : ") api_asup = None try: idx = int(choix) - 1 if 0 <= idx < len(apis_configurees): api_asup = apis_configurees[idx] except: for a in apis_configurees: if a["name"].lower() == choix.lower(): api_asup = a break if not api_asup: print("API introuvable.\n") return confirm = input(f"Êtes-vous sûr de vouloir supprimer '{api_asup['name']}' ? (o/n) : ") if confirm.lower() == 'o': apis_configurees.remove(api_asup) print(f"L’API '{api_asup['name']}' a été supprimée.\n") else: print("Opération annulée.\n")
def tester_endpoint():
print("=== Tester un endpoint ===")
if not apis_configurees:
print("Aucune API n’est configurée.\n")
return
textfor i, api in enumerate(apis_configurees, start=1): print(f"{i}. {api['name']}") choix = input("Sur quelle API tester un endpoint ? (nom ou numéro) : ") api_choisie = None try: idx = int(choix) - 1 if 0 <= idx < len(apis_configurees): api_choisie = apis_configurees[idx] except: for a in apis_configurees: if a["name"].lower() == choix.lower(): api_choisie = a break if not api_choisie: print("API introuvable.\n") return if not api_choisie["endpoints"]: print("Cette API n’a aucun endpoint configuré.\n") return print(f"Endpoints disponibles pour {api_choisie['name']} :") for i, ep in enumerate(api_choisie["endpoints"], start=1): print(f"{i}. {ep['name']} ({ep['method']} {ep['path']})") choix_ep = input("Quel endpoint tester ? (nom ou numéro) : ") ep_choisi = None try: eidx = int(choix_ep) - 1 if 0 <= eidx < len(api_choisie["endpoints"]): ep_choisi = api_choisie["endpoints"][eidx] except: for ep in api_choisie["endpoints"]: if ep["name"].lower() == choix_ep.lower(): ep_choisi = ep break if not ep_choisi: print("Endpoint introuvable.") return required_params = {} for rp in ep_choisi.get("required_params", []): required_params[rp] = input(f"Entrez la valeur pour '{rp}' : ") optional_params = {} for op in ep_choisi.get("optional_params", []): val = input(f"Valeur pour '{op}' (laisser vide si aucun) : ") if val: optional_params[op] = val base_url = api_choisie.get("base_url") or "" path = ep_choisi["path"] for k, v in required_params.items(): path = path.replace(f"{{{k}}}", v) url = base_url + path headers = dict(api_choisie.get("common_headers", {})) auth_info = api_choisie.get("auth_info", {}) if auth_info.get("required") and api_choisie.get("api_key_value"): # Si Bearer if auth_info["type"] and "bearer" in auth_info["type"].lower(): key_name = auth_info.get("key_name", "Authorization") headers[key_name] = f"Bearer {api_choisie['api_key_value']}" else: # Basic ou autre key_name = auth_info.get("key_name", "Authorization") headers[key_name] = api_choisie["api_key_value"] method = ep_choisi["method"].upper() params = optional_params print(f"\nTest de l'endpoint : {method} {url}") print(f"En-têtes : {headers}") print(f"Paramètres : {params}\n") try: if method == "GET": r = requests.get(url, headers=headers, params=params) elif method == "POST": r = requests.post(url, headers=headers, json=params) elif method == "PUT": r = requests.put(url, headers=headers, json=params) elif method == "DELETE": r = requests.delete(url, headers=headers, json=params) else: print("Méthode non gérée.") return print(f"Statut : {r.status_code}") try: print("Réponse JSON :") print(json.dumps(r.json(), indent=2)) except: print("Réponse brute :") print(r.text) except Exception as e: print(f"Erreur lors de l’appel : {e}")
def main():
while True:
print("=== Menu Principal ===")
print("1. Ajouter une API (assisté par IA)")
print("2. Liste des API configurées")
print("3. Modifier une API")
print("4. Supprimer une API")
print("5. Tester un endpoint")
print("6. Quitter")
textchoix = input("Choisissez une option : ") if choix == '1': ajouter_api() elif choix == '2': lister_apis() elif choix == '3': modifier_api() elif choix == '4': supprimer_api() elif choix == '5': tester_endpoint() elif choix == '6': print("Au revoir.") sys.exit(0) else: print("Choix invalide.\n")
if name == "main":
main()
je veux que tu me l'ameliore pour qu'il marche mieux et que je n'est pas ce type de probleme
=== Menu Principal ===
Https
The site is secure.
The https:// ensures that you are connecting to the official website and that any information you provide is encrypted and transmitted securely.
NASA logo{ APIs }
Overview
Generate API Key
Authentication
Recover API Key
Browse APIs
Search small
Search APIs
{ NASA APIs }
Welcome to the NASA API portal. The objective of this site is to make NASA data, including imagery, eminently accessible to application developers. This catalog focuses on broadly useful and user friendly APIs and does not hold every NASA API.
Get Started Browse APIs
Generate API Key
Your API key for [email protected] has been e-mailed to you. You can use your API key to begin making web service requests immediately.
If you don't receive your API Key via e-mail within a few minutes, please contact us.
For additional support, please contact us. When contacting us, please tell us what API you're accessing and provide the following account details so we can quickly find you:
Account Email: [email protected]
Account ID: be13d8b0-4c1c-47ff-9fb9-6392250058b6
Authentication
You do not need to authenticate in order to explore the NASA data. However, if you will be intensively using the APIs to, say, support a mobile application, then you should sign up for a NASA developer key.
Web Service Rate Limits
Limits are placed on the number of API requests you may make using your API key. Rate limits may vary by service, but the defaults are:
Hourly Limit: 1,000 requests per hour
For each API key, these limits are applied across all api.nasa.gov API requests. Exceeding these limits will lead to your API key being temporarily blocked from making further requests. The block will automatically be lifted by waiting an hour. If you need higher rate limits, contact us.
DEMO_KEY Rate Limits
In documentation examples, the special DEMO_KEY api key is used. This API key can be used for initially exploring APIs prior to signing up, but it has much lower rate limits, so you’re encouraged to signup for your own API key if you plan to use the API (signup is quick and easy). The rate limits for the DEMO_KEY are:
Hourly Limit: 30 requests per IP address per hour
Daily Limit: 50 requests per IP address per day
How Do I See My Current Usage?
Your can check your current rate limit and usage details by inspecting the X-RateLimit-Limit and X-RateLimit-Remaining HTTP headers that are returned on every API response. For example, if an API has the default hourly limit of 1,000 request, after making 2 requests, you will receive this HTTP header in the response of the second request:
X-RateLimit-Remaining: 998
The hourly counters for your API key reset on a rolling basis.
Example: If you made 500 requests at 10:15AM and 500 requests at 10:25AM, your API key would become temporarily blocked. This temporary block of your API key would cease at 11:15AM, at which point you could make 500 requests. At 11:25AM, you could then make another 500 requests.
Anyone can register for an api.nasa.gov key, which can be used to access data across federal agencies.
API Key Recovery
Please contact us for help recovering an old API keyInfo I Icon
Browse APIs
Search big
Search
APOD: Astronomy Picture of the Day
Asteroids NeoWs: Near Earth Object Web Service
Asteroids - NeoWs
NeoWs (Near Earth Object Web Service) is a RESTful web service for near earth Asteroid information. With NeoWs a user can: search for Asteroids based on their closest approach date to Earth, lookup a specific Asteroid with its NASA JPL small body id, as well as browse the overall data-set.
Data-set: All the data is from the NASA JPL Asteroid team (http://neo.jpl.nasa.gov/).
This API is maintained by SpaceRocks Team: David Greenfield, Arezu Sarvestani, Jason English and Peter Baunach.
Neo - Feed
Retrieve a list of Asteroids based on their closest approach date to Earth. GET https://api.nasa.gov/neo/rest/v1/feed?start_date=START_DATE&end_date=END_DATE&api_key=API_KEY
Query Parameters
Parameter Type Default Description
start_date YYYY-MM-DD none Starting date for asteroid search
end_date YYYY-MM-DD 7 days after start_date Ending date for asteroid search
api_key string DEMO_KEY api.nasa.gov key for expanded usage
Example query
https://api.nasa.gov/neo/rest/v1/feed?start_date=2015-09-07&end_date=2015-09-08&api_key=DEMO_KEY
Neo - Lookup
Lookup a specific Asteroid based on its NASA JPL small body (SPK-ID) ID GET https://api.nasa.gov/neo/rest/v1/neo/
Path Parameters
Parameter Type Default Description
asteroid_id int none Asteroid SPK-ID correlates to the NASA JPL small body
api_key string DEMO_KEY api.nasa.gov key for expanded usage
Example query
https://api.nasa.gov/neo/rest/v1/neo/3542519?api_key=DEMO_KEY
Neo - Browse
Browse the overall Asteroid data-set GET https://api.nasa.gov/neo/rest/v1/neo/browse/
Example query
https://api.nasa.gov/neo/rest/v1/neo/browse?api_key=DEMO_KEY
DONKI: Space Weather Database Of Notifications, Knowledge, Information
Earth: Unlock the significant public investment in earth observation data
EONET: The Earth Observatory Natural Event Tracker
EPIC: Earth Polychromatic Imaging Camera
Exoplanet: Programmatic access to NASA's Exoplanet Archive database
Open Science Data Repository: Programmatic interface for the Open Science Data Repository website
Insight: Mars Weather Service API
Mars Rover Photos: Image data gathered by NASA's Curiosity, Opportunity, and Spirit rovers on Mars
NASA Image and Video Library: API to access the NASA Image and Video Library site at images.nasa.gov
TechTransfer: Patents, Software, and Tech Transfer Reports
Satellite Situation Center: System to cast geocentric spacecraft location information into a framework of (empirical) geophysical regions
SSD/CNEOS: Solar System Dynamics and Center for Near-Earth Object Studies
Techport: API to make NASA technology project data available in a machine-readable format
TLE API: Two line element data for earth-orbiting objects at a given point in time
Vesta/Moon/Mars Trek WMTS: A Web Map Tile Service for the Vesta, Moon, and Mars Trek imagery projects
If you find a bug, please note that this page acts as a central catalog and key service for public APIs. It does not hold the actual API code. For bugs in the APIs, please look for a link to the individual API pages and reach out there. For a problem in this page, please add an issue or pull request to the GitHub repository.
code.nasa.gov
data.nasa.gov
api.nasa.gov
Open Innovation Team
Privacy
Accessibility
FOIA
NASA Official: Nidhi Wahi
Twitter GitHub
Office of the Chief Information Officer
[email protected]
ok merci
c'est la clé 5xK9D97IiDTTCjEnNaSIGAivfKkPOqDipGjDetne
et c'est l'api de la nasa
merci
skibidi
[INFO] La documentation est trop volumineuse, on génère un résumé d’abord.
[INFO] Résumé du chunk 1/5...
[INFO] Résumé du chunk 2/5...
[INFO] Résumé du chunk 3/5...
[INFO] Résumé du chunk 4/5...
[INFO] Résumé du chunk 5/5...
[INFO] Résumé global généré. Longueur du résumé : 5216 caractères.
Nom suggéré pour l’API : NASA API
Entrez le nom de l’API (NASA API) :
Entrez la valeur de la clé API ou du token : 5xK9D97IiDTTCjEnNaSIGAivfKkPOqDipGjDetne
[OK] L’API 'NASA API' a été ajoutée.
=== Menu Principal ===
Test de l'endpoint : GET https://api.nasa.gov/neo/rest/v1/neo/browse
En-têtes : {'Accept': 'application/json', 'api_key': '5xK9D97IiDTTCjEnNaSIGAivfKkPOqDipGjDetne'}
Paramètres : {}
Statut : 403
Réponse JSON :
{
"error": {
"code": "API_KEY_MISSING",
"message": "No api_key was supplied. Get one at https://api.nasa.gov:443"
}
}
=== Menu Principal ===
=== Menu Principal ===
Test de l'endpoint : GET https://api.nasa.gov/exoplanet
En-têtes : {'Accept': 'application/json', 'api_key': '5xK9D97IiDTTCjEnNaSIGAivfKkPOqDipGjDetne'}
Paramètres : {}
Statut : 404
Réponse JSON :
Réponse brute :
</head> <body>text.container { margin: 50px auto 40px auto; width: 600px; text-align: center; } a { color: #4183c4; text-decoration: none; } a:hover { text-decoration: underline; } h1 { width: 800px; position:relative; left: -100px; letter-spacing: -1px; line-height: 60px; font-size: 60px; font-weight: 100; margin: 0px 0 50px 0; text-shadow: 0 1px 0 #fff; } p { color: rgba(0, 0, 0, 0.5); margin: 20px 0; line-height: 1.6; } ul { list-style: none; margin: 25px 0; padding: 0; } li { display: table-cell; font-weight: bold; width: 1%; } .logo { display: inline-block; margin-top: 35px; } .logo-img-2x { display: none; } @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and ( min--moz-device-pixel-ratio: 2), only screen and ( -o-min-device-pixel-ratio: 2/1), only screen and ( min-device-pixel-ratio: 2), only screen and ( min-resolution: 192dpi), only screen and ( min-resolution: 2dppx) { .logo-img-1x { display: none; } .logo-img-2x { display: inline-block; } } #suggestions { margin-top: 35px; color: #ccc; } #suggestions a { color: #666666; font-weight: 200; font-size: 14px; margin: 0 10px; } </style>
</body> </html>text<div class="container"> <h1>404</h1> <p><strong>File not found</strong></p> <p> The site configured at this address does not contain the requested file. </p> <p> If this is your site, make sure that the filename case matches the URL as well as any file permissions.<br> For root URLs (like <code>http://example.com/</code>) you must provide an <code>index.html</code> file. </p> <p> <a href="https://help.github.com/pages/">Read the full documentation</a> for more information about using <strong>GitHub Pages</strong>. </p> <div id="suggestions"> <a href="https://githubstatus.com">GitHub Status</a> — <a href="https://twitter.com/githubstatus">@githubstatus</a> </div> <a href="/" class="logo logo-img-1x"> <img width="32" height="32" title="" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpFMTZCRDY3REIzRjAxMUUyQUQzREIxQzRENUFFNUM5NiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpFMTZCRDY3RUIzRjAxMUUyQUQzREIxQzRENUFFNUM5NiI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkUxNkJENjdCQjNGMDExRTJBRDNEQjFDNEQ1QUU1Qzk2IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkUxNkJENjdDQjNGMDExRTJBRDNEQjFDNEQ1QUU1Qzk2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+SM9MCAAAA+5JREFUeNrEV11Ik1EY3s4+ddOp29Q5b0opCgKFsoKoi5Kg6CIhuwi6zLJLoYLopq4qsKKgi4i6CYIoU/q5iDAKs6syoS76IRWtyJ+p7cdt7sf1PGOD+e0c3dygAx/67ZzzPM95/877GYdHRg3ZjMXFxepQKNS6sLCwJxqNNuFpiMfjVs4ZjUa/pmmjeD6VlJS8NpvNT4QQ7mxwjSsJiEQim/1+/9lgMHgIr5ohuxG1WCw9Vqv1clFR0dCqBODElV6v90ogEDjGdYbVjXhpaendioqK07CIR7ZAqE49PT09BPL2PMgTByQGsYiZlQD4uMXtdr+JxWINhgINYhGT2MsKgMrm2dnZXgRXhaHAg5jEJodUAHxux4LudHJE9RdEdA+i3Juz7bGHe4mhE9FNrgwBCLirMFV9Okh5eflFh8PR5nK5nDabrR2BNJlKO0T35+Li4n4+/J+/JQCxhmu5h3uJoXNHPbmWZAHMshWB8l5/ipqammaAf0zPDDx1ONV3vurdidqwAQL+pEc8sLcAe1CCvQ3YHxIW8Pl85xSWNC1hADDIv0rIE/o4J0k3kww4xSlwIhcq3EFFOm7KN/hUGOQkt0CFa5WpNJlMvxBEz/IVQAxg/ZRZl9wiHA63yDYieM7DnLP5CiAGsC7I5sgtYKJGWe2A8seFqgFJrJjEPY1Cn3pJ8/9W1e5VWsFDTEmFrBcoDhZJEQkXuhICMyKpjhahqN21hRYATKfUOlDmkygrR4o4C0VOLGJKrOITKB4jijzdXygBKixyC5TDQdnk/Pz8qRw6oOWGlsTKGOQW6OH6FBWsyePxdOXLTgxiyebILZCjz+GLgMIKnXNzc49YMlcRdHXcSwxFVgTInQhC9G33UhNoJLuqq6t345p9y3eUy8OTk5PjAHuI9uo4b07FBaOhsu0A4Unc+T1TU1Nj3KsSSE5yJ65jqF2DDd8QqWYmAZrIM2VlZTdnZmb6AbpdV9V6ec9znf5Q7HjYumdRE0JOp3MjitO4SFa+cZz8Umqe3TCbSLvdfkR/kWDdNQl5InuTcysOcpFT35ZrbBxx4p3JAHlZVVW1D/634VRt+FvLBgK/v5LV9WS+10xMTEwtRw7XvqOL+e2Q8V3AYIOIAXQ26/heWVnZCVfcyKHg2CBgTpmPmjYM8l24GyaUHyaIh7XwfR9ErE8qHoDfn2LTNAVC0HX6MFcBIP8Bi+6F6cdW/DICkANRfx99fEYFQ7Nph5i/uQiA214gno7K+guhaiKg9gC62+M8eR7XsBsYJ4ilam60Fb7r7uAj8wFyuwM1oIOWgfmDy6RXEEQzJMPe23DXrVS7rtyD3Df8z/FPgAEAzWU5Ku59ZAUAAAAASUVORK5CYII="> </a> <a href="/" class="logo logo-img-2x"> <img width="32" height="32" title="" alt="" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyRpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuMy1jMDExIDY2LjE0NTY2MSwgMjAxMi8wMi8wNi0xNDo1NjoyNyAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiAoTWFjaW50b3NoKSIgeG1wTU06SW5zdGFuY2VJRD0ieG1wLmlpZDpEQUM1QkUxRUI0MUMxMUUyQUQzREIxQzRENUFFNUM5NiIgeG1wTU06RG9jdW1lbnRJRD0ieG1wLmRpZDpEQUM1QkUxRkI0MUMxMUUyQUQzREIxQzRENUFFNUM5NiI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOkUxNkJENjdGQjNGMDExRTJBRDNEQjFDNEQ1QUU1Qzk2IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOkUxNkJENjgwQjNGMDExRTJBRDNEQjFDNEQ1QUU1Qzk2Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiA8P3hwYWNrZXQgZW5kPSJyIj8+hfPRaQAAB6lJREFUeNrsW2mME2UYbodtt+2222u35QheoCCYGBQligIJgkZJNPzgigoaTEj8AdFEMfADfyABkgWiiWcieK4S+QOiHAYUj2hMNKgYlEujpNttu9vttbvdw+chU1K6M535pt3ubHCSyezR+b73eb73+t7vrfXsufOW4bz6+vom9/b23ovnNNw34b5xYGAgODg46Mbt4mesVmsWd1qSpHhdXd2fuP/Afcput5/A88xwymcdBgLqenp6FuRyuWV4zu/v759QyWBjxoz5t76+/gun09mK5xFyakoCAPSaTCazNpvNPoYVbh6O1YKGRF0u13sNDQ27QMzfpiAAKj0lnU6/gBVfAZW2WWpwwVzy0IgP3G73FpjI6REhAGA9qVRqA1b9mVoBVyIC2tDi8Xg24+dUzQiAbS/s7Ox8G2o/3mKCC+Zw0efzPQEfcVjYrARX3dbV1bUtHo8fMgt42f+Mp0yUTVQbdWsAHVsikdiHkHaPxcQXQufXgUBgMRxme9U0AAxfH4vFvjM7eF6UkbJS5qoQwEQGA57Ac5JllFyUVZZ5ckUEgMVxsK2jlSYzI+QXJsiyjzNEAJyJAzb/KQa41jJKL8pODMQiTEAymXw5n8/P0IjD3bh7Rgog59aanxiIRTVvV/oj0tnHca/WMrVwODwB3raTGxzkBg/gnZVapFV62Wy2n5AO70HM/5wbJ0QnXyQSaVPDIuNZzY0V3ntHMwxiwHA0Gj2Np7ecIBDgaDAYXKCQJM1DhrgJ3nhulcPbl8j4NmHe46X/g60fwbz3aewjkqFQaAqebWU1AOqyQwt8Id6qEHMc97zu7u7FGGsn7HAiVuosVw7P35C1nccdgSCxop1dHeZswmfHMnxBo6ZTk+jN8dl/vF7vWofDsa+MLN9oEUBMxOb3+1eoEsBVw6Zmua49r8YmhAKDiEPcMwBsxMiqQ+ixzPFxZyqRpXARG/YOr1ObFJ0gUskXBbamcR1OKmMUvDxHRAu8/LmY3jFLMUpFqz9HxG65smYJdyKyECOxDiEAe/p1gjF2oonivZAsxVgl2daa4EQWCW6J55qFAFFZiJWYLxNQy2qOSUzGRsyXCUDIeliwAHEO4WSlWQBRFoZakXcKmCXmyXAKs0Ve9vl8q42WoIYpJU4hV3hKcNs8m9gl7p/xQ73eF5kB4j5mNrWmTJRNwAzqiV1CxjVTZCIkEq+Z1bZFZSN2CenmVAFVy4Plz8xKAGWjjAKFk6lCBMDR/MJjLLMSQNm43xAiQKTaA+9/wewhDjL+JVI1kkTSSOTcKbMTwPqESAot6dn6Fr1gHwVJju6IRuyiByPuUUBAg5DGkAgBmxlvdgIEK9gDkohdY/BJo4CAG0R8miRSsGABkgVQs4KXu098IgUXSSRsFAoKZiVAVDY2WUiiPTjYRi41KwGisrGsLtlsth8Fiwnz2fBkQvWfRtlE3iF2yW63/yCacXZ1dW02GwGyTFaRd4idJnCKHRaCxYRHoG5LTKT6SyiToP1fJHbmAYPYRR0UnZQtMnA6s0zg+GZBlt0Gdo7EPHgpE3Q6nZ8YyLhc8Xj8MJh/aKTAY+5FPAKHLE7RdwuYJZmNwzyCMkBCYyKROJBMJl9B/PXXCjjmCmDOVzH3fiPpObEWGqoKe4EBl8v1hlqsdLvd23mkxHM9pc9kMpmno9HoeTii7ewbHEZPPx1ztLS1tV3AnGuMjiNjvbQFuHw6zDo5By7dTPAQNBgMLrRarTkSls1mnwT7uwp9virx9QzbW/HuV/j5d/b+6jniKlllP8lkeONJDk+dq9GsQTnC4fB1heO0K47Hwe7WdDr9nAKgXwOBwHI+C45Htj1d6sd429TUNEcmUdc+PRaLHcvn87dXW4ugzdsaGxufL94NFv9zi1J7GVbhlvb2dnaJ3SVrxfc+n2+NTsZ7/H7/Mr3g5XdSIHyJSH1PZ+7fToyl2+ErqilgZ4NaLYB9goVGaHjR93Hv1ZrU4XDsFT20kH3PObzbWk0CgG1jacVIUnAQb9F+VexyLMzkpcLv0IJV7AHQIOCAUYHx7v5qgScmYHtTqSAyZLEJTK22Bie4iq3xsqpm4SAf9Hq9a2DnJ4uLK3SEULcdRvp3i3zHySqpficxEdsQc1NrlYXXvR+O7qASSezXB+h1SuUomgg9LL8BUoV4749EIolKh+EiqWmqVEZlDgHks2pxHw7xTqUQw9J5NcAXOK10AGIoZ6Zli6JY6Z1Q461KoZ4NiKLHarW+KDsxlDUPHZ5zPQZqUVDPJsTqb5n9malbpAh8C2XXDLl62+WZIDFRUlNVOiwencnNU3aQEkL+cDMSoLvZo2fQB7AJssNAuFuvorlDVVkkg2I87+jo2K2QAVphDrfyViK5VqtO34OkaxXCp+7drdDBCAdubm6eidX+2WwqT5komwh4YQLk+H4aE93h8Xg2gvHekQZOGSgLZTLyDTLJ4Lx9/KZWKBSainT4Iy3FqQBfnUZR42PKQFksBr9QKVXCPusD3OiA/RkQ5kP8qV/Jl1WywAp/6+dcmPM2zL1UrUahe4JqfnWWKXIul3uUbfP8njAFLW1OFr3gdFtZ72cNH+PtQT7/brW+NXqJAHh0y9V8/U/A1U7AfwIMAD7mS3pCbuWJAAAAAElFTkSuQmCC"> </a> </div>
=== Menu Principal ===
Voici une version améliorée du script qui prend en compte les spécificités de l’API de la NASA, notamment le fait que l’api_key
doit être transmise sous forme de paramètre de requête (query parameter) et non dans les headers. J’ai également ajouté quelques garde-fous pour éviter que le menu principal ne plante si l’utilisateur saisit une valeur non prévue (par exemple taper la clé d’API au lieu d’un chiffre).
Principales améliorations apportées :
Gestion de l'API key :
auth_info["key_name"]
est "api_key"
, alors on force son utilisation en tant que paramètre de requête."Authorization"
(ou autre) et que auth_info["type"]
contient "Bearer"
ou "Basic"
, on la passe dans les headers.Fusion des paramètres :
api_key
mais n’existe pas sous la forme /{api_key}
dans l’URL, on le passera en query param.Robustesse du menu :
Affichage minimal quand on fait un test d’endpoint :
Optionnel : Ajout d’un header "Accept": "application/json"
par défaut (peut être enlevé si non nécessaire).
pythonimport sys import json import requests from groq import Groq # Stockage en mémoire des APIs (à adapter au besoin) apis_configurees = [] # Paramètre : longueur max avant de résumer MAX_CHARS_DIRECT_ANALYSIS = 3000 # --------------------------------------------------------------------------- # 1. Fonction de résumé (texte brut) si la doc est trop volumineuse def summarizer_groq(long_text, groq_api_key="gsk_XXXXXXXXXXXXXXX"): """ Découpe la documentation en chunks et génère un résumé global en langage naturel. Ceci n'utilise pas le mode JSON : on veut juste un résumé texte. """ client = Groq(api_key=groq_api_key) chunk_size = 3000 chunks = [] start = 0 while start < len(long_text): end = start + chunk_size chunks.append(long_text[start:end]) start = end summaries = [] for i, chunk_text in enumerate(chunks, start=1): print(f"[INFO] Résumé du chunk {i}/{len(chunks)}...") messages = [ { "role": "system", "content": ( "Tu es un assistant chargé de résumer la documentation d'API. " "Retourne un résumé concis (en langage courant) du texte fourni. " "Ne génère pas de JSON, pas de code, juste un texte résumé clair." ) }, { "role": "user", "content": chunk_text } ] try: completion = client.chat.completions.create( messages=messages, model="llama-3.3-70b-versatile", temperature=0.2, max_completion_tokens=1024, top_p=1, stream=False ) summary_text = completion.choices[0].message.content.strip() summaries.append(summary_text) except Exception as e: print(f"[ERREUR] Impossible de résumer le chunk {i} : {e}") summaries.append("") combined_summary = "\n".join(summaries) print(f"[INFO] Résumé global généré. Longueur du résumé : {len(combined_summary)} caractères.") return combined_summary # --------------------------------------------------------------------------- # 2. Fonction d'analyse finale en JSON def analyser_api_avec_groq(input_text, groq_api_key="gsk_XXXXXXXXXXXXXXXXXXX"): """ 1) Si le texte est trop long, on génère un résumé texte via summarizer_groq. 2) On passe ensuite (ou directement) le texte final dans un prompt qui demande un JSON strict, avec le schéma suivant : { "api_type": "REST | GraphQL | SOAP", "base_url": "string", "auth_info": { "type": "string (Bearer, Basic, etc.)", "key_name": "string", "required": true/false }, "common_headers": { "Header-Name": "Header-Value" }, "endpoints": [ { "name": "string", "path": "string", "method": "GET | POST | ...", "required_params": ["param1", "param2"], "optional_params": ["param1", "param2"], "description": "string" } ], "suggested_name": "string", "rate_limit": "string", "confidence_score": 0.0 } """ # 1) Résume si trop volumineux text_for_analysis = input_text if len(input_text) > MAX_CHARS_DIRECT_ANALYSIS: print("[INFO] La documentation est trop volumineuse, on génère un résumé d’abord.") text_for_analysis = summarizer_groq(input_text, groq_api_key=groq_api_key) # 2) Appel Chat Completion en mode JSON client = Groq(api_key=groq_api_key) messages = [ { "role": "system", "content": ( "Tu es un assistant d'analyse d'API, tu dois répondre UNIQUEMENT en JSON valide, sans code superflu. " "Respecte le schéma JSON suivant (toutes les clés doivent exister) :\n\n" "{\n" " \"api_type\": \"REST | GraphQL | SOAP\",\n" " \"base_url\": \"string\",\n" " \"auth_info\": {\n" " \"type\": \"string (Bearer, Basic, etc.)\",\n" " \"key_name\": \"string\",\n" " \"required\": true/false\n" " },\n" " \"common_headers\": {\n" " \"Header-Name\": \"Header-Value\"\n" " },\n" " \"endpoints\": [\n" " {\n" " \"name\": \"string\",\n" " \"path\": \"string\",\n" " \"method\": \"GET | POST | ...\",\n" " \"required_params\": [\"param1\", \"param2\"],\n" " \"optional_params\": [\"param1\", \"param2\"],\n" " \"description\": \"string\"\n" " }\n" " ],\n" " \"suggested_name\": \"string\",\n" " \"rate_limit\": \"string\",\n" " \"confidence_score\": 0.0\n" "}\n\n" "Analyse le texte ci-après et renvoie STRICTEMENT un JSON conforme, sans texte additionnel." ) }, { "role": "user", "content": text_for_analysis } ] try: chat_completion = client.chat.completions.create( messages=messages, model="llama-3.3-70b-versatile", temperature=0.0, max_completion_tokens=1024, top_p=1, stream=False, response_format={"type": "json_object"} ) content = chat_completion.choices[0].message.content data = json.loads(content) return data except Exception as e: print(f"[ERREUR] Échec de la conversion en JSON : {e}") print("[INFO] Nous allons retourner un squelette par défaut.") return { "api_type": None, "base_url": None, "auth_info": { "type": None, "key_name": None, "required": False }, "common_headers": {}, "endpoints": [], "suggested_name": "API_Inconnue", "rate_limit": None, "confidence_score": 0.0 } # --------------------------------------------------------------------------- # 3. Fonctions du menu def ajouter_api(): print("=== Ajout d’une nouvelle API ===") # On ne se sert pas de la réponse (o/n) ici, mais on le laisse par cohérence. _ = input("Voulez-vous coller la documentation de l’API ? (o/n) : ") print("Collez la documentation ci-dessous (finissez par un skibidi vide) :") lignes_doc = [] while True: ligne = input() if ligne == "skibidi": break lignes_doc.append(ligne) doc_api = "\n".join(lignes_doc) # Simple fallback si rien n’est fourni if not doc_api.strip(): doc_api = "Pas d'information sur l'API." # Appel Groq pour analyse resultats_analyse = analyser_api_avec_groq(doc_api, groq_api_key="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") confidence_score = resultats_analyse.get("confidence_score", 0.0) if confidence_score < 0.5: print( "Le score de confiance de l’analyse est faible. " "Les informations retournées peuvent être partielles ou incorrectes.\n" ) # On lit les champs api_type = resultats_analyse.get("api_type") base_url = resultats_analyse.get("base_url") auth_info = resultats_analyse.get("auth_info", {}) common_headers = resultats_analyse.get("common_headers", {}) endpoints = resultats_analyse.get("endpoints", []) suggested_name = resultats_analyse.get("suggested_name", "NouvelleAPI") rate_limit = resultats_analyse.get("rate_limit") print(f"Nom suggéré pour l’API : {suggested_name}") nom_api = input(f"Entrez le nom de l’API ({suggested_name}) : ") if not nom_api.strip(): nom_api = suggested_name # Si auth_info.required == True, on demande la clé api_key_value = None if auth_info.get("required", False): api_key_value = input("Entrez la valeur de la clé API ou du token : ") # Construction de la config nouvelle_api = { "name": nom_api, "type": api_type, "base_url": base_url, "auth_info": auth_info, "api_key_value": api_key_value, "common_headers": common_headers, "endpoints": endpoints, "rate_limit": rate_limit } apis_configurees.append(nouvelle_api) print(f"\n[OK] L’API '{nom_api}' a été ajoutée.") print(f" - Type : {api_type}") print(f" - URL de base : {base_url}\n") def lister_apis(): print("=== Liste des API configurées ===") if not apis_configurees: print("Aucune API n’est configurée.\n") return for i, api in enumerate(apis_configurees, start=1): print(f"{i}. Nom : {api['name']}") print(f" URL de base : {api['base_url'] or 'Non renseignée'}") print(f" Type : {api['type'] or 'Inconnu'}") if api["rate_limit"]: print(f" Limitation de débit : {api['rate_limit']}") if api["endpoints"]: print(" Endpoints :") for ep in api["endpoints"]: print(f" - {ep['name']} ({ep['method']} {ep['path']})") else: print(" Aucun endpoint configuré.") print() print() def modifier_api(): print("=== Modification d’une API ===") if not apis_configurees: print("Aucune API n’est configurée.\n") return # On affiche la liste for i, api in enumerate(apis_configurees, start=1): print(f"{i}. {api['name']}") choix = input("Quelle API souhaitez-vous modifier ? (nom ou numéro) : ") api_choisie = None # On tente un cast en int pour voir si c’est un numéro try: idx = int(choix) - 1 if 0 <= idx < len(apis_configurees): api_choisie = apis_configurees[idx] except ValueError: # Sinon, on tente par nom for a in apis_configurees: if a["name"].lower() == choix.lower(): api_choisie = a break if not api_choisie: print("API introuvable.\n") return print(f"\nAPI sélectionnée : {api_choisie['name']}") print("Que voulez-vous modifier ? (ex: 'changer l'URL de base', 'changer la clé API', " "'ajouter un endpoint', 'modifier un endpoint', 'supprimer un endpoint')") action = input("> ").lower() if "url" in action: new_url = input("Nouvelle URL de base : ") api_choisie["base_url"] = new_url print("URL de base modifiée.\n") if "clé" in action or "key" in action: new_key = input("Nouvelle clé API : ") api_choisie["api_key_value"] = new_key print("Clé API modifiée.\n") if "ajouter un endpoint" in action: print("=== Ajout d'un endpoint ===") nom_ep = input("Nom du nouvel endpoint : ") path_ep = input("Chemin (ex: /playlists/{playlist_id}/tracks) : ") methode = input("Méthode HTTP (GET, POST, etc.) : ") params_req = [p.strip() for p in input("Paramètres requis (séparés par des virgules) : ").split(",") if p.strip()] params_opt = [p.strip() for p in input("Paramètres optionnels (séparés par des virgules) : ").split(",") if p.strip()] new_ep = { "name": nom_ep, "path": path_ep, "method": methode.upper(), "required_params": params_req, "optional_params": params_opt, "description": "" } api_choisie["endpoints"].append(new_ep) print(f"Endpoint '{nom_ep}' ajouté.\n") if "modifier un endpoint" in action: print("=== Modification d'un endpoint ===") if not api_choisie["endpoints"]: print("Aucun endpoint à modifier.") return for i, ep in enumerate(api_choisie["endpoints"], start=1): print(f"{i}. {ep['name']} ({ep['method']} {ep['path']})") choix_ep = input("Quel endpoint ? (numéro ou nom) : ") ep_choisi = None try: eidx = int(choix_ep) - 1 if 0 <= eidx < len(api_choisie["endpoints"]): ep_choisi = api_choisie["endpoints"][eidx] except ValueError: for ep in api_choisie["endpoints"]: if ep["name"].lower() == choix_ep.lower(): ep_choisi = ep break if not ep_choisi: print("Endpoint introuvable.") return print(f"Endpoint sélectionné : {ep_choisi['name']}") modif_ep = input("Que voulez-vous faire ? (ex: 'ajouter un paramètre', 'changer la méthode', etc.) : ").lower() if "ajouter un paramètre" in modif_ep: nom_p = input("Nom du paramètre : ") r_o = input("Paramètre requis ou optionnel ? (r/o) : ") if r_o.lower() == 'r': ep_choisi["required_params"].append(nom_p) else: ep_choisi["optional_params"].append(nom_p) print(f"Paramètre '{nom_p}' ajouté.\n") # D’autres modifications possibles... if "supprimer un endpoint" in action: print("=== Suppression d'un endpoint ===") if not api_choisie["endpoints"]: print("Aucun endpoint à supprimer.") return for i, ep in enumerate(api_choisie["endpoints"], start=1): print(f"{i}. {ep['name']} ({ep['method']} {ep['path']})") choix_ep = input("Quel endpoint supprimer ? (numéro ou nom) : ") ep_asup = None try: eidx = int(choix_ep) - 1 if 0 <= eidx < len(api_choisie["endpoints"]): ep_asup = api_choisie["endpoints"][eidx] except ValueError: for ep in api_choisie["endpoints"]: if ep["name"].lower() == choix_ep.lower(): ep_asup = ep break if ep_asup: api_choisie["endpoints"].remove(ep_asup) print(f"Endpoint '{ep_asup['name']}' supprimé.") else: print("Endpoint introuvable.") print("Modification(s) terminée(s).\n") def supprimer_api(): print("=== Suppression d’une API ===") if not apis_configurees: print("Aucune API n’est configurée.\n") return for i, api in enumerate(apis_configurees, start=1): print(f"{i}. {api['name']}") choix = input("Quelle API supprimer ? (nom ou numéro) : ") api_asup = None try: idx = int(choix) - 1 if 0 <= idx < len(apis_configurees): api_asup = apis_configurees[idx] except ValueError: for a in apis_configurees: if a["name"].lower() == choix.lower(): api_asup = a break if not api_asup: print("API introuvable.\n") return confirm = input(f"Êtes-vous sûr de vouloir supprimer '{api_asup['name']}' ? (o/n) : ") if confirm.lower() == 'o': apis_configurees.remove(api_asup) print(f"L’API '{api_asup['name']}' a été supprimée.\n") else: print("Opération annulée.\n") def tester_endpoint(): print("=== Tester un endpoint ===") if not apis_configurees: print("Aucune API n’est configurée.\n") return for i, api in enumerate(apis_configurees, start=1): print(f"{i}. {api['name']}") choix = input("Sur quelle API tester un endpoint ? (nom ou numéro) : ") api_choisie = None try: idx = int(choix) - 1 if 0 <= idx < len(apis_configurees): api_choisie = apis_configurees[idx] except ValueError: for a in apis_configurees: if a["name"].lower() == choix.lower(): api_choisie = a break if not api_choisie: print("API introuvable.\n") return if not api_choisie["endpoints"]: print("Cette API n’a aucun endpoint configuré.\n") return print(f"Endpoints disponibles pour {api_choisie['name']} :") for i, ep in enumerate(api_choisie["endpoints"], start=1): print(f"{i}. {ep['name']} ({ep['method']} {ep['path']})") choix_ep = input("Quel endpoint tester ? (nom ou numéro) : ") ep_choisi = None try: eidx = int(choix_ep) - 1 if 0 <= eidx < len(api_choisie["endpoints"]): ep_choisi = api_choisie["endpoints"][eidx] except ValueError: for ep in api_choisie["endpoints"]: if ep["name"].lower() == choix_ep.lower(): ep_choisi = ep break if not ep_choisi: print("Endpoint introuvable.") return # On va demander les valeurs pour chaque param requis required_params_values = {} for rp in ep_choisi.get("required_params", []): val = input(f"Entrez la valeur pour '{rp}' : ") required_params_values[rp] = val # On va demander les valeurs pour chaque param optionnel optional_params_values = {} for op in ep_choisi.get("optional_params", []): val = input(f"Valeur pour '{op}' (laisser vide si aucun) : ") if val: optional_params_values[op] = val # Préparation de l’URL base_url = api_choisie.get("base_url") or "" path = ep_choisi["path"] # Remplacement dans le path si on a des placeholders {param} # et retrait du param si on a pu le remplacer query_params = {} for k, v in required_params_values.items(): placeholder = f"{{{k}}}" if placeholder in path: path = path.replace(placeholder, v) else: # S'il n'y a pas de placeholder correspondant, on le mettra en query param query_params[k] = v # Tous les optionnels vont en query params query_params.update(optional_params_values) # Gestion de l’authentification headers = dict(api_choisie.get("common_headers", {})) # Ex : on force "Accept: application/json" par défaut (ou non) if "Accept" not in headers: headers["Accept"] = "application/json" auth_info = api_choisie.get("auth_info", {}) api_key_value = api_choisie.get("api_key_value") if auth_info.get("required") and api_key_value: # Exemple : si c’est un Bearer if auth_info["type"] and "bearer" in auth_info["type"].lower(): key_name = auth_info.get("key_name", "Authorization") headers[key_name] = f"Bearer {api_key_value}" # Exemple : si c’est un Basic elif auth_info["type"] and "basic" in auth_info["type"].lower(): key_name = auth_info.get("key_name", "Authorization") headers[key_name] = f"Basic {api_key_value}" else: # Si key_name = "api_key", NASA veut un query param "api_key=XXXX" if auth_info.get("key_name", "").lower() == "api_key": query_params["api_key"] = api_key_value else: # Sinon on le place dans un header key_name = auth_info.get("key_name", "X-API-Key") headers[key_name] = api_key_value # Construction de l'URL finale url = base_url + path method = ep_choisi["method"].upper() print(f"\nTest de l'endpoint : {method} {url}") print(f"En-têtes : {headers}") print(f"Paramètres : {query_params}\n") try: if method == "GET": r = requests.get(url, headers=headers, params=query_params) elif method == "POST": # On envoie ici en JSON, à adapter si l’API l’exige autrement r = requests.post(url, headers=headers, json=query_params) elif method == "PUT": r = requests.put(url, headers=headers, json=query_params) elif method == "DELETE": r = requests.delete(url, headers=headers, json=query_params) else: print("Méthode non gérée.") return print(f"Statut : {r.status_code}") # Tentative de parsing JSON try: print("Réponse JSON :") print(json.dumps(r.json(), indent=2)) except: print("Réponse brute :") print(r.text) except Exception as e: print(f"Erreur lors de l’appel : {e}") def main(): while True: print("=== Menu Principal ===") print("1. Ajouter une API (assisté par IA)") print("2. Liste des API configurées") print("3. Modifier une API") print("4. Supprimer une API") print("5. Tester un endpoint") print("6. Quitter") choix = input("Choisissez une option : ").strip() # On essaie de caster en int pour éviter l'erreur # s'il tape '5xK9...' par inadvertance try: choix_num = int(choix) except ValueError: print("Choix invalide.\n") continue if choix_num == 1: ajouter_api() elif choix_num == 2: lister_apis() elif choix_num == 3: modifier_api() elif choix_num == 4: supprimer_api() elif choix_num == 5: tester_endpoint() elif choix_num == 6: print("Au revoir.") sys.exit(0) else: print("Choix invalide.\n") if __name__ == "__main__": main()
Transmission de la clé API NASA :
json{ "type": "", "key_name": "api_key", "required": true }
api["api_key_value"]
.key_name = "api_key"
. Donc on insère "api_key": "<LA_CLE>"
dans query_params
.?api_key=<LA_CLE>
.Placeholders dans le path (ex. "/neo/rest/v1/neo/{asteroid_id}"
) :
asteroid_id
, on remplace "{asteroid_id}"
dans l’URL par la valeur saisie.Robustesse du menu :
try/except ValueError
pour s’assurer que la saisie est bien un entier. Si ce n’est pas le cas, on réaffiche le menu.En-tête Accept: application/json
ajouté par défaut, pour faciliter le parsing des réponses JSON.
En l’état, ce script devrait mieux gérer le cas de la NASA (et d’autres APIs) et éviter l’erreur No api_key was supplied
puisque la clé sera maintenant passée dans la query string.
c'est censé être le point d'interogration mais ça ne me configure pas le bon type fait en sorte que la verificaztion des types soit plus poussé
Voici une version améliorée qui effectue une vérification plus stricte des choix dans le menu principal (et dans d’autres parties), notamment pour éviter qu’un simple point d’interrogation ou une saisie non numérique provoque une erreur ou soit interprété comme un entier.
Fonction lire_int_in_range
:
Utilisation de lire_int_in_range
:
main()
), au lieu de faire un simple input() + try/except ValueError
, on appelle lire_int_in_range
.Exemple d’aide si user_input == '?'
:
Validation du type d’API (optionnel) :
api_type
est bien "REST"
, "GraphQL"
ou "SOAP"
quand Groq vous le fournit (ou quand vous le modifiez). Mais cela dépend de votre usage : ce n’est pas toujours nécessaire.pythonimport sys import json import requests from groq import Groq # Stockage en mémoire des APIs (à adapter au besoin) apis_configurees = [] # Paramètre : longueur max avant de résumer MAX_CHARS_DIRECT_ANALYSIS = 3000 # --------------------------------------------------------------------------- # 1. Fonction de résumé (texte brut) si la doc est trop volumineuse def summarizer_groq(long_text, groq_api_key="gsk_XXXXXXXXXXXXXXX"): """ Découpe la documentation en chunks et génère un résumé global en langage naturel. Ceci n'utilise pas le mode JSON : on veut juste un résumé texte. """ client = Groq(api_key=groq_api_key) chunk_size = 3000 chunks = [] start = 0 while start < len(long_text): end = start + chunk_size chunks.append(long_text[start:end]) start = end summaries = [] for i, chunk_text in enumerate(chunks, start=1): print(f"[INFO] Résumé du chunk {i}/{len(chunks)}...") messages = [ { "role": "system", "content": ( "Tu es un assistant chargé de résumer la documentation d'API. " "Retourne un résumé concis (en langage courant) du texte fourni. " "Ne génère pas de JSON, pas de code, juste un texte résumé clair." ) }, { "role": "user", "content": chunk_text } ] try: completion = client.chat.completions.create( messages=messages, model="llama-3.3-70b-versatile", temperature=0.2, max_completion_tokens=1024, top_p=1, stream=False ) summary_text = completion.choices[0].message.content.strip() summaries.append(summary_text) except Exception as e: print(f"[ERREUR] Impossible de résumer le chunk {i} : {e}") summaries.append("") combined_summary = "\n".join(summaries) print(f"[INFO] Résumé global généré. Longueur du résumé : {len(combined_summary)} caractères.") return combined_summary # --------------------------------------------------------------------------- # 2. Fonction d'analyse finale en JSON def analyser_api_avec_groq(input_text, groq_api_key="gsk_XXXXXXXXXXXXXXXXXXX"): """ 1) Si le texte est trop long, on génère un résumé texte via summarizer_groq. 2) On passe ensuite (ou directement) le texte final dans un prompt qui demande un JSON strict (voir schéma ci-dessous). """ # 1) Résume si trop volumineux text_for_analysis = input_text if len(input_text) > MAX_CHARS_DIRECT_ANALYSIS: print("[INFO] La documentation est trop volumineuse, on génère un résumé d’abord.") text_for_analysis = summarizer_groq(input_text, groq_api_key=groq_api_key) # 2) Appel Chat Completion en mode JSON client = Groq(api_key=groq_api_key) messages = [ { "role": "system", "content": ( "Tu es un assistant d'analyse d'API, tu dois répondre UNIQUEMENT en JSON valide, sans code superflu. " "Respecte le schéma JSON suivant (toutes les clés doivent exister) :\n\n" "{\n" " \"api_type\": \"REST | GraphQL | SOAP\",\n" " \"base_url\": \"string\",\n" " \"auth_info\": {\n" " \"type\": \"string (Bearer, Basic, etc.)\",\n" " \"key_name\": \"string\",\n" " \"required\": true/false\n" " },\n" " \"common_headers\": {\n" " \"Header-Name\": \"Header-Value\"\n" " },\n" " \"endpoints\": [\n" " {\n" " \"name\": \"string\",\n" " \"path\": \"string\",\n" " \"method\": \"GET | POST | ...\",\n" " \"required_params\": [\"param1\", \"param2\"],\n" " \"optional_params\": [\"param1\", \"param2\"],\n" " \"description\": \"string\"\n" " }\n" " ],\n" " \"suggested_name\": \"string\",\n" " \"rate_limit\": \"string\",\n" " \"confidence_score\": 0.0\n" "}\n\n" "Analyse le texte ci-après et renvoie STRICTEMENT un JSON conforme, sans texte additionnel." ) }, { "role": "user", "content": text_for_analysis } ] try: chat_completion = client.chat.completions.create( messages=messages, model="llama-3.3-70b-versatile", temperature=0.0, max_completion_tokens=1024, top_p=1, stream=False, response_format={"type": "json_object"} ) content = chat_completion.choices[0].message.content data = json.loads(content) return data except Exception as e: print(f"[ERREUR] Échec de la conversion en JSON : {e}") print("[INFO] Nous allons retourner un squelette par défaut.") return { "api_type": None, "base_url": None, "auth_info": { "type": None, "key_name": None, "required": False }, "common_headers": {}, "endpoints": [], "suggested_name": "API_Inconnue", "rate_limit": None, "confidence_score": 0.0 } # --------------------------------------------------------------------------- # 3. FONCTIONS D’OUTIL POUR L’INTERFACE def lire_int_in_range(prompt: str, min_val: int, max_val: int) -> int: """ Demande à l'utilisateur de saisir un entier dans la plage [min_val..max_val]. Si l'utilisateur saisit '?', on affiche un petit message d'aide (personnalisable). Répète la question tant que la valeur n'est pas un entier correct. Retourne l'entier validé. """ while True: saisie = input(prompt).strip() # Exemple de gestion d'un '?' ou autre commande spéciale if saisie == "?": print("Aide : veuillez saisir un entier compris entre " f"{min_val} et {max_val}.") print("Tapez un nombre valide, ou Ctrl+C pour annuler.") continue # Sinon, on tente la conversion try: val = int(saisie) if min_val <= val <= max_val: return val else: print(f"Choix invalide (doit être entre {min_val} et {max_val}).\n") except ValueError: print("Choix invalide (entrez un nombre). Réessayez.\n") def selectionner_api() -> dict: """ Affiche la liste des API configurées, demande à l'utilisateur d'en choisir une par numéro. Retourne le dict correspondant ou None si aucune API. """ if not apis_configurees: print("Aucune API n’est configurée.\n") return None print("=== Liste des APIs disponibles ===") for i, api in enumerate(apis_configurees, start=1): print(f"{i}. {api['name']}") # On lit un choix (numéro) dans la plage [1..len(apis_configurees)] choix_num = lire_int_in_range( prompt=f"Quelle API souhaitez-vous sélectionner ? [1..{len(apis_configurees)}] : ", min_val=1, max_val=len(apis_configurees) ) return apis_configurees[choix_num - 1] def selectionner_endpoint(api: dict) -> dict: """ Affiche la liste des endpoints pour l'API donnée, demande à l'utilisateur d'en choisir un par numéro. Retourne le dict correspondant ou None si aucun endpoint. """ if not api["endpoints"]: print("Cette API n’a aucun endpoint configuré.\n") return None print(f"Endpoints disponibles pour {api['name']} :") for i, ep in enumerate(api["endpoints"], start=1): print(f"{i}. {ep['name']} ({ep['method']} {ep['path']})") choix_ep_num = lire_int_in_range( prompt=f"Quel endpoint tester ? [1..{len(api['endpoints'])}] : ", min_val=1, max_val=len(api["endpoints"]) ) return api["endpoints"][choix_ep_num - 1] # --------------------------------------------------------------------------- # 4. Fonctions du menu def ajouter_api(): print("=== Ajout d’une nouvelle API ===") _ = input("Voulez-vous coller la documentation de l’API ? (o/n) : ") print("Collez la documentation ci-dessous (finissez par un skibidi vide) :") lignes_doc = [] while True: ligne = input() if ligne == "skibidi": break lignes_doc.append(ligne) doc_api = "\n".join(lignes_doc) if not doc_api.strip(): doc_api = "Pas d'information sur l'API." # Appel Groq pour analyse resultats_analyse = analyser_api_avec_groq(doc_api, groq_api_key="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") confidence_score = resultats_analyse.get("confidence_score", 0.0) if confidence_score < 0.5: print( "Le score de confiance de l’analyse est faible. " "Les informations retournées peuvent être partielles ou incorrectes.\n" ) # Champs retournés api_type = resultats_analyse.get("api_type") base_url = resultats_analyse.get("base_url") auth_info = resultats_analyse.get("auth_info", {}) common_headers = resultats_analyse.get("common_headers", {}) endpoints = resultats_analyse.get("endpoints", []) suggested_name = resultats_analyse.get("suggested_name", "NouvelleAPI") rate_limit = resultats_analyse.get("rate_limit") print(f"Nom suggéré pour l’API : {suggested_name}") nom_api = input(f"Entrez le nom de l’API ({suggested_name}) : ") if not nom_api.strip(): nom_api = suggested_name # Si auth_info.required == True, on demande la clé api_key_value = None if auth_info.get("required", False): api_key_value = input("Entrez la valeur de la clé API ou du token : ") # Construction de la config nouvelle_api = { "name": nom_api, "type": api_type, "base_url": base_url, "auth_info": auth_info, "api_key_value": api_key_value, "common_headers": common_headers, "endpoints": endpoints, "rate_limit": rate_limit } apis_configurees.append(nouvelle_api) print(f"\n[OK] L’API '{nom_api}' a été ajoutée.") print(f" - Type : {api_type}") print(f" - URL de base : {base_url}\n") def lister_apis(): print("=== Liste des API configurées ===") if not apis_configurees: print("Aucune API n’est configurée.\n") return for i, api in enumerate(apis_configurees, start=1): print(f"{i}. Nom : {api['name']}") print(f" URL de base : {api['base_url'] or 'Non renseignée'}") print(f" Type : {api['type'] or 'Inconnu'}") if api["rate_limit"]: print(f" Limitation de débit : {api['rate_limit']}") if api["endpoints"]: print(" Endpoints :") for ep in api["endpoints"]: print(f" - {ep['name']} ({ep['method']} {ep['path']})") else: print(" Aucun endpoint configuré.") print() print() def modifier_api(): print("=== Modification d’une API ===") api_choisie = selectionner_api() if not api_choisie: return print(f"\nAPI sélectionnée : {api_choisie['name']}") print("Que voulez-vous modifier ? (ex: 'changer l'URL de base', 'changer la clé API', " "'ajouter un endpoint', 'modifier un endpoint', 'supprimer un endpoint')") action = input("> ").lower() if "url" in action: new_url = input("Nouvelle URL de base : ") api_choisie["base_url"] = new_url print("URL de base modifiée.\n") if "clé" in action or "key" in action: new_key = input("Nouvelle clé API : ") api_choisie["api_key_value"] = new_key print("Clé API modifiée.\n") if "ajouter un endpoint" in action: print("=== Ajout d'un endpoint ===") nom_ep = input("Nom du nouvel endpoint : ") path_ep = input("Chemin (ex: /playlists/{playlist_id}/tracks) : ") methode = input("Méthode HTTP (GET, POST, etc.) : ") params_req = [p.strip() for p in input("Paramètres requis (séparés par des virgules) : ").split(",") if p.strip()] params_opt = [p.strip() for p in input("Paramètres optionnels (séparés par des virgules) : ").split(",") if p.strip()] new_ep = { "name": nom_ep, "path": path_ep, "method": methode.upper(), "required_params": params_req, "optional_params": params_opt, "description": "" } api_choisie["endpoints"].append(new_ep) print(f"Endpoint '{nom_ep}' ajouté.\n") if "modifier un endpoint" in action: print("=== Modification d'un endpoint ===") if not api_choisie["endpoints"]: print("Aucun endpoint à modifier.") return print("Liste des endpoints :") for i, ep in enumerate(api_choisie["endpoints"], start=1): print(f"{i}. {ep['name']} ({ep['method']} {ep['path']})") choix_ep = lire_int_in_range( f"Quel endpoint modifier ? [1..{len(api_choisie['endpoints'])}] : ", 1, len(api_choisie["endpoints"]) ) ep_choisi = api_choisie["endpoints"][choix_ep - 1] print(f"Endpoint sélectionné : {ep_choisi['name']}") modif_ep = input("Que voulez-vous faire ? (ex: 'ajouter un paramètre', 'changer la méthode', etc.) : ").lower() if "ajouter un paramètre" in modif_ep: nom_p = input("Nom du paramètre : ") r_o = input("Paramètre requis ou optionnel ? (r/o) : ") if r_o.lower() == 'r': ep_choisi["required_params"].append(nom_p) else: ep_choisi["optional_params"].append(nom_p) print(f"Paramètre '{nom_p}' ajouté.\n") # D’autres modifications possibles... if "supprimer un endpoint" in action: print("=== Suppression d'un endpoint ===") if not api_choisie["endpoints"]: print("Aucun endpoint à supprimer.") return print("Liste des endpoints :") for i, ep in enumerate(api_choisie["endpoints"], start=1): print(f"{i}. {ep['name']} ({ep['method']} {ep['path']})") choix_ep = lire_int_in_range( f"Quel endpoint supprimer ? [1..{len(api_choisie['endpoints'])}] : ", 1, len(api_choisie["endpoints"]) ) ep_asup = api_choisie["endpoints"][choix_ep - 1] api_choisie["endpoints"].remove(ep_asup) print(f"Endpoint '{ep_asup['name']}' supprimé.") print("Modification(s) terminée(s).\n") def supprimer_api(): print("=== Suppression d’une API ===") api_choisie = selectionner_api() if not api_choisie: return confirm = input(f"Êtes-vous sûr de vouloir supprimer '{api_choisie['name']}' ? (o/n) : ") if confirm.lower() == 'o': apis_configurees.remove(api_choisie) print(f"L’API '{api_choisie['name']}' a été supprimée.\n") else: print("Opération annulée.\n") def tester_endpoint(): print("=== Tester un endpoint ===") api_choisie = selectionner_api() if not api_choisie: return ep_choisi = selectionner_endpoint(api_choisie) if not ep_choisi: return # On va demander les valeurs pour chaque param requis required_params_values = {} for rp in ep_choisi.get("required_params", []): val = input(f"Entrez la valeur pour '{rp}' : ") required_params_values[rp] = val # On va demander les valeurs pour chaque param optionnel optional_params_values = {} for op in ep_choisi.get("optional_params", []): val = input(f"Valeur pour '{op}' (laisser vide si aucun) : ") if val: optional_params_values[op] = val # Préparation de l’URL base_url = api_choisie.get("base_url") or "" path = ep_choisi["path"] # Remplacement dans le path si on a des placeholders {param} # et retrait du param si on a pu le remplacer query_params = {} for k, v in required_params_values.items(): placeholder = f"{{{k}}}" if placeholder in path: path = path.replace(placeholder, v) else: # S'il n'y a pas de placeholder correspondant, on le mettra en query param query_params[k] = v # Tous les optionnels vont en query params query_params.update(optional_params_values) # Gestion de l’authentification headers = dict(api_choisie.get("common_headers", {})) if "Accept" not in headers: headers["Accept"] = "application/json" auth_info = api_choisie.get("auth_info", {}) api_key_value = api_choisie.get("api_key_value") if auth_info.get("required") and api_key_value: # Exemple : si c’est un Bearer if auth_info["type"] and "bearer" in auth_info["type"].lower(): key_name = auth_info.get("key_name", "Authorization") headers[key_name] = f"Bearer {api_key_value}" # Exemple : si c’est un Basic elif auth_info["type"] and "basic" in auth_info["type"].lower(): key_name = auth_info.get("key_name", "Authorization") headers[key_name] = f"Basic {api_key_value}" else: # Si key_name = "api_key", NASA veut un query param "api_key=XXXX" if auth_info.get("key_name", "").lower() == "api_key": query_params["api_key"] = api_key_value else: # Sinon on le place dans un header key_name = auth_info.get("key_name", "X-API-Key") headers[key_name] = api_key_value # Construction de l'URL finale url = base_url + path method = ep_choisi["method"].upper() print(f"\nTest de l'endpoint : {method} {url}") print(f"En-têtes : {headers}") print(f"Paramètres : {query_params}\n") try: if method == "GET": r = requests.get(url, headers=headers, params=query_params) elif method == "POST": r = requests.post(url, headers=headers, json=query_params) elif method == "PUT": r = requests.put(url, headers=headers, json=query_params) elif method == "DELETE": r = requests.delete(url, headers=headers, json=query_params) else: print("Méthode non gérée.") return print(f"Statut : {r.status_code}") try: print("Réponse JSON :") print(json.dumps(r.json(), indent=2)) except: print("Réponse brute :") print(r.text) except Exception as e: print(f"Erreur lors de l’appel : {e}") # --------------------------------------------------------------------------- # 5. MAIN def main(): while True: print("=== Menu Principal ===") print("1. Ajouter une API (assisté par IA)") print("2. Liste des API configurées") print("3. Modifier une API") print("4. Supprimer une API") print("5. Tester un endpoint") print("6. Quitter") choix_num = lire_int_in_range("Choisissez une option [1..6] : ", 1, 6) if choix_num == 1: ajouter_api() elif choix_num == 2: lister_apis() elif choix_num == 3: modifier_api() elif choix_num == 4: supprimer_api() elif choix_num == 5: tester_endpoint() elif choix_num == 6: print("Au revoir.") sys.exit(0) if __name__ == "__main__": main()
lire_int_in_range
vous évite de devoir gérer manuellement les try/except
partout. Elle boucle jusqu’à obtenir un entier valide dans la fourchette souhaitée.De cette manière, si l’utilisateur tape un point d’interrogation ou une chaîne non prévue, on ne casse pas le programme : on l’informe juste que c’est invalide, et on le redirige vers une nouvelle saisie.
fait en sorte que les apis que j'ajoute sois sauvegarder dans un json
import sys
import json
import requests
from groq import Groq
apis_configurees = []
MAX_CHARS_DIRECT_ANALYSIS = 3000
def summarizer_groq(long_text, groq_api_key="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"):
"""
Découpe la documentation en chunks et génère un résumé global en langage naturel.
Ceci n'utilise pas le mode JSON : on veut juste un résumé texte.
"""
client = Groq(api_key=groq_api_key)
textchunk_size = 3000 chunks = [] start = 0 while start < len(long_text): end = start + chunk_size chunks.append(long_text[start:end]) start = end summaries = [] for i, chunk_text in enumerate(chunks, start=1): print(f"[INFO] Résumé du chunk {i}/{len(chunks)}...") messages = [ { "role": "system", "content": ( "Tu es un assistant chargé de résumer la documentation d'API. " "Retourne un résumé concis (en langage courant) du texte fourni. " "Ne génère pas de JSON, pas de code, juste un texte résumé clair." ) }, { "role": "user", "content": chunk_text } ] try: completion = client.chat.completions.create( messages=messages, model="llama-3.3-70b-versatile", temperature=0.2, max_completion_tokens=1024, top_p=1, stream=False ) summary_text = completion.choices[0].message.content.strip() summaries.append(summary_text) except Exception as e: print(f"[ERREUR] Impossible de résumer le chunk {i} : {e}") summaries.append("") combined_summary = "\n".join(summaries) print(f"[INFO] Résumé global généré. Longueur du résumé : {len(combined_summary)} caractères.") return combined_summary
def analyser_api_avec_groq(input_text, groq_api_key="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"):
"""
1) Si le texte est trop long, on génère un résumé texte via summarizer_groq.
2) On passe ensuite (ou directement) le texte final dans un prompt
qui demande un JSON strict (voir schéma ci-dessous).
"""
# 1) Résume si trop volumineux
text_for_analysis = input_text
if len(input_text) > MAX_CHARS_DIRECT_ANALYSIS:
print("[INFO] La documentation est trop volumineuse, on génère un résumé d’abord.")
text_for_analysis = summarizer_groq(input_text, groq_api_key=groq_api_key)
text# 2) Appel Chat Completion en mode JSON client = Groq(api_key=groq_api_key) messages = [ { "role": "system", "content": ( "Tu es un assistant d'analyse d'API, tu dois répondre UNIQUEMENT en JSON valide, sans code superflu. " "Respecte le schéma JSON suivant (toutes les clés doivent exister) :\n\n" "{\n" " \"api_type\": \"REST | GraphQL | SOAP\",\n" " \"base_url\": \"string\",\n" " \"auth_info\": {\n" " \"type\": \"string (Bearer, Basic, etc.)\",\n" " \"key_name\": \"string\",\n" " \"required\": true/false\n" " },\n" " \"common_headers\": {\n" " \"Header-Name\": \"Header-Value\"\n" " },\n" " \"endpoints\": [\n" " {\n" " \"name\": \"string\",\n" " \"path\": \"string\",\n" " \"method\": \"GET | POST | ...\",\n" " \"required_params\": [\"param1\", \"param2\"],\n" " \"optional_params\": [\"param1\", \"param2\"],\n" " \"description\": \"string\"\n" " }\n" " ],\n" " \"suggested_name\": \"string\",\n" " \"rate_limit\": \"string\",\n" " \"confidence_score\": 0.0\n" "}\n\n" "Analyse le texte ci-après et renvoie STRICTEMENT un JSON conforme, sans texte additionnel." ) }, { "role": "user", "content": text_for_analysis } ] try: chat_completion = client.chat.completions.create( messages=messages, model="llama-3.3-70b-versatile", temperature=0.0, max_completion_tokens=1024, top_p=1, stream=False, response_format={"type": "json_object"} ) content = chat_completion.choices[0].message.content data = json.loads(content) return data except Exception as e: print(f"[ERREUR] Échec de la conversion en JSON : {e}") print("[INFO] Nous allons retourner un squelette par défaut.") return { "api_type": None, "base_url": None, "auth_info": { "type": None, "key_name": None, "required": False }, "common_headers": {}, "endpoints": [], "suggested_name": "API_Inconnue", "rate_limit": None, "confidence_score": 0.0 }
def lire_int_in_range(prompt: str, min_val: int, max_val: int) -> int:
"""
Demande à l'utilisateur de saisir un entier dans la plage [min_val..max_val].
Si l'utilisateur saisit '?', on affiche un petit message d'aide (personnalisable).
Répète la question tant que la valeur n'est pas un entier correct.
Retourne l'entier validé.
"""
while True:
saisie = input(prompt).strip()
text# Exemple de gestion d'un '?' ou autre commande spéciale if saisie == "?": print("Aide : veuillez saisir un entier compris entre " f"{min_val} et {max_val}.") print("Tapez un nombre valide, ou Ctrl+C pour annuler.") continue # Sinon, on tente la conversion try: val = int(saisie) if min_val <= val <= max_val: return val else: print(f"Choix invalide (doit être entre {min_val} et {max_val}).\n") except ValueError: print("Choix invalide (entrez un nombre). Réessayez.\n")
def selectionner_api() -> dict:
"""
Affiche la liste des API configurées, demande à l'utilisateur d'en choisir
une par numéro. Retourne le dict correspondant ou None si aucune API.
"""
if not apis_configurees:
print("Aucune API n’est configurée.\n")
return None
textprint("=== Liste des APIs disponibles ===") for i, api in enumerate(apis_configurees, start=1): print(f"{i}. {api['name']}") # On lit un choix (numéro) dans la plage [1..len(apis_configurees)] choix_num = lire_int_in_range( prompt=f"Quelle API souhaitez-vous sélectionner ? [1..{len(apis_configurees)}] : ", min_val=1, max_val=len(apis_configurees) ) return apis_configurees[choix_num - 1]
def selectionner_endpoint(api: dict) -> dict:
"""
Affiche la liste des endpoints pour l'API donnée, demande à l'utilisateur
d'en choisir un par numéro. Retourne le dict correspondant ou None si aucun endpoint.
"""
if not api["endpoints"]:
print("Cette API n’a aucun endpoint configuré.\n")
return None
textprint(f"Endpoints disponibles pour {api['name']} :") for i, ep in enumerate(api["endpoints"], start=1): print(f"{i}. {ep['name']} ({ep['method']} {ep['path']})") choix_ep_num = lire_int_in_range( prompt=f"Quel endpoint tester ? [1..{len(api['endpoints'])}] : ", min_val=1, max_val=len(api["endpoints"]) ) return api["endpoints"][choix_ep_num - 1]
def ajouter_api():
print("=== Ajout d’une nouvelle API ===")
text_ = input("Voulez-vous coller la documentation de l’API ? (o/n) : ") print("Collez la documentation ci-dessous (finissez par un skibidi vide) :") lignes_doc = [] while True: ligne = input() if ligne == "skibidi": break lignes_doc.append(ligne) doc_api = "\n".join(lignes_doc) if not doc_api.strip(): doc_api = "Pas d'information sur l'API." # Appel Groq pour analyse resultats_analyse = analyser_api_avec_groq(doc_api, groq_api_key="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") confidence_score = resultats_analyse.get("confidence_score", 0.0) if confidence_score < 0.5: print( "Le score de confiance de l’analyse est faible. " "Les informations retournées peuvent être partielles ou incorrectes.\n" ) # Champs retournés api_type = resultats_analyse.get("api_type") base_url = resultats_analyse.get("base_url") auth_info = resultats_analyse.get("auth_info", {}) common_headers = resultats_analyse.get("common_headers", {}) endpoints = resultats_analyse.get("endpoints", []) suggested_name = resultats_analyse.get("suggested_name", "NouvelleAPI") rate_limit = resultats_analyse.get("rate_limit") print(f"Nom suggéré pour l’API : {suggested_name}") nom_api = input(f"Entrez le nom de l’API ({suggested_name}) : ") if not nom_api.strip(): nom_api = suggested_name # Si auth_info.required == True, on demande la clé api_key_value = None if auth_info.get("required", False): api_key_value = input("Entrez la valeur de la clé API ou du token : ") # Construction de la config nouvelle_api = { "name": nom_api, "type": api_type, "base_url": base_url, "auth_info": auth_info, "api_key_value": api_key_value, "common_headers": common_headers, "endpoints": endpoints, "rate_limit": rate_limit } apis_configurees.append(nouvelle_api) print(f"\n[OK] L’API '{nom_api}' a été ajoutée.") print(f" - Type : {api_type}") print(f" - URL de base : {base_url}\n")
def lister_apis():
print("=== Liste des API configurées ===")
if not apis_configurees:
print("Aucune API n’est configurée.\n")
return
textfor i, api in enumerate(apis_configurees, start=1): print(f"{i}. Nom : {api['name']}") print(f" URL de base : {api['base_url'] or 'Non renseignée'}") print(f" Type : {api['type'] or 'Inconnu'}") if api["rate_limit"]: print(f" Limitation de débit : {api['rate_limit']}") if api["endpoints"]: print(" Endpoints :") for ep in api["endpoints"]: print(f" - {ep['name']} ({ep['method']} {ep['path']})") else: print(" Aucun endpoint configuré.") print() print()
def modifier_api():
print("=== Modification d’une API ===")
api_choisie = selectionner_api()
if not api_choisie:
return
textprint(f"\nAPI sélectionnée : {api_choisie['name']}") print("Que voulez-vous modifier ? (ex: 'changer l'URL de base', 'changer la clé API', " "'ajouter un endpoint', 'modifier un endpoint', 'supprimer un endpoint')") action = input("> ").lower() if "url" in action: new_url = input("Nouvelle URL de base : ") api_choisie["base_url"] = new_url print("URL de base modifiée.\n") if "clé" in action or "key" in action: new_key = input("Nouvelle clé API : ") api_choisie["api_key_value"] = new_key print("Clé API modifiée.\n") if "ajouter un endpoint" in action: print("=== Ajout d'un endpoint ===") nom_ep = input("Nom du nouvel endpoint : ") path_ep = input("Chemin (ex: /playlists/{playlist_id}/tracks) : ") methode = input("Méthode HTTP (GET, POST, etc.) : ") params_req = [p.strip() for p in input("Paramètres requis (séparés par des virgules) : ").split(",") if p.strip()] params_opt = [p.strip() for p in input("Paramètres optionnels (séparés par des virgules) : ").split(",") if p.strip()] new_ep = { "name": nom_ep, "path": path_ep, "method": methode.upper(), "required_params": params_req, "optional_params": params_opt, "description": "" } api_choisie["endpoints"].append(new_ep) print(f"Endpoint '{nom_ep}' ajouté.\n") if "modifier un endpoint" in action: print("=== Modification d'un endpoint ===") if not api_choisie["endpoints"]: print("Aucun endpoint à modifier.") return print("Liste des endpoints :") for i, ep in enumerate(api_choisie["endpoints"], start=1): print(f"{i}. {ep['name']} ({ep['method']} {ep['path']})") choix_ep = lire_int_in_range( f"Quel endpoint modifier ? [1..{len(api_choisie['endpoints'])}] : ", 1, len(api_choisie["endpoints"]) ) ep_choisi = api_choisie["endpoints"][choix_ep - 1] print(f"Endpoint sélectionné : {ep_choisi['name']}") modif_ep = input("Que voulez-vous faire ? (ex: 'ajouter un paramètre', 'changer la méthode', etc.) : ").lower() if "ajouter un paramètre" in modif_ep: nom_p = input("Nom du paramètre : ") r_o = input("Paramètre requis ou optionnel ? (r/o) : ") if r_o.lower() == 'r': ep_choisi["required_params"].append(nom_p) else: ep_choisi["optional_params"].append(nom_p) print(f"Paramètre '{nom_p}' ajouté.\n") # D’autres modifications possibles... if "supprimer un endpoint" in action: print("=== Suppression d'un endpoint ===") if not api_choisie["endpoints"]: print("Aucun endpoint à supprimer.") return print("Liste des endpoints :") for i, ep in enumerate(api_choisie["endpoints"], start=1): print(f"{i}. {ep['name']} ({ep['method']} {ep['path']})") choix_ep = lire_int_in_range( f"Quel endpoint supprimer ? [1..{len(api_choisie['endpoints'])}] : ", 1, len(api_choisie["endpoints"]) ) ep_asup = api_choisie["endpoints"][choix_ep - 1] api_choisie["endpoints"].remove(ep_asup) print(f"Endpoint '{ep_asup['name']}' supprimé.") print("Modification(s) terminée(s).\n")
def supprimer_api():
print("=== Suppression d’une API ===")
api_choisie = selectionner_api()
if not api_choisie:
return
textconfirm = input(f"Êtes-vous sûr de vouloir supprimer '{api_choisie['name']}' ? (o/n) : ") if confirm.lower() == 'o': apis_configurees.remove(api_choisie) print(f"L’API '{api_choisie['name']}' a été supprimée.\n") else: print("Opération annulée.\n")
def tester_endpoint():
print("=== Tester un endpoint ===")
api_choisie = selectionner_api()
if not api_choisie:
return
textep_choisi = selectionner_endpoint(api_choisie) if not ep_choisi: return # On va demander les valeurs pour chaque param requis required_params_values = {} for rp in ep_choisi.get("required_params", []): val = input(f"Entrez la valeur pour '{rp}' : ") required_params_values[rp] = val # On va demander les valeurs pour chaque param optionnel optional_params_values = {} for op in ep_choisi.get("optional_params", []): val = input(f"Valeur pour '{op}' (laisser vide si aucun) : ") if val: optional_params_values[op] = val # Préparation de l’URL base_url = api_choisie.get("base_url") or "" path = ep_choisi["path"] # Remplacement dans le path si on a des placeholders {param} # et retrait du param si on a pu le remplacer query_params = {} for k, v in required_params_values.items(): placeholder = f"{{{k}}}" if placeholder in path: path = path.replace(placeholder, v) else: # S'il n'y a pas de placeholder correspondant, on le mettra en query param query_params[k] = v # Tous les optionnels vont en query params query_params.update(optional_params_values) # Gestion de l’authentification headers = dict(api_choisie.get("common_headers", {})) if "Accept" not in headers: headers["Accept"] = "application/json" auth_info = api_choisie.get("auth_info", {}) api_key_value = api_choisie.get("api_key_value") if auth_info.get("required") and api_key_value: # Exemple : si c’est un Bearer if auth_info["type"] and "bearer" in auth_info["type"].lower(): key_name = auth_info.get("key_name", "Authorization") headers[key_name] = f"Bearer {api_key_value}" # Exemple : si c’est un Basic elif auth_info["type"] and "basic" in auth_info["type"].lower(): key_name = auth_info.get("key_name", "Authorization") headers[key_name] = f"Basic {api_key_value}" else: # Si key_name = "api_key", NASA veut un query param "api_key=XXXX" if auth_info.get("key_name", "").lower() == "api_key": query_params["api_key"] = api_key_value else: # Sinon on le place dans un header key_name = auth_info.get("key_name", "X-API-Key") headers[key_name] = api_key_value # Construction de l'URL finale url = base_url + path method = ep_choisi["method"].upper() print(f"\nTest de l'endpoint : {method} {url}") print(f"En-têtes : {headers}") print(f"Paramètres : {query_params}\n") try: if method == "GET": r = requests.get(url, headers=headers, params=query_params) elif method == "POST": r = requests.post(url, headers=headers, json=query_params) elif method == "PUT": r = requests.put(url, headers=headers, json=query_params) elif method == "DELETE": r = requests.delete(url, headers=headers, json=query_params) else: print("Méthode non gérée.") return print(f"Statut : {r.status_code}") try: print("Réponse JSON :") print(json.dumps(r.json(), indent=2)) except: print("Réponse brute :") print(r.text) except Exception as e: print(f"Erreur lors de l’appel : {e}")
def main():
while True:
print("=== Menu Principal ===")
print("1. Ajouter une API (assisté par IA)")
print("2. Liste des API configurées")
print("3. Modifier une API")
print("4. Supprimer une API")
print("5. Tester un endpoint")
print("6. Quitter")
textchoix_num = lire_int_in_range("Choisissez une option [1..6] : ", 1, 6) if choix_num == 1: ajouter_api() elif choix_num == 2: lister_apis() elif choix_num == 3: modifier_api() elif choix_num == 4: supprimer_api() elif choix_num == 5: tester_endpoint() elif choix_num == 6: print("Au revoir.") sys.exit(0)
if name == "main":
main()
Voici une version améliorée du script qui sauvegarde la liste des APIs dans un fichier JSON (par exemple apis_configurees.json
). À chaque fois qu’on ajoute, modifie ou supprime une API, on met à jour ce fichier. Ainsi, même si le script est relancé, on retrouve les APIs déjà configurées.
Fichier de configuration :
charger_apis()
et sauvegarder_apis()
.apis_configurees.json
(vous pouvez changer son nom au besoin).Chargement au démarrage :
main()
, on essaie de charger la liste des APIs depuis le fichier.apis_configurees
vide.Sauvegarde après chaque opération :
ajouter_api()
, modifier_api()
, supprimer_api()
, on appelle sauvegarder_apis()
.Format du JSON :
apis_configurees
. Chaque élément est un dictionnaire décrivant l’API, incluant endpoints
, etc.pythonimport sys import json import os import requests from groq import Groq # Nom du fichier où l'on stocke les APIs FICHIER_APIS = "apis_configurees.json" # Stockage en mémoire des APIs apis_configurees = [] # Paramètre : longueur max avant de résumer MAX_CHARS_DIRECT_ANALYSIS = 3000 # --------------------------------------------------------------------------- # 1. Fonctions d'IO pour sauvegarder/charger les APIs def sauvegarder_apis(): """Sauvegarde la liste des APIs dans FICHIER_APIS au format JSON.""" try: with open(FICHIER_APIS, "w", encoding="utf-8") as f: json.dump(apis_configurees, f, indent=2, ensure_ascii=False) print(f"[INFO] Liste des APIs sauvegardée dans {FICHIER_APIS}.") except Exception as e: print(f"[ERREUR] Impossible de sauvegarder dans {FICHIER_APIS} : {e}") def charger_apis(): """Charge la liste des APIs depuis FICHIER_APIS (si présent).""" global apis_configurees if os.path.exists(FICHIER_APIS): try: with open(FICHIER_APIS, "r", encoding="utf-8") as f: apis_configurees = json.load(f) print(f"[INFO] {len(apis_configurees)} API(s) chargée(s) depuis {FICHIER_APIS}.") except Exception as e: print(f"[ERREUR] Impossible de lire {FICHIER_APIS} : {e}") apis_configurees = [] else: apis_configurees = [] # --------------------------------------------------------------------------- # 2. Fonction de résumé (texte brut) si la doc est trop volumineuse def summarizer_groq(long_text, groq_api_key="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"): """ Découpe la documentation en chunks et génère un résumé global en langage naturel. Ceci n'utilise pas le mode JSON : on veut juste un résumé texte. """ client = Groq(api_key=groq_api_key) chunk_size = 3000 chunks = [] start = 0 while start < len(long_text): end = start + chunk_size chunks.append(long_text[start:end]) start = end summaries = [] for i, chunk_text in enumerate(chunks, start=1): print(f"[INFO] Résumé du chunk {i}/{len(chunks)}...") messages = [ { "role": "system", "content": ( "Tu es un assistant chargé de résumer la documentation d'API. " "Retourne un résumé concis (en langage courant) du texte fourni. " "Ne génère pas de JSON, pas de code, juste un texte résumé clair." ) }, { "role": "user", "content": chunk_text } ] try: completion = client.chat.completions.create( messages=messages, model="llama-3.3-70b-versatile", temperature=0.2, max_completion_tokens=1024, top_p=1, stream=False ) summary_text = completion.choices[0].message.content.strip() summaries.append(summary_text) except Exception as e: print(f"[ERREUR] Impossible de résumer le chunk {i} : {e}") summaries.append("") combined_summary = "\n".join(summaries) print(f"[INFO] Résumé global généré. Longueur du résumé : {len(combined_summary)} caractères.") return combined_summary # --------------------------------------------------------------------------- # 3. Fonction d'analyse finale en JSON def analyser_api_avec_groq(input_text, groq_api_key="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"): """ 1) Si le texte est trop long, on génère un résumé texte via summarizer_groq. 2) On passe ensuite (ou directement) le texte final dans un prompt qui demande un JSON strict (voir schéma ci-dessous). """ # 1) Résume si trop volumineux text_for_analysis = input_text if len(input_text) > MAX_CHARS_DIRECT_ANALYSIS: print("[INFO] La documentation est trop volumineuse, on génère un résumé d’abord.") text_for_analysis = summarizer_groq(input_text, groq_api_key=groq_api_key) # 2) Appel Chat Completion en mode JSON client = Groq(api_key=groq_api_key) messages = [ { "role": "system", "content": ( "Tu es un assistant d'analyse d'API, tu dois répondre UNIQUEMENT en JSON valide, sans code superflu. " "Respecte le schéma JSON suivant (toutes les clés doivent exister) :\n\n" "{\n" " \"api_type\": \"REST | GraphQL | SOAP\",\n" " \"base_url\": \"string\",\n" " \"auth_info\": {\n" " \"type\": \"string (Bearer, Basic, etc.)\",\n" " \"key_name\": \"string\",\n" " \"required\": true/false\n" " },\n" " \"common_headers\": {\n" " \"Header-Name\": \"Header-Value\"\n" " },\n" " \"endpoints\": [\n" " {\n" " \"name\": \"string\",\n" " \"path\": \"string\",\n" " \"method\": \"GET | POST | ...\",\n" " \"required_params\": [\"param1\", \"param2\"],\n" " \"optional_params\": [\"param1\", \"param2\"],\n" " \"description\": \"string\"\n" " }\n" " ],\n" " \"suggested_name\": \"string\",\n" " \"rate_limit\": \"string\",\n" " \"confidence_score\": 0.0\n" "}\n\n" "Analyse le texte ci-après et renvoie STRICTEMENT un JSON conforme, sans texte additionnel." ) }, { "role": "user", "content": text_for_analysis } ] try: chat_completion = client.chat.completions.create( messages=messages, model="llama-3.3-70b-versatile", temperature=0.0, max_completion_tokens=1024, top_p=1, stream=False, response_format={"type": "json_object"} ) content = chat_completion.choices[0].message.content data = json.loads(content) return data except Exception as e: print(f"[ERREUR] Échec de la conversion en JSON : {e}") print("[INFO] Nous allons retourner un squelette par défaut.") return { "api_type": None, "base_url": None, "auth_info": { "type": None, "key_name": None, "required": False }, "common_headers": {}, "endpoints": [], "suggested_name": "API_Inconnue", "rate_limit": None, "confidence_score": 0.0 } # --------------------------------------------------------------------------- # 4. FONCTIONS D’OUTIL POUR L’INTERFACE def lire_int_in_range(prompt: str, min_val: int, max_val: int) -> int: """ Demande à l'utilisateur de saisir un entier dans la plage [min_val..max_val]. Si l'utilisateur saisit '?', on affiche un petit message d'aide (personnalisable). Répète la question tant que la valeur n'est pas un entier correct. Retourne l'entier validé. """ while True: saisie = input(prompt).strip() # Exemple de gestion d'un '?' ou autre commande spéciale if saisie == "?": print("Aide : veuillez saisir un entier compris entre " f"{min_val} et {max_val}.") print("Tapez un nombre valide, ou Ctrl+C pour annuler.") continue # Sinon, on tente la conversion try: val = int(saisie) if min_val <= val <= max_val: return val else: print(f"Choix invalide (doit être entre {min_val} et {max_val}).\n") except ValueError: print("Choix invalide (entrez un nombre). Réessayez.\n") def selectionner_api() -> dict: """ Affiche la liste des API configurées, demande à l'utilisateur d'en choisir une par numéro. Retourne le dict correspondant ou None si aucune API. """ if not apis_configurees: print("Aucune API n’est configurée.\n") return None print("=== Liste des APIs disponibles ===") for i, api in enumerate(apis_configurees, start=1): print(f"{i}. {api['name']}") # On lit un choix (numéro) dans la plage [1..len(apis_configurees)] choix_num = lire_int_in_range( prompt=f"Quelle API souhaitez-vous sélectionner ? [1..{len(apis_configurees)}] : ", min_val=1, max_val=len(apis_configurees) ) return apis_configurees[choix_num - 1] def selectionner_endpoint(api: dict) -> dict: """ Affiche la liste des endpoints pour l'API donnée, demande à l'utilisateur d'en choisir un par numéro. Retourne le dict correspondant ou None si aucun endpoint. """ if not api["endpoints"]: print("Cette API n’a aucun endpoint configuré.\n") return None print(f"Endpoints disponibles pour {api['name']} :") for i, ep in enumerate(api["endpoints"], start=1): print(f"{i}. {ep['name']} ({ep['method']} {ep['path']})") choix_ep_num = lire_int_in_range( prompt=f"Quel endpoint tester ? [1..{len(api['endpoints'])}] : ", min_val=1, max_val=len(api["endpoints"]) ) return api["endpoints"][choix_ep_num - 1] # --------------------------------------------------------------------------- # 5. Fonctions du menu def ajouter_api(): print("=== Ajout d’une nouvelle API ===") _ = input("Voulez-vous coller la documentation de l’API ? (o/n) : ") print("Collez la documentation ci-dessous (finissez par un skibidi vide) :") lignes_doc = [] while True: ligne = input() if ligne == "skibidi": break lignes_doc.append(ligne) doc_api = "\n".join(lignes_doc) if not doc_api.strip(): doc_api = "Pas d'information sur l'API." # Appel Groq pour analyse resultats_analyse = analyser_api_avec_groq(doc_api, groq_api_key="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") confidence_score = resultats_analyse.get("confidence_score", 0.0) if confidence_score < 0.5: print( "Le score de confiance de l’analyse est faible. " "Les informations retournées peuvent être partielles ou incorrectes.\n" ) # Champs retournés api_type = resultats_analyse.get("api_type") base_url = resultats_analyse.get("base_url") auth_info = resultats_analyse.get("auth_info", {}) common_headers = resultats_analyse.get("common_headers", {}) endpoints = resultats_analyse.get("endpoints", []) suggested_name = resultats_analyse.get("suggested_name", "NouvelleAPI") rate_limit = resultats_analyse.get("rate_limit") print(f"Nom suggéré pour l’API : {suggested_name}") nom_api = input(f"Entrez le nom de l’API ({suggested_name}) : ") if not nom_api.strip(): nom_api = suggested_name # Si auth_info.required == True, on demande la clé api_key_value = None if auth_info.get("required", False): api_key_value = input("Entrez la valeur de la clé API ou du token : ") # Construction de la config nouvelle_api = { "name": nom_api, "type": api_type, "base_url": base_url, "auth_info": auth_info, "api_key_value": api_key_value, "common_headers": common_headers, "endpoints": endpoints, "rate_limit": rate_limit } apis_configurees.append(nouvelle_api) print(f"\n[OK] L’API '{nom_api}' a été ajoutée.") print(f" - Type : {api_type}") print(f" - URL de base : {base_url}\n") # On sauvegarde dans le fichier JSON sauvegarder_apis() def lister_apis(): print("=== Liste des API configurées ===") if not apis_configurees: print("Aucune API n’est configurée.\n") return for i, api in enumerate(apis_configurees, start=1): print(f"{i}. Nom : {api['name']}") print(f" URL de base : {api['base_url'] or 'Non renseignée'}") print(f" Type : {api['type'] or 'Inconnu'}") if api["rate_limit"]: print(f" Limitation de débit : {api['rate_limit']}") if api["endpoints"]: print(" Endpoints :") for ep in api["endpoints"]: print(f" - {ep['name']} ({ep['method']} {ep['path']})") else: print(" Aucun endpoint configuré.") print() print() def modifier_api(): print("=== Modification d’une API ===") api_choisie = selectionner_api() if not api_choisie: return print(f"\nAPI sélectionnée : {api_choisie['name']}") print("Que voulez-vous modifier ? (ex: 'changer l'URL de base', 'changer la clé API', " "'ajouter un endpoint', 'modifier un endpoint', 'supprimer un endpoint')") action = input("> ").lower() if "url" in action: new_url = input("Nouvelle URL de base : ") api_choisie["base_url"] = new_url print("URL de base modifiée.\n") if "clé" in action or "key" in action: new_key = input("Nouvelle clé API : ") api_choisie["api_key_value"] = new_key print("Clé API modifiée.\n") if "ajouter un endpoint" in action: print("=== Ajout d'un endpoint ===") nom_ep = input("Nom du nouvel endpoint : ") path_ep = input("Chemin (ex: /playlists/{playlist_id}/tracks) : ") methode = input("Méthode HTTP (GET, POST, etc.) : ") params_req = [p.strip() for p in input("Paramètres requis (séparés par des virgules) : ").split(",") if p.strip()] params_opt = [p.strip() for p in input("Paramètres optionnels (séparés par des virgules) : ").split(",") if p.strip()] new_ep = { "name": nom_ep, "path": path_ep, "method": methode.upper(), "required_params": params_req, "optional_params": params_opt, "description": "" } api_choisie["endpoints"].append(new_ep) print(f"Endpoint '{nom_ep}' ajouté.\n") if "modifier un endpoint" in action: print("=== Modification d'un endpoint ===") if not api_choisie["endpoints"]: print("Aucun endpoint à modifier.") return print("Liste des endpoints :") for i, ep in enumerate(api_choisie["endpoints"], start=1): print(f"{i}. {ep['name']} ({ep['method']} {ep['path']})") choix_ep = lire_int_in_range( f"Quel endpoint modifier ? [1..{len(api_choisie['endpoints'])}] : ", 1, len(api_choisie["endpoints"]) ) ep_choisi = api_choisie["endpoints"][choix_ep - 1] print(f"Endpoint sélectionné : {ep_choisi['name']}") modif_ep = input("Que voulez-vous faire ? (ex: 'ajouter un paramètre', 'changer la méthode', etc.) : ").lower() if "ajouter un paramètre" in modif_ep: nom_p = input("Nom du paramètre : ") r_o = input("Paramètre requis ou optionnel ? (r/o) : ") if r_o.lower() == 'r': ep_choisi["required_params"].append(nom_p) else: ep_choisi["optional_params"].append(nom_p) print(f"Paramètre '{nom_p}' ajouté.\n") # D’autres modifications possibles... if "supprimer un endpoint" in action: print("=== Suppression d'un endpoint ===") if not api_choisie["endpoints"]: print("Aucun endpoint à supprimer.") return print("Liste des endpoints :") for i, ep in enumerate(api_choisie["endpoints"], start=1): print(f"{i}. {ep['name']} ({ep['method']} {ep['path']})") choix_ep = lire_int_in_range( f"Quel endpoint supprimer ? [1..{len(api_choisie['endpoints'])}] : ", 1, len(api_choisie["endpoints"]) ) ep_asup = api_choisie["endpoints"][choix_ep - 1] api_choisie["endpoints"].remove(ep_asup) print(f"Endpoint '{ep_asup['name']}' supprimé.") print("Modification(s) terminée(s).\n") # On sauvegarde les modifications sauvegarder_apis() def supprimer_api(): print("=== Suppression d’une API ===") api_choisie = selectionner_api() if not api_choisie: return confirm = input(f"Êtes-vous sûr de vouloir supprimer '{api_choisie['name']}' ? (o/n) : ") if confirm.lower() == 'o': apis_configurees.remove(api_choisie) print(f"L’API '{api_choisie['name']}' a été supprimée.\n") sauvegarder_apis() else: print("Opération annulée.\n") def tester_endpoint(): print("=== Tester un endpoint ===") api_choisie = selectionner_api() if not api_choisie: return ep_choisi = selectionner_endpoint(api_choisie) if not ep_choisi: return # On va demander les valeurs pour chaque param requis required_params_values = {} for rp in ep_choisi.get("required_params", []): val = input(f"Entrez la valeur pour '{rp}' : ") required_params_values[rp] = val # On va demander les valeurs pour chaque param optionnel optional_params_values = {} for op in ep_choisi.get("optional_params", []): val = input(f"Valeur pour '{op}' (laisser vide si aucun) : ") if val: optional_params_values[op] = val # Préparation de l’URL base_url = api_choisie.get("base_url") or "" path = ep_choisi["path"] # Remplacement dans le path si on a des placeholders {param} # et retrait du param si on a pu le remplacer query_params = {} for k, v in required_params_values.items(): placeholder = f"{{{k}}}" if placeholder in path: path = path.replace(placeholder, v) else: # S'il n'y a pas de placeholder correspondant, on le mettra en query param query_params[k] = v # Tous les optionnels vont en query params query_params.update(optional_params_values) # Gestion de l’authentification headers = dict(api_choisie.get("common_headers", {})) if "Accept" not in headers: headers["Accept"] = "application/json" auth_info = api_choisie.get("auth_info", {}) api_key_value = api_choisie.get("api_key_value") if auth_info.get("required") and api_key_value: # Exemple : si c’est un Bearer if auth_info["type"] and "bearer" in auth_info["type"].lower(): key_name = auth_info.get("key_name", "Authorization") headers[key_name] = f"Bearer {api_key_value}" # Exemple : si c’est un Basic elif auth_info["type"] and "basic" in auth_info["type"].lower(): key_name = auth_info.get("key_name", "Authorization") headers[key_name] = f"Basic {api_key_value}" else: # Si key_name = "api_key", NASA veut un query param "api_key=XXXX" if auth_info.get("key_name", "").lower() == "api_key": query_params["api_key"] = api_key_value else: # Sinon on le place dans un header key_name = auth_info.get("key_name", "X-API-Key") headers[key_name] = api_key_value # Construction de l'URL finale url = base_url + path method = ep_choisi["method"].upper() print(f"\nTest de l'endpoint : {method} {url}") print(f"En-têtes : {headers}") print(f"Paramètres : {query_params}\n") try: if method == "GET": r = requests.get(url, headers=headers, params=query_params) elif method == "POST": r = requests.post(url, headers=headers, json=query_params) elif method == "PUT": r = requests.put(url, headers=headers, json=query_params) elif method == "DELETE": r = requests.delete(url, headers=headers, json=query_params) else: print("Méthode non gérée.") return print(f"Statut : {r.status_code}") try: print("Réponse JSON :") print(json.dumps(r.json(), indent=2)) except: print("Réponse brute :") print(r.text) except Exception as e: print(f"Erreur lors de l’appel : {e}") # --------------------------------------------------------------------------- # 6. MAIN def main(): # On charge la liste des APIs en début de programme charger_apis() while True: print("=== Menu Principal ===") print("1. Ajouter une API (assisté par IA)") print("2. Liste des API configurées") print("3. Modifier une API") print("4. Supprimer une API") print("5. Tester un endpoint") print("6. Quitter") choix_num = lire_int_in_range("Choisissez une option [1..6] : ", 1, 6) if choix_num == 1: ajouter_api() elif choix_num == 2: lister_apis() elif choix_num == 3: modifier_api() elif choix_num == 4: supprimer_api() elif choix_num == 5: tester_endpoint() elif choix_num == 6: print("Au revoir.") sys.exit(0) if __name__ == "__main__": main()
FICHIER_APIS
: c’est le nom du fichier (par défaut apis_configurees.json
) où sont stockées les informations sur les APIs.charger_apis()
: appelé au lancement du script, il charge (si présent) le fichier JSON dans la variable globale apis_configurees
.sauvegarder_apis()
: à chaque fois qu’on apporte une modification (ajout, édition ou suppression), on appelle cette fonction pour réécrire le fichier JSON."name"
, "base_url"
, "type"
, "auth_info"
, "endpoints"
, etc.Ainsi, lorsque vous relancerez votre script, il relira automatiquement le fichier apis_configurees.json
et vous retrouverez vos APIs.