From 43e1e8e23852e6d6a6aac6219fe393366b8100ee Mon Sep 17 00:00:00 2001 From: Eli Date: Mon, 7 Oct 2024 10:06:55 -0500 Subject: [PATCH] Fix pypi extra dependency install bug. --- Dockerfile | 4 +--- pyproject.toml | 2 +- readmeai/config/settings.py | 8 ++------ readmeai/models/anthropic.py | 21 ++++++++++----------- readmeai/models/gemini.py | 6 ++++-- readmeai/models/openai.py | 3 ++- tests/models/test_anthropic.py | 19 +++++++++++++++++++ tests/models/test_gemini.py | 2 +- 8 files changed, 40 insertions(+), 25 deletions(-) diff --git a/Dockerfile b/Dockerfile index cc1ea003..9a222932 100644 --- a/Dockerfile +++ b/Dockerfile @@ -5,9 +5,7 @@ WORKDIR /app ENV GIT_PYTHON_REFRESH=quiet RUN apt-get update \ - && apt-get install -y --no-install-recommends git \ - && apt-get clean \ - && apt-get purge -y --auto-remove git \ + && apt-get install -y git \ && rm -rf /var/lib/apt/lists/* RUN pip install --no-cache-dir --upgrade readmeai diff --git a/pyproject.toml b/pyproject.toml index b41fff60..4d650d78 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "readmeai" -version = "0.5.95" +version = "0.5.96" description = "Automated README file generator, powered by AI." authors = ["Eli "] license = "MIT" diff --git a/readmeai/config/settings.py b/readmeai/config/settings.py index 79537f23..af2500d8 100644 --- a/readmeai/config/settings.py +++ b/readmeai/config/settings.py @@ -18,11 +18,7 @@ ) from pydantic_extra_types.color import Color -from readmeai.config.constants import ( - BadgeStyleOptions, - ImageOptions, - LLMService, -) +from readmeai.config.constants import BadgeStyleOptions, ImageOptions from readmeai.errors import GitValidationError from readmeai.logger import get_logger from readmeai.readers.git.providers import GitURL, parse_git_url @@ -162,7 +158,7 @@ class ModelSettings(BaseModel): LLM API model settings and parameters. """ - api: str = Field(default=LLMService.OFFLINE) + api: str base_url: str context_window: PositiveInt encoder: str diff --git a/readmeai/models/anthropic.py b/readmeai/models/anthropic.py index 47812243..aa5a0ab5 100644 --- a/readmeai/models/anthropic.py +++ b/readmeai/models/anthropic.py @@ -19,9 +19,15 @@ import anthropic ANTHROPIC_AVAILABLE = True + ANTHROPIC_EXCEPTIONS = ( + anthropic.APIError, + anthropic.APIConnectionError, + anthropic.RateLimitError, + ) except ImportError: anthropic = None ANTHROPIC_AVAILABLE = False + ANTHROPIC_EXCEPTIONS = tuple() class AnthropicHandler(BaseModelHandler): @@ -74,15 +80,7 @@ async def _build_payload(self, prompt: str, tokens: int) -> dict[str, Any]: @retry( stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=4, max=10), - retry=retry_if_exception_type( - ( - anthropic.APIError, - anthropic.APIConnectionError, - anthropic.RateLimitError, - ) - if ANTHROPIC_AVAILABLE - else tuple() - ), + retry=retry_if_exception_type(ANTHROPIC_EXCEPTIONS), ) async def _make_request( self, @@ -107,6 +105,7 @@ async def _make_request( parameters = await self._build_payload(prompt, tokens) async with self.rate_limit_semaphore: + self._logger.info(f"Making request to Anthropic for '{index}'") response = await self.client.messages.create(**parameters) data = ( response.content[0].text @@ -118,9 +117,9 @@ async def _make_request( ) return index, data - except () as e: + except ANTHROPIC_EXCEPTIONS as e: self._logger.error( - f"Error processing request for '{index}': {e!r}" + f"API Error processing request for '{index}': {e!r}" ) raise # Re-raise for retry decorator diff --git a/readmeai/models/gemini.py b/readmeai/models/gemini.py index fc504364..57083bfa 100644 --- a/readmeai/models/gemini.py +++ b/readmeai/models/gemini.py @@ -66,7 +66,7 @@ def _model_settings(self): # Safely get top_p from config, use default if not available self.top_p = getattr(self.config.llm, "top_p", self.top_p) - async def _build_payload(self, prompt: str, tokens: int) -> dict[str, Any]: + async def _build_payload(self, prompt: str, tokens: int) -> Any: """Build payload for POST request to the Gemini API.""" if not GENAI_AVAILABLE: raise RuntimeError( @@ -87,7 +87,9 @@ async def _build_payload(self, prompt: str, tokens: int) -> dict[str, Any]: aiohttp.ClientError, aiohttp.ClientResponseError, aiohttp.ClientConnectorError, - ), + ) + if GENAI_AVAILABLE + else tuple() ), ) async def _make_request( diff --git a/readmeai/models/openai.py b/readmeai/models/openai.py index f06e6ab4..10ec0add 100644 --- a/readmeai/models/openai.py +++ b/readmeai/models/openai.py @@ -1,5 +1,6 @@ """OpenAI API model handler implementation, with Ollama support.""" +import os from typing import Any import aiohttp @@ -39,7 +40,7 @@ def _model_settings(self): if self.config.llm.api == LLMService.OPENAI.name: self.url = f"{self.host_name}{self.path}" - self.client = openai.OpenAI() + self.client = openai.OpenAI(api_key=os.getenv("OPENAI_API_KEY")) elif self.config.llm.api == LLMService.OLLAMA.name: self.url = f"{self.localhost}{self.path}" diff --git a/tests/models/test_anthropic.py b/tests/models/test_anthropic.py index 1c134814..14f6dc70 100644 --- a/tests/models/test_anthropic.py +++ b/tests/models/test_anthropic.py @@ -8,9 +8,18 @@ from readmeai.ingestion.models import RepositoryContext from readmeai.models.anthropic import AnthropicHandler +try: + import anthropic + + ANTHROPIC_AVAILABLE = True +except ImportError: + ANTHROPIC_AVAILABLE = False + @pytest.fixture def anthropic_handler(repository_context_fixture: RepositoryContext): + if not ANTHROPIC_AVAILABLE: + pytest.skip("Anthropic library is not available") config_loader = ConfigLoader() context = repository_context_fixture return AnthropicHandler(config_loader, context) @@ -18,6 +27,8 @@ def anthropic_handler(repository_context_fixture: RepositoryContext): @pytest.mark.asyncio async def test_model_settings(anthropic_handler: AnthropicHandler): + if not ANTHROPIC_AVAILABLE: + pytest.skip("Anthropic library is not available") anthropic_handler._model_settings() assert isinstance(anthropic_handler.client, anthropic.AsyncAnthropic) assert anthropic_handler.model == "claude-3-opus-20240229" @@ -25,6 +36,8 @@ async def test_model_settings(anthropic_handler: AnthropicHandler): @pytest.mark.asyncio async def test_build_payload(anthropic_handler: AnthropicHandler): + if not ANTHROPIC_AVAILABLE: + pytest.skip("Anthropic library is not available") prompt = "Test prompt" tokens = 100 payload = await anthropic_handler._build_payload(prompt, tokens) @@ -39,6 +52,8 @@ async def test_build_payload(anthropic_handler: AnthropicHandler): async def test_make_request_success( mock_create, mock_token_handler, anthropic_handler: AnthropicHandler ): + if not ANTHROPIC_AVAILABLE: + pytest.skip("Anthropic library is not available") mock_token_handler.return_value = "Processed prompt" mock_token_handler.side_effect = lambda *args: args[2] mock_create.return_value = MagicMock( @@ -62,6 +77,8 @@ async def test_make_request_success( async def test_make_request_api_error( mock_create, mock_token_handler, anthropic_handler: AnthropicHandler ): + if not ANTHROPIC_AVAILABLE: + pytest.skip("Anthropic library is not available") mock_token_handler.return_value = "Processed prompt" mock_create.side_effect = anthropic.APIError( message="API error", @@ -83,6 +100,8 @@ async def test_make_request_api_error( async def test_make_request_unexpected_error( mock_create, mock_token_handler, anthropic_handler: AnthropicHandler ): + if not ANTHROPIC_AVAILABLE: + pytest.skip("Anthropic library is not available") mock_token_handler.return_value = "Processed prompt" mock_create.side_effect = Exception("Unexpected error") anthropic_handler.client = MagicMock() diff --git a/tests/models/test_gemini.py b/tests/models/test_gemini.py index 3a4b72cd..188baebd 100644 --- a/tests/models/test_gemini.py +++ b/tests/models/test_gemini.py @@ -35,7 +35,7 @@ async def test_model_settings(gemini_handler: GeminiHandler): async def test_build_payload(gemini_handler: GeminiHandler): payload = await gemini_handler._build_payload("test prompt", 100) assert isinstance(payload, genai.types.GenerationConfig) - assert payload.max_output_tokens == 699 + assert payload.max_output_tokens == 100 assert payload.temperature == 0.1 assert payload.top_p == 0.9