Skip to content

Commit 17e7837

Browse files
author
Paweł Kędzia
committed
Add OpenAIResponseHandler with Ollama response conversion and update VllmChatCompletion and OpenAI completion handlers to use unified response processing.
1 parent 19a254d commit 17e7837

File tree

3 files changed

+76
-5
lines changed

3 files changed

+76
-5
lines changed

llm_router_api/core/api_types/openai.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
from __future__ import annotations
22

3+
import datetime
4+
from dateutil import parser
5+
36
from llm_router_api.core.api_types.types_i import ApiTypesI
47

58

@@ -39,3 +42,53 @@ def completions_ep(self) -> str:
3942

4043
def completions_method(self) -> str:
4144
return "POST"
45+
46+
47+
class OpenAIConverters:
48+
class FromOllama:
49+
@staticmethod
50+
def convert(response):
51+
created_at = response.get("created_at")
52+
if not created_at:
53+
created_at = datetime.datetime.now().timestamp()
54+
else:
55+
created_at = parser.isoparse(created_at).timestamp()
56+
prompt_tokens = int(response.get("prompt_eval_count", 0))
57+
completion_tokens = int(response.get("eval_count", 0))
58+
59+
return {
60+
"id": response.get("id"),
61+
"object": "chat.completion",
62+
"created": created_at,
63+
"model": response.get("model", ""),
64+
"choices": [
65+
{
66+
"index": 0,
67+
"message": {
68+
"role": "assistant",
69+
"content": response["message"]["content"],
70+
"refusal": None,
71+
"annotations": None,
72+
"audio": None,
73+
"function_call": None,
74+
"tool_calls": [],
75+
"reasoning_content": response["message"].get("thinking"),
76+
},
77+
"logprobs": None,
78+
"finish_reason": response.get("done_reason", "stop"),
79+
"stop_reason": None,
80+
"token_ids": None,
81+
}
82+
],
83+
"service_tier": None,
84+
"system_fingerprint": None,
85+
"usage": {
86+
"prompt_tokens": prompt_tokens,
87+
"total_tokens": prompt_tokens + completion_tokens,
88+
"completion_tokens": completion_tokens,
89+
"prompt_tokens_details": None,
90+
},
91+
"prompt_logprobs": None,
92+
"prompt_token_ids": None,
93+
"kv_transfer_params": None,
94+
}

llm_router_api/endpoints/builtin/openai.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,30 @@
77
derived classes for completions and model listing.
88
"""
99

10+
import abc
1011
import datetime
12+
1113
from typing import Optional, Dict, Any, List
1214

1315
from rdl_ml_utils.handlers.prompt_handler import PromptHandler
1416

1517
from llm_router_api.core.decorators import EP
18+
from llm_router_api.core.api_types.openai import OpenAIConverters
1619
from llm_router_api.base.model_handler import ModelHandler
1720
from llm_router_api.base.constants import REST_API_LOG_LEVEL
1821
from llm_router_api.endpoints.passthrough import PassthroughI
1922

2023

21-
class OpenAICompletionHandler(PassthroughI):
24+
class OpenAIResponseHandler(PassthroughI, abc.ABC):
25+
@staticmethod
26+
def prepare_response_function(response):
27+
response = response.json()
28+
if "message" in response:
29+
return OpenAIConverters.FromOllama.convert(response=response)
30+
return response
31+
32+
33+
class OpenAICompletionHandler(OpenAIResponseHandler):
2234
"""
2335
Completion endpoint that re‑uses the chat implementation but targets the
2436
``/chat/completions`` route of an OpenAI‑compatible service.
@@ -51,8 +63,10 @@ def __init__(
5163
method="POST",
5264
)
5365

66+
self._prepare_response_function = self.prepare_response_function
5467

55-
class OpenAICompletionHandlerWOApi(PassthroughI):
68+
69+
class OpenAICompletionHandlerWOApi(OpenAIResponseHandler):
5670
"""
5771
Completion endpoint that re‑uses the chat implementation but targets the
5872
``/chat/completions`` route of an OpenAI‑compatible service.
@@ -85,6 +99,8 @@ def __init__(
8599
method="POST",
86100
)
87101

102+
self._prepare_response_function = self.prepare_response_function
103+
88104

89105
class OpenAIModelsHandler(PassthroughI):
90106
"""

llm_router_api/endpoints/builtin/vllm.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
from typing import Optional, Dict, Any, List
1+
from typing import Optional
22

33
from rdl_ml_utils.handlers.prompt_handler import PromptHandler
44

55
from llm_router_api.base.model_handler import ModelHandler
66
from llm_router_api.base.constants import REST_API_LOG_LEVEL
7-
from llm_router_api.endpoints.passthrough import PassthroughI
7+
from llm_router_api.endpoints.builtin.openai import OpenAIResponseHandler
88

99

10-
class VllmChatCompletion(PassthroughI):
10+
class VllmChatCompletion(OpenAIResponseHandler):
1111
REQUIRED_ARGS = None
1212
OPTIONAL_ARGS = None
1313
SYSTEM_PROMPT_NAME = None
@@ -53,3 +53,5 @@ def __init__(
5353
dont_add_api_prefix=dont_add_api_prefix,
5454
direct_return=False,
5555
)
56+
57+
self._prepare_response_function = self.prepare_response_function

0 commit comments

Comments
 (0)