Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion aidial_adapter_openai/audio_api/transcribe/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ def _get_usage(
) -> TokenUsage | None:
# NOTE: whisper has completely different API for its responses
duration: Any | None = getattr(chunk, "duration", None)
if duration is not None and isinstance(duration, (float, int)):
if duration is not None and isinstance(duration, float | int):
return TokenUsage(prompt_tokens=int(duration))

usage_dict: dict | None = getattr(chunk, "usage", None) # type: ignore
Expand Down
4 changes: 2 additions & 2 deletions aidial_adapter_openai/audio_api/transcribe/prompt.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

import mimetypes
from typing import Any, List
from typing import Any

from aidial_sdk.exceptions import RequestValidationError
from pydantic import BaseModel
Expand Down Expand Up @@ -50,7 +50,7 @@ async def from_request(

system_message = _collect_system_messages(messages)

audios: List[FileResource] = []
audios: list[FileResource] = []

for message in result:
for file in message.files:
Expand Down
14 changes: 7 additions & 7 deletions aidial_adapter_openai/chat_completions/gpt.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import AsyncIterator, Callable, Coroutine, List, Mapping, Tuple
from collections.abc import AsyncIterator, Callable, Coroutine, Mapping

from aidial_sdk.exceptions import InvalidRequestError
from openai import AsyncAzureOpenAI, AsyncOpenAI, AsyncStream
Expand Down Expand Up @@ -29,10 +29,10 @@

async def multi_modal_truncate_prompt(
request: dict,
messages: List[MultiModalMessage],
messages: list[MultiModalMessage],
max_prompt_tokens: int,
tokenizer: Tokenizer,
) -> Tuple[List[MultiModalMessage], DiscardedMessages, TruncatedTokens]:
) -> tuple[list[MultiModalMessage], DiscardedMessages, TruncatedTokens]:
return await truncate_prompt(
messages=messages,
message_tokens=tokenizer.tokenize_request_message,
Expand Down Expand Up @@ -62,9 +62,9 @@ def _extract_max_prompt_tokens(request: dict) -> int | None:


async def _truncate_messages(
request: dict, messages: List[MultiModalMessage], tokenizer: Tokenizer
) -> Tuple[
List[MultiModalMessage],
request: dict, messages: list[MultiModalMessage], tokenizer: Tokenizer
) -> tuple[
list[MultiModalMessage],
DiscardedMessages | None,
Callable[[], Coroutine[None, None, TruncatedTokens]],
]:
Expand Down Expand Up @@ -109,7 +109,7 @@ async def chat_completion(
eliminate_empty_choices: bool,
) -> ResponseWithHeaders[AsyncIterator[dict] | dict]:
n: int = request.get("n") or 1
messages: List[dict] = request["messages"]
messages: list[dict] = request["messages"]
model_name = request["model"]

multi_modal_messages = await ResourceProcessor(
Expand Down
3 changes: 2 additions & 1 deletion aidial_adapter_openai/chat_completions/gpt_audio.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
DIAL-compatible format with attachments and stages.
"""

from typing import AsyncIterator, TypeVar
from collections.abc import AsyncIterator
from typing import TypeVar

from pydantic import BaseModel

Expand Down
5 changes: 3 additions & 2 deletions aidial_adapter_openai/chat_completions/gpt_oss.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,16 @@
https://cookbook.openai.com/articles/gpt-oss/handle-raw-cot
"""

from typing import AsyncIterator, Set, TypeVar
from collections.abc import AsyncIterator
from typing import TypeVar

from pydantic import BaseModel

from aidial_adapter_openai.utils.streaming import map_stream


class _ResponseTransformer(BaseModel):
opened_reasoning_stages: Set[int] = set()
opened_reasoning_stages: set[int] = set()
"""Indices of choices where a reasoning stage was open.
"""

Expand Down
2 changes: 1 addition & 1 deletion aidial_adapter_openai/chat_completions/non_gpt.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import AsyncIterator
from collections.abc import AsyncIterator

from openai import AsyncAzureOpenAI, AsyncOpenAI, AsyncStream
from openai.types.chat.chat_completion import ChatCompletion
Expand Down
28 changes: 14 additions & 14 deletions aidial_adapter_openai/chat_completions/transformation.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from dataclasses import dataclass
from typing import List, Set, assert_never
from typing import assert_never

from aidial_sdk.exceptions import InvalidRequestError
from openai.types.chat import (
Expand Down Expand Up @@ -46,15 +46,15 @@ class Error:

class MessageTransformer:
file_storage: FileStorage | None
errors: Set[Error]
images: List[ImageResource]
files: List[FileResource]
errors: set[Error]
images: list[ImageResource]
files: list[FileResource]

def __init__(
self,
*,
file_storage: FileStorage | None,
errors: Set[Error] | None = None,
errors: set[Error] | None = None,
):
self.file_storage = file_storage
self.errors = set() if errors is None else errors
Expand All @@ -81,12 +81,12 @@ async def try_download_resource(
return None

async def download_attachments(
self, attachments: List[dict]
) -> List[ChatCompletionContentPartImageParam | File]:
self, attachments: list[dict]
) -> list[ChatCompletionContentPartImageParam | File]:
if attachments:
logger.debug(f"original attachments: {attachments}")

ret: List[ChatCompletionContentPartImageParam | File] = []
ret: list[ChatCompletionContentPartImageParam | File] = []
for attachment in attachments:
if result := await self.download_attachment(attachment):
ret.append(result)
Expand Down Expand Up @@ -145,15 +145,15 @@ async def download_content(
self,
content: (
str
| List[ChatCompletionContentPartParam | ContentArrayOfContentPart]
| list[ChatCompletionContentPartParam | ContentArrayOfContentPart]
),
) -> List[ChatCompletionContentPartParam | ContentArrayOfContentPart]:
) -> list[ChatCompletionContentPartParam | ContentArrayOfContentPart]:
if isinstance(content, str):
parts = [create_text_content_part(content)]
else:
parts = content

ret: List[
ret: list[
ChatCompletionContentPartParam | ContentArrayOfContentPart
] = []
for part in parts:
Expand Down Expand Up @@ -192,9 +192,9 @@ class ResourceProcessor(BaseModel):
file_storage: FileStorage | None

async def transform_messages(
self, messages: List[dict]
) -> List[MultiModalMessage]:
errors: Set[Error] = set()
self, messages: list[dict]
) -> list[MultiModalMessage]:
errors: set[Error] = set()
transformations = [
await MessageTransformer(
file_storage=self.file_storage, errors=errors
Expand Down
7 changes: 4 additions & 3 deletions aidial_adapter_openai/completions.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from typing import Any, AsyncIterator, Dict
from collections.abc import AsyncIterator
from typing import Any

from aidial_sdk.exceptions import RequestValidationError
from openai import AsyncAzureOpenAI, AsyncOpenAI, AsyncStream
Expand All @@ -18,7 +19,7 @@ def sanitize_text(text: str) -> str:

def convert_to_chat_completions_response(
chunk: Completion, is_stream: bool
) -> Dict[str, Any]:
) -> dict[str, Any]:
converted_chunk = build_chunk(
id=chunk.id,
model=chunk.model,
Expand All @@ -37,7 +38,7 @@ def convert_to_chat_completions_response(

async def chat_completion(
*,
request: Dict[str, Any],
request: dict[str, Any],
client: AsyncAzureOpenAI | AsyncOpenAI,
prompt_template: str | None,
) -> AsyncIterator[dict] | dict:
Expand Down
24 changes: 12 additions & 12 deletions aidial_adapter_openai/configuration/app_config.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
from __future__ import annotations

import os
from typing import Dict, List, assert_never
from typing import assert_never

from aidial_sdk.exceptions import InternalServerError

Expand Down Expand Up @@ -39,23 +39,23 @@ class DeploymentAPIType(ExtraForbidModel):


class ApplicationConfig(ExtraForbidModel):
TIKTOKEN_MODEL_MAPPING: Dict[str, str] = {}
TIKTOKEN_MODEL_MAPPING: dict[str, str] = {}

DALLE3_DEPLOYMENTS: List[str] = []
DALLE3_DEPLOYMENTS: list[str] = []
DALLE3_AZURE_API_VERSION: str = "2024-02-01"

GPT_IMAGE_1_DEPLOYMENTS: List[str] = []
GPT_IMAGE_1_DEPLOYMENTS: list[str] = []
GPT_IMAGE_1_AZURE_API_VERSION: str = "2025-04-01-preview"

MISTRAL_DEPLOYMENTS: List[str] = []
DATABRICKS_DEPLOYMENTS: List[str] = []
GPT4O_DEPLOYMENTS: List[str] = []
GPT4O_MINI_DEPLOYMENTS: List[str] = []
AZURE_AI_VISION_DEPLOYMENTS: List[str] = []
MISTRAL_DEPLOYMENTS: list[str] = []
DATABRICKS_DEPLOYMENTS: list[str] = []
GPT4O_DEPLOYMENTS: list[str] = []
GPT4O_MINI_DEPLOYMENTS: list[str] = []
AZURE_AI_VISION_DEPLOYMENTS: list[str] = []

API_VERSIONS_MAPPING: Dict[str, str] = {}
COMPLETION_DEPLOYMENTS_PROMPT_TEMPLATES: Dict[str, str] = {}
NON_STREAMING_DEPLOYMENTS: List[str] = []
API_VERSIONS_MAPPING: dict[str, str] = {}
COMPLETION_DEPLOYMENTS_PROMPT_TEMPLATES: dict[str, str] = {}
NON_STREAMING_DEPLOYMENTS: list[str] = []
ELIMINATE_EMPTY_CHOICES: bool = False

AUDIO_AZURE_API_VERSION: str = "2025-03-01-preview"
Expand Down
13 changes: 5 additions & 8 deletions aidial_adapter_openai/dial_api/embedding_inputs.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
from collections.abc import AsyncIterator, Callable, Coroutine
from typing import (
AsyncIterator,
Callable,
Coroutine,
List,
TypeVar,
assert_never,
cast,
Expand All @@ -15,7 +12,7 @@
_T = TypeVar("_T")

_Coro = Coroutine[None, None, _T]
_Tokens = List[int]
_Tokens = list[int]


async def reject_tokens(tokens: _Tokens):
Expand All @@ -25,7 +22,7 @@ async def reject_tokens(tokens: _Tokens):
)


async def reject_mixed(input: List[str | Attachment]):
async def reject_mixed(input: list[str | Attachment]):
raise RequestValidationError(
"Embedding inputs composed of multiple texts and/or attachments aren't supported"
)
Expand All @@ -37,7 +34,7 @@ async def collect_embedding_inputs(
on_text: Callable[[str], _Coro[_T]],
on_attachment: Callable[[Attachment], _Coro[_T]],
on_tokens: Callable[[_Tokens], _Coro[_T]] = reject_tokens,
on_mixed: Callable[[List[str | Attachment]], _Coro[_T]] = reject_mixed,
on_mixed: Callable[[list[str | Attachment]], _Coro[_T]] = reject_mixed,
) -> AsyncIterator[_T]:
async def _on_str_or_attachment(input: str | Attachment) -> _T:
if isinstance(input, str):
Expand Down Expand Up @@ -70,7 +67,7 @@ async def _on_str_or_attachment(input: str | Attachment) -> _T:
return

for input in request.custom_input:
if isinstance(input, (str, Attachment)):
if isinstance(input, str | Attachment):
yield await _on_str_or_attachment(input)
elif isinstance(input, list):
if len(input) == 0:
Expand Down
4 changes: 2 additions & 2 deletions aidial_adapter_openai/dial_api/request.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
from typing import Any, Type, TypeVar
from typing import Any, TypeVar

from aidial_sdk.exceptions import RequestValidationError
from pydantic import BaseModel, ValidationError

_T = TypeVar("_T", bound=BaseModel)


def parse_configuration(cls: Type[_T], data: Any) -> _T | None:
def parse_configuration(cls: type[_T], data: Any) -> _T | None:
if (cf := data.get("custom_fields")) is None:
return None

Expand Down
7 changes: 3 additions & 4 deletions aidial_adapter_openai/dial_api/resource.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import base64
import mimetypes
from abc import ABC, abstractmethod
from typing import List

from aidial_sdk.chat_completion import Attachment
from pydantic import BaseModel, model_validator
Expand All @@ -25,17 +24,17 @@ class MissingContentTypeError(ValidationError):

class UnsupportedContentTypeError(ValidationError):
type: str
supported_types: List[str]
supported_types: list[str]

def __init__(self, *, message: str, type: str, supported_types: List[str]):
def __init__(self, *, message: str, type: str, supported_types: list[str]):
self.type = type
self.supported_types = supported_types
super().__init__(message)


class DialResource(ABC, BaseModel):
entity_name: str | None = None
supported_types: List[str] | None = None
supported_types: list[str] | None = None

@abstractmethod
async def download(self, storage: FileStorage | None) -> Resource: ...
Expand Down
2 changes: 1 addition & 1 deletion aidial_adapter_openai/dial_api/sdk_adapter.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from typing import Callable, Coroutine
from collections.abc import Callable, Coroutine

import fastapi
from aidial_sdk.chat_completion import Request as DIALRequest
Expand Down
8 changes: 4 additions & 4 deletions aidial_adapter_openai/dial_api/storage.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import base64
import hashlib
import mimetypes
from typing import Mapping, Optional
from collections.abc import Mapping
from urllib.parse import unquote, urljoin

from pydantic import BaseModel, SecretStr
Expand All @@ -28,7 +28,7 @@ class FileStorage(BaseModel):
dial_url: str
api_key: SecretStr

bucket: Optional[Bucket] = None
bucket: Bucket | None = None

@property
def headers(self) -> Mapping[str, str]:
Expand Down Expand Up @@ -129,14 +129,14 @@ def _compute_hash_digest(file_content: str | bytes) -> str:

DIAL_USE_FILE_STORAGE = get_env_bool("DIAL_USE_FILE_STORAGE", False)

DIAL_URL: Optional[str] = None
DIAL_URL: str | None = None
if DIAL_USE_FILE_STORAGE:
DIAL_URL = get_env(
"DIAL_URL", "DIAL_URL must be set to use the DIAL file storage"
)


def create_file_storage(headers: Mapping[str, str]) -> Optional[FileStorage]:
def create_file_storage(headers: Mapping[str, str]) -> FileStorage | None:
if not DIAL_USE_FILE_STORAGE or DIAL_URL is None:
return None

Expand Down
Loading
Loading