Spaces:
Sleeping
Sleeping
Download bot/channel_points_runtime.py from JuanCS-Dev/twitch-byte-bot: direct link, hf CLI and curl.
- Browser
- Download file 2.17 kB
-
https://huggingface.co/spaces/JuanCS-Dev/twitch-byte-bot/resolve/main/bot/channel_points_runtime.py
- Command line
-
hf download hf://spaces/JuanCS-Dev/twitch-byte-bot/bot/channel_points_runtime.py
-
curl -L -o channel_points_runtime.py https://huggingface.co/spaces/JuanCS-Dev/twitch-byte-bot/resolve/main/bot/channel_points_runtime.py
2.17 kB
| """Channel Points runtime — viewers redeem points to make Byte speak. | |
| The 2026 flagship engagement: a viewer redeems a custom reward and Byte voices | |
| their message in persona. Redemptions to the dedicated "voice" reward are | |
| spoken (sanitized + length-capped); anything else is filed as a streamer | |
| suggestion in the risk queue. Pure/testable core; the EventSub subscription | |
| that feeds it activates in eventsub mode with the channel:read:redemptions scope. | |
| """ | |
| from __future__ import annotations | |
| from typing import Any | |
| from bot.control_plane import control_plane | |
| from bot.control_plane_constants import RISK_SUGGEST_STREAMER | |
| from bot.voice_runtime import voice_runtime | |
| MAX_REDEMPTION_CHARS = 200 | |
| _VOICE_REWARD_MARKERS = ("byte fala", "byte fale", "fala byte", "byte tts", "byte speak") | |
| def is_voice_reward(reward_title: str) -> bool: | |
| lowered = (reward_title or "").strip().lower() | |
| return any(marker in lowered for marker in _VOICE_REWARD_MARKERS) | |
| def _sanitize(text: str) -> str: | |
| return " ".join((text or "").split())[:MAX_REDEMPTION_CHARS] | |
| def process_redemption(user: str, reward_title: str, user_input: str = "") -> dict[str, Any]: | |
| """Turn a Channel Points redemption into voice (voice reward) or a suggestion.""" | |
| safe_user = (user or "viewer").strip() or "viewer" | |
| message = _sanitize(user_input) | |
| if is_voice_reward(reward_title): | |
| if not message: | |
| return {"ok": False, "reason": "empty_message"} | |
| spoken = voice_runtime.say(f"{safe_user} diz: {message}", source="channel_points") | |
| return {"ok": True, "action": "voice", "spoke": spoken.get("spoke", False)} | |
| # Non-voice rewards go to the risk queue for the streamer to handle. | |
| item = control_plane.enqueue_action( | |
| kind="channel_points", | |
| risk=RISK_SUGGEST_STREAMER, | |
| title=f"Resgate de {safe_user}: {(_sanitize(reward_title) or 'recompensa')}", | |
| body=message or "(sem mensagem)", | |
| payload={"user": safe_user, "reward": _sanitize(reward_title)}, | |
| created_by="channel_points", | |
| ) | |
| return {"ok": True, "action": "queued", "item": item} | |
| __all__ = ["is_voice_reward", "process_redemption"] | |