-
-
Notifications
You must be signed in to change notification settings - Fork 8.8k
feat - add a new endpoint get_tokenizer_info
to provide tokenizer/chat-template information
#20575
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
e2efa8f
ade7167
855b7bf
8ff1d1b
167fd62
3b2ea85
0e0c04e
8eb5461
a42e7e9
14a42ac
a69b705
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,7 +1,7 @@ | ||||||||||||||||
# SPDX-License-Identifier: Apache-2.0 | ||||||||||||||||
# SPDX-FileCopyrightText: Copyright contributors to the vLLM project | ||||||||||||||||
|
||||||||||||||||
from typing import Final, Optional, Union | ||||||||||||||||
from dataclasses import dataclass | ||||||||||||||||
from typing import Any, Final, Optional, Union | ||||||||||||||||
|
||||||||||||||||
import jinja2 | ||||||||||||||||
from fastapi import Request | ||||||||||||||||
|
@@ -17,11 +17,13 @@ | |||||||||||||||
ErrorResponse, | ||||||||||||||||
TokenizeChatRequest, | ||||||||||||||||
TokenizeRequest, | ||||||||||||||||
TokenizeResponse) | ||||||||||||||||
TokenizeResponse, | ||||||||||||||||
TokenizerInfoResponse) | ||||||||||||||||
# yapf: enable | ||||||||||||||||
from vllm.entrypoints.openai.serving_engine import OpenAIServing | ||||||||||||||||
from vllm.entrypoints.openai.serving_models import OpenAIServingModels | ||||||||||||||||
from vllm.logger import init_logger | ||||||||||||||||
from vllm.transformers_utils.tokenizer import AnyTokenizer | ||||||||||||||||
|
||||||||||||||||
logger = init_logger(__name__) | ||||||||||||||||
|
||||||||||||||||
|
@@ -155,3 +157,51 @@ async def create_detokenize( | |||||||||||||||
input_text = prompt_input["prompt"] | ||||||||||||||||
|
||||||||||||||||
return DetokenizeResponse(prompt=input_text) | ||||||||||||||||
|
||||||||||||||||
async def get_tokenizer_info( | ||||||||||||||||
self, ) -> Union[TokenizerInfoResponse, ErrorResponse]: | ||||||||||||||||
"""Get comprehensive tokenizer information.""" | ||||||||||||||||
try: | ||||||||||||||||
tokenizer = await self.engine_client.get_tokenizer() | ||||||||||||||||
info = TokenizerInfo(tokenizer, self.chat_template).to_dict() | ||||||||||||||||
return TokenizerInfoResponse(**info) | ||||||||||||||||
except Exception as e: | ||||||||||||||||
return self.create_error_response( | ||||||||||||||||
f"Failed to get tokenizer info: {str(e)}") | ||||||||||||||||
Comment on lines
+168
to
+170
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Catching a broad
Suggested change
|
||||||||||||||||
|
||||||||||||||||
|
||||||||||||||||
@dataclass | ||||||||||||||||
class TokenizerInfo: | ||||||||||||||||
tokenizer: AnyTokenizer | ||||||||||||||||
chat_template: Optional[str] | ||||||||||||||||
|
||||||||||||||||
def to_dict(self) -> dict[str, Any]: | ||||||||||||||||
"""Return the tokenizer configuration.""" | ||||||||||||||||
return self._get_tokenizer_config() | ||||||||||||||||
|
||||||||||||||||
def _get_tokenizer_config(self) -> dict[str, Any]: | ||||||||||||||||
"""Get tokenizer configuration directly from the tokenizer object.""" | ||||||||||||||||
config = (dict(self.tokenizer.init_kwargs) | ||||||||||||||||
if hasattr(self.tokenizer, "init_kwargs") | ||||||||||||||||
and self.tokenizer.init_kwargs else {}) | ||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||||||||||||
|
||||||||||||||||
# Remove file path fields | ||||||||||||||||
config.pop("vocab_file", None) | ||||||||||||||||
config.pop("merges_file", None) | ||||||||||||||||
|
||||||||||||||||
config = self._make_json_serializable(config) | ||||||||||||||||
config["tokenizer_class"] = type(self.tokenizer).__name__ | ||||||||||||||||
if self.chat_template: | ||||||||||||||||
config["chat_template"] = self.chat_template | ||||||||||||||||
return config | ||||||||||||||||
|
||||||||||||||||
def _make_json_serializable(self, obj): | ||||||||||||||||
"""Convert any non-JSON-serializable objects to serializable format.""" | ||||||||||||||||
if hasattr(obj, "content"): | ||||||||||||||||
return obj.content | ||||||||||||||||
elif isinstance(obj, dict): | ||||||||||||||||
return {k: self._make_json_serializable(v) for k, v in obj.items()} | ||||||||||||||||
elif isinstance(obj, list): | ||||||||||||||||
return [self._make_json_serializable(item) for item in obj] | ||||||||||||||||
else: | ||||||||||||||||
return obj |
Uh oh!
There was an error while loading. Please reload this page.