from langgraph.graph import StateGraph, START
from langchain_ollama import ChatOllama
from langgraph.types import Send
from typing_extensions import TypedDict
from typing import Annotated
from pydantic import BaseModel,Field
import operator
class Section(BaseModel):
num: int = Field(description="章节序号")
name:str=Field(description="章节标题,采用“【第三章】 迷雾重现”的形式")
description:str=Field(description="章节描述,最前面是章节标题,后面是章节内容。章节标题采用“【第三章】 迷雾重现”的形式,单独一行")
class Sections(BaseModel):
sections: list[Section] = Field(description="文章的各个子章节")
class State(TypedDict):
storyLine:str
sections:list[Section]
completedSections:Annotated[list,operator.add]
novel:str
class WorkerState(TypedDict):
section:Section
completedSections:Annotated[list,operator.add]
llm = ChatOllama(model="qwen2.5:7b")
def getWholeStory(state):
prompt = "你是一位著名小说家,正在创作一部精彩的侦探小说,首先给出故事梗概,1000字左右。"
state["storyLine"] = llm.invoke(prompt).content
print("storyLine " + "*" * 80)
print(state["storyLine"])
return state
def orchestrate(state):
planner = llm.with_structured_output(Sections)
result = planner.invoke("""你是一位著名小说家,正在创作一部精彩的侦探小说,根据下面的【故事梗概】,将小说分成10个章节,并给出章节的剧情发展。1000字左右。
【故事梗概】
"""+state["storyLine"])
state["sections"] = result.sections
print("sections " + "*" * 80)
for section in state["sections"]:
print(str(section.name+' '+section.description))
return state
def work(state:WorkerState):
prompt = """你是一位著名小说家,正在创作一部精彩的侦探小说,根据下面提供的【章节标题】和【章节概述】,完成其中的一个章节,最前面是章节标题,后面是章节内容。章节标题采用“【第三章】 迷雾重现”的形式,单独一行。章节的序号为"""+str(state["section"].num)+""",本章节长度1500字左右
【章节标题】
"""+state["section"].name+"""
【章节概述】
"""+state["section"].description
result = llm.invoke(prompt)
return {"num":state["section"].num,"name":state["section"].name,"description":state["section"].description,"completedSections":[{"num":state["section"].num,"content":result.content}]}
def synthesizer(state):
completedSections = sorted(state["completedSections"],key=lambda completeSection:completeSection["num"])
novel = "\n\n".join([completeSection["content"] for completeSection in completedSections])
state["novel"] = novel
return state
def assignWorkers(state:State):
return [Send("work",{"section":s}) for s in state["sections"]]
def buildGraph():
graphBuilder = StateGraph(State)
graphBuilder.add_node("getWholeStory", getWholeStory)
graphBuilder.add_node("orchestrate", orchestrate)
graphBuilder.add_node("work", work)
graphBuilder.add_node("synthesizer", synthesizer)
graphBuilder.add_edge(START, "getWholeStory")
graphBuilder.add_edge("getWholeStory", "orchestrate")
graphBuilder.add_conditional_edges("orchestrate",assignWorkers,["work"])
graphBuilder.add_edge("work", "synthesizer")
graph = graphBuilder.compile()
return graph
if __name__ == "__main__":
graph = buildGraph()
from courseCode import showGraph
showGraph.showGraphInCode(graph, "graph.jpg")
state: State = {}
result = graph.invoke(state)
print("final " + "*" * 80)
print(result["novel"])