1use chrono::{DateTime, Utc};
11use std::collections::HashMap;
12use tokio::sync::mpsc;
13
14use super::blueprint_manager::BlueprintManager;
15use super::types::{
16 Blueprint, BusinessProcess, ModuleType, MoscowPriority, NfrCategory, NonFunctionalRequirement,
17 ProcessStep, ProcessType, SystemModule,
18};
19
20#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
26pub enum DialogPhase {
27 #[default]
28 Welcome,
29 ProjectBackground,
30 BusinessProcess,
31 SystemModule,
32 NFR,
33 Summary,
34 Complete,
35}
36
37#[derive(Debug, Clone)]
39pub struct DialogState {
40 pub id: String,
41 pub phase: DialogPhase,
42 pub project_name: String,
43 pub project_description: String,
44 pub target_users: Vec<String>,
45 pub problems_to_solve: Vec<String>,
46 pub business_processes: Vec<BusinessProcessDraft>,
47 pub modules: Vec<SystemModuleDraft>,
48 pub nfrs: Vec<NFRDraft>,
49 pub history: Vec<DialogMessage>,
50 pub created_at: DateTime<Utc>,
51 pub updated_at: DateTime<Utc>,
52}
53
54impl Default for DialogState {
55 fn default() -> Self {
56 Self {
57 id: uuid::Uuid::new_v4().to_string(),
58 phase: DialogPhase::Welcome,
59 project_name: String::new(),
60 project_description: String::new(),
61 target_users: vec![],
62 problems_to_solve: vec![],
63 business_processes: vec![],
64 modules: vec![],
65 nfrs: vec![],
66 history: vec![],
67 created_at: Utc::now(),
68 updated_at: Utc::now(),
69 }
70 }
71}
72
73#[derive(Debug, Clone)]
75pub struct DialogMessage {
76 pub id: String,
77 pub role: MessageRole,
78 pub content: String,
79 pub timestamp: DateTime<Utc>,
80 pub phase: DialogPhase,
81}
82
83#[derive(Debug, Clone, Copy, PartialEq, Eq)]
85pub enum MessageRole {
86 Assistant,
87 User,
88}
89
90#[derive(Debug, Clone)]
92pub struct BusinessProcessDraft {
93 pub name: String,
94 pub description: String,
95 pub process_type: ProcessDraftType,
96 pub steps: Vec<String>,
97}
98
99#[derive(Debug, Clone, Copy, PartialEq, Eq)]
101pub enum ProcessDraftType {
102 Core,
103 Support,
104 Management,
105}
106
107#[derive(Debug, Clone)]
109pub struct SystemModuleDraft {
110 pub name: String,
111 pub description: String,
112 pub module_type: ModuleDraftType,
113 pub responsibilities: Vec<String>,
114 pub tech_stack: Vec<String>,
115 pub dependencies: Vec<String>,
116}
117
118#[derive(Debug, Clone, Copy, PartialEq, Eq)]
120pub enum ModuleDraftType {
121 Frontend,
122 Backend,
123 Database,
124 Service,
125 Infrastructure,
126}
127
128impl From<ModuleDraftType> for ModuleType {
129 fn from(t: ModuleDraftType) -> Self {
130 match t {
131 ModuleDraftType::Frontend => ModuleType::Frontend,
132 ModuleDraftType::Backend => ModuleType::Backend,
133 ModuleDraftType::Database => ModuleType::Database,
134 ModuleDraftType::Service => ModuleType::Service,
135 ModuleDraftType::Infrastructure => ModuleType::Infrastructure,
136 }
137 }
138}
139
140#[derive(Debug, Clone)]
142pub struct NFRDraft {
143 pub category: NFRDraftCategory,
144 pub name: String,
145 pub description: String,
146 pub priority: NFRDraftPriority,
147 pub metrics: Option<String>,
148}
149
150#[derive(Debug, Clone, Copy, PartialEq, Eq)]
152pub enum NFRDraftCategory {
153 Performance,
154 Security,
155 Availability,
156 Scalability,
157 Usability,
158 Maintainability,
159 Other,
160}
161
162impl From<NFRDraftCategory> for NfrCategory {
163 fn from(c: NFRDraftCategory) -> Self {
164 match c {
165 NFRDraftCategory::Performance => NfrCategory::Performance,
166 NFRDraftCategory::Security => NfrCategory::Security,
167 NFRDraftCategory::Availability => NfrCategory::Availability,
168 NFRDraftCategory::Scalability => NfrCategory::Scalability,
169 NFRDraftCategory::Usability => NfrCategory::Usability,
170 NFRDraftCategory::Maintainability => NfrCategory::Maintainability,
171 NFRDraftCategory::Other => NfrCategory::Other,
172 }
173 }
174}
175
176#[derive(Debug, Clone, Copy, PartialEq, Eq)]
178pub enum NFRDraftPriority {
179 Must,
180 Should,
181 Could,
182}
183
184impl From<NFRDraftPriority> for MoscowPriority {
185 fn from(p: NFRDraftPriority) -> Self {
186 match p {
187 NFRDraftPriority::Must => MoscowPriority::Must,
188 NFRDraftPriority::Should => MoscowPriority::Should,
189 NFRDraftPriority::Could => MoscowPriority::Could,
190 }
191 }
192}
193
194#[derive(Debug, Clone)]
196pub enum DialogEvent {
197 Started {
198 session_id: String,
199 },
200 Message {
201 session_id: String,
202 message: DialogMessage,
203 },
204 PhaseChanged {
205 session_id: String,
206 phase: DialogPhase,
207 },
208 Ended {
209 session_id: String,
210 },
211}
212
213fn get_phase_prompt(phase: DialogPhase) -> &'static str {
219 match phase {
220 DialogPhase::Welcome => {
221 r#"你好!我是你的项目需求分析助手。
222
223在开始构建项目蓝图之前,我需要了解一些关于你项目的信息。这个过程分为几个步骤:
224
2251. **项目背景** - 了解你的目标用户和要解决的问题
2262. **核心流程** - 梳理主要的业务流程
2273. **系统模块** - 确定需要的功能模块
2284. **非功能要求** - 讨论性能、安全等要求
2295. **确认汇总** - 生成蓝图草案供你确认
230
231让我们开始吧!首先,请告诉我:
232
233**你的项目叫什么名字?想要解决什么问题?**"#
234 }
235
236 DialogPhase::ProjectBackground => {
237 r#"很好!现在让我更深入地了解你的项目背景。
238
239请回答以下问题:
240
2411. **目标用户是谁?** (例如:企业员工、普通消费者、开发者...)
2422. **他们目前面临什么痛点?**
2433. **你的解决方案有什么独特之处?**
2444. **项目的预期规模是怎样的?** (用户量、数据量等)
245
246你可以一次回答所有问题,也可以逐个回答。"#
247 }
248
249 DialogPhase::BusinessProcess => {
250 r#"太棒了!现在让我们来梳理业务流程。
251
252一个好的业务流程设计能帮助我们更清晰地理解系统需求。请思考:
253
2541. **核心业务流程** - 用户完成主要任务的步骤
2552. **支撑流程** - 支持核心业务的辅助流程
2563. **管理流程** - 后台管理相关的流程
257
258请描述你项目的主要业务流程,包括:
259- 流程名称
260- 流程类型(核心/支撑/管理)
261- 主要步骤"#
262 }
263
264 DialogPhase::SystemModule => {
265 r#"非常好!现在让我们来划分系统模块。
266
267每个模块需要包含:
268- 模块名称
269- 模块类型(前端/后端/数据库/服务/基础设施)
270- 主要职责
271- 技术栈建议
272- 依赖关系
273
274请告诉我:
2751. 你认为需要哪些模块?
2762. 你对技术栈有什么偏好?"#
277 }
278
279 DialogPhase::NFR => {
280 r#"模块设计很清晰!现在让我们讨论非功能性要求。
281
282非功能性要求包括:
283
2841. **性能** - 响应时间、吞吐量、并发数
2852. **安全** - 认证、授权、数据加密
2863. **可用性** - 系统可用时间、故障恢复
2874. **可扩展性** - 水平扩展、垂直扩展
2885. **可维护性** - 代码质量、文档、监控
289
290请告诉我你对这些方面的要求。"#
291 }
292
293 DialogPhase::Summary => {
294 r#"太棒了!我已经收集了所有需求信息。
295
296请仔细检查并确认蓝图草案。
297
298你可以:
2991. **确认** - 蓝图没问题,可以进入下一步
3002. **修改** - 告诉我需要修改的内容
3013. **重来** - 重新开始需求收集
302
303请输入"确认"、"修改 [内容]"或"重来"。"#
304 }
305
306 DialogPhase::Complete => {
307 r#"蓝图已创建完成!
308
309你可以:
3101. 查看完整蓝图
3112. 提交审核
3123. 确认签字后开始执行
313
314祝你的项目顺利!"#
315 }
316 }
317}
318
319pub struct RequirementDialogManager {
325 sessions: HashMap<String, DialogState>,
326 event_sender: Option<mpsc::Sender<DialogEvent>>,
327}
328
329impl Default for RequirementDialogManager {
330 fn default() -> Self {
331 Self::new()
332 }
333}
334
335impl RequirementDialogManager {
336 pub fn new() -> Self {
338 Self {
339 sessions: HashMap::new(),
340 event_sender: None,
341 }
342 }
343
344 #[allow(dead_code)]
346 pub fn with_event_sender(mut self, sender: mpsc::Sender<DialogEvent>) -> Self {
347 self.event_sender = Some(sender);
348 self
349 }
350
351 async fn emit(&self, event: DialogEvent) {
353 if let Some(ref sender) = self.event_sender {
354 let _ = sender.send(event).await;
355 }
356 }
357
358 pub async fn start_dialog(&mut self) -> DialogState {
360 let mut state = DialogState::default();
361
362 state.history.push(DialogMessage {
364 id: uuid::Uuid::new_v4().to_string(),
365 role: MessageRole::Assistant,
366 content: get_phase_prompt(DialogPhase::Welcome).to_string(),
367 timestamp: Utc::now(),
368 phase: DialogPhase::Welcome,
369 });
370
371 self.sessions.insert(state.id.clone(), state.clone());
372 self.emit(DialogEvent::Started {
373 session_id: state.id.clone(),
374 })
375 .await;
376
377 state
378 }
379
380 pub async fn process_user_input(
382 &mut self,
383 session_id: &str,
384 input: &str,
385 ) -> Result<DialogMessage, String> {
386 let (current_phase, mut state_clone) = {
388 let state = self
389 .sessions
390 .get(session_id)
391 .ok_or_else(|| format!("对话会话 {} 不存在", session_id))?;
392 (state.phase, state.clone())
393 };
394
395 let user_message = DialogMessage {
397 id: uuid::Uuid::new_v4().to_string(),
398 role: MessageRole::User,
399 content: input.to_string(),
400 timestamp: Utc::now(),
401 phase: current_phase,
402 };
403 state_clone.history.push(user_message.clone());
404 state_clone.updated_at = Utc::now();
405
406 let (response, next_phase) = match current_phase {
408 DialogPhase::Welcome => {
409 Self::process_welcome_input_static(&mut state_clone, input);
410 (
411 Self::format_welcome_response_static(&state_clone),
412 DialogPhase::ProjectBackground,
413 )
414 }
415 DialogPhase::ProjectBackground => {
416 Self::process_background_input_static(&mut state_clone, input);
417 (
418 Self::format_background_response_static(&state_clone),
419 DialogPhase::BusinessProcess,
420 )
421 }
422 DialogPhase::BusinessProcess => {
423 Self::process_business_process_input_static(&mut state_clone, input);
424 (
425 Self::format_business_process_response_static(&state_clone),
426 DialogPhase::SystemModule,
427 )
428 }
429 DialogPhase::SystemModule => {
430 Self::process_module_input_static(&mut state_clone, input);
431 (
432 Self::format_module_response_static(&state_clone),
433 DialogPhase::NFR,
434 )
435 }
436 DialogPhase::NFR => {
437 Self::process_nfr_input_static(&mut state_clone, input);
438 let summary = Self::generate_summary_static(&state_clone);
439 (
440 format!("{}\n\n{}", summary, get_phase_prompt(DialogPhase::Summary)),
441 DialogPhase::Summary,
442 )
443 }
444 DialogPhase::Summary => Self::process_summary_input_static(&mut state_clone, input),
445 DialogPhase::Complete => ("对话已完成。".to_string(), DialogPhase::Complete),
446 };
447
448 state_clone.phase = next_phase;
450
451 let assistant_message = DialogMessage {
453 id: uuid::Uuid::new_v4().to_string(),
454 role: MessageRole::Assistant,
455 content: response,
456 timestamp: Utc::now(),
457 phase: state_clone.phase,
458 };
459 state_clone.history.push(assistant_message.clone());
460
461 self.sessions.insert(session_id.to_string(), state_clone);
463
464 self.emit(DialogEvent::Message {
465 session_id: session_id.to_string(),
466 message: assistant_message.clone(),
467 })
468 .await;
469
470 Ok(assistant_message)
471 }
472
473 fn process_welcome_input_static(state: &mut DialogState, input: &str) {
475 let first_line = input.lines().next().unwrap_or(input);
476 state.project_name = first_line.chars().take(50).collect();
477 state.project_description = input.to_string();
478 }
479
480 fn format_welcome_response_static(state: &DialogState) -> String {
482 format!(
483 "很好!我了解了:\n\n**项目名称**:{}\n**项目目标**:{}\n\n{}",
484 state.project_name,
485 state
486 .project_description
487 .chars()
488 .take(200)
489 .collect::<String>(),
490 get_phase_prompt(DialogPhase::ProjectBackground)
491 )
492 }
493
494 fn process_background_input_static(state: &mut DialogState, input: &str) {
496 for line in input.lines() {
497 let line_lower = line.to_lowercase();
498 if line_lower.contains("用户") || line_lower.contains("user") {
499 state.target_users.push(line.to_string());
500 }
501 if line_lower.contains("问题") || line_lower.contains("痛点") {
502 state.problems_to_solve.push(line.to_string());
503 }
504 }
505 if state.target_users.is_empty() && state.problems_to_solve.is_empty() {
506 state.project_description.push('\n');
507 state.project_description.push_str(input);
508 }
509 }
510
511 fn format_background_response_static(state: &DialogState) -> String {
513 format!(
514 "太棒了!我已经记录了这些背景信息:\n\n**目标用户**:{}\n**要解决的问题**:\n{}\n\n{}",
515 if state.target_users.is_empty() {
516 "待确定".to_string()
517 } else {
518 state.target_users.join("、")
519 },
520 if state.problems_to_solve.is_empty() {
521 "- 待确定".to_string()
522 } else {
523 state
524 .problems_to_solve
525 .iter()
526 .map(|p| format!("- {}", p))
527 .collect::<Vec<_>>()
528 .join("\n")
529 },
530 get_phase_prompt(DialogPhase::BusinessProcess)
531 )
532 }
533
534 fn process_business_process_input_static(state: &mut DialogState, input: &str) {
536 let mut current_process: Option<BusinessProcessDraft> = None;
537
538 for line in input.lines() {
539 let line = line.trim();
540 if line.is_empty() {
541 continue;
542 }
543
544 let process_type = if line.contains("核心") {
545 Some(ProcessDraftType::Core)
546 } else if line.contains("支撑") {
547 Some(ProcessDraftType::Support)
548 } else if line.contains("管理") {
549 Some(ProcessDraftType::Management)
550 } else {
551 None
552 };
553
554 if let Some(pt) = process_type {
555 if let Some(p) = current_process.take() {
556 state.business_processes.push(p);
557 }
558 current_process = Some(BusinessProcessDraft {
559 name: line.to_string(),
560 description: String::new(),
561 process_type: pt,
562 steps: vec![],
563 });
564 } else if let Some(ref mut p) = current_process {
565 if line.starts_with('-') || line.starts_with('•') || line.starts_with("步骤") {
566 p.steps
567 .push(line.trim_start_matches(['-', '•', ' ']).to_string());
568 } else {
569 p.description.push_str(line);
570 p.description.push(' ');
571 }
572 }
573 }
574
575 if let Some(p) = current_process {
576 state.business_processes.push(p);
577 }
578
579 if state.business_processes.is_empty() {
580 state.business_processes.push(BusinessProcessDraft {
581 name: "主要业务流程".to_string(),
582 description: input.to_string(),
583 process_type: ProcessDraftType::Core,
584 steps: input
585 .lines()
586 .filter(|l| !l.trim().is_empty())
587 .map(|l| l.to_string())
588 .collect(),
589 });
590 }
591 }
592
593 fn format_business_process_response_static(state: &DialogState) -> String {
595 let processes_str = state
596 .business_processes
597 .iter()
598 .map(|p| {
599 format!(
600 "- **{}** ({:?}): {} 个步骤",
601 p.name,
602 p.process_type,
603 p.steps.len()
604 )
605 })
606 .collect::<Vec<_>>()
607 .join("\n");
608
609 format!(
610 "我已记录以下业务流程:\n\n{}\n\n{}",
611 processes_str,
612 get_phase_prompt(DialogPhase::SystemModule)
613 )
614 }
615
616 fn process_module_input_static(state: &mut DialogState, input: &str) {
618 let mut current_module: Option<SystemModuleDraft> = None;
619
620 for line in input.lines() {
621 let line = line.trim();
622 if line.is_empty() {
623 continue;
624 }
625
626 let module_type = if line.contains("前端")
627 || line.contains("frontend")
628 || line.contains("UI")
629 {
630 Some(ModuleDraftType::Frontend)
631 } else if line.contains("后端") || line.contains("backend") || line.contains("API") {
632 Some(ModuleDraftType::Backend)
633 } else if line.contains("数据") || line.contains("database") || line.contains("存储")
634 {
635 Some(ModuleDraftType::Database)
636 } else if line.contains("服务") || line.contains("service") {
637 Some(ModuleDraftType::Service)
638 } else {
639 None
640 };
641
642 if let Some(mt) = module_type {
643 if let Some(m) = current_module.take() {
644 state.modules.push(m);
645 }
646 current_module = Some(SystemModuleDraft {
647 name: line.to_string(),
648 description: String::new(),
649 module_type: mt,
650 responsibilities: vec![],
651 tech_stack: vec![],
652 dependencies: vec![],
653 });
654 } else if let Some(ref mut m) = current_module {
655 if line.starts_with('-') || line.starts_with('•') {
656 m.responsibilities
657 .push(line.trim_start_matches(['-', '•', ' ']).to_string());
658 } else {
659 m.description.push_str(line);
660 m.description.push(' ');
661 }
662 }
663 }
664
665 if let Some(m) = current_module {
666 state.modules.push(m);
667 }
668
669 if state.modules.is_empty() {
670 state.modules.push(SystemModuleDraft {
671 name: "主模块".to_string(),
672 description: input.to_string(),
673 module_type: ModuleDraftType::Backend,
674 responsibilities: input
675 .lines()
676 .filter(|l| !l.trim().is_empty())
677 .map(|l| l.to_string())
678 .collect(),
679 tech_stack: vec![],
680 dependencies: vec![],
681 });
682 }
683 }
684
685 fn format_module_response_static(state: &DialogState) -> String {
687 let modules_str = state
688 .modules
689 .iter()
690 .map(|m| {
691 format!(
692 "- **{}** ({:?}): {} 项职责",
693 m.name,
694 m.module_type,
695 m.responsibilities.len()
696 )
697 })
698 .collect::<Vec<_>>()
699 .join("\n");
700
701 format!(
702 "我已记录以下系统模块:\n\n{}\n\n{}",
703 modules_str,
704 get_phase_prompt(DialogPhase::NFR)
705 )
706 }
707
708 fn process_nfr_input_static(state: &mut DialogState, input: &str) {
710 for line in input.lines() {
711 let line = line.trim();
712 if line.is_empty() {
713 continue;
714 }
715
716 let category = if line.contains("性能") || line.contains("performance") {
717 NFRDraftCategory::Performance
718 } else if line.contains("安全") || line.contains("security") {
719 NFRDraftCategory::Security
720 } else if line.contains("可用") || line.contains("availability") {
721 NFRDraftCategory::Availability
722 } else if line.contains("可维护") || line.contains("maintainability") {
723 NFRDraftCategory::Maintainability
724 } else {
725 NFRDraftCategory::Other
726 };
727
728 state.nfrs.push(NFRDraft {
729 name: line.to_string(),
730 description: line.to_string(),
731 category,
732 priority: NFRDraftPriority::Should,
733 metrics: None,
734 });
735 }
736
737 if state.nfrs.is_empty() {
738 state.nfrs.push(NFRDraft {
739 name: "基本可用性".to_string(),
740 description: "系统应保持基本可用".to_string(),
741 category: NFRDraftCategory::Availability,
742 priority: NFRDraftPriority::Must,
743 metrics: None,
744 });
745 }
746 }
747
748 fn generate_summary_static(state: &DialogState) -> String {
750 let mut summary = String::new();
751 summary.push_str(&format!("# 蓝图摘要:{}\n\n", state.project_name));
752 summary.push_str(&format!("## 项目描述\n{}\n\n", state.project_description));
753
754 summary.push_str("## 业务流程\n");
755 for p in &state.business_processes {
756 summary.push_str(&format!("- **{}** ({:?})\n", p.name, p.process_type));
757 for step in &p.steps {
758 summary.push_str(&format!(" - {}\n", step));
759 }
760 }
761 summary.push('\n');
762
763 summary.push_str("## 系统模块\n");
764 for m in &state.modules {
765 summary.push_str(&format!("- **{}** ({:?})\n", m.name, m.module_type));
766 for r in &m.responsibilities {
767 summary.push_str(&format!(" - {}\n", r));
768 }
769 }
770 summary.push('\n');
771
772 summary.push_str("## 非功能性要求\n");
773 for n in &state.nfrs {
774 summary.push_str(&format!(
775 "- **{}** ({:?}, {:?})\n",
776 n.name, n.category, n.priority
777 ));
778 }
779
780 summary
781 }
782
783 fn process_summary_input_static(
785 _state: &mut DialogState,
786 input: &str,
787 ) -> (String, DialogPhase) {
788 let input_lower = input.to_lowercase();
789 if input_lower.contains("确认")
790 || input_lower.contains("ok")
791 || input_lower.contains("好")
792 || input_lower.contains("yes")
793 {
794 (
795 "太好了!蓝图已确认。现在可以生成正式蓝图了。".to_string(),
796 DialogPhase::Complete,
797 )
798 } else if input_lower.contains("修改") || input_lower.contains("改") {
799 (
800 "好的,请告诉我需要修改的内容。".to_string(),
801 DialogPhase::Summary,
802 )
803 } else {
804 (
805 "请确认蓝图内容是否正确,或告诉我需要修改的地方。".to_string(),
806 DialogPhase::Summary,
807 )
808 }
809 }
810
811 #[allow(dead_code)]
813 fn process_welcome_input(&self, state: &mut DialogState, input: &str) {
814 Self::process_welcome_input_static(state, input);
815 }
816
817 #[allow(dead_code)]
819 fn format_welcome_response(&self, state: &DialogState) -> String {
820 Self::format_welcome_response_static(state)
821 }
822
823 #[allow(dead_code)]
825 fn process_background_input(&self, state: &mut DialogState, input: &str) {
826 Self::process_background_input_static(state, input);
827 }
828
829 #[allow(dead_code)]
831 fn format_background_response(&self, state: &DialogState) -> String {
832 Self::format_background_response_static(state)
833 }
834
835 #[allow(dead_code)]
837 fn process_business_process_input(&self, state: &mut DialogState, input: &str) {
838 Self::process_business_process_input_static(state, input);
839 }
840
841 #[allow(dead_code)]
843 fn format_business_process_response(&self, state: &DialogState) -> String {
844 Self::format_business_process_response_static(state)
845 }
846
847 #[allow(dead_code)]
849 fn process_module_input(&self, state: &mut DialogState, input: &str) {
850 if state.modules.is_empty() {
852 state.modules = self.suggest_modules(state);
853 }
854 Self::process_module_input_static(state, input);
855 }
856
857 #[allow(dead_code)]
859 fn format_module_response(&self, state: &DialogState) -> String {
860 Self::format_module_response_static(state)
861 }
862
863 #[allow(dead_code)]
865 fn suggest_modules(&self, state: &DialogState) -> Vec<SystemModuleDraft> {
866 let mut modules = Vec::new();
867
868 let has_user_flow = state
870 .business_processes
871 .iter()
872 .any(|p| p.name.contains("用户") || p.name.contains("登录") || p.name.contains("注册"));
873
874 modules.push(SystemModuleDraft {
876 name: "前端应用".to_string(),
877 description: "用户界面".to_string(),
878 module_type: ModuleDraftType::Frontend,
879 responsibilities: vec!["用户界面渲染".to_string(), "用户交互处理".to_string()],
880 tech_stack: vec!["React".to_string(), "TypeScript".to_string()],
881 dependencies: vec!["后端服务".to_string()],
882 });
883
884 modules.push(SystemModuleDraft {
886 name: "后端服务".to_string(),
887 description: "业务逻辑处理".to_string(),
888 module_type: ModuleDraftType::Backend,
889 responsibilities: vec!["API 接口".to_string(), "业务逻辑".to_string()],
890 tech_stack: vec!["Node.js".to_string(), "Express".to_string()],
891 dependencies: vec!["数据库".to_string()],
892 });
893
894 modules.push(SystemModuleDraft {
896 name: "数据库".to_string(),
897 description: "数据持久化".to_string(),
898 module_type: ModuleDraftType::Database,
899 responsibilities: vec!["数据存储".to_string(), "数据查询".to_string()],
900 tech_stack: vec!["PostgreSQL".to_string()],
901 dependencies: vec![],
902 });
903
904 if has_user_flow {
906 modules.push(SystemModuleDraft {
907 name: "认证服务".to_string(),
908 description: "用户认证和授权".to_string(),
909 module_type: ModuleDraftType::Service,
910 responsibilities: vec!["用户认证".to_string(), "权限管理".to_string()],
911 tech_stack: vec!["JWT".to_string()],
912 dependencies: vec!["数据库".to_string()],
913 });
914 }
915
916 modules
917 }
918
919 #[allow(dead_code)]
921 fn process_nfr_input(&self, state: &mut DialogState, input: &str) {
922 let input_lower = input.to_lowercase();
924
925 if input_lower.contains("性能")
927 || input_lower.contains("响应")
928 || input_lower.contains("ms")
929 {
930 state.nfrs.push(NFRDraft {
931 category: NFRDraftCategory::Performance,
932 name: "API 响应时间".to_string(),
933 description: "API 平均响应时间应控制在合理范围内".to_string(),
934 priority: NFRDraftPriority::Should,
935 metrics: Some("< 500ms".to_string()),
936 });
937 }
938
939 if input_lower.contains("安全")
941 || input_lower.contains("认证")
942 || input_lower.contains("加密")
943 {
944 state.nfrs.push(NFRDraft {
945 category: NFRDraftCategory::Security,
946 name: "用户认证".to_string(),
947 description: "实现安全的用户认证机制".to_string(),
948 priority: NFRDraftPriority::Must,
949 metrics: None,
950 });
951 }
952
953 if input_lower.contains("可用") || input_lower.contains("99") {
955 state.nfrs.push(NFRDraft {
956 category: NFRDraftCategory::Availability,
957 name: "系统可用性".to_string(),
958 description: "系统应保持高可用性".to_string(),
959 priority: NFRDraftPriority::Should,
960 metrics: Some("99.9%".to_string()),
961 });
962 }
963
964 if state.nfrs.is_empty() {
966 state.nfrs = self.get_default_nfrs();
967 }
968 }
969
970 #[allow(dead_code)]
972 fn get_default_nfrs(&self) -> Vec<NFRDraft> {
973 vec![
974 NFRDraft {
975 category: NFRDraftCategory::Performance,
976 name: "API 响应时间".to_string(),
977 description: "API 平均响应时间应控制在合理范围内".to_string(),
978 priority: NFRDraftPriority::Should,
979 metrics: Some("< 500ms".to_string()),
980 },
981 NFRDraft {
982 category: NFRDraftCategory::Security,
983 name: "用户认证".to_string(),
984 description: "实现安全的用户认证机制".to_string(),
985 priority: NFRDraftPriority::Must,
986 metrics: None,
987 },
988 NFRDraft {
989 category: NFRDraftCategory::Availability,
990 name: "系统可用性".to_string(),
991 description: "系统应保持高可用性".to_string(),
992 priority: NFRDraftPriority::Should,
993 metrics: Some("99.9%".to_string()),
994 },
995 ]
996 }
997
998 #[allow(dead_code)]
1000 fn generate_summary(&self, state: &DialogState) -> String {
1001 let processes_str = state
1002 .business_processes
1003 .iter()
1004 .map(|p| {
1005 let type_str = match p.process_type {
1006 ProcessDraftType::Core => "核心",
1007 ProcessDraftType::Support => "支撑",
1008 ProcessDraftType::Management => "管理",
1009 };
1010 format!("- **{}**({}):{}", p.name, type_str, p.steps.join(" → "))
1011 })
1012 .collect::<Vec<_>>()
1013 .join("\n");
1014
1015 let modules_str = state
1016 .modules
1017 .iter()
1018 .map(|m| {
1019 let type_str = match m.module_type {
1020 ModuleDraftType::Frontend => "前端",
1021 ModuleDraftType::Backend => "后端",
1022 ModuleDraftType::Database => "数据库",
1023 ModuleDraftType::Service => "服务",
1024 ModuleDraftType::Infrastructure => "基础设施",
1025 };
1026 format!(
1027 "- **{}**({}):{}",
1028 m.name,
1029 type_str,
1030 m.responsibilities.join("、")
1031 )
1032 })
1033 .collect::<Vec<_>>()
1034 .join("\n");
1035
1036 let nfrs_str = state
1037 .nfrs
1038 .iter()
1039 .map(|n| {
1040 let priority_str = match n.priority {
1041 NFRDraftPriority::Must => "MUST",
1042 NFRDraftPriority::Should => "SHOULD",
1043 NFRDraftPriority::Could => "COULD",
1044 };
1045 let metrics_str = n
1046 .metrics
1047 .as_ref()
1048 .map(|m| format!("({})", m))
1049 .unwrap_or_default();
1050 format!(
1051 "- [{}] {}:{}{}",
1052 priority_str, n.name, n.description, metrics_str
1053 )
1054 })
1055 .collect::<Vec<_>>()
1056 .join("\n");
1057
1058 format!(
1059 r#"# 蓝图草案:{}
1060
1061## 项目概述
1062{}
1063
1064**目标用户**:{}
1065
1066## 业务流程({} 个)
1067{}
1068
1069## 系统模块({} 个)
1070{}
1071
1072## 非功能要求({} 项)
1073{}
1074
1075---"#,
1076 state.project_name,
1077 state.project_description,
1078 if state.target_users.is_empty() {
1079 "待定".to_string()
1080 } else {
1081 state.target_users.join("、")
1082 },
1083 state.business_processes.len(),
1084 processes_str,
1085 state.modules.len(),
1086 modules_str,
1087 state.nfrs.len(),
1088 nfrs_str
1089 )
1090 }
1091
1092 #[allow(dead_code)]
1094 fn process_summary_input(&self, state: &mut DialogState, input: &str) -> (String, DialogPhase) {
1095 let normalized = input.trim().to_lowercase();
1096
1097 if normalized == "确认" || normalized == "confirm" || normalized == "yes" {
1098 (
1100 get_phase_prompt(DialogPhase::Complete).to_string(),
1101 DialogPhase::Complete,
1102 )
1103 } else if normalized == "重来" || normalized == "restart" {
1104 state.phase = DialogPhase::Welcome;
1106 state.project_name.clear();
1107 state.project_description.clear();
1108 state.target_users.clear();
1109 state.problems_to_solve.clear();
1110 state.business_processes.clear();
1111 state.modules.clear();
1112 state.nfrs.clear();
1113 (
1114 format!(
1115 "好的,让我们重新开始。\n\n{}",
1116 get_phase_prompt(DialogPhase::Welcome)
1117 ),
1118 DialogPhase::Welcome,
1119 )
1120 } else {
1121 let summary = self.generate_summary(state);
1123 (format!("已记录您的修改意见。\n\n{}\n\n请确认修改后的内容。输入「确认」、「修改 [内容]」或「重来」。", summary), DialogPhase::Summary)
1124 }
1125 }
1126
1127 pub async fn create_blueprint_from_state(
1129 &self,
1130 state: &DialogState,
1131 blueprint_manager: &mut BlueprintManager,
1132 ) -> Result<Blueprint, String> {
1133 let blueprint = blueprint_manager
1135 .create_blueprint(
1136 state.project_name.clone(),
1137 state.project_description.clone(),
1138 )
1139 .await
1140 .map_err(|e| e.to_string())?;
1141
1142 for process in &state.business_processes {
1144 let bp = BusinessProcess {
1145 id: uuid::Uuid::new_v4().to_string(),
1146 name: process.name.clone(),
1147 description: process.description.clone(),
1148 process_type: ProcessType::ToBe,
1149 steps: process
1150 .steps
1151 .iter()
1152 .enumerate()
1153 .map(|(i, step)| ProcessStep {
1154 id: uuid::Uuid::new_v4().to_string(),
1155 order: i as u32 + 1,
1156 name: step.clone(),
1157 description: step.clone(),
1158 actor: "user".to_string(),
1159 system_action: None,
1160 user_action: Some(step.clone()),
1161 conditions: vec![],
1162 outcomes: vec![],
1163 })
1164 .collect(),
1165 actors: vec!["user".to_string()],
1166 inputs: vec![],
1167 outputs: vec![],
1168 };
1169 blueprint_manager
1170 .add_business_process(&blueprint.id, bp)
1171 .await
1172 .map_err(|e| e.to_string())?;
1173 }
1174
1175 let mut module_id_map: HashMap<String, String> = HashMap::new();
1177
1178 for module in &state.modules {
1179 let sys_module = SystemModule {
1180 id: uuid::Uuid::new_v4().to_string(),
1181 name: module.name.clone(),
1182 description: module.description.clone(),
1183 module_type: module.module_type.into(),
1184 responsibilities: module.responsibilities.clone(),
1185 dependencies: vec![],
1186 interfaces: vec![],
1187 tech_stack: Some(module.tech_stack.clone()),
1188 root_path: None,
1189 };
1190 module_id_map.insert(module.name.clone(), sys_module.id.clone());
1191 blueprint_manager
1192 .add_module(&blueprint.id, sys_module)
1193 .await
1194 .map_err(|e| e.to_string())?;
1195 }
1196
1197 for nfr in &state.nfrs {
1199 let requirement = NonFunctionalRequirement {
1200 id: uuid::Uuid::new_v4().to_string(),
1201 category: nfr.category.into(),
1202 name: nfr.name.clone(),
1203 description: nfr.description.clone(),
1204 priority: nfr.priority.into(),
1205 metric: nfr.metrics.clone(),
1206 };
1207 blueprint_manager
1208 .add_nfr(&blueprint.id, requirement)
1209 .await
1210 .map_err(|e| e.to_string())?;
1211 }
1212
1213 let blueprint = blueprint_manager
1215 .get_blueprint(&blueprint.id)
1216 .await
1217 .ok_or_else(|| "无法获取创建的蓝图".to_string())?;
1218
1219 Ok(blueprint)
1220 }
1221
1222 pub fn get_dialog_state(&self, session_id: &str) -> Option<&DialogState> {
1224 self.sessions.get(session_id)
1225 }
1226
1227 pub fn get_current_phase_prompt(&self, session_id: &str) -> String {
1229 self.sessions
1230 .get(session_id)
1231 .map(|s| get_phase_prompt(s.phase).to_string())
1232 .unwrap_or_default()
1233 }
1234
1235 pub async fn end_dialog(&mut self, session_id: &str) {
1237 self.sessions.remove(session_id);
1238 self.emit(DialogEvent::Ended {
1239 session_id: session_id.to_string(),
1240 })
1241 .await;
1242 }
1243}
1244
1245pub fn create_requirement_dialog_manager() -> RequirementDialogManager {
1251 RequirementDialogManager::new()
1252}