ForcePilot/backend/package/yuxi/channel/extensions/minecraft/streaming.py

62 lines
1.6 KiB
Python
Raw Normal View History

import asyncio
import logging
from collections.abc import Awaitable, Callable
logger = logging.getLogger(__name__)
MC_CHAT_MAX_CHARS = 256
CHUNK_PREFIX_OVERHEAD = 8
DELAY_BETWEEN_CHUNKS = 0.5
def split_for_minecraft(
content: str,
max_chars: int = MC_CHAT_MAX_CHARS,
page_indicator: bool = True,
) -> list[str]:
result: list[str] = []
remaining = content
while remaining:
available = max_chars
if len(remaining) <= available:
result.append(remaining)
break
split_at = -1
for sep in ("\n", "", "", "", ". ", "! ", "? ", "", ", ", " "):
pos = remaining.rfind(sep, 0, available)
if pos > available * 0.5:
split_at = pos + len(sep)
break
if split_at == -1:
split_at = available
result.append(remaining[:split_at].rstrip())
remaining = remaining[split_at:].lstrip()
if page_indicator and len(result) > 1:
total = len(result)
result = [f"[{i + 1}/{total}] {chunk}" for i, chunk in enumerate(result)]
return result
async def stream_block_minecraft(
send_fn: Callable[[str], Awaitable[None]],
content: str,
chunk_delay: float = DELAY_BETWEEN_CHUNKS,
) -> None:
chunks = split_for_minecraft(content)
total = len(chunks)
logger.info("Minecraft streaming: %d chars -> %d chunks", len(content), total)
for i, chunk in enumerate(chunks):
await send_fn(chunk)
if i < total - 1:
logger.debug("Chunk %d/%d sent, waiting %.1fs", i + 1, total, chunk_delay)
await asyncio.sleep(chunk_delay)