Spaces:
Paused
Paused
| """ | |
| Calming script generation using the Hugging Face Inference API | |
| or pre-written templates. | |
| The previous version used Dolphin-X1-8B via llama-cpp-python locally. That | |
| required a heavy build step on HF Spaces. This version uses the serverless | |
| HF Inference API and enforces a per-project cooldown via | |
| `shared.inference_client` to protect credit budgets. | |
| Override model: set `CRITTERCALM_MODEL` env var. Default is | |
| `Qwen/Qwen2.5-7B-Instruct` (small, fast, free-tier friendly). The | |
| system prompt is unchanged — output format is identical. | |
| """ | |
| from __future__ import annotations | |
| import logging | |
| import os | |
| import sys | |
| from pathlib import Path | |
| from typing import List, Dict, Optional | |
| # Repo-root path setup so we can import shared.inference_client | |
| _THIS = Path(__file__).resolve() | |
| _REPO_ROOT = _THIS.parent.parent.parent | |
| if str(_REPO_ROOT) not in sys.path: | |
| sys.path.insert(0, str(_REPO_ROOT)) | |
| from shared.inference_client import ( # noqa: E402 | |
| chat_messages, | |
| cooldown_active, | |
| cooldown_status, | |
| generate as _client_generate, | |
| INFERENCE_MODEL as DEFAULT_MODEL, | |
| ) | |
| from content.templates import get_template # noqa: E402 | |
| log = logging.getLogger("crittercalm.content") | |
| CALMING_SYSTEM_PROMPT = """You are a compassionate animal behavior expert who creates calming, | |
| soothing spoken messages for pets. Your words will be spoken aloud to the animal. | |
| Guidelines: | |
| - Use simple, rhythmic language with gentle repetition | |
| - Speak directly to the animal using its name if provided | |
| - Match the tone to the situation (soothing for anxiety, steady for storms, etc.) | |
| - Incorporate species-specific calming techniques: | |
| * Dogs: calm reassurance, short phrases, mention of familiar routines | |
| * Cats: soft, slow cadence, blink references, safe-space imagery | |
| * Chickens: gentle clucking sounds described, flock-safety messaging | |
| * Birds: soft whistles, perch-and-rest imagery | |
| * Rabbits: gentle burrow imagery, safety themes | |
| * Horses: steady breathing cues, herd-companion reassurance | |
| - Keep messages between 30 seconds and 3 minutes when spoken | |
| - Never use scary words or raise alarm | |
| - End each message with a gentle fade-out phrase | |
| Output ONLY the spoken script — no stage directions, no explanations.""" | |
| def _model() -> str: | |
| return os.environ.get("CRITTERCALM_MODEL", DEFAULT_MODEL) | |
| def create_script_prompt( | |
| animal: str, | |
| situation: str, | |
| duration_minutes: int, | |
| pet_name: str = "", | |
| custom_message: str = "", | |
| ) -> str: | |
| """Build the user prompt for script generation.""" | |
| pet_part = f" The pet's name is \"{pet_name}\"." if pet_name else "" | |
| custom_part = f" Incorporate this personal note: \"{custom_message}\"" if custom_message else "" | |
| return ( | |
| f"Write a {duration_minutes}-minute calming spoken message for a {animal} " | |
| f"that is experiencing {situation}.{pet_part}{custom_part}" | |
| ) | |
| def generate_calming_script( | |
| animal: str, | |
| situation: str, | |
| duration_minutes: int, | |
| custom_message: str = "", | |
| pet_name: str = "", | |
| dolphin_llm=None, # legacy param — ignored; we use the HF Inference API | |
| ) -> str: | |
| """Generate a calming script using HF Inference API or fallback templates. | |
| Args: | |
| animal: Animal type | |
| situation: Stress situation | |
| duration_minutes: Target session length | |
| custom_message: Optional custom message | |
| pet_name: Optional pet name | |
| dolphin_llm: Legacy parameter (ignored) | |
| Returns: | |
| Generated calming script as a string | |
| """ | |
| user_prompt = create_script_prompt( | |
| animal=animal, | |
| situation=situation, | |
| duration_minutes=duration_minutes, | |
| pet_name=pet_name, | |
| custom_message=custom_message, | |
| ) | |
| # Try inference (cooldown-aware) | |
| if not cooldown_active("crittercalm"): | |
| try: | |
| messages = chat_messages(CALMING_SYSTEM_PROMPT, user_prompt) | |
| result = _client_generate( | |
| project="crittercalm", | |
| messages=messages, | |
| max_new_tokens=int(duration_minutes * 200), # rough token budget | |
| temperature=0.7, | |
| ) | |
| script = result.text.strip() | |
| if script: | |
| log.info(f"LLM script generated: {len(script)} chars") | |
| return script | |
| except RuntimeError: | |
| # Cooldown — fall through to template | |
| log.info("crittercalm inference cooldown; using template") | |
| except Exception as exc: | |
| log.warning(f"LLM generation failed, using template: {exc}") | |
| else: | |
| log.info("crittercalm inference cooldown active; using template") | |
| # Fallback: pre-written templates | |
| return get_template(animal, situation, pet_name, custom_message) | |
| def cooldown_snapshot() -> dict: | |
| return { | |
| "model": _model(), | |
| "cooldown": cooldown_status("crittercalm"), | |
| } | |