Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@

import httpx

from celeste.client import APIMixin
from celeste.core import UsageField
from celeste.io import FinishReason
from celeste.mime_types import ApplicationMimeType

from . import config


class AnthropicMessagesClient:
class AnthropicMessagesClient(APIMixin):
"""Mixin for Anthropic Messages API capabilities.

Provides shared implementation for all capabilities using the Messages API:
Expand All @@ -39,8 +40,8 @@ def _build_request(
**parameters: Any,
) -> Any:
"""Build request with Anthropic-specific defaults."""
request = super()._build_request(inputs, **parameters) # type: ignore[misc]
request["model"] = self.model.id # type: ignore[attr-defined]
request = super()._build_request(inputs, **parameters)
request["model"] = self.model.id

# Apply max_tokens default if not set (Anthropic requires it)
if "max_tokens" not in request:
Expand All @@ -53,7 +54,7 @@ def _build_headers(self, request_body: dict[str, Any]) -> dict[str, str]:
beta_features: list[str] = request_body.pop("_beta_features", [])

headers: dict[str, str] = {
**self.auth.get_headers(), # type: ignore[attr-defined]
**self.auth.get_headers(),
config.HEADER_ANTHROPIC_VERSION: config.ANTHROPIC_VERSION,
"Content-Type": ApplicationMimeType.JSON,
}
Expand All @@ -75,7 +76,7 @@ async def _make_request(
"""Make HTTP request to Anthropic Messages API endpoint."""
headers = self._build_headers(request_body)

return await self.http_client.post( # type: ignore[attr-defined,no-any-return]
return await self.http_client.post(
f"{config.BASE_URL}{config.AnthropicMessagesEndpoint.CREATE_MESSAGE}",
headers=headers,
json_body=request_body,
Expand All @@ -90,7 +91,7 @@ def _make_stream_request(
request_body["stream"] = True
headers = self._build_headers(request_body)

return self.http_client.stream_post( # type: ignore[attr-defined,no-any-return]
return self.http_client.stream_post(
f"{config.BASE_URL}{config.AnthropicMessagesEndpoint.CREATE_MESSAGE}",
headers=headers,
json_body=request_body,
Expand Down Expand Up @@ -147,7 +148,7 @@ def _build_metadata(self, response_data: dict[str, Any]) -> dict[str, Any]:
filtered_data = {
k: v for k, v in response_data.items() if k not in content_fields
}
return super()._build_metadata(filtered_data) # type: ignore[misc,no-any-return]
return super()._build_metadata(filtered_data)


__all__ = ["AnthropicMessagesClient"]
19 changes: 10 additions & 9 deletions packages/providers/bfl/src/celeste_bfl/images/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@

import httpx

from celeste.client import APIMixin
from celeste.core import UsageField
from celeste.io import FinishReason
from celeste.mime_types import ApplicationMimeType

from . import config


class BFLImagesClient:
class BFLImagesClient(APIMixin):
"""Mixin for BFL Images API operations.

Provides shared implementation:
Expand Down Expand Up @@ -44,30 +45,30 @@ async def _make_request(
2. Poll polling_url until Ready/Failed
3. Return response with _submit_metadata for usage parsing
"""
auth_headers = self.auth.get_headers() # type: ignore[attr-defined]
auth_headers = self.auth.get_headers()
headers = {
**auth_headers,
"Content-Type": ApplicationMimeType.JSON,
"Accept": ApplicationMimeType.JSON,
}

endpoint = config.BFLImagesEndpoint.CREATE_IMAGE.format(model_id=self.model.id) # type: ignore[attr-defined]
endpoint = config.BFLImagesEndpoint.CREATE_IMAGE.format(model_id=self.model.id)

# Phase 1: Submit job
submit_response = await self.http_client.post( # type: ignore[attr-defined]
submit_response = await self.http_client.post(
f"{config.BASE_URL}{endpoint}",
headers=headers,
json_body=request_body,
)

if submit_response.status_code != 200:
return submit_response # type: ignore[no-any-return]
return submit_response

submit_data = submit_response.json()
polling_url = submit_data.get("polling_url")

if not polling_url:
msg = f"No polling_url in {self.provider} response" # type: ignore[attr-defined]
msg = f"No polling_url in {self.provider} response"
raise ValueError(msg)

# Phase 2: Poll for completion
Expand All @@ -80,16 +81,16 @@ async def _make_request(
while True:
elapsed = time.monotonic() - start_time
if elapsed >= config.POLLING_TIMEOUT:
msg = f"{self.provider} polling timed out after {config.POLLING_TIMEOUT} seconds" # type: ignore[attr-defined]
msg = f"{self.provider} polling timed out after {config.POLLING_TIMEOUT} seconds"
raise TimeoutError(msg)

poll_response = await self.http_client.get( # type: ignore[attr-defined]
poll_response = await self.http_client.get(
polling_url,
headers=poll_headers,
)

if poll_response.status_code != 200:
return poll_response # type: ignore[no-any-return]
return poll_response

poll_data = poll_response.json()
status = poll_data.get("status")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@

import httpx

from celeste.client import APIMixin
from celeste.core import UsageField
from celeste.io import FinishReason
from celeste.mime_types import ApplicationMimeType

from . import config


class BytePlusImagesClient:
class BytePlusImagesClient(APIMixin):
"""Mixin for BytePlus Images API capabilities.

Provides shared implementation for all capabilities using the Images API:
Expand All @@ -39,11 +40,11 @@ async def _make_request(
request_body["stream"] = False

headers = {
**self.auth.get_headers(), # type: ignore[attr-defined]
**self.auth.get_headers(),
"Content-Type": ApplicationMimeType.JSON,
}

return await self.http_client.post( # type: ignore[attr-defined,no-any-return]
return await self.http_client.post(
f"{config.BASE_URL}{config.BytePlusImagesEndpoint.CREATE_IMAGE}",
headers=headers,
json_body=request_body,
Expand All @@ -58,11 +59,11 @@ def _make_stream_request(
request_body["stream"] = True

headers = {
**self.auth.get_headers(), # type: ignore[attr-defined]
**self.auth.get_headers(),
"Content-Type": ApplicationMimeType.JSON,
}

return self.http_client.stream_post( # type: ignore[attr-defined,no-any-return]
return self.http_client.stream_post(
f"{config.BASE_URL}{config.BytePlusImagesEndpoint.CREATE_IMAGE}",
headers=headers,
json_body=request_body,
Expand Down Expand Up @@ -114,7 +115,7 @@ def _build_metadata(self, response_data: dict[str, Any]) -> Any:
filtered_data = {
k: v for k, v in response_data.items() if k not in content_fields
}
metadata = super()._build_metadata(filtered_data) # type: ignore[misc]
metadata = super()._build_metadata(filtered_data)

# Add provider-specific parsed fields
seed = response_data.get("seed")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import httpx

from celeste.client import APIMixin
from celeste.core import UsageField
from celeste.io import FinishReason
from celeste.mime_types import ApplicationMimeType
Expand All @@ -16,7 +17,7 @@
logger = logging.getLogger(__name__)


class BytePlusVideosClient:
class BytePlusVideosClient(APIMixin):
"""Mixin for BytePlus ModelArk Videos API with async polling.

Provides shared implementation:
Expand Down Expand Up @@ -46,22 +47,22 @@ async def _make_request(
2. Poll CONTENT_STATUS endpoint until succeeded/failed/canceled
3. Return response with final status data
"""
auth_headers = self.auth.get_headers() # type: ignore[attr-defined]
auth_headers = self.auth.get_headers()
headers = {
**auth_headers,
"Content-Type": ApplicationMimeType.JSON,
}

# Phase 1: Submit job
logger.debug("Submitting video generation task to BytePlus")
submit_response = await self.http_client.post( # type: ignore[attr-defined]
submit_response = await self.http_client.post(
f"{config.BASE_URL}{config.BytePlusVideosEndpoint.CREATE_VIDEO}",
headers=headers,
json_body=request_body,
)

if submit_response.status_code != 200:
return submit_response # type: ignore[no-any-return]
return submit_response

submit_data = submit_response.json()
task_id = submit_data["id"]
Expand All @@ -82,13 +83,13 @@ async def _make_request(
status_url = f"{config.BASE_URL}{config.BytePlusVideosEndpoint.GET_VIDEO_STATUS.format(task_id=task_id)}"
logger.debug(f"Polling BytePlus task status: {task_id}")

status_response = await self.http_client.get( # type: ignore[attr-defined]
status_response = await self.http_client.get(
status_url,
headers=headers,
)

if status_response.status_code != 200:
return status_response # type: ignore[no-any-return]
return status_response

status_data = status_response.json()
status = status_data.get("status")
Expand Down
17 changes: 9 additions & 8 deletions packages/providers/cohere/src/celeste_cohere/chat/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@

import httpx

from celeste.client import APIMixin
from celeste.core import UsageField
from celeste.io import FinishReason
from celeste.mime_types import ApplicationMimeType

from . import config


class CohereChatClient:
class CohereChatClient(APIMixin):
"""Mixin for Cohere Chat API capabilities.

Provides shared implementation for all capabilities using the Chat API:
Expand All @@ -37,14 +38,14 @@ async def _make_request(
**parameters: Any,
) -> httpx.Response:
"""Make HTTP request to Cohere Chat API endpoint."""
request_body["model"] = self.model.id # type: ignore[attr-defined]
request_body["model"] = self.model.id

headers = {
**self.auth.get_headers(), # type: ignore[attr-defined]
**self.auth.get_headers(),
"Content-Type": ApplicationMimeType.JSON,
}

return await self.http_client.post( # type: ignore[attr-defined,no-any-return]
return await self.http_client.post(
f"{config.BASE_URL}{config.CohereChatEndpoint.CREATE_CHAT}",
headers=headers,
json_body=request_body,
Expand All @@ -56,15 +57,15 @@ def _make_stream_request(
**parameters: Any,
) -> AsyncIterator[dict[str, Any]]:
"""Make streaming request to Cohere Chat API endpoint."""
request_body["model"] = self.model.id # type: ignore[attr-defined]
request_body["model"] = self.model.id
request_body["stream"] = True

headers = {
**self.auth.get_headers(), # type: ignore[attr-defined]
**self.auth.get_headers(),
"Content-Type": ApplicationMimeType.JSON,
}

return self.http_client.stream_post( # type: ignore[attr-defined,no-any-return]
return self.http_client.stream_post(
f"{config.BASE_URL}{config.CohereChatEndpoint.CREATE_CHAT}",
headers=headers,
json_body=request_body,
Expand Down Expand Up @@ -113,7 +114,7 @@ def _build_metadata(self, response_data: dict[str, Any]) -> dict[str, Any]:
filtered_data = {
k: v for k, v in response_data.items() if k not in content_fields
}
return super()._build_metadata(filtered_data) # type: ignore[misc,no-any-return]
return super()._build_metadata(filtered_data)


__all__ = ["CohereChatClient"]
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@

import httpx

from celeste.client import APIMixin
from celeste.mime_types import ApplicationMimeType, AudioMimeType

from . import config


class ElevenLabsTextToSpeechClient:
class ElevenLabsTextToSpeechClient(APIMixin):
"""Mixin for ElevenLabs Text-to-Speech API.

Provides shared implementation for speech generation:
Expand Down Expand Up @@ -44,19 +45,19 @@ async def _make_request(
voice_id = parameters.get("voice", config.DEFAULT_VOICE_ID)

# Set model_id
request_body["model_id"] = self.model.id # type: ignore[attr-defined]
request_body["model_id"] = self.model.id

# Build URL with voice_id in path
endpoint = config.ElevenLabsTextToSpeechEndpoint.CREATE_SPEECH.format(
voice_id=voice_id
)

headers = {
**self.auth.get_headers(), # type: ignore[attr-defined]
**self.auth.get_headers(),
"Content-Type": ApplicationMimeType.JSON,
}

return await self.http_client.post( # type: ignore[attr-defined,no-any-return]
return await self.http_client.post(
f"{config.BASE_URL}{endpoint}",
headers=headers,
json_body=request_body,
Expand All @@ -78,15 +79,15 @@ def _make_stream_request(
voice_id = parameters.get("voice", config.DEFAULT_VOICE_ID)

# Set model_id
request_body["model_id"] = self.model.id # type: ignore[attr-defined]
request_body["model_id"] = self.model.id

# Build URL with voice_id in path
endpoint = config.ElevenLabsTextToSpeechEndpoint.STREAM_SPEECH.format(
voice_id=voice_id
)

headers = {
**self.auth.get_headers(), # type: ignore[attr-defined]
**self.auth.get_headers(),
"Content-Type": ApplicationMimeType.JSON,
}

Expand All @@ -106,7 +107,7 @@ async def _stream_binary_audio(

Wraps httpx streaming to yield dicts compatible with Stream interface.
"""
client = await self.http_client._get_client() # type: ignore[attr-defined]
client = await self.http_client._get_client()

async with client.stream(
"POST",
Expand Down
Loading
Loading