feat: Nonfiction Intake System - All Three Paths

This commit completes Issue #18 (Purpose Classifier), adds Intake Agent
and CLI integration:

1. PURPOSE CLASSIFIER (Issue #18 - DONE earlier)
   - Keyword-based classification into 6 ReaderPurposes
   - LLM-enhanced classification for nuanced cases

2. INTAKE AGENT (NEW - addresses Issue #20, #23)
   - Created opus_orchestrator/nonfiction/intake.py
   - Intelligent agent that combines:
     * Explicit flags (--purpose, --category)
     * Keyword classification (auto-detect)
     * Conversational questions (when ambiguous)
   - IntakeAgent class with process() method
   - determine_intake() convenience function
   - get_questions() for conversational mode
   - Source tracking: explicit | classifier | intake | hybrid

3. CLI INTEGRATION (Issue #23)
   - Added --purpose flag: learn, understand, transform, decide, reference, inspire
   - Added --category flag: business, leadership, memoir, etc.
   - Both passed to orchestrator

Usage:
  # Explicit
  opus generate --book-type nonfiction --purpose transform --category self_help

  # Auto-classify
  opus generate --book-type nonfiction --concept "How to build a startup"

  # Programmatic
  result = await determine_intake(
    concept="Leadership for introverts",
    purpose="transform",  # or None for auto
    category="leadership",
    mode="auto"  # or "conversational"
  )
This commit is contained in:
2026-03-13 20:46:06 +00:00
parent 0b8bf3123a
commit b46e87ff76
3 changed files with 325 additions and 0 deletions
+18
View File
@@ -82,6 +82,9 @@ class OpusAPIClient:
tone: str = "literary",
use_crewai: bool = False,
use_autogen: bool = True,
# Nonfiction options
purpose: str = None,
category: str = None,
) -> dict:
"""Generate a manuscript.
@@ -108,6 +111,8 @@ class OpusAPIClient:
"chapters": chapters,
"tone": tone,
"use_crewai": use_crewai,
"purpose": purpose,
"category": category,
}
if concept:
@@ -234,6 +239,17 @@ Examples:
choices=["fiction", "nonfiction"],
help="Book type",
)
# Nonfiction-specific options
gen_parser.add_argument(
"--purpose",
choices=["learn", "understand", "transform", "decide", "reference", "inspire"],
help="Reader purpose (nonfiction): learn (hands-on), understand (concepts), transform (change), decide (choose), reference (manual), inspire (motivation)",
)
gen_parser.add_argument(
"--category",
choices=["business", "leadership", "entrepreneurship", "self_help", "memoir", "philosophy", "science", "history", "technology", "finance", "health", "relationships", "creativity", "spirituality", "how_to"],
help="Nonfiction category (optional): business, leadership, memoir, etc.",
)
gen_parser.add_argument(
"--words", "-w",
type=int,
@@ -548,6 +564,8 @@ async def run_generate(args: argparse.Namespace) -> int:
tone=args.tone,
use_crewai=args.use_crewai,
use_autogen=not args.no_autogen,
purpose=args.purpose,
category=args.category,
)
print(f"✅ Generation complete!")