refactor(devgen/providers): shared provider base class
Abstract out generate validation and error handling into BaseProvider, eliminating duplicated logic across Anthropic, OpenRouter, and OpenAI providers.
This commit is contained in:
7 files changed
+223
-259
No files matched your search
@@ -1,34 +1,19 @@
|
||||
import requests
|
||||
|
||||
from devgen.providers.base import BaseProvider
|
||||
from devgen.utils import format_token_limit_error, is_token_limit_error
|
||||
|
||||
|
||||
class HuggingfaceProvider:
|
||||
class HuggingfaceProvider(BaseProvider):
|
||||
"""Generates content using Hugging Face Inference API."""
|
||||
|
||||
DISPLAY_NAME = "Hugging Face"
|
||||
API_URL_TEMPLATE = "https://api-inference.huggingface.co/models/{model}"
|
||||
DEFAULT_MODEL = "mistralai/Mistral-7B-Instruct-v0.2"
|
||||
|
||||
def generate(
|
||||
self,
|
||||
prompt: str,
|
||||
api_key: str,
|
||||
model: str = "mistralai/Mistral-7B-Instruct-v0.2",
|
||||
**kwargs,
|
||||
) -> str:
|
||||
"""Generates a response using Hugging Face API."""
|
||||
if not api_key:
|
||||
raise ValueError(
|
||||
"Hugging Face API token is missing. "
|
||||
"Set it via `devgen setup config` or pass --api-key."
|
||||
)
|
||||
|
||||
def _generate(self, prompt, api_key, model, **kwargs):
|
||||
api_url = self.API_URL_TEMPLATE.format(model=model)
|
||||
headers = {"Authorization": f"Bearer {api_key}"}
|
||||
|
||||
# HF models often expect specific prompting formats, but we'll send raw prompt
|
||||
# Some models are text-generation, some are conversational.
|
||||
# Assuming text-generation for generic usage.
|
||||
|
||||
payload = {
|
||||
"inputs": prompt,
|
||||
"parameters": {"max_new_tokens": 500, "return_full_text": False},
|
||||
@@ -38,31 +23,12 @@ class HuggingfaceProvider:
|
||||
response = requests.post(api_url, headers=headers, json=payload)
|
||||
response.raise_for_status()
|
||||
result = response.json()
|
||||
|
||||
if isinstance(result, list) and result and "generated_text" in result[0]:
|
||||
return result[0]["generated_text"].strip()
|
||||
elif isinstance(result, dict) and "error" in result:
|
||||
err = result["error"]
|
||||
if "is currently loading" in str(err).lower():
|
||||
raise RuntimeError(
|
||||
f"Hugging Face model is loading: {err}. "
|
||||
"Wait a minute and retry, or pick a different model."
|
||||
)
|
||||
if is_token_limit_error(err):
|
||||
raise RuntimeError(
|
||||
format_token_limit_error("Hugging Face", err)
|
||||
) from err
|
||||
raise RuntimeError(f"Hugging Face API error: {err}")
|
||||
else:
|
||||
raise RuntimeError(
|
||||
"Hugging Face returned an unexpected response shape. "
|
||||
"The model may not support text-generation."
|
||||
)
|
||||
|
||||
except requests.HTTPError as e:
|
||||
status = e.response.status_code if e.response is not None else "?"
|
||||
if is_token_limit_error(e):
|
||||
raise RuntimeError(format_token_limit_error("Hugging Face", e)) from e
|
||||
raise RuntimeError(
|
||||
format_token_limit_error(self.DISPLAY_NAME, e)
|
||||
) from e
|
||||
status = e.response.status_code if e.response is not None else "?"
|
||||
raise RuntimeError(
|
||||
f"Hugging Face request failed (HTTP {status}): {e}. "
|
||||
"Check the model id and your token permissions."
|
||||
@@ -71,9 +37,18 @@ class HuggingfaceProvider:
|
||||
raise RuntimeError(
|
||||
f"Hugging Face network error: {e}. Check your connection."
|
||||
) from e
|
||||
except RuntimeError:
|
||||
raise
|
||||
except Exception as e:
|
||||
if is_token_limit_error(e):
|
||||
raise RuntimeError(format_token_limit_error("Hugging Face", e)) from e
|
||||
raise RuntimeError(f"Hugging Face generation failed: {e}") from e
|
||||
|
||||
if isinstance(result, list) and result and "generated_text" in result[0]:
|
||||
return result[0]["generated_text"]
|
||||
if isinstance(result, dict) and "error" in result:
|
||||
err = result["error"]
|
||||
if "is currently loading" in str(err).lower():
|
||||
raise RuntimeError(
|
||||
f"Hugging Face model is loading: {err}. "
|
||||
"Wait a minute and retry, or pick a different model."
|
||||
)
|
||||
raise RuntimeError(f"Hugging Face API error: {err}")
|
||||
raise RuntimeError(
|
||||
"Hugging Face returned an unexpected response shape. "
|
||||
"The model may not support text-generation."
|
||||
)
|
||||
Reference in new issue
Block a user