diff --git a/README.md b/README.md index d2b8bb4..63c2c67 100644 --- a/README.md +++ b/README.md @@ -210,6 +210,17 @@ The prefix is stripped before sending the request to the API. Similarly, use the `oai-azure:` model name prefix to use a model deployed via Azure Open AI. For example, `oai-azure:my-deployment-name`. +With assistant configuration, you can override the base URL and API key for a specific assistant. + +```yaml +# ~/.config/gpt-cli/gpt.yml +assistants: + llama: + model: oai-compat:meta-llama/llama-3.3-70b-instruct + openai_base_url_override: https://openrouter.ai/api/v1 + openai_api_key_override: $OPENROUTER_API_KEY +``` + ## Other chat bots ### Anthropic Claude diff --git a/gptcli/__init__.py b/gptcli/__init__.py index 260c070..e19434e 100644 --- a/gptcli/__init__.py +++ b/gptcli/__init__.py @@ -1 +1 @@ -__version__ = "0.3.1" +__version__ = "0.3.3" diff --git a/gptcli/assistant.py b/gptcli/assistant.py index e08f3f7..fb37b52 100644 --- a/gptcli/assistant.py +++ b/gptcli/assistant.py @@ -21,6 +21,8 @@ class AssistantConfig(TypedDict, total=False): messages: List[Message] model: str + openai_base_url_override: Optional[str] + openai_api_key_override: Optional[str] temperature: float top_p: float @@ -67,7 +69,11 @@ class AssistantConfig(TypedDict, total=False): } -def get_completion_provider(model: str) -> CompletionProvider: +def get_completion_provider( + model: str, + openai_base_url_override: Optional[str] = None, + openai_api_key_override: Optional[str] = None, +) -> CompletionProvider: if ( model.startswith("gpt") or model.startswith("ft:gpt") @@ -75,7 +81,9 @@ def get_completion_provider(model: str) -> CompletionProvider: or model.startswith("chatgpt") or model.startswith("o1") ): - return OpenAICompletionProvider() + return OpenAICompletionProvider( + openai_base_url_override, openai_api_key_override + ) elif model.startswith("oai-azure:"): return AzureOpenAICompletionProvider() elif model.startswith("claude"): @@ -115,11 +123,15 @@ def init_messages(self) -> List[Message]: def _param(self, param: str) -> Any: # Use the value from the config if exists # Otherwise, use the default value - return self.config.get(param, CONFIG_DEFAULTS[param]) + return self.config.get(param, CONFIG_DEFAULTS.get(param, None)) def complete_chat(self, messages, stream: bool = True) -> Iterator[CompletionEvent]: model = self._param("model") - completion_provider = get_completion_provider(model) + completion_provider = get_completion_provider( + model, + self._param("openai_base_url_override"), + self._param("openai_api_key_override"), + ) return completion_provider.complete( messages, { diff --git a/gptcli/providers/openai.py b/gptcli/providers/openai.py index 10717e5..5afbccd 100644 --- a/gptcli/providers/openai.py +++ b/gptcli/providers/openai.py @@ -1,7 +1,7 @@ import re from typing import Iterator, List, Optional, cast import openai -from openai import AzureOpenAI, OpenAI +from openai import OpenAI from openai.types.chat import ChatCompletionMessageParam from gptcli.completion import ( @@ -17,8 +17,10 @@ class OpenAICompletionProvider(CompletionProvider): - def __init__(self): - self.client = OpenAI(api_key=openai.api_key, base_url=openai.base_url) + def __init__(self, base_url: Optional[str] = None, api_key: Optional[str] = None): + self.client = OpenAI( + api_key=api_key or openai.api_key, base_url=base_url or openai.base_url + ) def complete( self, messages: List[Message], args: dict, stream: bool = False @@ -137,6 +139,7 @@ def pricing(self, model: str) -> Optional[Pricing]: "response": 12.0 / 1_000_000, } + def gpt_pricing(model: str) -> Optional[Pricing]: if model.startswith("gpt-3.5-turbo-16k"): return GPT_3_5_TURBO_16K_PRICE_PER_TOKEN diff --git a/pyproject.toml b/pyproject.toml index 41f65ef..ff7c5e2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "gpt-command-line" -version = "0.3.0" +version = "0.3.2" description = "Command-line interface for ChatGPT and Claude" authors = [{name = "Val Kharitonov", email = "val@kharvd.com"}] readme = "README.md" @@ -17,12 +17,12 @@ classifiers = [ "Topic :: Scientific/Engineering :: Artificial Intelligence", ] dependencies = [ - "anthropic~=0.39.0", + "anthropic~=0.44.0", "attrs~=24.2.0", "black~=24.10.0", - "cohere~=5.11.4", - "google-generativeai==0.7.2", - "openai~=1.54.4", + "cohere~=5.13.11", + "google-generativeai~=0.8.4", + "openai~=1.60.0", "prompt-toolkit~=3.0.48", "pytest~=8.3.3", "PyYAML~=6.0.2",