diff --git a/api-openwebui/secretchat-api-example.py b/api-openwebui/secretchat-api-example.py new file mode 100644 index 0000000..0e984d2 --- /dev/null +++ b/api-openwebui/secretchat-api-example.py @@ -0,0 +1,154 @@ +#!/usr/bin/env python3 + +""" +secretchat-api-example.py + +• Prints model IDs at start +• Shows which model handles each sentence, 5 sentences + +Requires: + pip install requests python-dotenv +""" + +import os +import random +import time +from typing import List, Union, Tuple, Optional + +import requests +from dotenv import load_dotenv + + +# ── API-key helper ─────────────────────────────────────────────────────────── +def load_api_key() -> str: + load_dotenv(os.path.join(os.path.expanduser("~"), ".secretlab.env")) + key = os.getenv("SECRETLAB_API_KEY") + if not key: + raise ValueError("SECRETLAB_API_KEY not found") + return key + + +# ── /api/models helper ─────────────────────────────────────────────────────── +def fetch_model_ids(api_key: str, base_url: str) -> List[str]: + resp = requests.get( + f"{base_url}/api/models", + headers={"Authorization": f"Bearer {api_key}"}, + timeout=300, + ) + resp.raise_for_status() + raw: Union[list, dict] = resp.json() + + if isinstance(raw, dict): # unwrap {"models":[...]} or similar + for key in ("models", "data", "items", "result"): + if key in raw and isinstance(raw[key], list): + raw = raw[key] + break + + if not isinstance(raw, list): + raise RuntimeError("Unexpected /api/models response") + + ids: List[str] = [] + for item in raw: + if isinstance(item, str): + ids.append(item) + elif isinstance(item, dict): + if isinstance(item.get("model"), str): + ids.append(item["model"]) + elif isinstance(item.get("ollama"), dict) and isinstance( + item["ollama"].get("model"), str + ): + ids.append(item["ollama"]["model"]) + if not ids: + raise RuntimeError("No model IDs found") + return ids + + +# ── classify helper ────────────────────────────────────────────────────────── +def classify( + sentence: str, + api_key: str, + base_url: str, + models: List[str], + retries: int = 6, + backoff: int = 2, +) -> Tuple[str, Optional[str]]: + """Return (model_used, classification or None).""" + url = f"{base_url}/api/chat/completions" + + for attempt in range(1, retries + 1): + model = random.choice(models) + payload = { + "model": model, + "messages": [ + { + "role": "system", + "content": ( + "Respond ONLY with 'Positive' or 'Negative'. " + "No other words or punctuation." + ), + }, + {"role": "user", "content": f"Classify this:\n{sentence}"}, + ], + "temperature": 0.0, + } + + try: + r = requests.post( + url, + headers={ + "Authorization": f"Bearer {api_key}", + "Content-Type": "application/json", + }, + json=payload, + timeout=300, + ) + if r.status_code == 200: + result = r.json()["choices"][0]["message"]["content"].strip() + return model, result + print(f"API error {r.status_code}: {r.text}") + return model, None + except requests.exceptions.RequestException as e: + print(f"Network error ({attempt}/{retries}): {e}") + if attempt < retries: + time.sleep(backoff) + backoff *= 2 + else: + return model, None + + +# ── main loop ──────────────────────────────────────────────────────────────── +def main() -> None: + api_key = load_api_key() + BASE = "https://chat.secretlab.page" + models = fetch_model_ids(api_key, BASE) + + print("Models:") + for m in models: + print(m) + print("-" * 40, "\n") + + sentences = [ + "I love sunny days!", + "This is a bland sandwich.", + "I really hate waiting in long lines.", + "The meeting was okay, nothing special.", + "I am so excited about the upcoming holidays!", + ] + + for run in range(1): # repeat 1 times + print(f"\n--- Run {run+1} ---\n") + + for idx, s in enumerate(sentences, 1): + model_used, res = classify(s, api_key, BASE, models) + + print(f"Sentence {idx}: {s}") + print(f"Model : {model_used}") + print(f"Result : {res or 'Failed'}\n") + + time.sleep(1) # optional pause between runs + + print("\nAll runs complete!\n") + + +if __name__ == "__main__": + main()