Spaces:
Paused
Paused
File size: 4,866 Bytes
144ed35 e4b2617 144ed35 e4b2617 144ed35 e4b2617 144ed35 e4b2617 144ed35 e4b2617 144ed35 e4b2617 144ed35 e4b2617 144ed35 e4b2617 144ed35 e4b2617 144ed35 e4b2617 144ed35 e4b2617 144ed35 e4b2617 144ed35 e4b2617 144ed35 e4b2617 144ed35 e4b2617 144ed35 e4b2617 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 | """
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"),
}
|