From b522a0f76386490f980cbae0079d62a03be9b0ba Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Mon, 5 Feb 2024 15:03:27 -0500 Subject: [PATCH 1/3] Add --req-time-cost --- libretranslate/app.py | 23 +++++++++++++++++++---- libretranslate/default_values.py | 5 +++++ libretranslate/main.py | 7 +++++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/libretranslate/app.py b/libretranslate/app.py index 17f15c5..4ea7be0 100644 --- a/libretranslate/app.py +++ b/libretranslate/app.py @@ -1,4 +1,5 @@ import io +import math import os import re import tempfile @@ -219,6 +220,13 @@ def create_app(args): from flask_limiter import Limiter + def limits_cost(): + req_cost = getattr(request, 'req_cost', 1) + if args.req_time_cost > 0: + return max(req_cost, int(math.ceil(getattr(request, 'duration', 0) / args.req_time_cost))) + else: + return req_cost + limiter = Limiter( key_func=get_remote_address, default_limits=get_routes_limits( @@ -226,7 +234,7 @@ def create_app(args): ), storage_uri=args.req_limit_storage, default_limits_deduct_when=lambda req: True, # Force cost to be called after the request - default_limits_cost=lambda: getattr(request, 'req_cost', 1) + default_limits_cost=limits_cost ) else: from .no_limiter import Limiter @@ -325,12 +333,19 @@ def create_app(args): status = e.code raise e finally: - duration = max(default_timer() - start_t, 0) - measure_request.labels(request.path, status, ip, ak).observe(duration) + request.duration = max(default_timer() - start_t, 0) + measure_request.labels(request.path, status, ip, ak).observe(request.duration) g.dec() return measure_func else: - return func + @wraps(func) + def time_func(*a, **kw): + start_t = default_timer() + try: + return func(*a, **kw) + finally: + request.duration = max(default_timer() - start_t, 0) + return time_func @bp.errorhandler(400) def invalid_api(e): diff --git a/libretranslate/default_values.py b/libretranslate/default_values.py index 96a833e..b93cd76 100644 --- a/libretranslate/default_values.py +++ b/libretranslate/default_values.py @@ -81,6 +81,11 @@ _default_options_objects = [ 'default_value': -1, 'value_type': 'int' }, + { + 'name': 'REQ_TIME_COST', + 'default_value': -1, + 'value_type': 'int' + }, { 'name': 'BATCH_LIMIT', 'default_value': -1, diff --git a/libretranslate/main.py b/libretranslate/main.py index 581e4f5..8337c70 100644 --- a/libretranslate/main.py +++ b/libretranslate/main.py @@ -63,6 +63,13 @@ def get_args(): metavar="", help="Set the maximum number of request limit offences that a client can exceed before being banned. (%(default)s)", ) + parser.add_argument( + "--req-time-cost", + default=DEFARGS['REQ_TIME_COST'], + type=int, + metavar="", + help="Considers a time cost (in seconds) for request limiting purposes. If a request takes 10 seconds and this value is set to 5, the request cost is either 2 or the actual request cost (whichever is greater). (%(default)s)", + ) parser.add_argument( "--batch-limit", default=DEFARGS['BATCH_LIMIT'], From 1e50dc92bfd4ca637f5ccd6c691b9f9c248ff074 Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Mon, 5 Feb 2024 15:13:20 -0500 Subject: [PATCH 2/3] Update README --- README.md | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 85de97b..e23fda1 100644 --- a/README.md +++ b/README.md @@ -165,26 +165,27 @@ Arguments passed to the process or set via environment variables are split into ### Configuration Parameters -| Argument | Description | Default Parameter | Env. name | -|-----------------------------|-------------------------------------------------------------------------------------------------------------| -------------------- |------------------------------| -| --host | Set host to bind the server to | `127.0.0.1` | LT_HOST | -| --port | Set port to bind the server to | `5000` | LT_PORT | -| --char-limit | Set character limit | `No limit` | LT_CHAR_LIMIT | -| --req-limit | Set maximum number of requests per minute per client (outside of limits set by api keys) | `No limit` | LT_REQ_LIMIT | -| --req-limit-storage | Storage URI to use for request limit data storage. See [Flask Limiter](https://flask-limiter.readthedocs.io/en/stable/configuration.html) | `memory://` | LT_REQ_LIMIT_STORAGE | -| --batch-limit | Set maximum number of texts to translate in a batch request | `No limit` | LT_BATCH_LIMIT | -| --ga-id | Enable Google Analytics on the API client page by providing an ID | `Empty (no tracking)` | LT_GA_ID | -| --frontend-language-source | Set frontend default language - source | `auto` | LT_FRONTEND_LANGUAGE_SOURCE | -| --frontend-language-target | Set frontend default language - target | `locale` (match site's locale) | LT_FRONTEND_LANGUAGE_TARGET | -| --frontend-timeout | Set frontend translation timeout | `500` | LT_FRONTEND_TIMEOUT | -| --api-keys-db-path | Use a specific path inside the container for the local database. Can be absolute or relative | `db/api_keys.db` | LT_API_KEYS_DB_PATH | -| --api-keys-remote | Use this remote endpoint to query for valid API keys instead of using the local database | `Empty (use local db instead)` | LT_API_KEYS_REMOTE | -| --get-api-key-link | Show a link in the UI where to direct users to get an API key | `Empty (no link shown on web ui)` | LT_GET_API_KEY_LINK | -| --shared-storage | Shared storage URI to use for multi-process data sharing (e.g. when using gunicorn) | `memory://` | LT_SHARED_STORAGE | -| --load-only | Set available languages | `Empty (use all from argostranslate)` | LT_LOAD_ONLY | -| --threads | Set number of threads | `4` | LT_THREADS | -| --metrics-auth-token | Protect the /metrics endpoint by allowing only clients that have a valid Authorization Bearer token | `Empty (no auth required)` | LT_METRICS_AUTH_TOKEN | -| --url-prefix | Add prefix to URL: example.com:5000/url-prefix/ | `/` | LT_URL_PREFIX | +| Argument | Description | Default Parameter | Env. name | +| -------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | --------------------------- | +| --host | Set host to bind the server to | `127.0.0.1` | LT_HOST | +| --port | Set port to bind the server to | `5000` | LT_PORT | +| --char-limit | Set character limit | `No limit` | LT_CHAR_LIMIT | +| --req-limit | Set maximum number of requests per minute per client (outside of limits set by api keys) | `No limit` | LT_REQ_LIMIT | +| --req-limit-storage | Storage URI to use for request limit data storage. See [Flask Limiter](https://flask-limiter.readthedocs.io/en/stable/configuration.html) | `memory://` | LT_REQ_LIMIT_STORAGE | +| --req-time-cost | Considers a time cost (in seconds) for request limiting purposes. If a request takes 10 seconds and this value is set to 5, the request cost is either 2 or the actual request cost (whichever is greater). | `No time cost` | LT_REQ_TIME_COST | +| --batch-limit | Set maximum number of texts to translate in a batch request | `No limit` | LT_BATCH_LIMIT | +| --ga-id | Enable Google Analytics on the API client page by providing an ID | `Empty (no tracking)` | LT_GA_ID | +| --frontend-language-source | Set frontend default language - source | `auto` | LT_FRONTEND_LANGUAGE_SOURCE | +| --frontend-language-target | Set frontend default language - target | `locale` (match site's locale) | LT_FRONTEND_LANGUAGE_TARGET | +| --frontend-timeout | Set frontend translation timeout | `500` | LT_FRONTEND_TIMEOUT | +| --api-keys-db-path | Use a specific path inside the container for the local database. Can be absolute or relative | `db/api_keys.db` | LT_API_KEYS_DB_PATH | +| --api-keys-remote | Use this remote endpoint to query for valid API keys instead of using the local database | `Empty (use local db instead)` | LT_API_KEYS_REMOTE | +| --get-api-key-link | Show a link in the UI where to direct users to get an API key | `Empty (no link shown on web ui)` | LT_GET_API_KEY_LINK | +| --shared-storage | Shared storage URI to use for multi-process data sharing (e.g. when using gunicorn) | `memory://` | LT_SHARED_STORAGE | +| --load-only | Set available languages | `Empty (use all from argostranslate)` | LT_LOAD_ONLY | +| --threads | Set number of threads | `4` | LT_THREADS | +| --metrics-auth-token | Protect the /metrics endpoint by allowing only clients that have a valid Authorization Bearer token | `Empty (no auth required)` | LT_METRICS_AUTH_TOKEN | +| --url-prefix | Add prefix to URL: example.com:5000/url-prefix/ | `/` | LT_URL_PREFIX | ### Notes: From 176d37df737ae9db20e67bcd2c9ab9298da21a89 Mon Sep 17 00:00:00 2001 From: Piero Toffanin Date: Mon, 5 Feb 2024 15:16:32 -0500 Subject: [PATCH 3/3] Remove trailing whitespace test --- .pre-commit-config.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 55e8f4b..fee2cd1 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,8 +9,6 @@ repos: name: " ✔️ Check TOML" - id: check-json name: " ✔️ Check JSON" - - id: trailing-whitespace - name: " ✂️ Trim trailing whitespaces" - repo: https://github.com/charliermarsh/ruff-pre-commit rev: v0.0.277 hooks: