Spaces:
Sleeping
Sleeping
File size: 5,715 Bytes
e68cec5 | 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 | """μΉ΄λ₯΄λ°λΌ μ±ν°1 νλ μ΄ CLI β λ¦¬λ© λ£¨ν + κ°μ
ν¬μΌ (M4 ν΅ν©).
μ¬μ©λ²:
.venv/bin/python scripts/play.py # λνν (ν¬μΌμ LLM ν€ μμΌλ©΄ μ±ν
)
.venv/bin/python scripts/play.py --policy trust --quiet # μλ νλ μ΄, μλ© νμΈ
.venv/bin/python scripts/play.py --chat # ν¬μΌ μμ μ±ν
κ°μ (OPENAI_API_KEY νμ)
.venv/bin/python scripts/play.py --no-chat # ν¬μΌ μ±ν
λκΈ° (μ νμ§λ§)
ν¬μΌ μ±ν
: μ νμ§ μΉ΄λμμ λ²νΈ λμ μμ ν
μ€νΈλ₯Ό μ
λ ₯νλ©΄ μΉ΄λ₯΄λ°λΌμ λνκ° μ΄λ¦¬κ³ ,
director μλ ΄(λλ ν΄ μν) ν μ νμ§λ‘ 볡κ·νλ€.
"""
from __future__ import annotations
import argparse
import asyncio
import os
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent.parent))
from engine.repositories.content import ContentRepository # noqa: E402
from engine.services.story import StepResult, StoryEngine # noqa: E402
DIM = "\033[2m"
BOLD = "\033[1m"
RESET = "\033[0m"
def render(step: StepResult, quiet: bool):
if quiet or step.card is None:
return
c = step.card
print(f"\n{BOLD}ββ {c.id} Β· {c.title} ββ{RESET}")
for b in step.narration:
if b.type == "dialogue_center":
print(f"\n{BOLD} β {b.text} β{RESET}\n")
elif b.type == "character_dialogue":
print(f' {b.speaker}: "{b.text}"')
elif b.type == "stage_direction":
print(f"{DIM} ({b.text}){RESET}")
else:
print("\n" + b.text)
async def pocket_chat(pocket_service, engine: StoryEngine, card_id: str, first_line: str):
"""κ°μ
ν¬μΌ μμ μ±ν
β μλ ΄/ν΄ μνκΉμ§ λκ³ μ¨μ μνλ₯Ό 컀λ°νλ€."""
sid = await pocket_service.open(card_id, engine.state)
line = first_line
while True:
turn = await pocket_service.run_turn(sid, line)
print(f"\n {BOLD}μΉ΄λ₯΄λ°λΌ{RESET}: {turn.reply}")
if turn.converged:
print(f"{DIM} (μ₯λ©΄μ΄ μ‘°μ©ν λ€μμΌλ‘ κΈ°μ΄λ€ β {turn.reason}){RESET}")
break
line = input("λ(λ‘λΌ) > ").strip()
if not line:
break
log = await pocket_service.close(sid, engine.state)
return log
def pick_or_chat(step: StepResult, policy: str, chat_enabled: bool):
"""μ νμ§ μ
λ ₯ λλ μμ ν
μ€νΈ(ν¬μΌ μ±ν
μ§μ
). λ°ν: ('choice', idx) | ('chat', text)."""
choices = step.choices
if policy != "ask":
for i, ch in enumerate(choices):
if ch.axis == policy:
return "choice", i
for i, ch in enumerate(choices):
if ch.axis in (None, "neutral"):
return "choice", i
return "choice", 0
for i, ch in enumerate(choices):
print(f" [{i + 1}] {ch.label}")
if chat_enabled:
print(f"{DIM} (λ²νΈ λμ νκ³ μΆμ λ§μ μ°λ©΄ μΉ΄λ₯΄λ°λΌμ λνν©λλ€){RESET}")
while True:
raw = input("μ ν > ").strip()
if raw.isdigit() and 1 <= int(raw) <= len(choices):
return "choice", int(raw) - 1
if raw and chat_enabled:
return "chat", raw
if raw and not chat_enabled:
print(f"{DIM} (ν¬μΌ μ±ν
κΊΌμ§ β λ²νΈλ₯Ό μ
λ ₯νμΈμ){RESET}")
async def main():
ap = argparse.ArgumentParser()
ap.add_argument("--policy", default="ask", choices=["ask", "trust", "doubt", "neutral"])
ap.add_argument("--quiet", action="store_true")
ap.add_argument("--content", default="content")
ap.add_argument("--chat", action="store_true", help="ν¬μΌ μμ μ±ν
κ°μ νμ±ν")
ap.add_argument("--no-chat", action="store_true", help="ν¬μΌ μμ μ±ν
λΉνμ±ν")
args = ap.parse_args()
chat_enabled = not args.no_chat and (args.chat or bool(os.environ.get("OPENAI_API_KEY")))
repo = ContentRepository(args.content)
engine = StoryEngine(repo)
pocket_service = None
if chat_enabled:
from engine.plugins.logging import TurnLoggingPlugin
from engine.services.pocket import PocketService
pocket_service = PocketService(repo, plugins=[TurnLoggingPlugin()])
step = engine.start()
while step.ending is None:
render(step, args.quiet)
if step.choices:
while True:
kind, val = pick_or_chat(step, args.policy, chat_enabled)
if kind == "choice":
choice, step = engine.choose(val)
if not args.quiet:
print(f"\n{DIM}β· {choice.label}{RESET}")
if choice.result:
print(choice.result)
break
card = repo.get_card(engine.current_id)
if not card.can_chat:
print(f"{DIM} (μ΄ μ₯λ©΄μμ κ·Έλ
κ° μ리μ μλ€ β λ²νΈλ₯Ό μ
λ ₯νμΈμ){RESET}")
continue
await pocket_chat(pocket_service, engine, engine.current_id, val)
# μ±ν
ν κ°μ μΉ΄λμ μ νμ§λ‘ λ³΅κ· (λλ¬μ Β·λΆκΈ°λ μ½λκ° λ³΄μ₯)
else:
if not args.quiet and args.policy == "ask":
input(f"{DIM}(λ€μ β){RESET}")
step = engine.advance()
s = engine.state
print(f"\n{BOLD}βββ μ±ν° μ’
λ£: {step.ending.label} βββ{RESET}")
print(f"{DIM}[λλ²κ·Έ β μ μ λΉλ
ΈμΆ] trust={s.trust_score} doubt={s.doubt_score} "
f"frailty={s.frailty} level={s.trust_level} μΉ΄λ {len(engine.visited)}μ₯ λ°©λ¬Έ{RESET}")
if __name__ == "__main__":
asyncio.run(main())
|