Merge pull request #484 from pipecat-ai/mb/llm-input-params
Add input params for OpenAI, Anthropic, Together AI LLMs
This commit is contained in:
@@ -13,6 +13,7 @@ from dataclasses import dataclass
|
||||
from PIL import Image
|
||||
from asyncio import CancelledError
|
||||
import re
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from pipecat.frames.frames import (
|
||||
Frame,
|
||||
@@ -74,20 +75,28 @@ class AnthropicContextAggregatorPair:
|
||||
class AnthropicLLMService(LLMService):
|
||||
"""This class implements inference with Anthropic's AI models
|
||||
"""
|
||||
class InputParams(BaseModel):
|
||||
enable_prompt_caching_beta: Optional[bool] = False
|
||||
max_tokens: Optional[int] = Field(default_factory=lambda: 4096, ge=1)
|
||||
temperature: Optional[float] = Field(default_factory=lambda: NOT_GIVEN, ge=0.0, le=1.0)
|
||||
top_k: Optional[int] = Field(default_factory=lambda: NOT_GIVEN, ge=0)
|
||||
top_p: Optional[float] = Field(default_factory=lambda: NOT_GIVEN, ge=0.0, le=1.0)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
api_key: str,
|
||||
model: str = "claude-3-5-sonnet-20240620",
|
||||
max_tokens: int = 4096,
|
||||
enable_prompt_caching_beta: bool = False,
|
||||
params: InputParams = InputParams(),
|
||||
**kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self._client = AsyncAnthropic(api_key=api_key)
|
||||
self.set_model_name(model)
|
||||
self._max_tokens = max_tokens
|
||||
self._enable_prompt_caching_beta = enable_prompt_caching_beta
|
||||
self._max_tokens = params.max_tokens
|
||||
self._enable_prompt_caching_beta: bool = params.enable_prompt_caching_beta or False
|
||||
self._temperature = params.temperature
|
||||
self._top_k = params.top_k
|
||||
self._top_p = params.top_p
|
||||
|
||||
def can_generate_metrics(self) -> bool:
|
||||
return True
|
||||
@@ -105,6 +114,26 @@ class AnthropicLLMService(LLMService):
|
||||
_assistant=assistant
|
||||
)
|
||||
|
||||
async def set_enable_prompt_caching_beta(self, enable_prompt_caching_beta: bool):
|
||||
logger.debug(f"Switching LLM enable_prompt_caching_beta to: [{enable_prompt_caching_beta}]")
|
||||
self._enable_prompt_caching_beta = enable_prompt_caching_beta
|
||||
|
||||
async def set_max_tokens(self, max_tokens: int):
|
||||
logger.debug(f"Switching LLM max_tokens to: [{max_tokens}]")
|
||||
self._max_tokens = max_tokens
|
||||
|
||||
async def set_temperature(self, temperature: float):
|
||||
logger.debug(f"Switching LLM temperature to: [{temperature}]")
|
||||
self._temperature = temperature
|
||||
|
||||
async def set_top_k(self, top_k: float):
|
||||
logger.debug(f"Switching LLM top_k to: [{top_k}]")
|
||||
self._top_k = top_k
|
||||
|
||||
async def set_top_p(self, top_p: float):
|
||||
logger.debug(f"Switching LLM top_p to: [{top_p}]")
|
||||
self._top_p = top_p
|
||||
|
||||
async def _process_context(self, context: OpenAILLMContext):
|
||||
# Usage tracking. We track the usage reported by Anthropic in prompt_tokens and
|
||||
# completion_tokens. We also estimate the completion tokens from output text
|
||||
@@ -140,7 +169,10 @@ class AnthropicLLMService(LLMService):
|
||||
messages=messages,
|
||||
model=self.model_name,
|
||||
max_tokens=self._max_tokens,
|
||||
stream=True)
|
||||
stream=True,
|
||||
temperature=self._temperature,
|
||||
top_k=self._top_k,
|
||||
top_p=self._top_p)
|
||||
|
||||
await self.stop_ttfb_metrics()
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@ import json
|
||||
import httpx
|
||||
from dataclasses import dataclass
|
||||
|
||||
from typing import AsyncGenerator, Dict, List, Literal
|
||||
from typing import AsyncGenerator, Dict, List, Literal, Optional
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from loguru import logger
|
||||
from PIL import Image
|
||||
@@ -48,7 +49,7 @@ from pipecat.services.ai_services import (
|
||||
)
|
||||
|
||||
try:
|
||||
from openai import AsyncOpenAI, AsyncStream, DefaultAsyncHttpxClient, BadRequestError
|
||||
from openai import AsyncOpenAI, AsyncStream, DefaultAsyncHttpxClient, BadRequestError, NOT_GIVEN
|
||||
from openai.types.chat import ChatCompletionChunk, ChatCompletionMessageParam
|
||||
except ModuleNotFoundError as e:
|
||||
logger.error(f"Exception: {e}")
|
||||
@@ -81,11 +82,31 @@ class BaseOpenAILLMService(LLMService):
|
||||
as well as tool choices and the tool, which is used if requesting function
|
||||
calls from the LLM.
|
||||
"""
|
||||
class InputParams(BaseModel):
|
||||
frequency_penalty: Optional[float] = Field(
|
||||
default_factory=lambda: NOT_GIVEN, ge=-2.0, le=2.0)
|
||||
presence_penalty: Optional[float] = Field(
|
||||
default_factory=lambda: NOT_GIVEN, ge=-2.0, le=2.0)
|
||||
seed: Optional[int] = Field(default_factory=lambda: NOT_GIVEN, ge=0)
|
||||
temperature: Optional[float] = Field(default_factory=lambda: NOT_GIVEN, ge=0.0, le=2.0)
|
||||
top_p: Optional[float] = Field(default_factory=lambda: NOT_GIVEN, ge=0.0, le=1.0)
|
||||
|
||||
def __init__(self, *, model: str, api_key=None, base_url=None, **kwargs):
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
model: str,
|
||||
api_key=None,
|
||||
base_url=None,
|
||||
params: InputParams = InputParams(),
|
||||
**kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.set_model_name(model)
|
||||
self._client = self.create_client(api_key=api_key, base_url=base_url, **kwargs)
|
||||
self._frequency_penalty = params.frequency_penalty
|
||||
self._presence_penalty = params.presence_penalty
|
||||
self._seed = params.seed
|
||||
self._temperature = params.temperature
|
||||
self._top_p = params.top_p
|
||||
|
||||
def create_client(self, api_key=None, base_url=None, **kwargs):
|
||||
return AsyncOpenAI(
|
||||
@@ -100,6 +121,26 @@ class BaseOpenAILLMService(LLMService):
|
||||
def can_generate_metrics(self) -> bool:
|
||||
return True
|
||||
|
||||
async def set_frequency_penalty(self, frequency_penalty: float):
|
||||
logger.debug(f"Switching LLM frequency_penalty to: [{frequency_penalty}]")
|
||||
self._frequency_penalty = frequency_penalty
|
||||
|
||||
async def set_presence_penalty(self, presence_penalty: float):
|
||||
logger.debug(f"Switching LLM presence_penalty to: [{presence_penalty}]")
|
||||
self._presence_penalty = presence_penalty
|
||||
|
||||
async def set_seed(self, seed: int):
|
||||
logger.debug(f"Switching LLM seed to: [{seed}]")
|
||||
self._seed = seed
|
||||
|
||||
async def set_temperature(self, temperature: float):
|
||||
logger.debug(f"Switching LLM temperature to: [{temperature}]")
|
||||
self._temperature = temperature
|
||||
|
||||
async def set_top_p(self, top_p: float):
|
||||
logger.debug(f"Switching LLM top_p to: [{top_p}]")
|
||||
self._top_p = top_p
|
||||
|
||||
async def get_chat_completions(
|
||||
self,
|
||||
context: OpenAILLMContext,
|
||||
@@ -110,7 +151,12 @@ class BaseOpenAILLMService(LLMService):
|
||||
messages=messages,
|
||||
tools=context.tools,
|
||||
tool_choice=context.tool_choice,
|
||||
stream_options={"include_usage": True}
|
||||
stream_options={"include_usage": True},
|
||||
frequency_penalty=self._frequency_penalty,
|
||||
presence_penalty=self._presence_penalty,
|
||||
seed=self._seed,
|
||||
temperature=self._temperature,
|
||||
top_p=self._top_p
|
||||
)
|
||||
return chunks
|
||||
|
||||
@@ -248,8 +294,13 @@ class OpenAIContextAggregatorPair:
|
||||
|
||||
class OpenAILLMService(BaseOpenAILLMService):
|
||||
|
||||
def __init__(self, *, model: str = "gpt-4o", **kwargs):
|
||||
super().__init__(model=model, **kwargs)
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
model: str = "gpt-4o",
|
||||
params: BaseOpenAILLMService.InputParams = BaseOpenAILLMService.InputParams(),
|
||||
**kwargs):
|
||||
super().__init__(model=model, params=params, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def create_context_aggregator(context: OpenAILLMContext) -> OpenAIContextAggregatorPair:
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
import json
|
||||
import re
|
||||
import uuid
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
from typing import List
|
||||
from dataclasses import dataclass
|
||||
@@ -56,18 +57,30 @@ class TogetherContextAggregatorPair:
|
||||
class TogetherLLMService(LLMService):
|
||||
"""This class implements inference with Together's Llama 3.1 models
|
||||
"""
|
||||
class InputParams(BaseModel):
|
||||
frequency_penalty: Optional[float] = Field(default=None, ge=-2.0, le=2.0)
|
||||
max_tokens: Optional[int] = Field(default=4096, ge=1)
|
||||
presence_penalty: Optional[float] = Field(default=None, ge=-2.0, le=2.0)
|
||||
temperature: Optional[float] = Field(default=None, ge=0.0, le=1.0)
|
||||
top_k: Optional[int] = Field(default=None, ge=0)
|
||||
top_p: Optional[float] = Field(default=None, ge=0.0, le=1.0)
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
api_key: str,
|
||||
model: str = "meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo",
|
||||
max_tokens: int = 4096,
|
||||
params: InputParams = InputParams(),
|
||||
**kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self._client = AsyncTogether(api_key=api_key)
|
||||
self.set_model_name(model)
|
||||
self._max_tokens = max_tokens
|
||||
self._max_tokens = params.max_tokens
|
||||
self._frequency_penalty = params.frequency_penalty
|
||||
self._presence_penalty = params.presence_penalty
|
||||
self._temperature = params.temperature
|
||||
self._top_k = params.top_k
|
||||
self._top_p = params.top_p
|
||||
|
||||
def can_generate_metrics(self) -> bool:
|
||||
return True
|
||||
@@ -81,6 +94,30 @@ class TogetherLLMService(LLMService):
|
||||
_assistant=assistant
|
||||
)
|
||||
|
||||
async def set_frequency_penalty(self, frequency_penalty: float):
|
||||
logger.debug(f"Switching LLM frequency_penalty to: [{frequency_penalty}]")
|
||||
self._frequency_penalty = frequency_penalty
|
||||
|
||||
async def set_max_tokens(self, max_tokens: int):
|
||||
logger.debug(f"Switching LLM max_tokens to: [{max_tokens}]")
|
||||
self._max_tokens = max_tokens
|
||||
|
||||
async def set_presence_penalty(self, presence_penalty: float):
|
||||
logger.debug(f"Switching LLM presence_penalty to: [{presence_penalty}]")
|
||||
self._presence_penalty = presence_penalty
|
||||
|
||||
async def set_temperature(self, temperature: float):
|
||||
logger.debug(f"Switching LLM temperature to: [{temperature}]")
|
||||
self._temperature = temperature
|
||||
|
||||
async def set_top_k(self, top_k: float):
|
||||
logger.debug(f"Switching LLM top_k to: [{top_k}]")
|
||||
self._top_k = top_k
|
||||
|
||||
async def set_top_p(self, top_p: float):
|
||||
logger.debug(f"Switching LLM top_p to: [{top_p}]")
|
||||
self._top_p = top_p
|
||||
|
||||
async def _process_context(self, context: OpenAILLMContext):
|
||||
try:
|
||||
await self.push_frame(LLMFullResponseStartFrame())
|
||||
@@ -95,6 +132,11 @@ class TogetherLLMService(LLMService):
|
||||
model=self.model_name,
|
||||
max_tokens=self._max_tokens,
|
||||
stream=True,
|
||||
frequency_penalty=self._frequency_penalty,
|
||||
presence_penalty=self._presence_penalty,
|
||||
temperature=self._temperature,
|
||||
top_k=self._top_k,
|
||||
top_p=self._top_p
|
||||
)
|
||||
|
||||
# Function calling
|
||||
|
||||
Reference in New Issue
Block a user