Groq max_tokens problème

创建于:2025年1月17日

使用 OpenAI 01 回答 OpenAI01

问题

import 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
class api:
@staticmethod
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")
@staticmethod
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}")

@staticmethod

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
@staticmethod
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,
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
@staticmethod
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 = api.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,
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


@staticmethod
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 = api.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]

@staticmethod
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 = api.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
@staticmethod
def ajouter_api():
print("=== Ajout d’une nouvelle API ===")
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 = api.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
api.sauvegarder_apis()

@staticmethod
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()

@staticmethod
def modifier_api():
print("=== Modification d’une API ===")
api_choisie = api.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 = api.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 = api.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
api.sauvegarder_apis()

@staticmethod
def supprimer_api():
print("=== Suppression d’une API ===")
api_choisie = api.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")
api.sauvegarder_apis()
else:
print("Opération annulée.\n")

@staticmethod
def tester_endpoint():
print("=== Tester un endpoint ===")
api_choisie = api.selectionner_api()
if not api_choisie:
return

ep_choisi = api.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(self):
# On charge la liste des APIs en début de programme
api.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 = api.lire_int_in_range("Choisissez une option [1..6] : ", 1, 6)

if choix_num == 1:
api.ajouter_api()
elif choix_num == 2:
api.lister_apis()
elif choix_num == 3:
api.modifier_api()
elif choix_num == 4:
api.supprimer_api()
elif choix_num == 5:
api.tester_endpoint()
elif choix_num == 6:
print("Au revoir.")
sys.exit(0)

[ERREUR] Échec de la conversion en JSON : Completions.create() got an unexpected keyword argument 'max_completion_tokens'
[INFO] Nous allons retourner un squelette par défaut.
Le score de confiance de l’analyse est faible. Les informations retournées peuvent être partielles ou incorrectes.

Nom suggéré pour l’API : API_Inconnue
Entrez le nom de l’API (API_Inconnue) :

思考

Identifying error sources

The script is encountering an unexpected keyword argument error. This might stem from older code segments or the library being outdated.

Identifying potential issues

The error might stem from an outdated Groq library version or a misalignment between the library version and the code snippet. It seems the max_completion_tokens parameter is not specified in the code provided.

Investigating potential causes

The unexpected argument might stem from an older library version, a coding error, or an environment setting, suggesting the user should either update the library or adjust their approach.

Identifying the issue

The problem could be due to an outdated library version, a coding mistake, or a wrong parameter name like max_tokens instead of max_completion_tokens.

Identifying the issue

OK, let me see. The error likely results from using an outdated library version, incorrect code, or a mistaken parameter name. Solving this involves checking the version, updating the library, or tweaking the code.

Thought about handling API data pendant 13 secondes

回答

It looks like the Groq Python client you are using does not support the parameter max_completion_tokens, so it raises:

Completions.create() got an unexpected keyword argument 'max_completion_tokens'

However, in the code you pasted, there is no explicit mention of max_completion_tokens. That usually means one of two things is happening:

  1. Some other part of your code (not shown in the snippet) is calling
    client.chat.completions.create(..., max_completion_tokens=...),
    or

  2. The Groq library’s version you installed is not aligned with the usage in your code, and it's automatically appending max_completion_tokens somewhere (or expecting a different argument name, like max_tokens).


How to fix

  1. Search for max_completion_tokens in your entire project
    Make sure there is absolutely no part of your code still passing max_completion_tokens=... to client.chat.completions.create().

  2. If you need to limit tokens, switch to max_tokens
    In some versions of the Groq or OpenAI-like clients, the parameter to control token limit is named max_tokens. For example:

    completion = client.chat.completions.create( model="llama-3.3-70b-versatile", messages=messages, max_tokens=1000, # Instead of max_completion_tokens temperature=0.0, top_p=1, stream=False )

    But first check Groq’s latest documentation or help(client.chat.completions.create) in a Python shell to confirm which parameters are actually supported.

  3. Update (or downgrade) your Groq Python client
    If you are on an older version of groq-lm or the Groq Python SDK, try upgrading:

    pip install --upgrade groq-lm

    Then see if max_completion_tokens is officially supported. Conversely, if you’re using code from an older example but you installed a newer library, that example might be out of date (or vice versa).

Usually, removing max_completion_tokens (or renaming it to whatever the library currently expects, such as max_tokens) will resolve the error right away.


Why the JSON fallback message?

Once that call to client.chat.completions.create fails, your catch block:

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 { ... }

forces the script to return a minimal fallback JSON structure. Hence the message:

[ERREUR] Échec de la conversion en JSON : Completions.create() got an unexpected keyword argument ...
[INFO] Nous allons retourner un squelette par défaut.
Le score de confiance de l’analyse est faible...

As soon as you fix or remove that unsupported parameter, the code should proceed to parse the model’s output and return a proper JSON result (with a better “confidence_score,” etc.).


In summary: remove or rename max_completion_tokens to match the current Groq parameters (very likely max_tokens), or update the library so that your code and the installed version are consistent. That will get rid of the error and allow your script to parse the JSON response from the model.

问题

improve my code pls and make it more efficient and show me full code

思考

Merging code** Combining code into a single file or multiple files, removing or renaming repeated code, and using classes to store APIs for efficient organization, are essential steps towards a more streamlined and maintainable codebase.

Enhancing code refinement

I’m focused on removing duplication, managing debug prints, and improving user input handling. Also, planning to introduce docstrings, type hints, and refining the chunking function for summarizer.

Refining code approach

I’m discussing maintaining consistency by using French, renaming classes for clarity, and keeping or removing specific references to ensure the code is relevant and effective.

Enhancing the code

I’m planning to refine the code by adding docstrings, type hints, and robust handling for partial inputs, chunking in summarization, and error management for missing Groq keys.

Renaming and streamlining

I’m working through renaming classes and functions for clarity, addressing duplication, enhancing code styling, and incorporating docstrings and type hints to create a more efficient and maintainable codebase.

Refining the final snippet

I’m ensuring the final code snippet is efficient and accessible, focusing on removing irrelevant arguments like max_completion_tokens and adhering strictly to the supported API's standard usage.

Thought about Groq API integration pendant 35 secondes

回答

Below is a refactored and cleaned-up version of your code in one file, with some additional comments, minor performance improvements, and better structure. It should remain fully compatible with your original logic and menu flow. The code is in French, as in your snippet, but you can easily adapt it.


Points d’amélioration / changements notables

  1. Structure & Lisibilité

    • Regroupement des fonctions dans une classe ApiManager (pour clarifier les responsabilités).
    • Ajout de docstrings et annotations de type (PEP 484) pour une meilleure maintenabilité.
    • Utilisation d’une seule variable globale apis_configurees conservée dans la classe.
    • Vérifications (try/except) plus robustes autour des appels à l’API Groq.
  2. Gestion de l’API Groq

    • Suppression de l’argument max_completion_tokens, qui n’est pas (ou plus) supporté par la version récente du client Groq.
    • Suppression de l’argument response_format={"type": "json_object"} si votre version du client Groq ne le supporte pas non plus.
    • Ajout d’un paramètre max_tokens=1000 (par exemple) pour limiter le nombre de tokens (adapter selon vos besoins).
  3. Factorisation

    • Certaines portions répétées (lecture de chunk, impression, etc.) sont simplifiées.
  4. Commentaires & Docstrings

    • Plus de commentaires pour expliquer le flux.
  5. Pas de dépendance fantôme à max_completion_tokens

    • Le bug du Completions.create() got an unexpected keyword argument 'max_completion_tokens' devrait disparaître.

Code Complet

import sys import json import os import requests from groq import Groq # --------------------------------------------------------------------------- # Constantes / Variables globales FICHIER_APIS = "apis_configurees.json" MAX_CHARS_DIRECT_ANALYSIS = 3000 DEFAULT_GROQ_API_KEY = "gsk_votre_cle_par_defaut_ici" # Adapter si besoin class ApiManager: """ Classe regroupant toutes les méthodes nécessaires : - Lecture/écriture des APIs (JSON) - Intéraction avec l'IA Groq pour résumé/analyse JSON - Menu et actions (ajout, modification, test, etc.) """ # Liste globale des APIs configurées apis_configurees = [] # ----------------------------------------------------------------------- # 1. Fonctions d'IO pour sauvegarder/charger les APIs @staticmethod def lire_int_in_range(prompt: str, min_val: int, max_val: int) -> int: """ Demande à l'utilisateur de saisir un entier dans [min_val..max_val]. Gère également le cas où l'utilisateur saisit '?' pour demander de l'aide. Retourne l'entier validé. """ while True: saisie = input(prompt).strip() if saisie == "?": print("Aide : veuillez saisir un entier compris entre " f"{min_val} et {max_val}. Tapez Ctrl+C pour annuler.") continue 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") @staticmethod def sauvegarder_apis() -> None: """ Sauvegarde la liste des APIs dans FICHIER_APIS au format JSON. """ try: with open(FICHIER_APIS, "w", encoding="utf-8") as f: json.dump(ApiManager.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}") @staticmethod def charger_apis() -> None: """ Charge la liste des APIs depuis FICHIER_APIS, si présent. """ if os.path.exists(FICHIER_APIS): try: with open(FICHIER_APIS, "r", encoding="utf-8") as f: ApiManager.apis_configurees = json.load(f) print(f"[INFO] {len(ApiManager.apis_configurees)} API(s) chargée(s) depuis {FICHIER_APIS}.") except Exception as e: print(f"[ERREUR] Impossible de lire {FICHIER_APIS} : {e}") ApiManager.apis_configurees = [] else: ApiManager.apis_configurees = [] # ----------------------------------------------------------------------- # 2. Fonction de résumé si la doc est trop volumineuse @staticmethod def summarizer_groq(long_text: str, groq_api_key: str = DEFAULT_GROQ_API_KEY) -> str: """ Découpe la documentation en chunks et génère un résumé global (texte brut). On utilise le modèle Chat via l'API Groq. """ 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( model="llama-3.3-70b-versatile", messages=messages, temperature=0.2, top_p=1, max_tokens=600, # Par exemple pour limiter 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 @staticmethod def analyser_api_avec_groq(input_text: str, groq_api_key: str = DEFAULT_GROQ_API_KEY) -> dict: """ 1) Si le texte est trop long, on génère un résumé via summarizer_groq. 2) On passe ensuite (ou directement) le texte final dans un prompt qui demande un JSON strict. 3) Retourne un dict Python. """ # 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 = ApiManager.summarizer_groq(input_text, groq_api_key=groq_api_key) # 2) Appel Chat Completion pour le JSON client = Groq(api_key=groq_api_key) messages = [ { "role": "system", "content": ( "Tu es un assistant d'analyse d'API. Ta réponse doit être EXCLUSIVEMENT du JSON valide. " "Respecte ce schéma complet :\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" "Ne fournis aucun texte additionnel. Juste le JSON." ) }, { "role": "user", "content": text_for_analysis } ] try: chat_completion = client.chat.completions.create( model="llama-3.3-70b-versatile", messages=messages, temperature=0.0, top_p=1, max_tokens=1500, # Ajuster selon la taille souhaitée stream=False ) content = chat_completion.choices[0].message.content.strip() # Tentative de parsing JSON data = json.loads(content) return data except Exception as e: print(f"[ERREUR] Échec de la conversion en JSON : {e}") print("[INFO] Retour d’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 CLI @staticmethod def selectionner_api() -> dict | None: """ Affiche la liste des API configurées, demande un choix, retourne le dict de l'API choisie. Retourne None s'il n'y en a aucune. """ if not ApiManager.apis_configurees: print("Aucune API n’est configurée.\n") return None print("=== Liste des APIs disponibles ===") for i, api_info in enumerate(ApiManager.apis_configurees, start=1): print(f"{i}. {api_info['name']}") choix_num = ApiManager.lire_int_in_range( prompt=f"Quelle API souhaitez-vous sélectionner ? [1..{len(ApiManager.apis_configurees)}] : ", min_val=1, max_val=len(ApiManager.apis_configurees) ) return ApiManager.apis_configurees[choix_num - 1] @staticmethod def selectionner_endpoint(api_info: dict) -> dict | None: """ Affiche la liste des endpoints, demande un choix, retourne le dict du endpoint choisi. Retourne None s'il n'y en a aucun. """ if not api_info["endpoints"]: print("Cette API n’a aucun endpoint configuré.\n") return None print(f"Endpoints disponibles pour {api_info['name']} :") for i, ep in enumerate(api_info["endpoints"], start=1): print(f"{i}. {ep['name']} ({ep['method']} {ep['path']})") choix_ep_num = ApiManager.lire_int_in_range( prompt=f"Quel endpoint tester ? [1..{len(api_info['endpoints'])}] : ", min_val=1, max_val=len(api_info["endpoints"]) ) return api_info["endpoints"][choix_ep_num - 1] # ----------------------------------------------------------------------- # 5. Fonctions du menu @staticmethod def ajouter_api() -> None: """ Ajoute une nouvelle API en collant sa documentation (utilise l'IA Groq pour l'analyser). """ print("=== Ajout d’une nouvelle API ===") print("Collez la documentation ci-dessous (tapez 'skibidi' sur une ligne vide pour finir) :") lignes_doc = [] while True: ligne = input() if ligne.strip() == "skibidi": break lignes_doc.append(ligne) doc_api = "\n".join(lignes_doc).strip() if not doc_api: doc_api = "Pas d'information sur l'API." # Analyse par IA resultats_analyse = ApiManager.analyser_api_avec_groq(doc_api) 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}) : ").strip() if not nom_api: nom_api = suggested_name # Si l'API nécessite une clé/token 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 } ApiManager.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") # Sauvegarde ApiManager.sauvegarder_apis() @staticmethod def lister_apis() -> None: """ Affiche toutes les APIs configurées (avec leurs endpoints). """ print("=== Liste des API configurées ===") if not ApiManager.apis_configurees: print("Aucune API n’est configurée.\n") return for i, api_info in enumerate(ApiManager.apis_configurees, start=1): print(f"{i}. Nom : {api_info['name']}") print(f" URL de base : {api_info['base_url'] or 'Non renseignée'}") print(f" Type : {api_info['type'] or 'Inconnu'}") if api_info["rate_limit"]: print(f" Limitation de débit : {api_info['rate_limit']}") if api_info["endpoints"]: print(" Endpoints :") for ep in api_info["endpoints"]: print(f" - {ep['name']} ({ep['method']} {ep['path']})") else: print(" Aucun endpoint configuré.") print() print() @staticmethod def modifier_api() -> None: """ Permet de modifier diverses infos sur une API existante : URL de base, clé, endpoints, etc. """ print("=== Modification d’une API ===") api_choisie = ApiManager.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 for i, ep in enumerate(api_choisie["endpoints"], start=1): print(f"{i}. {ep['name']} ({ep['method']} {ep['path']})") choix_ep = ApiManager.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, à adapter selon vos besoins... 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 = ApiManager.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") ApiManager.sauvegarder_apis() @staticmethod def supprimer_api() -> None: """ Supprime complètement une API de la liste (après confirmation). """ print("=== Suppression d’une API ===") api_choisie = ApiManager.selectionner_api() if not api_choisie: return confirm = input(f"Êtes-vous sûr de vouloir supprimer '{api_choisie['name']}' ? (o/n) : ").lower() if confirm == 'o': ApiManager.apis_configurees.remove(api_choisie) print(f"L’API '{api_choisie['name']}' a été supprimée.\n") ApiManager.sauvegarder_apis() else: print("Opération annulée.\n") @staticmethod def tester_endpoint() -> None: """ Permet de tester un endpoint en temps réel : - Sélectionne une API - Sélectionne un endpoint - Demande les paramètres requis/optionnels - Lance la requête HTTP et affiche la réponse. """ print("=== Tester un endpoint ===") api_choisie = ApiManager.selectionner_api() if not api_choisie: return ep_choisi = ApiManager.selectionner_endpoint(api_choisie) if not ep_choisi: return # Paramètres 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 # Paramètres optionnels 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 des placeholders {param} dans le path query_params = {} for k, v in required_params_values.items(): placeholder = f"{{{k}}}" if placeholder in path: path = path.replace(placeholder, v) else: query_params[k] = v # 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: # Parfois, c'est un param "api_key" dans l'URL 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/json) : {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, ensure_ascii=False)) except Exception: print("Réponse brute :") print(r.text) except Exception as e: print(f"Erreur lors de l’appel : {e}") # ----------------------------------------------------------------------- # 6. MAIN @staticmethod def main() -> None: """ Fonction principale de l'application (menu en boucle). """ # On charge la liste des APIs au démarrage ApiManager.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 = ApiManager.lire_int_in_range("Choisissez une option [1..6] : ", 1, 6) if choix_num == 1: ApiManager.ajouter_api() elif choix_num == 2: ApiManager.lister_apis() elif choix_num == 3: ApiManager.modifier_api() elif choix_num == 4: ApiManager.supprimer_api() elif choix_num == 5: ApiManager.tester_endpoint() elif choix_num == 6: print("Au revoir.") sys.exit(0) # --------------------------------------------------------------------------- # Point d'entrée du script if __name__ == "__main__": ApiManager.main()

Comment utiliser ?

  1. Installer les dépendances :

    pip install requests groq-lm

    (ou toute autre version requise selon votre environnement).

  2. Exécuter :

    python nom_du_script.py

    Cela lancera le menu en boucle.

  3. Clé API Groq :

    • Remplacez la valeur DEFAULT_GROQ_API_KEY en haut du code par votre clé réelle.
    • Ou, si vous préférez, passez-la en paramètre dans analyser_api_avec_groq(doc_api, groq_api_key="votre_cle").
  4. Fichier JSON :

    • Les configurations sont enregistrées dans apis_configurees.json (vous pouvez changer le nom dans la constante FICHIER_APIS).
    • Chaque fois que vous modifiez/ajoutez/supprimez une API via le menu, le fichier est mis à jour.

Ainsi, ce code amélioré devrait être plus lisible, plus robuste, et éviter l’erreur liée à max_completion_tokens. Bien sûr, vous pouvez l’adapter selon vos besoins (nouveaux prompts, autre modèle Groq, etc.). Bon codage !

问题

c'est quoi ça ? [INFO] Résumé global généré. Longueur du résumé : 2198 caractères.
[ERREUR] Échec de la conversion en JSON : Completions.create() got an unexpected keyword argument 'max_completion_tokens'
[INFO] Nous allons retourner un squelette par défaut.
Le score de confiance de l’analyse est faible. Les informations retournées peuvent être partielles ou incorrectes.
l'erreur

思考

Thought about error handling with Groq API pendant quelques secondes

回答

Ce message d’erreur indique simplement que la bibliothèque Groq que vous utilisez ne reconnaît pas l’argument max_completion_tokens. Autrement dit, le code (ou la bibliothèque elle-même) essaie d’appeler la méthode Completions.create() avec un paramètre qui n’est pas supporté dans votre version de la librairie groq-lm.

En pratique, dès que cet appel échoue, votre code passe dans le except et retourne un « squelette par défaut » à la place de la vraie réponse JSON. Voilà pourquoi vous voyez :

[ERREUR] Échec de la conversion en JSON : Completions.create() got an unexpected 
keyword argument 'max_completion_tokens'
[INFO] Nous allons retourner un squelette par défaut.

et le script vous annonce un score de confiance faible (car le résultat est vide ou incomplet).


Pourquoi ça se produit ?

  1. Le code ou la bibliothèque passe max_completion_tokens=... à la méthode Completions.create(), mais votre version de la lib Groq ne le gère pas.
  2. Le paramètre correct peut être max_tokens (comme dans l’API OpenAI standard) ou aucun paramètre du tout.

Comment corriger ?

  1. Vérifier si, dans votre code, vous avez quelque part un appel du style :

    client.chat.completions.create( ..., max_completion_tokens=1234 )

    Si oui, supprimez ou remplacez max_completion_tokens par max_tokens.

  2. Vérifier votre version de groq-lm (ou autre bibliothèque Groq). Dans un terminal:

    pip show groq-lm

    Assurez-vous d’avoir la version la plus récente (ou adaptée à l’exemple).
    Pour mettre à jour :

    pip install --upgrade groq-lm
  3. Si vous ne trouvez pas ce paramètre dans votre code, il est possible que votre version de la lib Groq ajoute ou attend d’autres arguments. Dans ce cas, reportez-vous à la documentation de Groq pour vérifier la liste des paramètres supportés.

En somme, le message d’erreur signifie juste : « On me demande d’utiliser max_completion_tokens, mais je ne connais pas ce paramètre. » Supprimez-le ou remplacez-le par max_tokens et l’erreur devrait disparaître.

分享这个问答