This commit is contained in:
voocel
2026-03-07 21:25:55 +08:00
commit 27bd85ef90
60 changed files with 5658 additions and 0 deletions

77
state/outline.go Normal file
View File

@@ -0,0 +1,77 @@
package state
import (
"fmt"
"os"
"strings"
"github.com/voocel/ainovel-cli/domain"
)
// SavePremise 保存故事前提到 premise.md。
func (s *Store) SavePremise(content string) error {
return s.writeMarkdown("premise.md", content)
}
// LoadPremise 读取 premise.md。不存在时返回空字符串。
func (s *Store) LoadPremise() (string, error) {
data, err := s.readFile("premise.md")
if os.IsNotExist(err) {
return "", nil
}
return string(data), err
}
// SaveOutline 同时保存 outline.json机器读和 outline.md人读
func (s *Store) SaveOutline(entries []domain.OutlineEntry) error {
if err := s.writeJSON("outline.json", entries); err != nil {
return err
}
return s.writeMarkdown("outline.md", renderOutline(entries))
}
// LoadOutline 从 outline.json 读取结构化大纲。
func (s *Store) LoadOutline() ([]domain.OutlineEntry, error) {
var entries []domain.OutlineEntry
if err := s.readJSON("outline.json", &entries); err != nil {
if os.IsNotExist(err) {
return nil, nil
}
return nil, err
}
return entries, nil
}
// GetChapterOutline 获取指定章节的大纲条目。
func (s *Store) GetChapterOutline(chapter int) (*domain.OutlineEntry, error) {
entries, err := s.LoadOutline()
if err != nil {
return nil, err
}
for i := range entries {
if entries[i].Chapter == chapter {
return &entries[i], nil
}
}
return nil, fmt.Errorf("chapter %d not found in outline", chapter)
}
func renderOutline(entries []domain.OutlineEntry) string {
var b strings.Builder
b.WriteString("# 大纲\n\n")
for _, e := range entries {
fmt.Fprintf(&b, "## 第 %d 章:%s\n\n", e.Chapter, e.Title)
fmt.Fprintf(&b, "**核心事件**%s\n\n", e.CoreEvent)
if e.Hook != "" {
fmt.Fprintf(&b, "**钩子**%s\n\n", e.Hook)
}
if len(e.Scenes) > 0 {
b.WriteString("**场景**\n")
for i, sc := range e.Scenes {
fmt.Fprintf(&b, "%d. %s\n", i+1, sc)
}
b.WriteString("\n")
}
}
return b.String()
}