barunsaha commited on
Commit
a101741
·
1 Parent(s): f97d68c

Add support for new LLMs and update tests

Browse files
README.md CHANGED
@@ -84,19 +84,21 @@ Based on several experiments, SlideDeck AI generally recommends the use of **Mis
84
 
85
  The supported LLMs offer different styles of content generation. Use one of the following LLMs along with relevant API keys/access tokens, as appropriate, to create the content of the slide deck:
86
 
87
- | LLM | Provider (code) | Requires API key | Characteristics |
88
- |:---------------------------------| :------- |:-------------------------------------------------------------------------------------------------------------------------|:-------------------------|
89
- | Gemini 2.0 Flash | Google Gemini API (`gg`) | Mandatory; [get here](https://aistudio.google.com/apikey) | Faster, longer content |
90
- | Gemini 2.0 Flash Lite | Google Gemini API (`gg`) | Mandatory; [get here](https://aistudio.google.com/apikey) | Fastest, longer content |
91
- | Gemini 2.5 Flash | Google Gemini API (`gg`) | Mandatory; [get here](https://aistudio.google.com/apikey) | Faster, longer content |
92
- | Gemini 2.5 Flash Lite | Google Gemini API (`gg`) | Mandatory; [get here](https://aistudio.google.com/apikey) | Fastest, longer content |
93
- | GPT | Azure OpenAI (`az`) | Mandatory; [get here](https://ai.azure.com/resource/playground) NOTE: You need to have your subscription/billing set up | Faster, longer content |
94
- | Command R+ | Cohere (`co`) | Mandatory; [get here](https://dashboard.cohere.com/api-keys) | Shorter, simpler content |
95
- | Gemini-2.0-flash-001 | OpenRouter (`or`) | Mandatory; [get here](https://openrouter.ai/settings/keys) | Faster, longer content |
96
- | GPT-3.5 Turbo | OpenRouter (`or`) | Mandatory; [get here](https://openrouter.ai/settings/keys) | Faster, longer content |
97
- | DeepSeek V3-0324 | Together AI (`to`) | Mandatory; [get here](https://api.together.ai/settings/api-keys) | Slower, medium-length |
98
- | Llama 3.3 70B Instruct Turbo | Together AI (`to`) | Mandatory; [get here](https://api.together.ai/settings/api-keys) | Slower, detailed |
99
- | Llama 3.1 8B Instruct Turbo 128K | Together AI (`to`) | Mandatory; [get here](https://api.together.ai/settings/api-keys) | Faster, shorter |
 
 
100
 
101
  > **IMPORTANT**: SlideDeck AI does **NOT** store your API keys/tokens or transmit them elsewhere. If you provide your API key, it is only used to invoke the relevant LLM to generate contents. That's it! This is an
102
  Open-Source project, so feel free to audit the code and convince yourself.
 
84
 
85
  The supported LLMs offer different styles of content generation. Use one of the following LLMs along with relevant API keys/access tokens, as appropriate, to create the content of the slide deck:
86
 
87
+ | LLM | Provider (code) | Requires API key | Characteristics |
88
+ |:------------------------------------|:---------------------------------------------------------------------------------------------------------------------------------------------------|:-------------------------------------------------------------------------------------------------------------------------|:-------------------------|
89
+ | Claude Haiku 4.5 | Anthropic (`an`) | Mandatory; [get here](https://platform.claude.com/settings/keys) | Faster, detailed |
90
+ | Gemini 2.0 Flash | Google Gemini API (`gg`) | Mandatory; [get here](https://aistudio.google.com/apikey) | Faster, longer content |
91
+ | Gemini 2.0 Flash Lite | Google Gemini API (`gg`) | Mandatory; [get here](https://aistudio.google.com/apikey) | Fastest, longer content |
92
+ | Gemini 2.5 Flash | Google Gemini API (`gg`) | Mandatory; [get here](https://aistudio.google.com/apikey) | Faster, longer content |
93
+ | Gemini 2.5 Flash Lite | Google Gemini API (`gg`) | Mandatory; [get here](https://aistudio.google.com/apikey) | Fastest, longer content |
94
+ | GPT | Azure OpenAI (`az`) | Mandatory; [get here](https://ai.azure.com/resource/playground) NOTE: You need to have your subscription/billing set up | Faster, longer content |
95
+ | Command R+ | Cohere (`co`) | Mandatory; [get here](https://dashboard.cohere.com/api-keys) | Shorter, simpler content |
96
+ | Gemini-2.0-flash-001 | OpenRouter (`or`) | Mandatory; [get here](https://openrouter.ai/settings/keys) | Faster, longer content |
97
+ | GPT-3.5 Turbo | OpenRouter (`or`) | Mandatory; [get here](https://openrouter.ai/settings/keys) | Faster, longer content |
98
+ | DeepSeek V3-0324 | Together AI (`to`) | Mandatory; [get here](https://api.together.ai/settings/api-keys) | Slower, medium-length |
99
+ | Llama 3.3 70B Instruct Turbo | Together AI (`to`) | Mandatory; [get here](https://api.together.ai/settings/api-keys) | Slower, detailed |
100
+ | Llama 3.1 8B Instruct Turbo 128K | Together AI (`to`) | Mandatory; [get here](https://api.together.ai/settings/api-keys) | Faster, shorter |
101
+ | Llama-3.3-Swallow-70B-Instruct-v0.4 | SambaNova (`sn`) | Mandatory; [get here](https://cloud.sambanova.ai/apis) | Fast, shorter |
102
 
103
  > **IMPORTANT**: SlideDeck AI does **NOT** store your API keys/tokens or transmit them elsewhere. If you provide your API key, it is only used to invoke the relevant LLM to generate contents. That's it! This is an
104
  Open-Source project, so feel free to audit the code and convince yourself.
src/slidedeckai/global_config.py CHANGED
@@ -19,33 +19,52 @@ class GlobalConfig:
19
  """
20
  A data class holding the configurations.
21
  """
22
-
 
23
  PROVIDER_COHERE = 'co'
24
  PROVIDER_GOOGLE_GEMINI = 'gg'
25
- PROVIDER_HUGGING_FACE = 'hf'
26
- PROVIDER_AZURE_OPENAI = 'az'
27
  PROVIDER_OLLAMA = 'ol'
28
  PROVIDER_OPENROUTER = 'or'
29
  PROVIDER_TOGETHER_AI = 'to'
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  VALID_PROVIDERS = {
 
 
31
  PROVIDER_COHERE,
32
  PROVIDER_GOOGLE_GEMINI,
33
- # PROVIDER_HUGGING_FACE,
34
  PROVIDER_OLLAMA,
35
- PROVIDER_TOGETHER_AI,
36
- PROVIDER_AZURE_OPENAI,
37
  PROVIDER_OPENROUTER,
 
 
38
  }
39
  PROVIDER_ENV_KEYS = {
40
- PROVIDER_COHERE: "COHERE_API_KEY",
41
- PROVIDER_GOOGLE_GEMINI: "GOOGLE_API_KEY",
42
- PROVIDER_HUGGING_FACE: "HUGGINGFACEHUB_API_TOKEN",
43
- PROVIDER_AZURE_OPENAI: "AZURE_OPENAI_API_KEY",
44
- PROVIDER_OPENROUTER: "OPENROUTER_API_KEY",
45
- PROVIDER_TOGETHER_AI: "TOGETHER_API_KEY",
 
46
  }
47
  PROVIDER_REGEX = re.compile(r'\[(.*?)\]')
48
  VALID_MODELS = {
 
 
 
 
 
49
  '[az]azure/open-ai': {
50
  'description': 'faster, detailed',
51
  'max_new_tokens': 8192,
@@ -76,16 +95,6 @@ class GlobalConfig:
76
  'max_new_tokens': 8192,
77
  'paid': True,
78
  },
79
- # '[hf]mistralai/Mistral-7B-Instruct-v0.2': {
80
- # 'description': 'faster, shorter',
81
- # 'max_new_tokens': 8192,
82
- # 'paid': False,
83
- # },
84
- # '[hf]mistralai/Mistral-Nemo-Instruct-2407': {
85
- # 'description': 'longer response',
86
- # 'max_new_tokens': 8192,
87
- # 'paid': False,
88
- # },
89
  '[or]google/gemini-2.0-flash-001': {
90
  'description': 'Google Gemini-2.0-flash-001 (via OpenRouter)',
91
  'max_new_tokens': 8192,
@@ -96,6 +105,11 @@ class GlobalConfig:
96
  'max_new_tokens': 4096,
97
  'paid': True,
98
  },
 
 
 
 
 
99
  '[to]deepseek-ai/DeepSeek-V3': {
100
  'description': 'slower, medium',
101
  'max_new_tokens': 8192,
 
19
  """
20
  A data class holding the configurations.
21
  """
22
+ PROVIDER_ANTHROPIC = 'an'
23
+ PROVIDER_AZURE_OPENAI = 'az'
24
  PROVIDER_COHERE = 'co'
25
  PROVIDER_GOOGLE_GEMINI = 'gg'
 
 
26
  PROVIDER_OLLAMA = 'ol'
27
  PROVIDER_OPENROUTER = 'or'
28
  PROVIDER_TOGETHER_AI = 'to'
29
+ PROVIDER_SAMBANOVA = 'sn'
30
+
31
+ LITELLM_PROVIDER_MAPPING = {
32
+ PROVIDER_ANTHROPIC: 'anthropic',
33
+ PROVIDER_GOOGLE_GEMINI: 'gemini',
34
+ PROVIDER_AZURE_OPENAI: 'azure',
35
+ PROVIDER_OPENROUTER: 'openrouter',
36
+ PROVIDER_COHERE: 'cohere',
37
+ PROVIDER_SAMBANOVA: 'sambanova',
38
+ PROVIDER_TOGETHER_AI: 'together_ai',
39
+ PROVIDER_OLLAMA: 'ollama',
40
+ }
41
+
42
  VALID_PROVIDERS = {
43
+ PROVIDER_ANTHROPIC,
44
+ PROVIDER_AZURE_OPENAI,
45
  PROVIDER_COHERE,
46
  PROVIDER_GOOGLE_GEMINI,
 
47
  PROVIDER_OLLAMA,
 
 
48
  PROVIDER_OPENROUTER,
49
+ PROVIDER_SAMBANOVA,
50
+ PROVIDER_TOGETHER_AI,
51
  }
52
  PROVIDER_ENV_KEYS = {
53
+ PROVIDER_ANTHROPIC: 'ANTHROPIC_API_KEY',
54
+ PROVIDER_COHERE: 'COHERE_API_KEY',
55
+ PROVIDER_GOOGLE_GEMINI: 'GOOGLE_API_KEY',
56
+ PROVIDER_AZURE_OPENAI: 'AZURE_OPENAI_API_KEY',
57
+ PROVIDER_OPENROUTER: 'OPENROUTER_API_KEY',
58
+ PROVIDER_SAMBANOVA: 'SAMBANOVA_API_KEY',
59
+ PROVIDER_TOGETHER_AI: 'TOGETHER_API_KEY',
60
  }
61
  PROVIDER_REGEX = re.compile(r'\[(.*?)\]')
62
  VALID_MODELS = {
63
+ '[an]claude-haiku-4-5': {
64
+ 'description': 'faster, detailed',
65
+ 'max_new_tokens': 8192,
66
+ 'paid': True,
67
+ },
68
  '[az]azure/open-ai': {
69
  'description': 'faster, detailed',
70
  'max_new_tokens': 8192,
 
95
  'max_new_tokens': 8192,
96
  'paid': True,
97
  },
 
 
 
 
 
 
 
 
 
 
98
  '[or]google/gemini-2.0-flash-001': {
99
  'description': 'Google Gemini-2.0-flash-001 (via OpenRouter)',
100
  'max_new_tokens': 8192,
 
105
  'max_new_tokens': 4096,
106
  'paid': True,
107
  },
108
+ '[sn]Llama-3.3-Swallow-70B-Instruct-v0.4': {
109
+ 'description': 'fast, shorter',
110
+ 'max_new_tokens': 8192,
111
+ 'paid': True,
112
+ },
113
  '[to]deepseek-ai/DeepSeek-V3': {
114
  'description': 'slower, medium',
115
  'max_new_tokens': 8192,
src/slidedeckai/helpers/llm_helper.py CHANGED
@@ -27,8 +27,8 @@ except ImportError:
27
 
28
  LLM_PROVIDER_MODEL_REGEX = re.compile(r'\[(.*?)\](.*)')
29
  OLLAMA_MODEL_REGEX = re.compile(r'[a-zA-Z0-9._:-]+$')
30
- # 94 characters long, only containing alphanumeric characters, hyphens, and underscores
31
- API_KEY_REGEX = re.compile(r'^[a-zA-Z0-9_-]{6,94}$')
32
 
33
 
34
  logger = logging.getLogger(__name__)
@@ -42,7 +42,6 @@ def get_provider_model(provider_model: str, use_ollama: bool) -> Tuple[str, str]
42
  :param use_ollama: Whether Ollama is used (i.e., running in offline mode).
43
  :return: The provider and the model name; empty strings in case no matching pattern found.
44
  """
45
-
46
  provider_model = provider_model.strip()
47
 
48
  if use_ollama:
@@ -99,7 +98,6 @@ def is_valid_llm_provider_model(
99
  :param azure_api_version: Azure OpenAI API version.
100
  :return: `True` if the settings "look" OK; `False` otherwise.
101
  """
102
-
103
  if not provider or not model or provider not in GlobalConfig.VALID_PROVIDERS:
104
  return False
105
 
@@ -132,16 +130,7 @@ def get_litellm_model_name(provider: str, model: str) -> Optional[str]:
132
  :param model: The model name.
133
  :return: LiteLLM-compatible model name, or None if provider is not supported.
134
  """
135
- provider_prefix_map = {
136
- GlobalConfig.PROVIDER_HUGGING_FACE: 'huggingface',
137
- GlobalConfig.PROVIDER_GOOGLE_GEMINI: 'gemini',
138
- GlobalConfig.PROVIDER_AZURE_OPENAI: 'azure',
139
- GlobalConfig.PROVIDER_OPENROUTER: 'openrouter',
140
- GlobalConfig.PROVIDER_COHERE: 'cohere',
141
- GlobalConfig.PROVIDER_TOGETHER_AI: 'together_ai',
142
- GlobalConfig.PROVIDER_OLLAMA: 'ollama',
143
- }
144
- prefix = provider_prefix_map.get(provider)
145
  if prefix:
146
  return f'{prefix}/{model}'
147
  # LiteLLM always expects a prefix for model names; if not found, return None
@@ -171,7 +160,6 @@ def stream_litellm_completion(
171
  :param azure_api_version: Azure OpenAI API version.
172
  :return: Iterator of response chunks.
173
  """
174
-
175
  if litellm is None:
176
  raise ImportError("LiteLLM is not installed. Please install it with: pip install litellm")
177
 
@@ -251,7 +239,6 @@ def get_litellm_llm(
251
  :param azure_api_version: Azure OpenAI API version.
252
  :return: A LiteLLM-compatible object for streaming; `None` in case of any error.
253
  """
254
-
255
  if litellm is None:
256
  raise ImportError("LiteLLM is not installed. Please install it with: pip install litellm")
257
 
 
27
 
28
  LLM_PROVIDER_MODEL_REGEX = re.compile(r'\[(.*?)\](.*)')
29
  OLLAMA_MODEL_REGEX = re.compile(r'[a-zA-Z0-9._:-]+$')
30
+ # 128 characters long, only containing alphanumeric characters, hyphens, and underscores
31
+ API_KEY_REGEX = re.compile(r'^[a-zA-Z0-9_-]{6,128}$')
32
 
33
 
34
  logger = logging.getLogger(__name__)
 
42
  :param use_ollama: Whether Ollama is used (i.e., running in offline mode).
43
  :return: The provider and the model name; empty strings in case no matching pattern found.
44
  """
 
45
  provider_model = provider_model.strip()
46
 
47
  if use_ollama:
 
98
  :param azure_api_version: Azure OpenAI API version.
99
  :return: `True` if the settings "look" OK; `False` otherwise.
100
  """
 
101
  if not provider or not model or provider not in GlobalConfig.VALID_PROVIDERS:
102
  return False
103
 
 
130
  :param model: The model name.
131
  :return: LiteLLM-compatible model name, or None if provider is not supported.
132
  """
133
+ prefix = GlobalConfig.LITELLM_PROVIDER_MAPPING.get(provider)
 
 
 
 
 
 
 
 
 
134
  if prefix:
135
  return f'{prefix}/{model}'
136
  # LiteLLM always expects a prefix for model names; if not found, return None
 
160
  :param azure_api_version: Azure OpenAI API version.
161
  :return: Iterator of response chunks.
162
  """
 
163
  if litellm is None:
164
  raise ImportError("LiteLLM is not installed. Please install it with: pip install litellm")
165
 
 
239
  :param azure_api_version: Azure OpenAI API version.
240
  :return: A LiteLLM-compatible object for streaming; `None` in case of any error.
241
  """
 
242
  if litellm is None:
243
  raise ImportError("LiteLLM is not installed. Please install it with: pip install litellm")
244
 
tests/unit/test_llm_helper.py CHANGED
@@ -26,7 +26,6 @@ from slidedeckai.global_config import GlobalConfig
26
  ('invalid[]model', False, ('', '')),
27
  ('', False, ('', '')),
28
  ('[invalid]model', False, ('', '')),
29
- ('[hf]mistral', False, ('', '')), # hf is not in VALID_PROVIDERS
30
  ],
31
  )
32
  def test_get_provider_model(provider_model, use_ollama, expected):
@@ -107,7 +106,6 @@ def test_is_valid_llm_provider_model(
107
  @pytest.mark.parametrize(
108
  'provider, model, expected',
109
  [
110
- (GlobalConfig.PROVIDER_HUGGING_FACE, 'mistral', 'huggingface/mistral'),
111
  (GlobalConfig.PROVIDER_GOOGLE_GEMINI, 'gemini-pro', 'gemini/gemini-pro'),
112
  (GlobalConfig.PROVIDER_OPENROUTER, 'openai/gpt-4', 'openrouter/openai/gpt-4'),
113
  (GlobalConfig.PROVIDER_COHERE, 'command', 'cohere/command'),
@@ -139,8 +137,8 @@ def test_stream_litellm_completion_success(mock_litellm):
139
  messages = [{'role': 'user', 'content': 'Say hello'}]
140
  result = list(
141
  stream_litellm_completion(
142
- provider='hf',
143
- model='mistral',
144
  messages=messages,
145
  max_tokens=100,
146
  api_key='test-key',
@@ -187,8 +185,8 @@ def test_stream_litellm_completion_error(mock_litellm):
187
  with pytest.raises(Exception) as exc_info:
188
  list(
189
  stream_litellm_completion(
190
- provider='hf',
191
- model='mistral',
192
  messages=messages,
193
  max_tokens=100,
194
  api_key='test-key',
@@ -203,8 +201,8 @@ def test_get_litellm_llm(mock_stream):
203
  mock_stream.return_value = iter(['Hello', ' world'])
204
 
205
  llm = get_litellm_llm(
206
- provider='hf',
207
- model='mistral',
208
  max_new_tokens=100,
209
  api_key='test-key',
210
  )
@@ -254,8 +252,8 @@ def test_stream_litellm_completion_message_format(mock_litellm):
254
  messages = [{'role': 'user', 'content': 'Test'}]
255
  result = list(
256
  stream_litellm_completion(
257
- provider='hf',
258
- model='mistral',
259
  messages=messages,
260
  max_tokens=100,
261
  api_key='test-key',
 
26
  ('invalid[]model', False, ('', '')),
27
  ('', False, ('', '')),
28
  ('[invalid]model', False, ('', '')),
 
29
  ],
30
  )
31
  def test_get_provider_model(provider_model, use_ollama, expected):
 
106
  @pytest.mark.parametrize(
107
  'provider, model, expected',
108
  [
 
109
  (GlobalConfig.PROVIDER_GOOGLE_GEMINI, 'gemini-pro', 'gemini/gemini-pro'),
110
  (GlobalConfig.PROVIDER_OPENROUTER, 'openai/gpt-4', 'openrouter/openai/gpt-4'),
111
  (GlobalConfig.PROVIDER_COHERE, 'command', 'cohere/command'),
 
137
  messages = [{'role': 'user', 'content': 'Say hello'}]
138
  result = list(
139
  stream_litellm_completion(
140
+ provider='gg',
141
+ model='gemini-2.5-flash-lite',
142
  messages=messages,
143
  max_tokens=100,
144
  api_key='test-key',
 
185
  with pytest.raises(Exception) as exc_info:
186
  list(
187
  stream_litellm_completion(
188
+ provider='gg',
189
+ model='gemini-2.5-flash-lite',
190
  messages=messages,
191
  max_tokens=100,
192
  api_key='test-key',
 
201
  mock_stream.return_value = iter(['Hello', ' world'])
202
 
203
  llm = get_litellm_llm(
204
+ provider='gg',
205
+ model='gemini-2.5-flash-lite',
206
  max_new_tokens=100,
207
  api_key='test-key',
208
  )
 
252
  messages = [{'role': 'user', 'content': 'Test'}]
253
  result = list(
254
  stream_litellm_completion(
255
+ provider='gg',
256
+ model='gemini-2.5-flash-lite',
257
  messages=messages,
258
  max_tokens=100,
259
  api_key='test-key',