from nc_py_api import Nextcloud import json from typing import Dict from datetime import datetime import os import re import config # Initialize Nextcloud client nc = Nextcloud( nextcloud_url=config.NEXTCLOUD_URL, nc_auth_user=config.NEXTCLOUD_USERNAME, nc_auth_pass=config.NEXTCLOUD_PASSWORD ) def validate_model_url(url: str) -> bool: """ Validate if the provided URL matches the expected format. Accepts both direct Ollama models and HuggingFace GGUF models. """ # Pattern for HuggingFace GGUF models hf_pattern = r'^hf\.co/[\w-]+/[\w\.-]+(?:-GGUF)?:Q[0-9]+(?:_[A-Z0-9_]+)?$' # Pattern for direct Ollama models ollama_pattern = r'^[\w\.-]+(?::\d+(?:\.\d+)?[b])?(?:-[\w-]+)?:Q[0-9]+(?:_[A-Z0-9_]+)?$' return bool(re.match(hf_pattern, url) or re.match(ollama_pattern, url)) def load_suggestions() -> Dict: """Load suggestions from Nextcloud with local file fallback.""" try: # Try to load from Nextcloud remote_data = nc.files.download(config.NEXTCLOUD_SUGGESTIONS_PATH) if remote_data: suggestions = json.loads(remote_data.decode('utf-8')) # Update local cache with open('model_suggestions.json', 'w') as f: json.dump(suggestions, f, indent=2) return suggestions except Exception as e: print(f"Could not load from Nextcloud: {e}") # Try local cache if os.path.exists('model_suggestions.json'): try: with open('model_suggestions.json', 'r') as f: return json.load(f) except Exception as e: print(f"Could not load from local cache: {e}") # Initialize new suggestions if both attempts fail return { "suggestions": {}, "last_updated": datetime.now().isoformat(), "total_suggestions": 0 } def save_suggestions(suggestions: Dict) -> bool: """Save suggestions to both Nextcloud and local cache.""" try: # Update metadata suggestions["last_updated"] = datetime.now().isoformat() suggestions["total_suggestions"] = sum(s["count"] for s in suggestions["suggestions"].values()) # Save to Nextcloud json_data = json.dumps(suggestions, indent=2) nc.files.upload(config.NEXTCLOUD_SUGGESTIONS_PATH, json_data.encode('utf-8')) # Update local cache with open('model_suggestions.json', 'w') as f: json.dump(suggestions, f, indent=2) return True except Exception as e: print(f"Error saving suggestions: {e}") return False def add_suggestion(model_url: str) -> str: """Add or update a model suggestion with validation.""" # Validate model URL format if not validate_model_url(model_url): return ("❌ Invalid model URL format. Please use either:\n" "- Ollama format: model-name:Q4_K_M\n" "- HuggingFace format: hf.co/username/model-name-GGUF:Q4_K_M") # Check if model is already approved if model_url in dict(config.get_approved_models()): return "ℹ️ This model is already in the arena!" suggestions = load_suggestions() current_time = datetime.now().isoformat() if model_url in suggestions["suggestions"]: suggestions["suggestions"][model_url].update({ "count": suggestions["suggestions"][model_url]["count"] + 1, "last_suggested": current_time }) message = (f"✨ Model suggestion updated! " f"This model has been suggested {suggestions['suggestions'][model_url]['count']} times.") else: suggestions["suggestions"][model_url] = { "count": 1, "first_suggested": current_time, "last_suggested": current_time } message = "✅ New model suggestion recorded successfully!" if save_suggestions(suggestions): return message return "❌ Error saving suggestion. Please try again later." def get_suggestions_html() -> str: """Generate HTML table of model suggestions with improved styling.""" suggestions = load_suggestions() # Sort suggestions by count (descending) and last suggested date sorted_suggestions = sorted( suggestions["suggestions"].items(), key=lambda x: (x[1]["count"], x[1]["last_suggested"]), reverse=True ) stats_header = f"""
Total Suggestions: {suggestions.get("total_suggestions", 0)} | Last Updated: {suggestions.get("last_updated", "Never").split("T")[0]}
""" html = f""" {stats_header} """ for index, (model_url, data) in enumerate(sorted_suggestions, start=1): rank_display = {1: "🥇", 2: "🥈", 3: "🥉"}.get(index, f"{index}") html += f""" """ html += "
Rank Model URL Suggestions First Suggested Last Suggested
{rank_display} {model_url} {data['count']} {data['first_suggested'].split('T')[0]} {data['last_suggested'].split('T')[0]}
" return html