77import httpx
88from httpx_retries import Retry , RetryTransport
99from PIL import Image
10+ from loguru import logger
1011
1112from .base_client import (
1213 DEFAULT_SYSTEM_PROMPT ,
@@ -63,14 +64,22 @@ def __init__(
6364
6465 if not server_url :
6566 server_url = _get_env ("MINERU_VL_SERVER" )
66-
6767 if server_url .endswith ("/" ): # keep server_url if it ends with '/'
6868 server_url = server_url .rstrip ("/" )
6969 else : # use base_url if it does not end with '/' (backward compatibility)
7070 server_url = self ._get_base_url (server_url )
71-
7271 self .server_url = server_url
73- self .server_headers = server_headers
72+
73+ api_key = os .getenv ("MINERU_VL_API_KEY" , "" ).strip ()
74+ if api_key :
75+ headers = dict (server_headers ) if server_headers else {}
76+ if "Authorization" in headers :
77+ logger .warning ("Overriding existing 'Authorization' header with MINERU_VL_API_KEY from environment variable." )
78+ headers ["Authorization" ] = f"Bearer { api_key } "
79+ self .server_headers = headers
80+ else :
81+ self .server_headers = server_headers
82+
7483 self .http_timeout = http_timeout
7584 self .max_retries = max_retries
7685 self .retry_backoff_factor = retry_backoff_factor
@@ -79,6 +88,7 @@ def __init__(
7988 self ._aio_client_sem = asyncio .Semaphore (1 )
8089 self ._aio_client_cache : dict [asyncio .AbstractEventLoop , httpx .AsyncClient ] = {}
8190
91+ model_name = model_name or os .getenv ("MINERU_VL_MODEL_NAME" )
8292 if model_name :
8393 self ._check_model_name (self .server_url , model_name )
8494 self .model_name = model_name
@@ -164,7 +174,8 @@ def _get_model_name(self, base_url: str) -> str:
164174 raise RequestError (f"No models found in response from { base_url } . Response body: { response .text } " )
165175 if len (models ) != 1 :
166176 raise RequestError (
167- f"Expected exactly one model from { base_url } , but got { len (models )} . Please specify the model name."
177+ f"Expected exactly one model from { base_url } , but got { len (models )} . Please specify the model name"
178+ f" or set the `MINERU_VL_MODEL_NAME` environment variable."
168179 )
169180 model_name = models [0 ].get ("id" , "" )
170181 if not model_name :
@@ -275,6 +286,11 @@ def get_response_content(self, response_data: dict) -> str:
275286 content = message ["content" ]
276287 if not (content is None or isinstance (content , str )):
277288 raise ServerError (f"Unexpected content type: { type (content )} ." )
289+ # Allow the end token to be configured via environment variable, falling back to the default.
290+ # Set MINERU_VLM_END_TOKEN to override or disable stripping (e.g., set to an empty string).
291+ end_token = os .getenv ("MINERU_VLM_END_TOKEN" , "<|im_end|>" )
292+ if end_token and isinstance (content , str ) and content .endswith (end_token ):
293+ content = content [:- len (end_token )]
278294 return content or ""
279295
280296 def predict (
0 commit comments