diff options
author | Heiner Lohaus <hlohaus@users.noreply.github.com> | 2024-11-24 23:34:59 +0100 |
---|---|---|
committer | Heiner Lohaus <hlohaus@users.noreply.github.com> | 2024-11-24 23:34:59 +0100 |
commit | c57321e2873c533a4f5d1cd5b278e3a8ca108656 (patch) | |
tree | 092f528d250071a604dd9c9c86858110ec450cb4 | |
parent | Improve slim docker build, Add openapi.json to release (diff) | |
download | gpt4free-c57321e2873c533a4f5d1cd5b278e3a8ca108656.tar gpt4free-c57321e2873c533a4f5d1cd5b278e3a8ca108656.tar.gz gpt4free-c57321e2873c533a4f5d1cd5b278e3a8ca108656.tar.bz2 gpt4free-c57321e2873c533a4f5d1cd5b278e3a8ca108656.tar.lz gpt4free-c57321e2873c533a4f5d1cd5b278e3a8ca108656.tar.xz gpt4free-c57321e2873c533a4f5d1cd5b278e3a8ca108656.tar.zst gpt4free-c57321e2873c533a4f5d1cd5b278e3a8ca108656.zip |
Diffstat (limited to '')
-rw-r--r-- | .github/workflows/publish-workflow.yaml | 4 | ||||
-rw-r--r-- | docker/Dockerfile-slim | 44 | ||||
-rw-r--r-- | g4f/api/__init__.py | 29 |
3 files changed, 25 insertions, 52 deletions
diff --git a/.github/workflows/publish-workflow.yaml b/.github/workflows/publish-workflow.yaml index 49ff03a5..9ad68bd8 100644 --- a/.github/workflows/publish-workflow.yaml +++ b/.github/workflows/publish-workflow.yaml @@ -16,7 +16,9 @@ jobs: python-version: "3.8" cache: 'pip' - name: Install requirements - run: pip install fastapi uvicorn python-multipart + run: | + pip install fastapi uvicorn python-multipart + pip install -r requirements-min.txt - name: Generate openapi.json run: | python -m etc.tool.openapi diff --git a/docker/Dockerfile-slim b/docker/Dockerfile-slim index 0a09395b..04238144 100644 --- a/docker/Dockerfile-slim +++ b/docker/Dockerfile-slim @@ -1,9 +1,8 @@ -FROM python:bookworm +FROM python:slim-bookworm ARG G4F_VERSION ARG G4F_USER=g4f ARG G4F_USER_ID=1000 -ARG PYDANTIC_VERSION=1.8.1 ENV G4F_VERSION $G4F_VERSION ENV G4F_USER $G4F_USER @@ -12,60 +11,29 @@ ENV G4F_DIR /app RUN apt-get update && apt-get upgrade -y \ && apt-get install -y git \ - && apt-get install --quiet --yes --no-install-recommends \ - build-essential \ # Add user and user group && groupadd -g $G4F_USER_ID $G4F_USER \ && useradd -rm -G sudo -u $G4F_USER_ID -g $G4F_USER_ID $G4F_USER \ && mkdir -p /var/log/supervisor \ && chown "${G4F_USER_ID}:${G4F_USER_ID}" /var/log/supervisor \ && echo "${G4F_USER}:${G4F_USER}" | chpasswd \ - && python -m pip install --upgrade pip + && python -m pip install --upgrade pip \ + && apt-get clean \ + && rm --recursive --force /var/lib/apt/lists/* /tmp/* /var/tmp/* USER $G4F_USER_ID WORKDIR $G4F_DIR ENV HOME /home/$G4F_USER -ENV PATH "${HOME}/.local/bin:${HOME}/.cargo/bin:${PATH}" +ENV PATH "${HOME}/.local/bin:${PATH}" # Create app dir and copy the project's requirements file into it RUN mkdir -p $G4F_DIR COPY requirements-min.txt $G4F_DIR COPY requirements-slim.txt $G4F_DIR -# Install rust toolchain -RUN curl https://sh.rustup.rs -sSf | bash -s -- -y - # Upgrade pip for the latest features and install the project's Python dependencies. -RUN pip install --no-cache-dir -r requirements-min.txt \ - && pip install --no-cache-dir --no-binary setuptools \ - Cython==0.29.22 \ - setuptools \ - # Install PyDantic - && pip install \ - -vvv \ - --no-cache-dir \ - --no-binary :all: \ - --global-option=build_ext \ - --global-option=-j8 \ - pydantic==${PYDANTIC_VERSION} \ - && cat requirements-slim.txt | xargs -n 1 pip install --no-cache-dir || true \ - # Remove build packages - && pip uninstall --yes \ - Cython \ - setuptools - -USER root - -# Clean up build deps -RUN rm --recursive --force "${HOME}/.rustup" \ - && rustup self uninstall -y \ - && apt-get purge --auto-remove --yes \ - build-essential \ - && apt-get clean \ - && rm --recursive --force /var/lib/apt/lists/* /tmp/* /var/tmp/* - -USER $G4F_USER_ID +RUN cat requirements-slim.txt | xargs -n 1 pip install --no-cache-dir || true # Copy the entire package into the container. ADD --chown=$G4F_USER:$G4F_USER g4f $G4F_DIR/g4f
\ No newline at end of file diff --git a/g4f/api/__init__.py b/g4f/api/__init__.py index e8e979b3..2f34fa6a 100644 --- a/g4f/api/__init__.py +++ b/g4f/api/__init__.py @@ -147,6 +147,9 @@ class ErrorResponse(Response): def from_message(cls, message: str, status_code: int = HTTP_500_INTERNAL_SERVER_ERROR): return cls(format_exception(message), status_code) + def render(self, content) -> bytes: + return str(content).encode(errors="ignore") + class AppConfig: ignored_providers: Optional[list[str]] = None g4f_api_key: Optional[str] = None @@ -186,9 +189,9 @@ class Api: user_g4f_api_key = await self.get_g4f_api_key(request) except HTTPException as e: if e.status_code == 403: - return ErrorResponse("G4F API key required", HTTP_401_UNAUTHORIZED) + return ErrorResponse.from_message("G4F API key required", HTTP_401_UNAUTHORIZED) if not secrets.compare_digest(self.g4f_api_key, user_g4f_api_key): - return ErrorResponse("Invalid G4F API key", HTTP_403_FORBIDDEN) + return ErrorResponse.from_message("Invalid G4F API key", HTTP_403_FORBIDDEN) return await call_next(request) def register_validation_exception_handler(self): @@ -249,7 +252,7 @@ class Api: 'created': 0, 'owned_by': model_info.base_provider }) - return ErrorResponse("The model does not exist.", HTTP_404_NOT_FOUND) + return ErrorResponse.from_message("The model does not exist.", HTTP_404_NOT_FOUND) @self.app.post("/v1/chat/completions", responses={ HTTP_200_OK: {"model": ChatCompletion}, @@ -318,13 +321,13 @@ class Api: except (ModelNotFoundError, ProviderNotFoundError) as e: logger.exception(e) - return ErrorResponse(e, HTTP_404_NOT_FOUND) + return ErrorResponse.from_exception(e, config, HTTP_404_NOT_FOUND) except MissingAuthError as e: logger.exception(e) - return ErrorResponse(e, HTTP_401_UNAUTHORIZED) + return ErrorResponse.from_exception(e, config, HTTP_401_UNAUTHORIZED) except Exception as e: logger.exception(e) - return ErrorResponse(e, HTTP_500_INTERNAL_SERVER_ERROR) + return ErrorResponse.from_exception(e, config, HTTP_500_INTERNAL_SERVER_ERROR) responses = { HTTP_200_OK: {"model": ImagesResponse}, @@ -359,13 +362,13 @@ class Api: return response except (ModelNotFoundError, ProviderNotFoundError) as e: logger.exception(e) - return ErrorResponse(e, HTTP_404_NOT_FOUND) + return ErrorResponse.from_exception(e, config, HTTP_404_NOT_FOUND) except MissingAuthError as e: logger.exception(e) - return ErrorResponse(e, HTTP_401_UNAUTHORIZED) + return ErrorResponse.from_exception(e, config, HTTP_401_UNAUTHORIZED) except Exception as e: logger.exception(e) - return ErrorResponse(e, HTTP_500_INTERNAL_SERVER_ERROR) + return ErrorResponse.from_exception(e, config, HTTP_500_INTERNAL_SERVER_ERROR) @self.app.get("/v1/providers", responses={ HTTP_200_OK: {"model": List[ProviderResponseModel]}, @@ -428,12 +431,12 @@ class Api: async def synthesize(request: Request, provider: str): try: provider_handler = convert_to_provider(provider) - except ProviderNotFoundError: - return ErrorResponse("Provider not found", HTTP_404_NOT_FOUND) + except ProviderNotFoundError as e: + return ErrorResponse.from_exception(e, status_code=HTTP_404_NOT_FOUND) if not hasattr(provider_handler, "synthesize"): - return ErrorResponse("Provider doesn't support synthesize", HTTP_404_NOT_FOUND) + return ErrorResponse.from_message("Provider doesn't support synthesize", HTTP_404_NOT_FOUND) if len(request.query_params) == 0: - return ErrorResponse("Missing query params", HTTP_422_UNPROCESSABLE_ENTITY) + return ErrorResponse.from_message("Missing query params", HTTP_422_UNPROCESSABLE_ENTITY) response_data = provider_handler.synthesize({**request.query_params}) content_type = getattr(provider_handler, "synthesize_content_type", "application/octet-stream") return StreamingResponse(response_data, media_type=content_type) |