doum_cli/llm/
prompt.rs

1use crate::system::SystemInfo;
2use handlebars::Handlebars;
3use rust_embed::RustEmbed;
4use serde_json::json;
5
6/// 프롬프트 정적 파일 임베딩
7#[derive(RustEmbed)]
8#[folder = "static/prompts/"]
9struct PromptAssets;
10
11/// 프롬프트 빌더
12pub struct PromptBuilder {
13    system_info: SystemInfo,
14    handlebars: Handlebars<'static>,
15}
16
17impl PromptBuilder {
18    /// 새 프롬프트 빌더 생성
19    pub fn new(system_info: SystemInfo) -> Self {
20        Self {
21            system_info,
22            handlebars: Handlebars::new(),
23        }
24    }
25
26    /// 프롬프트 파일 로드
27    fn load_prompt(name: &str) -> String {
28        PromptAssets::get(name)
29            .and_then(|file| {
30                std::str::from_utf8(file.data.as_ref())
31                    .ok()
32                    .map(|s| s.to_string())
33            })
34            .unwrap_or_else(|| {
35                eprintln!("Warning: Failed to load prompt file: {}", name);
36                tracing::warn!("Failed to load prompt file: {}", name);
37                String::new()
38            })
39    }
40
41    /// 시스템 프롬프트 생성
42    fn build_common_prompt(&self) -> String {
43        let template = Self::load_prompt("common.md");
44
45        let data = json!({
46            "os": self.system_info.os.as_str(),
47            "shell": self.system_info.shell.as_str(),
48            "current_dir": self.system_info.current_dir.display().to_string(),
49            "username": self.system_info.username.as_deref().unwrap_or("unknown"),
50            "hostname": self.system_info.hostname.as_deref().unwrap_or("unknown"),
51        });
52
53        self.handlebars
54            .render_template(&template, &data)
55            .unwrap_or(template)
56    }
57
58    /// Ask 모드용 메시지 배열 생성
59    pub fn build_ask(&self) -> String {
60        let common_prompt = self.build_common_prompt();
61        let ask_template = Self::load_prompt("ask.md");
62
63        let prompt = format!("{}\n\n---\n\n{}", common_prompt, ask_template);
64        prompt
65    }
66
67    /// Suggest 모드용 메시지 배열 생성
68    pub fn build_suggest(&self) -> String {
69        let common_prompt = self.build_common_prompt();
70        let suggest_template = Self::load_prompt("suggest.md");
71
72        let data = json!({
73            "os": self.system_info.os.as_str(),
74            "shell": self.system_info.shell.as_str(),
75        });
76
77        let suggest_prompt = self
78            .handlebars
79            .render_template(&suggest_template, &data)
80            .unwrap_or(suggest_template);
81
82        let prompt = format!("{}\n\n---\n\n{}", common_prompt, suggest_prompt);
83        prompt
84    }
85
86    /// 모드 선택용 메시지 배열 생성
87    pub fn build_mode_select(&self) -> String {
88        let common_prompt = self.build_common_prompt();
89        let mode_select_template = Self::load_prompt("mode_select.md");
90
91        let prompt = format!("{}\n\n---\n\n{}", common_prompt, mode_select_template);
92        prompt
93    }
94}