chrissoria commited on
Commit
74a0980
·
1 Parent(s): 459f28f

Add Free Models tier with GPT-4o, Gemini, Qwen, DeepSeek, Llama

Browse files
Files changed (1) hide show
  1. app.py +81 -61
app.py CHANGED
@@ -18,24 +18,36 @@ except ImportError as e:
18
  MAX_CATEGORIES = 10
19
  INITIAL_CATEGORIES = 3
20
 
21
- MODEL_CHOICES = [
22
- "Qwen/Qwen3-VL-235B-A22B-Instruct:novita (Free)",
23
- "deepseek-ai/DeepSeek-V3.1:novita (Free)",
24
- "meta-llama/Llama-4-Maverick-17B-128E-Instruct:groq (Free)",
 
 
25
  "gpt-4o",
 
 
 
 
 
 
26
  "claude-sonnet-4-5-20250929",
 
27
  "gemini-2.5-flash",
 
28
  ]
29
 
30
- HF_FREE_MODELS = {
31
- "Qwen/Qwen3-VL-235B-A22B-Instruct:novita (Free)": "Qwen/Qwen3-VL-235B-A22B-Instruct:novita",
32
- "deepseek-ai/DeepSeek-V3.1:novita (Free)": "deepseek-ai/DeepSeek-V3.1:novita",
33
- "meta-llama/Llama-4-Maverick-17B-128E-Instruct:groq (Free)": "meta-llama/Llama-4-Maverick-17B-128E-Instruct:groq",
34
- }
 
35
 
36
 
37
- def is_free_model(model):
38
- return "(Free)" in model
 
39
 
40
 
41
  def get_model_source(model):
@@ -77,7 +89,7 @@ def load_columns(file):
77
 
78
  def classify_data(spreadsheet_file, spreadsheet_column,
79
  cat1, cat2, cat3, cat4, cat5, cat6, cat7, cat8, cat9, cat10,
80
- model, model_source_input, api_key_input):
81
  """Main classification function."""
82
  if not CATLLM_AVAILABLE:
83
  return None, None, "**Error:** catllm package not available"
@@ -88,30 +100,31 @@ def classify_data(spreadsheet_file, spreadsheet_column,
88
  if not categories:
89
  return None, None, "**Error:** Please enter at least one category"
90
 
91
- # Get API key - priority: user input > environment variable
92
- if is_free_model(model):
93
- actual_api_key = os.environ.get("HF_API_KEY", "")
94
- actual_model = HF_FREE_MODELS.get(model, model.replace(" (Free)", ""))
95
- if not actual_api_key:
96
- return None, None, "**Error:** HuggingFace API key not configured in Space secrets"
 
 
 
 
 
 
 
 
 
 
 
 
 
97
  else:
98
- # For paid models, check user input first, then environment
99
- actual_model = model
100
  if api_key_input and api_key_input.strip():
101
  actual_api_key = api_key_input.strip()
102
  else:
103
- # Try to get from environment based on model
104
- if "gpt" in model.lower():
105
- actual_api_key = os.environ.get("OPENAI_API_KEY", "")
106
- elif "claude" in model.lower():
107
- actual_api_key = os.environ.get("ANTHROPIC_API_KEY", "")
108
- elif "gemini" in model.lower():
109
- actual_api_key = os.environ.get("GOOGLE_API_KEY", "")
110
- else:
111
- actual_api_key = ""
112
-
113
- if not actual_api_key:
114
- return None, None, f"**Error:** Please provide an API key for {model}"
115
 
116
  # Use user-selected model_source, or auto-detect if "auto"
117
  if model_source_input == "auto":
@@ -167,16 +180,12 @@ def add_category_field(current_count):
167
 
168
  def generate_code(spreadsheet_file, spreadsheet_column,
169
  cat1, cat2, cat3, cat4, cat5, cat6, cat7, cat8, cat9, cat10,
170
- model, model_source_input):
171
  """Generate Python code snippet based on user inputs."""
172
  all_cats = [cat1, cat2, cat3, cat4, cat5, cat6, cat7, cat8, cat9, cat10]
173
  categories = [c.strip() for c in all_cats if c and c.strip()]
174
 
175
- # Get the actual model name (strip " (Free)" suffix)
176
- if is_free_model(model):
177
- actual_model = HF_FREE_MODELS.get(model, model.replace(" (Free)", ""))
178
- else:
179
- actual_model = model
180
 
181
  # Determine model source
182
  if model_source_input == "auto":
@@ -284,9 +293,16 @@ https://github.com/chrissoria/cat-llm
284
  add_category_btn = gr.Button("+ Add More Categories", variant="secondary", size="sm")
285
 
286
  gr.Markdown("### Model")
 
 
 
 
 
 
 
287
  model = gr.Dropdown(
288
- choices=MODEL_CHOICES,
289
- value="Qwen/Qwen3-VL-235B-A22B-Instruct:novita (Free)",
290
  label="Model",
291
  allow_custom_value=True
292
  )
@@ -295,17 +311,18 @@ https://github.com/chrissoria/cat-llm
295
  choices=["auto", "openai", "anthropic", "google", "mistral", "xai", "huggingface", "perplexity"],
296
  value="auto",
297
  label="Model Source",
298
- info="Auto-detects from model name, or select manually. Use 'huggingface' for Qwen/Llama/DeepSeek models."
299
  )
300
 
301
  api_key = gr.Textbox(
302
- label="API Key (optional)",
303
  type="password",
304
- placeholder="Enter your API key, or leave blank to use Space secrets",
305
- info="For paid models, enter your key or configure in Space secrets"
 
306
  )
307
 
308
- api_key_status = gr.Markdown("**Free model selected** - no API key required!")
309
 
310
  with gr.Row():
311
  classify_btn = gr.Button("Classify", variant="primary")
@@ -322,22 +339,25 @@ https://github.com/chrissoria/cat-llm
322
  )
323
 
324
  # Event handlers
325
- def update_api_key_status(selected_model):
326
- if is_free_model(selected_model):
327
- return "**Free model selected** - no API key required!"
328
- elif "gpt" in selected_model.lower():
329
- return "**OpenAI model** - using OPENAI_API_KEY from secrets (or enter your own)"
330
- elif "claude" in selected_model.lower():
331
- return "**Anthropic model** - using ANTHROPIC_API_KEY from secrets (or enter your own)"
332
- elif "gemini" in selected_model.lower():
333
- return "**Google model** - using GOOGLE_API_KEY from secrets (or enter your own)"
334
  else:
335
- return "**Paid model** - enter your API key or configure in Space secrets"
 
 
 
 
336
 
337
- model.change(
338
- fn=update_api_key_status,
339
- inputs=[model],
340
- outputs=[api_key_status]
341
  )
342
 
343
  load_cols_btn.click(
@@ -354,13 +374,13 @@ https://github.com/chrissoria/cat-llm
354
 
355
  classify_btn.click(
356
  fn=classify_data,
357
- inputs=[spreadsheet_file, spreadsheet_column] + category_inputs + [model, model_source, api_key],
358
  outputs=[results, download_file, status]
359
  )
360
 
361
  see_code_btn.click(
362
  fn=generate_code,
363
- inputs=[spreadsheet_file, spreadsheet_column] + category_inputs + [model, model_source],
364
  outputs=[code_output]
365
  )
366
 
 
18
  MAX_CATEGORIES = 10
19
  INITIAL_CATEGORIES = 3
20
 
21
+ # Free models (uses Space secrets - no user API key needed)
22
+ FREE_MODEL_CHOICES = [
23
+ "Qwen/Qwen3-VL-235B-A22B-Instruct:novita",
24
+ "deepseek-ai/DeepSeek-V3.1:novita",
25
+ "meta-llama/Llama-4.1-8B-Instruct:novita",
26
+ "gemini-2.5-flash",
27
  "gpt-4o",
28
+ ]
29
+
30
+ # Paid models (user provides their own API key)
31
+ PAID_MODEL_CHOICES = [
32
+ "gpt-4o",
33
+ "gpt-4o-mini",
34
  "claude-sonnet-4-5-20250929",
35
+ "claude-3-5-haiku-20241022",
36
  "gemini-2.5-flash",
37
+ "gemini-2.0-flash",
38
  ]
39
 
40
+ # Models routed through HuggingFace
41
+ HF_ROUTED_MODELS = [
42
+ "Qwen/Qwen3-VL-235B-A22B-Instruct:novita",
43
+ "deepseek-ai/DeepSeek-V3.1:novita",
44
+ "meta-llama/Llama-4.1-8B-Instruct:novita",
45
+ ]
46
 
47
 
48
+ def is_free_model(model, model_tier):
49
+ """Check if using free tier (Space pays for API)."""
50
+ return model_tier == "Free Models"
51
 
52
 
53
  def get_model_source(model):
 
89
 
90
  def classify_data(spreadsheet_file, spreadsheet_column,
91
  cat1, cat2, cat3, cat4, cat5, cat6, cat7, cat8, cat9, cat10,
92
+ model_tier, model, model_source_input, api_key_input):
93
  """Main classification function."""
94
  if not CATLLM_AVAILABLE:
95
  return None, None, "**Error:** catllm package not available"
 
100
  if not categories:
101
  return None, None, "**Error:** Please enter at least one category"
102
 
103
+ actual_model = model
104
+
105
+ # Get API key based on tier
106
+ if is_free_model(model, model_tier):
107
+ # Free tier - use Space secrets
108
+ if model in HF_ROUTED_MODELS:
109
+ actual_api_key = os.environ.get("HF_API_KEY", "")
110
+ if not actual_api_key:
111
+ return None, None, "**Error:** HuggingFace API key not configured in Space secrets"
112
+ elif "gpt" in model.lower():
113
+ actual_api_key = os.environ.get("OPENAI_API_KEY", "")
114
+ if not actual_api_key:
115
+ return None, None, "**Error:** OpenAI API key not configured in Space secrets"
116
+ elif "gemini" in model.lower():
117
+ actual_api_key = os.environ.get("GOOGLE_API_KEY", "")
118
+ if not actual_api_key:
119
+ return None, None, "**Error:** Google API key not configured in Space secrets"
120
+ else:
121
+ actual_api_key = os.environ.get("HF_API_KEY", "")
122
  else:
123
+ # Paid tier - user provides their own API key
 
124
  if api_key_input and api_key_input.strip():
125
  actual_api_key = api_key_input.strip()
126
  else:
127
+ return None, None, f"**Error:** Please provide your API key for {model}"
 
 
 
 
 
 
 
 
 
 
 
128
 
129
  # Use user-selected model_source, or auto-detect if "auto"
130
  if model_source_input == "auto":
 
180
 
181
  def generate_code(spreadsheet_file, spreadsheet_column,
182
  cat1, cat2, cat3, cat4, cat5, cat6, cat7, cat8, cat9, cat10,
183
+ model_tier, model, model_source_input):
184
  """Generate Python code snippet based on user inputs."""
185
  all_cats = [cat1, cat2, cat3, cat4, cat5, cat6, cat7, cat8, cat9, cat10]
186
  categories = [c.strip() for c in all_cats if c and c.strip()]
187
 
188
+ actual_model = model
 
 
 
 
189
 
190
  # Determine model source
191
  if model_source_input == "auto":
 
293
  add_category_btn = gr.Button("+ Add More Categories", variant="secondary", size="sm")
294
 
295
  gr.Markdown("### Model")
296
+ model_tier = gr.Radio(
297
+ choices=["Free Models", "Bring Your Own Key"],
298
+ value="Free Models",
299
+ label="Model Tier",
300
+ info="Free models use our API keys. 'Bring Your Own Key' lets you use your own API key."
301
+ )
302
+
303
  model = gr.Dropdown(
304
+ choices=FREE_MODEL_CHOICES,
305
+ value="Qwen/Qwen3-VL-235B-A22B-Instruct:novita",
306
  label="Model",
307
  allow_custom_value=True
308
  )
 
311
  choices=["auto", "openai", "anthropic", "google", "mistral", "xai", "huggingface", "perplexity"],
312
  value="auto",
313
  label="Model Source",
314
+ info="Auto-detects from model name, or select manually."
315
  )
316
 
317
  api_key = gr.Textbox(
318
+ label="API Key",
319
  type="password",
320
+ placeholder="Enter your API key",
321
+ info="Required for 'Bring Your Own Key' tier",
322
+ visible=False
323
  )
324
 
325
+ api_key_status = gr.Markdown("**Free tier** - no API key required! We cover the cost while CatLLM is in review.")
326
 
327
  with gr.Row():
328
  classify_btn = gr.Button("Classify", variant="primary")
 
339
  )
340
 
341
  # Event handlers
342
+ def update_model_tier(tier):
343
+ """Update model choices and API key visibility based on tier."""
344
+ if tier == "Free Models":
345
+ return (
346
+ gr.update(choices=FREE_MODEL_CHOICES, value=FREE_MODEL_CHOICES[0]),
347
+ gr.update(visible=False),
348
+ "**Free tier** - no API key required! We cover the cost while CatLLM is in review."
349
+ )
 
350
  else:
351
+ return (
352
+ gr.update(choices=PAID_MODEL_CHOICES, value=PAID_MODEL_CHOICES[0]),
353
+ gr.update(visible=True),
354
+ "**Bring Your Own Key** - enter your API key below."
355
+ )
356
 
357
+ model_tier.change(
358
+ fn=update_model_tier,
359
+ inputs=[model_tier],
360
+ outputs=[model, api_key, api_key_status]
361
  )
362
 
363
  load_cols_btn.click(
 
374
 
375
  classify_btn.click(
376
  fn=classify_data,
377
+ inputs=[spreadsheet_file, spreadsheet_column] + category_inputs + [model_tier, model, model_source, api_key],
378
  outputs=[results, download_file, status]
379
  )
380
 
381
  see_code_btn.click(
382
  fn=generate_code,
383
+ inputs=[spreadsheet_file, spreadsheet_column] + category_inputs + [model_tier, model, model_source],
384
  outputs=[code_output]
385
  )
386