Skip to content

Commit

Permalink
ws
Browse files Browse the repository at this point in the history
  • Loading branch information
chyroc committed Jan 8, 2025
1 parent b6d5261 commit 8f43394
Show file tree
Hide file tree
Showing 22 changed files with 1,411 additions and 78 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ dist/
.env_private
scripts/
.cache/
output.wav
4 changes: 2 additions & 2 deletions cozepy/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from .audio.rooms import CreateRoomResp
from .audio.speech import AudioFormat
from .audio.translations import CreateTranslationResp
from .audio.transcriptions import CreateTranslationResp
from .audio.voices import Voice
from .auth import (
AsyncDeviceOAuthApp,
Expand Down Expand Up @@ -110,7 +110,7 @@
# audio.voices
"Voice",
"AudioFormat",
# audio.translations
# audio.transcriptions
"CreateTranslationResp",
# auth
"AsyncDeviceOAuthApp",
Expand Down
28 changes: 15 additions & 13 deletions cozepy/audio/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
if TYPE_CHECKING:
from .rooms import AsyncRoomsClient, RoomsClient
from .speech import AsyncSpeechClient, SpeechClient
from .translations import AsyncTranslationsClient, TranslationsClient
from .transcriptions import AsyncTranscriptionsClient, TranscriptionsClient
from .voices import AsyncVoicesClient, VoicesClient


Expand All @@ -20,7 +20,7 @@ def __init__(self, base_url: str, auth: Auth, requester: Requester):
self._rooms: Optional[RoomsClient] = None
self._voices: Optional[VoicesClient] = None
self._speech: Optional[SpeechClient] = None
self._translations: Optional[TranslationsClient] = None
self._transcriptions: Optional[TranscriptionsClient] = None

@property
def rooms(self) -> "RoomsClient":
Expand All @@ -39,12 +39,14 @@ def speech(self) -> "SpeechClient":
return self._speech

@property
def translations(self) -> "TranslationsClient":
if self._translations is None:
from .translations import TranslationsClient
def transcriptions(self) -> "TranscriptionsClient":
if self._transcriptions is None:
from .transcriptions import TranscriptionsClient

self._translations = TranslationsClient(base_url=self._base_url, auth=self._auth, requester=self._requester)
return self._translations
self._transcriptions = TranscriptionsClient(
base_url=self._base_url, auth=self._auth, requester=self._requester
)
return self._transcriptions

@property
def voices(self) -> "VoicesClient":
Expand All @@ -64,7 +66,7 @@ def __init__(self, base_url: str, auth: Auth, requester: Requester):
self._rooms: Optional[AsyncRoomsClient] = None
self._voices: Optional[AsyncVoicesClient] = None
self._speech: Optional[AsyncSpeechClient] = None
self._translations: Optional[AsyncTranslationsClient] = None
self._transcriptions: Optional[AsyncTranscriptionsClient] = None

@property
def rooms(self) -> "AsyncRoomsClient":
Expand All @@ -91,11 +93,11 @@ def voices(self) -> "AsyncVoicesClient":
return self._voices

@property
def translations(self) -> "AsyncTranslationsClient":
if self._translations is None:
from .translations import AsyncTranslationsClient
def transcriptions(self) -> "AsyncTranscriptionsClient":
if self._transcriptions is None:
from .transcriptions import AsyncTranscriptionsClient

self._translations = AsyncTranslationsClient(
self._transcriptions = AsyncTranscriptionsClient(
base_url=self._base_url, auth=self._auth, requester=self._requester
)
return self._translations
return self._transcriptions
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class CreateTranslationResp(CozeModel):
text: str


class TranslationsClient(object):
class TranscriptionsClient(object):
def __init__(self, base_url: str, auth: Auth, requester: Requester):
self._base_url = remove_url_trailing_slash(base_url)
self._auth = auth
Expand All @@ -30,15 +30,15 @@ def create(
:param file: The file to be translated.
:return: create translation result
"""
url = f"{self._base_url}/v1/audio/translations"
url = f"{self._base_url}/v1/audio/transcriptions"
headers: Optional[dict] = kwargs.get("headers")
files = {"file": _try_fix_file(file)}
return self._requester.request(
"post", url, stream=False, cast=CreateTranslationResp, headers=headers, files=files
)


class AsyncTranslationsClient(object):
class AsyncTranscriptionsClient(object):
"""
Room service async client.
"""
Expand All @@ -60,7 +60,7 @@ async def create(
:param file: The file to be translated.
:return: create translation result
"""
url = f"{self._base_url}/v1/audio/translations"
url = f"{self._base_url}/v1/audio/transcriptions"
files = {"file": _try_fix_file(file)}
headers: Optional[dict] = kwargs.get("headers")
return await self._requester.arequest(
Expand Down
8 changes: 3 additions & 5 deletions cozepy/audio/voices/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,11 +210,7 @@ async def clone(
return await self._requester.arequest("post", url, False, Voice, headers=headers, body=body, files=files)

async def list(
self,
*,
filter_system_voice: bool = False,
page_num: int = 1,
page_size: int = 100,
self, *, filter_system_voice: bool = False, page_num: int = 1, page_size: int = 100, **kwargs
) -> AsyncNumberPaged[Voice]:
"""
Get available voices, including system voices + user cloned voices
Expand All @@ -227,6 +223,7 @@ async def list(
:return: list of Voice
"""
url = f"{self._base_url}/v1/audio/voices"
headers: Optional[dict] = kwargs.get("headers")

def request_maker(i_page_num: int, i_page_size: int) -> HTTPRequest:
return self._requester.make_request(
Expand All @@ -237,6 +234,7 @@ def request_maker(i_page_num: int, i_page_size: int) -> HTTPRequest:
"page_num": i_page_num,
"page_size": i_page_size,
},
headers=headers,
cast=_PrivateListVoiceData,
is_async=False,
stream=False,
Expand Down
24 changes: 16 additions & 8 deletions cozepy/chat/__init__.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import base64
import json
import time
from enum import Enum
Expand All @@ -24,6 +25,8 @@ class MessageRole(str, Enum):


class MessageType(str, Enum):
UNKNOWN = ""

# User input content.
# 用户输入内容。
QUESTION = "question"
Expand Down Expand Up @@ -52,8 +55,6 @@ class MessageType(str, Enum):
# 多 answer 场景下,服务端会返回一个 verbose 包,对应的 content 为 JSON 格式,content.msg_type =generate_answer_finish 代表全部 answer 回复完成。不支持在请求中作为入参。
VERBOSE = "verbose"

UNKNOWN = ""


class MessageContentType(str, Enum):
# Text.
Expand Down Expand Up @@ -187,12 +188,19 @@ def build_assistant_answer(content: str, meta_data: Optional[Dict[str, str]] = N
meta_data=meta_data,
)

def get_audio(self) -> Optional[bytes]:
if self.content_type == MessageContentType.AUDIO:
return base64.b64decode(self.content)
return None


class ChatStatus(str, Enum):
"""
The running status of the session
"""

UNKNOWN = ""

# The session has been created.
CREATED = "created"

Expand All @@ -214,9 +222,9 @@ class ChatStatus(str, Enum):

class ChatError(CozeModel):
# The error code. An integer type. 0 indicates success, other values indicate failure.
code: int
code: int = 0
# The error message. A string type.
msg: str
msg: str = ""


class ChatRequiredActionType(str, Enum):
Expand Down Expand Up @@ -266,13 +274,13 @@ class ChatRequiredAction(CozeModel):
class ChatUsage(CozeModel):
# The total number of Tokens consumed in this chat, including the consumption for both the input
# and output parts.
token_count: int
token_count: int = 0

# The total number of Tokens consumed for the output part.
output_count: int
output_count: int = 0

# The total number of Tokens consumed for the input part.
input_count: int
input_count: int = 0


class Chat(CozeModel):
Expand Down Expand Up @@ -301,7 +309,7 @@ class Chat(CozeModel):
# completed: The Bot has finished processing, and the session has ended.
# failed: The session has failed.
# requires_action: The session is interrupted and requires further processing.
status: ChatStatus
status: ChatStatus = ChatStatus.UNKNOWN

# Details of the information needed for execution.
required_action: Optional[ChatRequiredAction] = None
Expand Down
10 changes: 10 additions & 0 deletions cozepy/coze.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from .files import AsyncFilesClient, FilesClient
from .knowledge import AsyncKnowledgeClient, KnowledgeClient # deprecated
from .templates import AsyncTemplatesClient, TemplatesClient
from .websockets import AsyncWebsocketsClient
from .workflows import AsyncWorkflowsClient, WorkflowsClient
from .workspaces import AsyncWorkspacesClient, WorkspacesClient

Expand Down Expand Up @@ -151,6 +152,7 @@ def __init__(
self._workspaces: Optional[AsyncWorkspacesClient] = None
self._audio: Optional[AsyncAudioClient] = None
self._templates: Optional[AsyncTemplatesClient] = None
self._websockets: Optional[AsyncWebsocketsClient] = None

@property
def bots(self) -> "AsyncBotsClient":
Expand Down Expand Up @@ -237,3 +239,11 @@ def templates(self) -> "AsyncTemplatesClient":

self._templates = AsyncTemplatesClient(self._base_url, self._auth, self._requester)
return self._templates

@property
def websockets(self) -> "AsyncWebsocketsClient":
if not self._websockets:
from .websockets import AsyncWebsocketsClient

self._websockets = AsyncWebsocketsClient(self._base_url, self._auth, self._requester)
return self._websockets
14 changes: 13 additions & 1 deletion cozepy/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ def remove_url_trailing_slash(base_url: str) -> str:
return base_url


def http_base_url_to_ws(base_url: str) -> str:
if not base_url:
raise ValueError("base_url cannot be empty")
if not base_url.startswith("https://"):
raise ValueError("base_url must start with 'https://'")
base_url = base_url.replace("https://", "wss://")

if "api-" in base_url:
return base_url.replace("api-", "ws-")
return base_url.replace("api.", "ws.")


def remove_none_values(d: dict) -> dict:
return {k: v for k, v in d.items() if v is not None}

Expand All @@ -55,7 +67,7 @@ def write_pcm_to_wav_file(
Save PCM binary data to WAV file
:param pcm_data: PCM binary data (24kHz, 16-bit, 1 channel, little-endian)
:param output_filename: Output WAV filename
:param filepath: Output WAV filename
"""

with wave.open(filepath, "wb") as wav_file:
Expand Down
29 changes: 29 additions & 0 deletions cozepy/websockets/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
from cozepy import Auth
from cozepy.request import Requester
from cozepy.util import http_base_url_to_ws, remove_url_trailing_slash

from .audio import AsyncWebsocketsAudioClient
from .chat import AsyncWebsocketsChatClient


class AsyncWebsocketsClient(object):
def __init__(self, base_url: str, auth: Auth, requester: Requester):
self._base_url = http_base_url_to_ws(remove_url_trailing_slash(base_url))
self._auth = auth
self._requester = requester

@property
def audio(self) -> AsyncWebsocketsAudioClient:
return AsyncWebsocketsAudioClient(
base_url=self._base_url,
auth=self._auth,
requester=self._requester,
)

@property
def chat(self) -> AsyncWebsocketsChatClient:
return AsyncWebsocketsChatClient(
base_url=self._base_url,
auth=self._auth,
requester=self._requester,
)
28 changes: 28 additions & 0 deletions cozepy/websockets/audio/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
from cozepy.auth import Auth
from cozepy.request import Requester

from .speech import AsyncWebsocketsAudioSpeechClient
from .transcriptions import AsyncWebsocketsAudioTranscriptionsClient


class AsyncWebsocketsAudioClient(object):
def __init__(self, base_url: str, auth: Auth, requester: Requester):
self._base_url = base_url
self._auth = auth
self._requester = requester

@property
def transcriptions(self) -> "AsyncWebsocketsAudioTranscriptionsClient":
return AsyncWebsocketsAudioTranscriptionsClient(
base_url=self._base_url,
auth=self._auth,
requester=self._requester,
)

@property
def speech(self) -> "AsyncWebsocketsAudioSpeechClient":
return AsyncWebsocketsAudioSpeechClient(
base_url=self._base_url,
auth=self._auth,
requester=self._requester,
)
Loading

0 comments on commit 8f43394

Please sign in to comment.