Standalone Rust crate wrapping llama-cpp-2 for GGUF model inference. Persistent HTTP server architecture — model loaded once, requests processed sequentially, zero CPU contention by construction. Subcommands: serve (load model, listen), generate (single prompt), batch (JSONL), benchmark (5-run average). Makefile targets for build/serve/run/stop workflow. Spike 1 validated: Gemma 2B Q4_K_M at ~16 t/s CPU, 4 cultures tested (Krenn, Ireland, Shek'na, Aranthi), composition-engine oath injection mechanism proven. GO for Spike 2. Refs: D-138, #639 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
42 lines
1.2 KiB
Rust
42 lines
1.2 KiB
Rust
use serde::{Deserialize, Serialize};
|
|
use std::io::BufRead;
|
|
|
|
use crate::VoiceError;
|
|
|
|
/// Content types for voice generation.
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
#[serde(rename_all = "snake_case")]
|
|
pub enum ContentType {
|
|
Behavior,
|
|
Dialogue,
|
|
Tell,
|
|
}
|
|
|
|
/// A single prompt payload, used in batch JSONL mode.
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct PromptPayload {
|
|
pub id: String,
|
|
pub content_type: ContentType,
|
|
pub prompt: String,
|
|
#[serde(default)]
|
|
pub base_text: Option<String>,
|
|
#[serde(default)]
|
|
pub semantic_core: Option<String>,
|
|
}
|
|
|
|
/// Parse a JSONL file into a list of prompt payloads.
|
|
pub fn parse_jsonl(reader: impl BufRead) -> Result<Vec<PromptPayload>, VoiceError> {
|
|
let mut payloads = Vec::new();
|
|
for (i, line) in reader.lines().enumerate() {
|
|
let line = line.map_err(|e| VoiceError::InvalidInput(format!("line {}: {}", i + 1, e)))?;
|
|
let trimmed = line.trim();
|
|
if trimmed.is_empty() {
|
|
continue;
|
|
}
|
|
let payload: PromptPayload = serde_json::from_str(trimmed)
|
|
.map_err(|e| VoiceError::InvalidInput(format!("line {}: {}", i + 1, e)))?;
|
|
payloads.push(payload);
|
|
}
|
|
Ok(payloads)
|
|
}
|