80 lines
2.1 KiB
Go
80 lines
2.1 KiB
Go
package app
|
||
|
||
import (
|
||
"fmt"
|
||
"path/filepath"
|
||
)
|
||
|
||
// Config 小说应用配置。
|
||
type Config struct {
|
||
Prompt string // 用户的小说需求
|
||
NovelName string // 小说名(用作输出目录名)
|
||
OutputDir string // 输出根目录,默认 output/{NovelName}
|
||
Provider string // LLM 提供商:openai / anthropic / gemini
|
||
ModelName string // LLM 模型名
|
||
APIKey string // API Key
|
||
BaseURL string // API Base URL(可选)
|
||
Style string // 写作风格(default/suspense/fantasy/romance)
|
||
ContextWindow int // 模型上下文窗口大小(token),默认 128000
|
||
}
|
||
|
||
// Prompts 嵌入的提示词。
|
||
type Prompts struct {
|
||
Coordinator string
|
||
ArchitectShort string
|
||
ArchitectMid string
|
||
ArchitectLong string
|
||
Writer string
|
||
Editor string
|
||
}
|
||
|
||
// Validate 校验配置(CLI 模式,要求 Prompt 非空)。
|
||
func (c *Config) Validate() error {
|
||
if c.Prompt == "" {
|
||
return fmt.Errorf("prompt is required")
|
||
}
|
||
return c.ValidateBase()
|
||
}
|
||
|
||
// ValidateBase 校验基础配置(TUI 模式下 Prompt 由用户输入,不在此检查)。
|
||
func (c *Config) ValidateBase() error {
|
||
if c.APIKey == "" {
|
||
return fmt.Errorf("api key is required (set OPENROUTER_API_KEY, Z_OPENAI_API_KEY, ANTHROPIC_API_KEY, or GEMINI_API_KEY)")
|
||
}
|
||
switch c.Provider {
|
||
case "openai", "anthropic", "gemini", "openrouter":
|
||
default:
|
||
return fmt.Errorf("unsupported provider %q (use openai/anthropic/gemini/openrouter)", c.Provider)
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// 各 provider 的默认模型名。
|
||
var defaultModels = map[string]string{
|
||
"openai": "gpt-4o",
|
||
"anthropic": "claude-sonnet-4-20250514",
|
||
"gemini": "gemini-2.5-pro",
|
||
}
|
||
|
||
// FillDefaults 填充默认值。
|
||
func (c *Config) FillDefaults() {
|
||
if c.NovelName == "" {
|
||
c.NovelName = "novel"
|
||
}
|
||
if c.OutputDir == "" {
|
||
c.OutputDir = filepath.Join("output", c.NovelName)
|
||
}
|
||
if c.Provider == "" {
|
||
c.Provider = "openai"
|
||
}
|
||
if c.ModelName == "" {
|
||
c.ModelName = defaultModels[c.Provider]
|
||
}
|
||
if c.Style == "" {
|
||
c.Style = "default"
|
||
}
|
||
if c.ContextWindow <= 0 {
|
||
c.ContextWindow = 128000
|
||
}
|
||
}
|