use std::sync::OnceLock; use serde::Deserialize; const ANCHOR_TEMPLATE_CONFIG: &str = include_str!("creation_agent_anchor_templates.json"); #[derive(Clone, Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub(crate) struct CreationAgentAnchorTemplateConfig { templates: Vec, } #[derive(Clone, Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub(crate) struct CreationAgentAnchorTemplate { pub template_id: String, pub display_name: String, pub creation_goal: String, pub anchor_questions: Vec, } #[derive(Clone, Debug, Deserialize)] #[serde(rename_all = "camelCase")] pub(crate) struct CreationAgentAnchorQuestion { pub key: String, pub label: String, pub question: String, pub required_effect: String, } static ANCHOR_TEMPLATES: OnceLock = OnceLock::new(); pub(crate) fn get_creation_agent_anchor_template( template_id: &str, ) -> Option<&'static CreationAgentAnchorTemplate> { load_creation_agent_anchor_templates() .templates .iter() .find(|template| template.template_id == template_id) } pub(crate) fn render_anchor_question_block(template: &CreationAgentAnchorTemplate) -> String { let mut lines = vec![ format!("模板目标:{}", template.creation_goal), "".to_string(), ]; lines.push("本模板只通过以下锚点问题体现差异:".to_string()); for (index, question) in template.anchor_questions.iter().enumerate() { lines.push(format!( "{}. {}({} / {}):{};达成效果:{}", index + 1, question.label, question.key, template.display_name, question.question, question.required_effect )); } lines.join("\n") } fn load_creation_agent_anchor_templates() -> &'static CreationAgentAnchorTemplateConfig { ANCHOR_TEMPLATES.get_or_init(|| { serde_json::from_str(ANCHOR_TEMPLATE_CONFIG) .expect("creation_agent_anchor_templates.json 必须是合法配置") }) }