lokesh180340026 commited on
Commit
62179bd
·
verified ·
1 Parent(s): 2ce366d

Fix 403: free-tier models first in dropdown, default=gemma3:12b, friendly error messages for subscription/auth/rate-limit

Browse files
Files changed (1) hide show
  1. llm.py +56 -29
llm.py CHANGED
@@ -1,65 +1,66 @@
1
  """
2
  Ollama Cloud API client for script generation.
3
  Uses OpenAI-compatible API at https://ollama.com/v1
 
 
 
 
 
4
  """
5
  import json
6
  import re
7
  from openai import OpenAI
8
 
9
 
10
- # Current Ollama Cloud models (from https://ollama.com/search?c=cloud)
11
- # These run on Ollama's infrastructure no local GPU needed
 
12
  OLLAMA_CLOUD_MODELS = [
13
- # --- Google ---
14
- "gemma3:27b",
15
- "gemma3:12b",
16
  "gemma3:4b",
 
 
 
 
 
 
 
 
 
 
17
  "gemma4:31b",
18
  "gemini-3-flash-preview",
19
- # --- Alibaba Qwen ---
 
 
 
20
  "qwen3.5:397b",
21
  "qwen3-coder:480b",
22
  "qwen3-coder-next",
23
  "qwen3-next:80b",
24
  "qwen3-vl:235b",
25
- # --- DeepSeek ---
26
- "deepseek-v3.1:671b",
27
- "deepseek-v3.2",
28
- "deepseek-v4-flash",
29
- # --- OpenAI ---
30
- "gpt-oss:120b",
31
- "gpt-oss:20b",
32
- # --- Mistral ---
33
  "mistral-large-3:675b",
34
  "devstral-2:123b",
35
- "devstral-small-2:24b",
36
- "ministral-3:14b",
37
- "ministral-3:8b",
38
- "ministral-3:3b",
39
- # --- MiniMax ---
40
  "minimax-m2.7",
41
  "minimax-m2.5",
42
  "minimax-m2.1",
43
  "minimax-m2",
44
- # --- Moonshot Kimi ---
45
  "kimi-k2.6",
46
  "kimi-k2.5",
47
  "kimi-k2:1t",
48
  "kimi-k2-thinking",
49
- # --- NVIDIA ---
50
  "nemotron-3-super",
51
- "nemotron-3-nano:30b",
52
- # --- Z.ai GLM ---
53
  "glm-5.1",
54
  "glm-5",
55
  "glm-4.7",
56
  "glm-4.6",
57
- # --- Deep Cogito ---
58
  "cogito-2.1:671b",
59
- # --- Essential AI ---
60
- "rnj-1:8b",
61
  ]
62
 
 
 
 
63
 
64
  def get_ollama_client(api_key: str, base_url: str = "https://ollama.com/v1") -> OpenAI:
65
  """Create an OpenAI-compatible client for Ollama cloud."""
@@ -70,7 +71,7 @@ def get_model_name(dropdown_value: str, custom_model: str) -> str:
70
  """Resolve model name: use custom input if provided, else dropdown."""
71
  if custom_model and custom_model.strip():
72
  return custom_model.strip()
73
- return dropdown_value
74
 
75
 
76
  def extract_json_from_text(text: str) -> str:
@@ -90,6 +91,33 @@ def extract_json_from_text(text: str) -> str:
90
  return text
91
 
92
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  def generate_viral_script(
94
  topic: str, research_text: str, key_facts: list[str],
95
  model: str, api_key: str, additional_notes: str = "",
@@ -160,7 +188,6 @@ Return ONLY the JSON array, no other text. Example format:
160
 
161
  content = response.choices[0].message.content
162
 
163
- # Handle models that use thinking tags (like qwen3, deepseek-r1)
164
  if "<think>" in content:
165
  content = re.sub(r'<think>[\s\S]*?</think>', '', content).strip()
166
 
@@ -193,7 +220,7 @@ Return ONLY the JSON array, no other text. Example format:
193
  }
194
 
195
  except Exception as e:
196
- raise RuntimeError(f"Script generation failed: {str(e)}")
197
 
198
 
199
  def generate_title(topic: str, model: str, api_key: str, base_url: str = "https://ollama.com/v1") -> str:
 
1
  """
2
  Ollama Cloud API client for script generation.
3
  Uses OpenAI-compatible API at https://ollama.com/v1
4
+
5
+ Ollama Cloud tiers (as of 2026):
6
+ Free — smaller models, 1 concurrent, light usage
7
+ Pro ($20/mo) — all models, 3 concurrent, 50x usage
8
+ Max ($100/mo) — all models, 10 concurrent, 250x usage
9
  """
10
  import json
11
  import re
12
  from openai import OpenAI
13
 
14
 
15
+ # Models tagged by estimated tier access.
16
+ # Top = likely Free tier (smaller models). Bottom = may need Pro/Max.
17
+ # If a model returns 403, the user needs to upgrade or pick a Free-tier model.
18
  OLLAMA_CLOUD_MODELS = [
19
+ # --- 🟢 Likely Free tier (smaller models) ---
 
 
20
  "gemma3:4b",
21
+ "gemma3:12b",
22
+ "gemma3:27b",
23
+ "ministral-3:3b",
24
+ "ministral-3:8b",
25
+ "ministral-3:14b",
26
+ "gpt-oss:20b",
27
+ "rnj-1:8b",
28
+ "devstral-small-2:24b",
29
+ "nemotron-3-nano:30b",
30
+ # --- 🔵 May need Pro/Max subscription ---
31
  "gemma4:31b",
32
  "gemini-3-flash-preview",
33
+ "deepseek-v4-flash",
34
+ "deepseek-v3.2",
35
+ "deepseek-v3.1:671b",
36
+ "gpt-oss:120b",
37
  "qwen3.5:397b",
38
  "qwen3-coder:480b",
39
  "qwen3-coder-next",
40
  "qwen3-next:80b",
41
  "qwen3-vl:235b",
42
+ "qwen3-vl:235b-instruct",
 
 
 
 
 
 
 
43
  "mistral-large-3:675b",
44
  "devstral-2:123b",
 
 
 
 
 
45
  "minimax-m2.7",
46
  "minimax-m2.5",
47
  "minimax-m2.1",
48
  "minimax-m2",
 
49
  "kimi-k2.6",
50
  "kimi-k2.5",
51
  "kimi-k2:1t",
52
  "kimi-k2-thinking",
 
53
  "nemotron-3-super",
 
 
54
  "glm-5.1",
55
  "glm-5",
56
  "glm-4.7",
57
  "glm-4.6",
 
58
  "cogito-2.1:671b",
 
 
59
  ]
60
 
61
+ # Default model — small, likely on free tier
62
+ DEFAULT_MODEL = "gemma3:12b"
63
+
64
 
65
  def get_ollama_client(api_key: str, base_url: str = "https://ollama.com/v1") -> OpenAI:
66
  """Create an OpenAI-compatible client for Ollama cloud."""
 
71
  """Resolve model name: use custom input if provided, else dropdown."""
72
  if custom_model and custom_model.strip():
73
  return custom_model.strip()
74
+ return dropdown_value or DEFAULT_MODEL
75
 
76
 
77
  def extract_json_from_text(text: str) -> str:
 
91
  return text
92
 
93
 
94
+ def _friendly_api_error(e: Exception, model: str) -> str:
95
+ """Turn raw API errors into user-friendly messages."""
96
+ err_str = str(e)
97
+ if "403" in err_str or "subscription" in err_str.lower() or "upgrade" in err_str.lower():
98
+ return (
99
+ f"Model '{model}' requires a paid Ollama subscription.\n\n"
100
+ f"Options:\n"
101
+ f" - Pick a Free-tier model (top of dropdown): gemma3:4b, gemma3:12b, gpt-oss:20b, etc.\n"
102
+ f" - Upgrade your Ollama plan at https://ollama.com/upgrade\n"
103
+ f" - Use a custom endpoint with your own model in the 'Custom Model Name' field."
104
+ )
105
+ if "401" in err_str or "unauthorized" in err_str.lower() or "invalid" in err_str.lower():
106
+ return (
107
+ f"Invalid Ollama API key. Please check your key at https://ollama.com/settings"
108
+ )
109
+ if "404" in err_str or "not found" in err_str.lower():
110
+ return (
111
+ f"Model '{model}' not found. Check the model name or try one from the dropdown."
112
+ )
113
+ if "rate" in err_str.lower() or "429" in err_str:
114
+ return (
115
+ f"Rate limit reached. Ollama free tier has limited usage. "
116
+ f"Wait a few minutes or upgrade at https://ollama.com/upgrade"
117
+ )
118
+ return f"Script generation failed: {err_str}"
119
+
120
+
121
  def generate_viral_script(
122
  topic: str, research_text: str, key_facts: list[str],
123
  model: str, api_key: str, additional_notes: str = "",
 
188
 
189
  content = response.choices[0].message.content
190
 
 
191
  if "<think>" in content:
192
  content = re.sub(r'<think>[\s\S]*?</think>', '', content).strip()
193
 
 
220
  }
221
 
222
  except Exception as e:
223
+ raise RuntimeError(_friendly_api_error(e, model))
224
 
225
 
226
  def generate_title(topic: str, model: str, api_key: str, base_url: str = "https://ollama.com/v1") -> str: