This commit is contained in:
jhpiedrahitao
2025-06-18 10:53:06 -05:00
parent 03a067d3e6
commit fae2d272d5
2 changed files with 48 additions and 36 deletions

View File

@@ -10,6 +10,7 @@ from typing import Any, Dict, List, Optional
from loguru import logger from loguru import logger
from openai import AsyncStream from openai import AsyncStream
from openai.types.chat import ChatCompletionChunk, ChatCompletionMessageParam from openai.types.chat import ChatCompletionChunk, ChatCompletionMessageParam
from pipecat.frames.frames import ( from pipecat.frames.frames import (
LLMTextFrame, LLMTextFrame,
) )
@@ -35,37 +36,42 @@ class SambaNovaLLMService(OpenAILLMService): # type: ignore
self, self,
*, *,
api_key: str, api_key: str,
model: str = 'Llama-4-Maverick-17B-128E-Instruct', model: str = "Llama-4-Maverick-17B-128E-Instruct",
base_url: str = 'https://api.sambanova.ai/v1', base_url: str = "https://api.sambanova.ai/v1",
**kwargs: Dict[Any, Any], **kwargs: Dict[Any, Any],
) -> None: ) -> None:
super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs) super().__init__(api_key=api_key, base_url=base_url, model=model, **kwargs)
def create_client( def create_client(
self, api_key: Optional[str] = None, base_url: Optional[str] = None, **kwargs: Dict[Any, Any] self,
api_key: Optional[str] = None,
base_url: Optional[str] = None,
**kwargs: Dict[Any, Any],
) -> Any: ) -> Any:
"""Create OpenAI-compatible client for SambaNova API endpoint.""" """Create OpenAI-compatible client for SambaNova API endpoint."""
logger.debug(f'Creating SambaNova client with API {base_url}') logger.debug(f"Creating SambaNova client with API {base_url}")
return super().create_client(api_key, base_url, **kwargs) return super().create_client(api_key, base_url, **kwargs)
async def get_chat_completions(self, context: OpenAILLMContext, messages: List[ChatCompletionMessageParam]) -> Any: async def get_chat_completions(
self, context: OpenAILLMContext, messages: List[ChatCompletionMessageParam]
) -> Any:
"""Get chat completions from SambaNova API endpoint.""" """Get chat completions from SambaNova API endpoint."""
params = { params = {
'model': self.model_name, "model": self.model_name,
'stream': True, "stream": True,
'messages': messages, "messages": messages,
'tools': context.tools, "tools": context.tools,
'tool_choice': context.tool_choice, "tool_choice": context.tool_choice,
'stream_options': {'include_usage': True}, "stream_options": {"include_usage": True},
'temperature': self._settings['temperature'], "temperature": self._settings["temperature"],
'top_p': self._settings['top_p'], "top_p": self._settings["top_p"],
'max_tokens': self._settings['max_tokens'], "max_tokens": self._settings["max_tokens"],
'max_completion_tokens': self._settings['max_completion_tokens'], "max_completion_tokens": self._settings["max_completion_tokens"],
} }
params.update(self._settings['extra']) params.update(self._settings["extra"])
chunks = await self._client.chat.completions.create(**params) chunks = await self._client.chat.completions.create(**params)
return chunks return chunks
@@ -78,13 +84,15 @@ class SambaNovaLLMService(OpenAILLMService): # type: ignore
arguments_list = [] arguments_list = []
tool_id_list = [] tool_id_list = []
func_idx = 0 func_idx = 0
function_name = '' function_name = ""
arguments = '' arguments = ""
tool_call_id = '' tool_call_id = ""
await self.start_ttfb_metrics() await self.start_ttfb_metrics()
chunk_stream: AsyncStream[ChatCompletionChunk] = await self._stream_chat_completions(context) chunk_stream: AsyncStream[ChatCompletionChunk] = await self._stream_chat_completions(
context
)
async for chunk in chunk_stream: async for chunk in chunk_stream:
if chunk.usage: if chunk.usage:
@@ -120,9 +128,9 @@ class SambaNovaLLMService(OpenAILLMService): # type: ignore
functions_list.append(function_name) functions_list.append(function_name)
arguments_list.append(arguments) arguments_list.append(arguments)
tool_id_list.append(tool_call_id) tool_id_list.append(tool_call_id)
function_name = '' function_name = ""
arguments = '' arguments = ""
tool_call_id = '' tool_call_id = ""
func_idx += 1 func_idx += 1
if tool_call.function and tool_call.function.name: if tool_call.function and tool_call.function.name:
function_name += tool_call.function.name function_name += tool_call.function.name
@@ -135,8 +143,10 @@ class SambaNovaLLMService(OpenAILLMService): # type: ignore
# When gpt-4o-audio / gpt-4o-mini-audio is used for llm or stt+llm # When gpt-4o-audio / gpt-4o-mini-audio is used for llm or stt+llm
# we need to get LLMTextFrame for the transcript # we need to get LLMTextFrame for the transcript
elif hasattr(chunk.choices[0].delta, 'audio') and chunk.choices[0].delta.audio.get('transcript'): elif hasattr(chunk.choices[0].delta, "audio") and chunk.choices[0].delta.audio.get(
await self.push_frame(LLMTextFrame(chunk.choices[0].delta.audio['transcript'])) "transcript"
):
await self.push_frame(LLMTextFrame(chunk.choices[0].delta.audio["transcript"]))
# if we got a function name and arguments, check to see if it's a function with # if we got a function name and arguments, check to see if it's a function with
# a registered handler. If so, run the registered callback, save the result to # a registered handler. If so, run the registered callback, save the result to
@@ -150,7 +160,9 @@ class SambaNovaLLMService(OpenAILLMService): # type: ignore
function_calls = [] function_calls = []
for function_name, arguments, tool_id in zip(functions_list, arguments_list, tool_id_list): for function_name, arguments, tool_id in zip(
functions_list, arguments_list, tool_id_list
):
# This allows compatibility until SambaNova API introduces indexing in tool calls. # This allows compatibility until SambaNova API introduces indexing in tool calls.
if len(arguments) < 1: if len(arguments) < 1:
continue continue

View File

@@ -27,9 +27,9 @@ class SambaNovaSTTService(BaseWhisperSTTService): # type: ignore
def __init__( def __init__(
self, self,
*, *,
model: str = 'Whisper-Large-v3', model: str = "Whisper-Large-v3",
api_key: Optional[str] = None, api_key: Optional[str] = None,
base_url: str = 'https://api.sambanova.ai/v1', base_url: str = "https://api.sambanova.ai/v1",
language: Optional[Language] = Language.EN, language: Optional[Language] = Language.EN,
prompt: Optional[str] = None, prompt: Optional[str] = None,
temperature: Optional[float] = None, temperature: Optional[float] = None,
@@ -50,16 +50,16 @@ class SambaNovaSTTService(BaseWhisperSTTService): # type: ignore
# Build kwargs dict with only set parameters # Build kwargs dict with only set parameters
kwargs = { kwargs = {
'file': ('audio.wav', audio, 'audio/wav'), "file": ("audio.wav", audio, "audio/wav"),
'model': self.model_name, "model": self.model_name,
'response_format': 'json', "response_format": "json",
'language': self._language, "language": self._language,
} }
if self._prompt is not None: if self._prompt is not None:
kwargs['prompt'] = self._prompt kwargs["prompt"] = self._prompt
if self._temperature is not None: if self._temperature is not None:
kwargs['temperature'] = self._temperature kwargs["temperature"] = self._temperature
return await self._client.audio.transcriptions.create(**kwargs) return await self._client.audio.transcriptions.create(**kwargs)