tinybard / projects /crittercalm /content /script_generator.py
Hermes Bot
feat: wire all 3 apps to HF Inference API + cooldowns
a9f90f6
Raw
History Blame Contribute Delete
4.87 kB
"""
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"),
}