From acff9abc703ed8226e6c1b955485a58249aed39e Mon Sep 17 00:00:00 2001 From: lonpatovaadelina Date: Thu, 28 May 2026 15:50:09 +0000 Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?= =?UTF-8?q?=D0=BD=20solution.py?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- solution.py | 120 +++------------------------------------------------- 1 file changed, 5 insertions(+), 115 deletions(-) diff --git a/solution.py b/solution.py index 3f3413f..0c9bdf6 100644 --- a/solution.py +++ b/solution.py @@ -1,115 +1,5 @@ -from typing import TypedDict -import json - -import questionary -from langgraph.graph import StateGraph -from langgraph.constants import START -from langgraph.types import interrupt, Command -from langgraph.checkpoint.memory import InMemorySaver -from langchain_openai import ChatOpenAI -from rich.console import Console - - -# ────────────────────── Состояние графа ────────────────────── - -class State(TypedDict): - """Состояние графа.""" - story: str # Текст истории, генерируемый LLM - options: list[str] # Варианты действий - choice: str | None # Выбор пользователя - ending: str | None # Концовка - - -# ────────────────────── Инструмент LLM ────────────────────── - -llm = ChatOpenAI(model="gpt-4o-mini", temperature=0.7) -console = Console() - - -def generate_story(state: State) -> State: - """Генерирует начало истории и варианты действий.""" - prompt = ( - "Generate a short adventure intro and three choices in JSON format.\n" - "The JSON should have keys 'intro' (string) and 'choices' (list of strings)." - ) - response = llm.invoke({"messages": [{"role": "system", "content": prompt}]}).content - data = json.loads(response) - - state["story"] = data["intro"] - state["options"] = data["choices"] - - # Пауза для выбора игрока - return interrupt(state, { - "type": "choice", - "question": f"{state['story']}\nВыберите действие:", - "options": state["options"], - }) - - -def finish_story(state: State) -> State: - """Генерирует окончание истории на основе выбранного варианта.""" - prompt = ( - f"Write an ending for the story based on the choice '{state['choice']}'. " - "Keep it concise and satisfying." - ) - response = llm.invoke({"messages": [{"role": "system", "content": prompt}]}).content - state["ending"] = response - return state - - -# ────────────────────── Граф ────────────────────── - -builder = StateGraph(State) -builder.add_node("generate", generate_story) -builder.add_node("finish", finish_story) - -builder.set_entry_point("generate") -builder.add_edge(START, "generate") -builder.add_conditional_edges( - "generate", - lambda x: True if x.get("choice") else None, - {True: "finish"}, -) -builder.add_edge("finish", START) # цикл можно завершить здесь - -graph = builder.compile(checkpointer=InMemorySaver()) - - -# ────────────────────── Запуск и обработка прерываний ────────────────────── - -def main() -> None: - thread_id = "interactive_story" - - init_state: State = {"story": "", "options": [], "choice": None, "ending": None} - config = {"configurable": {"thread_id": thread_id}} - - # Запускаем поток генерации - stream = graph.stream(Command(resume=init_state), config=config) - - for chunk in stream: - if "__interrupt__" in chunk: - payload = chunk["__interrupt__"][0].value - answer = questionary.select( - payload["question"], - choices=payload["options"], - ).ask() - if answer is None: - raise RuntimeError("Пользователь отменил ввод.") - # Возобновляем граф с выбранным вариантом - stream = graph.stream(Command(resume={"choice": answer}), config=config) - continue - - # Выводим сообщения от LLM - if "story" in chunk and chunk["story"]: - console.print(f"[bold cyan]История:[/]\n{chunk['story']}") - if "ending" in chunk and chunk["ending"]: - console.print(f"\n[bold green]Концовка:[/]\n{chunk['ending']}") - - # После завершения выводим итоговую историю - final_state = graph.get_state(config=config) - full_story = f"{final_state['story']}\n\n{final_state['ending']}" - console.print("\n[bold magenta]Итоговая история:[/]\n" + full_story) - - -if __name__ == "__main__": - main() \ No newline at end of file +langgraph +langchain +langchain-openai +questionary +rich \ No newline at end of file