Skip to main content
Glama
utils.py4.63 kB
""" Utility helpers shared across Promptheus modules. """ from __future__ import annotations import logging import re from typing import Callable, Iterable, Optional, TYPE_CHECKING from promptheus.logging_config import setup_logging if TYPE_CHECKING: from fastapi import Request try: import pyperclip except ImportError: pyperclip = None TOKEN_PATTERN = re.compile(r"[A-Za-z0-9_\-]{12,}") def sanitize_error_message(message: str, max_length: int = 160) -> str: """ Remove potentially sensitive substrings (API keys, tokens) and truncate overly long provider error messages before showing them to users. """ if not message: return "" masked = TOKEN_PATTERN.sub("***", message) sanitized = " ".join(masked.split()) if len(sanitized) > max_length: sanitized = sanitized[: max_length - 3] + "..." return sanitized def configure_logging(default_level: int = logging.INFO) -> None: """Backward-compatible wrapper around logging_config.setup_logging.""" setup_logging(default_level) def collapse_whitespace(lines: Iterable[str]) -> str: """Join lines while stripping trailing whitespace.""" return "\n".join(line.rstrip() for line in lines) def copy_to_clipboard(text: str, console, notify: Optional[Callable[[str], None]] = None) -> bool: """ Copy text to clipboard. Returns True if successful, False otherwise. If notify is provided, will call it with status messages. """ if pyperclip is None: msg = "[yellow]Warning: pyperclip not available - cannot copy to clipboard[/yellow]" if notify: notify(msg) else: console.print(msg) return False try: pyperclip.copy(text) msg = "[green]✓[/green] Copied to clipboard!" if notify: notify(msg) else: console.print(msg) return True except Exception as exc: sanitized = sanitize_error_message(str(exc)) msg = f"[yellow]Warning: Failed to copy to clipboard: {sanitized}[/yellow]" if notify: notify(msg) else: console.print(msg) return False def get_user_email(request: "Request") -> str: """ Extract user email from Cloudflare Access headers or future auth methods. Returns the authenticated user's email, or "unknown" if not authenticated. """ # Option 1: Try specific email header first (correct case) user_email = request.headers.get("CF-Access-Authenticated-User-Email") if not user_email: # Option 2: Try case-insensitive search for safety for header_name in request.headers: if header_name.lower() == "cf-access-authenticated-user-email": user_email = request.headers.get(header_name) break # Option 3: Fallback to subject if no email (contains provider:identifier format) if not user_email: subject = request.headers.get("CF-Access-Subject") if subject and "@" in subject: # If subject looks like an email user_email = subject # Future: Add custom auth extraction here # if not user_email and hasattr(request.state, "user"): # user_email = request.state.user.email return user_email or "unknown" def get_device_category(request: "Request") -> str: """ Extract basic device category from User-Agent header for privacy-safe logging. Returns: "mobile", "tablet", "desktop", or "unknown". Only extracts category, NOT detailed fingerprinting information. """ user_agent = request.headers.get("User-Agent", "").lower() if not user_agent: return "unknown" # Privacy-safe: Only detect basic device category # Avoid detailed fingerprinting, browser versions, or specific models # Mobile indicators (check first for specificity) mobile_indicators = ["mobile", "iphone", "ipod", "windows phone", "android"] # Tablet indicators (checked after confirming not mobile) tablet_indicators = ["ipad", "tablet", "kindle", "silk", "tab", "nexus", "sm-t", "gt-"] # Check for tablet-specific patterns first # iPads and explicit tablet indicators if "ipad" in user_agent or "tablet" in user_agent: return "tablet" # Android tablets (Android without "mobile") if "android" in user_agent and "mobile" not in user_agent: return "tablet" # Check for mobile indicators if any(indicator in user_agent for indicator in mobile_indicators): return "mobile" # Fallback to desktop for any other User-Agent return "desktop"

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/abhichandra21/Promptheus'

If you have feedback or need assistance with the MCP directory API, please join our Discord server