ai.rs (27499B)
1 use crate::ai_service::AIService; 2 use crate::chatops::{ChatCommand, ChatOpError, ChatOpResult, CommandContext}; 3 use std::sync::Arc; 4 use tokio::runtime::Runtime; 5 6 /// AI-powered message summarization 7 pub struct SummarizeCommand { 8 ai_service: Arc<AIService>, 9 runtime: Arc<Runtime>, 10 } 11 12 impl SummarizeCommand { 13 pub fn new(ai_service: Arc<AIService>, runtime: Arc<Runtime>) -> Self { 14 Self { 15 ai_service, 16 runtime, 17 } 18 } 19 } 20 21 impl ChatCommand for SummarizeCommand { 22 fn name(&self) -> &'static str { 23 "summarize" 24 } 25 fn description(&self) -> &'static str { 26 "Summarize recent chat activity (AI)" 27 } 28 fn usage(&self) -> &'static str { 29 "/summarize [count]" 30 } 31 fn aliases(&self) -> Vec<&'static str> { 32 vec!["tldr", "summary"] 33 } 34 35 fn execute( 36 &self, 37 args: Vec<String>, 38 _context: &CommandContext, 39 ) -> Result<ChatOpResult, ChatOpError> { 40 if !self.ai_service.is_available() { 41 return Ok(ChatOpResult::Error( 42 "AI service not configured. Please check OPENAI_API_KEY environment variable." 43 .to_string(), 44 )); 45 } 46 47 // Test if AI is actually functional (not just configured) 48 let ai_service = Arc::clone(&self.ai_service); 49 let is_functional = self 50 .runtime 51 .block_on(async move { ai_service.is_functional().await }); 52 53 if !is_functional { 54 return Ok(ChatOpResult::Error( 55 "AI service temporarily unavailable. This might be due to:\n\ 56 • API quota exceeded\n\ 57 • Billing issues\n\ 58 • Service outage\n\ 59 Please try again later or contact an admin." 60 .to_string(), 61 )); 62 } 63 64 let count = if !args.is_empty() { 65 args[0].parse::<usize>().unwrap_or(50).min(200) 66 } else { 67 50 68 }; 69 70 let ai_service = Arc::clone(&self.ai_service); 71 match self 72 .runtime 73 .block_on(async move { ai_service.summarize_chat(Some(count)).await }) 74 { 75 Some(summary) => { 76 let mut result = vec![ 77 "🤖 **Chat Summary**".to_string(), 78 "".to_string(), 79 format!("**Overview:** {}", summary.summary), 80 "".to_string(), 81 ]; 82 83 if !summary.key_points.is_empty() { 84 result.push("**Key Points:**".to_string()); 85 for point in summary.key_points { 86 result.push(format!("• {}", point)); 87 } 88 result.push("".to_string()); 89 } 90 91 if !summary.participants.is_empty() { 92 result.push(format!( 93 "**Active Participants:** {}", 94 summary.participants.join(", ") 95 )); 96 } 97 98 if !summary.topics.is_empty() { 99 result.push(format!( 100 "**Topics Discussed:** {}", 101 summary.topics.join(", ") 102 )); 103 } 104 105 result.push(format!("**Overall Mood:** {}", summary.sentiment_overview)); 106 result.push(format!("*(Analyzed {} recent messages)*", count)); 107 108 Ok(ChatOpResult::Block(result)) 109 } 110 None => Ok(ChatOpResult::Error( 111 "Failed to generate summary. Please try again.".to_string(), 112 )), 113 } 114 } 115 } 116 117 /// Language detection and translation command 118 pub struct TranslateCommand { 119 ai_service: Arc<AIService>, 120 runtime: Arc<Runtime>, 121 } 122 123 impl TranslateCommand { 124 pub fn new(ai_service: Arc<AIService>, runtime: Arc<Runtime>) -> Self { 125 Self { 126 ai_service, 127 runtime, 128 } 129 } 130 } 131 132 impl ChatCommand for TranslateCommand { 133 fn name(&self) -> &'static str { 134 "translate" 135 } 136 fn description(&self) -> &'static str { 137 "Translate text to another language" 138 } 139 fn usage(&self) -> &'static str { 140 "/translate <target_lang> <text>" 141 } 142 fn aliases(&self) -> Vec<&'static str> { 143 vec!["tr"] 144 } 145 146 fn execute( 147 &self, 148 args: Vec<String>, 149 _context: &CommandContext, 150 ) -> Result<ChatOpResult, ChatOpError> { 151 if args.len() < 2 { 152 return Err(ChatOpError::MissingArguments( 153 "Usage: /translate <language> <text>".to_string(), 154 )); 155 } 156 157 let target_lang = &args[0]; 158 let text = args[1..].join(" "); 159 160 // Try AI translation first if available 161 if self.ai_service.is_available() { 162 // Check if AI is functional 163 let ai_service_check = Arc::clone(&self.ai_service); 164 let is_functional = self 165 .runtime 166 .block_on(async move { ai_service_check.is_functional().await }); 167 168 if is_functional { 169 let ai_service = Arc::clone(&self.ai_service); 170 let target_lang_clone = target_lang.to_string(); 171 let text_clone = text.clone(); 172 173 match self.runtime.block_on(async move { 174 ai_service 175 .translate_text(&text_clone, &target_lang_clone) 176 .await 177 }) { 178 Some(translated) => { 179 return Ok(ChatOpResult::Message(format!( 180 "🌐 **Translation to {}:**\n{}", 181 target_lang, translated 182 ))); 183 } 184 None => { 185 // Fall through to basic translation 186 } 187 } 188 } 189 } 190 191 // Fallback to system translator 192 match std::process::Command::new("trans") 193 .arg("-b") 194 .arg("-t") 195 .arg(target_lang) 196 .arg(&text) 197 .output() 198 { 199 Ok(output) => { 200 if output.status.success() { 201 let translated = String::from_utf8_lossy(&output.stdout); 202 Ok(ChatOpResult::Message(format!( 203 "🌐 **Translation to {}:**\n{}", 204 target_lang, 205 translated.trim() 206 ))) 207 } else { 208 let encoded_text = text.replace(" ", "%20"); 209 Ok(ChatOpResult::Message(format!("🌐 Translation failed. Try: https://translate.google.com/?sl=auto&tl={}&text={}", target_lang, encoded_text))) 210 } 211 } 212 Err(_) => { 213 let encoded_text = text.replace(" ", "%20"); 214 Ok(ChatOpResult::Message(format!("🌐 System translator unavailable. Try: https://translate.google.com/?sl=auto&tl={}&text={}", target_lang, encoded_text))) 215 } 216 } 217 } 218 } 219 220 /// Language detection command 221 pub struct DetectCommand { 222 ai_service: Arc<AIService>, 223 runtime: Arc<Runtime>, 224 } 225 226 impl DetectCommand { 227 pub fn new(ai_service: Arc<AIService>, runtime: Arc<Runtime>) -> Self { 228 Self { 229 ai_service, 230 runtime, 231 } 232 } 233 } 234 235 impl ChatCommand for DetectCommand { 236 fn name(&self) -> &'static str { 237 "detect" 238 } 239 fn description(&self) -> &'static str { 240 "Detect the language of text" 241 } 242 fn usage(&self) -> &'static str { 243 "/detect <text>" 244 } 245 fn aliases(&self) -> Vec<&'static str> { 246 vec!["lang"] 247 } 248 249 fn execute( 250 &self, 251 args: Vec<String>, 252 _context: &CommandContext, 253 ) -> Result<ChatOpResult, ChatOpError> { 254 if args.is_empty() { 255 return Err(ChatOpError::MissingArguments( 256 "Please specify text to analyze".to_string(), 257 )); 258 } 259 260 let text = args.join(" "); 261 262 if self.ai_service.is_available() { 263 // Check if AI is functional 264 let ai_service_check = Arc::clone(&self.ai_service); 265 let is_functional = self 266 .runtime 267 .block_on(async move { ai_service_check.is_functional().await }); 268 269 if !is_functional { 270 return Ok(ChatOpResult::Error( 271 "AI service temporarily unavailable. Falling back to basic detection." 272 .to_string(), 273 )); 274 } 275 276 let ai_service = Arc::clone(&self.ai_service); 277 let text_clone = text.clone(); 278 match self 279 .runtime 280 .block_on(async move { ai_service.detect_language(&text_clone).await }) 281 { 282 Some(detection) => { 283 let confidence_emoji = if detection.confidence > 0.8 { 284 "🎯" 285 } else if detection.confidence > 0.6 { 286 "🎲" 287 } else { 288 "❓" 289 }; 290 291 Ok(ChatOpResult::Message(format!( 292 "{} **Language Detection:**\n**Language:** {} ({})\n**Confidence:** {:.0}%", 293 confidence_emoji, 294 detection.language, 295 detection.iso_code, 296 detection.confidence * 100.0 297 ))) 298 } 299 None => { 300 // Fallback to simple detection 301 let detection = crate::ai_service::fallback_language_detection(&text); 302 Ok(ChatOpResult::Message(format!( 303 "🔍 **Language Detection (Basic):**\n**Language:** {} ({})\n**Confidence:** {:.0}%", 304 detection.language, 305 detection.iso_code, 306 detection.confidence * 100.0 307 ))) 308 } 309 } 310 } else { 311 let detection = crate::ai_service::fallback_language_detection(&text); 312 Ok(ChatOpResult::Message(format!( 313 "🔍 **Language Detection (Basic):**\n**Language:** {} ({})\n**Confidence:** {:.0}%", 314 detection.language, 315 detection.iso_code, 316 detection.confidence * 100.0 317 ))) 318 } 319 } 320 } 321 322 /// Sentiment analysis command 323 pub struct SentimentCommand { 324 ai_service: Arc<AIService>, 325 runtime: Arc<Runtime>, 326 } 327 328 impl SentimentCommand { 329 pub fn new(ai_service: Arc<AIService>, runtime: Arc<Runtime>) -> Self { 330 Self { 331 ai_service, 332 runtime, 333 } 334 } 335 } 336 337 impl ChatCommand for SentimentCommand { 338 fn name(&self) -> &'static str { 339 "sentiment" 340 } 341 fn description(&self) -> &'static str { 342 "Analyze sentiment and emotions in text" 343 } 344 fn usage(&self) -> &'static str { 345 "/sentiment <text>" 346 } 347 fn aliases(&self) -> Vec<&'static str> { 348 vec!["mood", "feel"] 349 } 350 351 fn execute( 352 &self, 353 args: Vec<String>, 354 _context: &CommandContext, 355 ) -> Result<ChatOpResult, ChatOpError> { 356 if args.is_empty() { 357 return Err(ChatOpError::MissingArguments( 358 "Please specify text to analyze".to_string(), 359 )); 360 } 361 362 let text = args.join(" "); 363 364 if self.ai_service.is_available() { 365 // Check if AI is functional 366 let ai_service_check = Arc::clone(&self.ai_service); 367 let is_functional = self 368 .runtime 369 .block_on(async move { ai_service_check.is_functional().await }); 370 371 if !is_functional { 372 return Ok(ChatOpResult::Error( 373 "AI service temporarily unavailable. Cannot analyze sentiment.".to_string(), 374 )); 375 } 376 377 let ai_service = Arc::clone(&self.ai_service); 378 let text_clone = text.clone(); 379 match self 380 .runtime 381 .block_on(async move { ai_service.analyze_sentiment(&text_clone).await }) 382 { 383 Some(analysis) => { 384 let sentiment_emoji = match analysis.sentiment.as_str() { 385 "positive" => "😊", 386 "negative" => "😔", 387 _ => "😐", 388 }; 389 390 let mut result = vec![ 391 format!("{} **Sentiment Analysis:**", sentiment_emoji), 392 format!( 393 "**Sentiment:** {} (Score: {:.2})", 394 analysis.sentiment, analysis.score 395 ), 396 format!("**Confidence:** {:.0}%", analysis.confidence * 100.0), 397 ]; 398 399 if !analysis.emotions.is_empty() { 400 result.push(format!("**Emotions:** {}", analysis.emotions.join(", "))); 401 } 402 403 Ok(ChatOpResult::Block(result)) 404 } 405 None => { 406 // Fallback to simple analysis 407 let analysis = crate::ai_service::fallback_sentiment_analysis(&text); 408 let sentiment_emoji = match analysis.sentiment.as_str() { 409 "positive" => "😊", 410 "negative" => "😔", 411 _ => "😐", 412 }; 413 414 Ok(ChatOpResult::Message(format!( 415 "{} **Sentiment (Basic):** {} (Score: {:.2})", 416 sentiment_emoji, analysis.sentiment, analysis.score 417 ))) 418 } 419 } 420 } else { 421 let analysis = crate::ai_service::fallback_sentiment_analysis(&text); 422 let sentiment_emoji = match analysis.sentiment.as_str() { 423 "positive" => "😊", 424 "negative" => "😔", 425 _ => "😐", 426 }; 427 428 Ok(ChatOpResult::Message(format!( 429 "{} **Sentiment (Basic):** {} (Score: {:.2})", 430 sentiment_emoji, analysis.sentiment, analysis.score 431 ))) 432 } 433 } 434 } 435 436 /// Chat atmosphere command 437 pub struct AtmosphereCommand { 438 ai_service: Arc<AIService>, 439 } 440 441 impl AtmosphereCommand { 442 pub fn new(ai_service: Arc<AIService>) -> Self { 443 Self { ai_service } 444 } 445 } 446 447 impl ChatCommand for AtmosphereCommand { 448 fn name(&self) -> &'static str { 449 "atmosphere" 450 } 451 fn description(&self) -> &'static str { 452 "Get current chat mood and activity" 453 } 454 fn usage(&self) -> &'static str { 455 "/atmosphere" 456 } 457 fn aliases(&self) -> Vec<&'static str> { 458 vec!["vibe", "mood"] 459 } 460 461 fn execute( 462 &self, 463 _args: Vec<String>, 464 _context: &CommandContext, 465 ) -> Result<ChatOpResult, ChatOpError> { 466 let atmosphere = self.ai_service.get_chat_atmosphere(); 467 Ok(ChatOpResult::Message(format!( 468 "**Current Chat Atmosphere:**\n{}", 469 atmosphere 470 ))) 471 } 472 } 473 474 /// Advanced moderation test command 475 pub struct ModCheckCommand { 476 ai_service: Arc<AIService>, 477 runtime: Arc<Runtime>, 478 } 479 480 impl ModCheckCommand { 481 pub fn new(ai_service: Arc<AIService>, runtime: Arc<Runtime>) -> Self { 482 Self { 483 ai_service, 484 runtime, 485 } 486 } 487 } 488 489 impl ChatCommand for ModCheckCommand { 490 fn name(&self) -> &'static str { 491 "modcheck" 492 } 493 fn description(&self) -> &'static str { 494 "Test AI moderation on a message" 495 } 496 fn usage(&self) -> &'static str { 497 "/modcheck <text>" 498 } 499 fn aliases(&self) -> Vec<&'static str> { 500 vec!["checkmod"] 501 } 502 503 fn execute( 504 &self, 505 args: Vec<String>, 506 _context: &CommandContext, 507 ) -> Result<ChatOpResult, ChatOpError> { 508 if !self.ai_service.is_available() { 509 return Ok(ChatOpResult::Error( 510 "AI service not configured. Check OPENAI_API_KEY environment variable.".to_string(), 511 )); 512 } 513 514 // Test if AI is actually functional (not just configured) 515 let ai_service_check = Arc::clone(&self.ai_service); 516 let is_functional = self 517 .runtime 518 .block_on(async move { ai_service_check.is_functional().await }); 519 520 if !is_functional { 521 return Ok(ChatOpResult::Error( 522 "AI moderation service temporarily unavailable. This might be due to:\n\ 523 • API quota exceeded\n\ 524 • Billing issues\n\ 525 • Service outage\n\ 526 Please try again later or contact an admin." 527 .to_string(), 528 )); 529 } 530 531 if args.is_empty() { 532 return Err(ChatOpError::MissingArguments( 533 "Please specify text to check".to_string(), 534 )); 535 } 536 537 let text = args.join(" "); 538 let recent_msgs = self.ai_service.get_recent_messages(5); 539 let context = recent_msgs 540 .iter() 541 .map(|m| format!("{}: {}", m.author, m.content)) 542 .collect::<Vec<_>>() 543 .join(" | "); 544 545 let ai_service = Arc::clone(&self.ai_service); 546 match self 547 .runtime 548 .block_on(async move { ai_service.advanced_moderation(&text, &context).await }) 549 { 550 Some(result) => { 551 let action_emoji = match result.suggested_action.as_str() { 552 "ban" => "🔨", 553 "kick" => "👢", 554 "warn" => "⚠️", 555 _ => "✅", 556 }; 557 558 let mut response = vec![ 559 format!("{} **AI Moderation Check:**", action_emoji), 560 format!( 561 "**Should Moderate:** {}", 562 if result.should_moderate { "YES" } else { "NO" } 563 ), 564 format!("**Severity:** {}/10", result.severity), 565 format!("**Suggested Action:** {}", result.suggested_action), 566 format!("**Confidence:** {:.0}%", result.confidence * 100.0), 567 ]; 568 569 if !result.reasons.is_empty() { 570 response.push("**Reasons:**".to_string()); 571 for reason in result.reasons { 572 response.push(format!("• {}", reason)); 573 } 574 } 575 576 Ok(ChatOpResult::Block(response)) 577 } 578 None => Ok(ChatOpResult::Error( 579 "Failed to analyze message. Please try again.".to_string(), 580 )), 581 } 582 } 583 } 584 585 /// AI service status command 586 pub struct AIStatusCommand { 587 ai_service: Arc<AIService>, 588 } 589 590 impl AIStatusCommand { 591 pub fn new(ai_service: Arc<AIService>) -> Self { 592 Self { ai_service } 593 } 594 } 595 596 impl ChatCommand for AIStatusCommand { 597 fn name(&self) -> &'static str { 598 "aistatus" 599 } 600 fn description(&self) -> &'static str { 601 "Check AI service status and statistics" 602 } 603 fn usage(&self) -> &'static str { 604 "/aistatus" 605 } 606 fn aliases(&self) -> Vec<&'static str> { 607 vec!["aiinfo"] 608 } 609 610 fn execute( 611 &self, 612 _args: Vec<String>, 613 _context: &CommandContext, 614 ) -> Result<ChatOpResult, ChatOpError> { 615 let stats = self.ai_service.get_stats(); 616 617 let mut result = vec!["🤖 **AI Service Status:**".to_string(), "".to_string()]; 618 619 for (key, value) in stats { 620 let display_key = match key.as_str() { 621 "available" => "Service Available", 622 "message_history" => "Messages in History", 623 "language_cache" => "Language Cache Size", 624 "sentiment_cache" => "Sentiment Cache Size", 625 "max_history" => "Max History Size", 626 _ => &key, 627 }; 628 result.push(format!("**{}:** {}", display_key, value)); 629 } 630 631 result.push("".to_string()); 632 result.push("Available Commands: /summarize, /translate, /detect, /sentiment, /atmosphere, /modcheck".to_string()); 633 634 Ok(ChatOpResult::Block(result)) 635 } 636 } 637 638 /// Code fixing command with AI enhancement 639 pub struct FixCommand { 640 ai_service: Arc<AIService>, 641 #[allow(dead_code)] 642 runtime: Arc<Runtime>, 643 } 644 645 impl FixCommand { 646 pub fn new(ai_service: Arc<AIService>, runtime: Arc<Runtime>) -> Self { 647 Self { 648 ai_service, 649 runtime, 650 } 651 } 652 } 653 654 impl ChatCommand for FixCommand { 655 fn name(&self) -> &'static str { 656 "fix" 657 } 658 fn description(&self) -> &'static str { 659 "Attempt to fix code issues (AI)" 660 } 661 fn usage(&self) -> &'static str { 662 "/fix <code>" 663 } 664 665 fn execute( 666 &self, 667 args: Vec<String>, 668 _context: &CommandContext, 669 ) -> Result<ChatOpResult, ChatOpError> { 670 if args.is_empty() { 671 return Err(ChatOpError::MissingArguments( 672 "Please specify code to fix".to_string(), 673 )); 674 } 675 676 let code = args.join(" "); 677 678 // Enhanced basic analysis 679 let mut suggestions = vec!["🔧 **Code Fix Suggestions:**".to_string()]; 680 681 // Language detection 682 if code.contains("fn ") || code.contains("let ") || code.contains("mut ") { 683 suggestions.push( 684 "• **Rust detected**: Use `cargo check` and `clippy` for detailed analysis" 685 .to_string(), 686 ); 687 } else if code.contains("def ") || code.contains("import ") { 688 suggestions.push( 689 "• **Python detected**: Check indentation and use `pylint` or `flake8`".to_string(), 690 ); 691 } else if code.contains("function ") || code.contains("const ") || code.contains("=>") { 692 suggestions.push( 693 "• **JavaScript detected**: Use ESLint for comprehensive checking".to_string(), 694 ); 695 } 696 697 // Common issues 698 if code.contains("unwrap()") { 699 suggestions.push( 700 "• Replace `unwrap()` with proper error handling using `?` or `match`".to_string(), 701 ); 702 } 703 704 if code.contains("panic!") { 705 suggestions.push("• Consider returning `Result` instead of using `panic!`".to_string()); 706 } 707 708 if !code.contains("//") && !code.contains("#") && !code.contains("/*") && code.len() > 50 { 709 suggestions.push("• Add comments to explain complex logic".to_string()); 710 } 711 712 if code.len() > 300 { 713 suggestions 714 .push("• Consider breaking this into smaller, more focused functions".to_string()); 715 } 716 717 // AI enhancement note 718 if self.ai_service.is_available() { 719 suggestions.push("".to_string()); 720 suggestions 721 .push("💡 *For detailed AI-powered code review, use `/review <code>`*".to_string()); 722 } else { 723 suggestions.push("".to_string()); 724 suggestions.push( 725 "💡 *Enable AI service (OPENAI_API_KEY) for enhanced code analysis*".to_string(), 726 ); 727 } 728 729 Ok(ChatOpResult::Block(suggestions)) 730 } 731 } 732 733 /// Enhanced code review command 734 pub struct ReviewCommand { 735 ai_service: Arc<AIService>, 736 runtime: Arc<Runtime>, 737 } 738 739 impl ReviewCommand { 740 pub fn new(ai_service: Arc<AIService>, runtime: Arc<Runtime>) -> Self { 741 Self { 742 ai_service, 743 runtime, 744 } 745 } 746 } 747 748 impl ChatCommand for ReviewCommand { 749 fn name(&self) -> &'static str { 750 "review" 751 } 752 fn description(&self) -> &'static str { 753 "Get comprehensive code review (AI)" 754 } 755 fn usage(&self) -> &'static str { 756 "/review <code>" 757 } 758 759 fn execute( 760 &self, 761 args: Vec<String>, 762 _context: &CommandContext, 763 ) -> Result<ChatOpResult, ChatOpError> { 764 if args.is_empty() { 765 return Err(ChatOpError::MissingArguments( 766 "Please specify code to review".to_string(), 767 )); 768 } 769 770 let code = args.join(" "); 771 772 // Check if AI is functional 773 let ai_service_check = Arc::clone(&self.ai_service); 774 let is_functional = if self.ai_service.is_available() { 775 self.runtime 776 .block_on(async move { ai_service_check.is_functional().await }) 777 } else { 778 false 779 }; 780 781 if !is_functional { 782 // Fallback to enhanced basic review 783 let mut suggestions = vec!["📝 **Code Review (Basic Analysis):**".to_string()]; 784 785 if code.len() > 200 { 786 suggestions.push( 787 "• Consider breaking this into smaller functions for better maintainability" 788 .to_string(), 789 ); 790 } 791 792 if code.contains("TODO") || code.contains("FIXME") || code.contains("XXX") { 793 suggestions 794 .push("• Address TODO/FIXME comments before production deployment".to_string()); 795 } 796 797 if !code.contains("//") && !code.contains("#") && !code.contains("/*") { 798 suggestions.push( 799 "• Add descriptive comments explaining the logic and purpose".to_string(), 800 ); 801 } 802 803 if code.contains("panic!") || code.contains("unwrap()") { 804 suggestions 805 .push("• Implement proper error handling instead of panicking".to_string()); 806 } 807 808 if code.split('\n').count() > 20 { 809 suggestions.push( 810 "• Function appears long - consider extracting helper functions".to_string(), 811 ); 812 } 813 814 // Variable naming check 815 if code.chars().filter(|c| c.is_uppercase()).count() as f32 / code.len() as f32 > 0.3 { 816 suggestions 817 .push("• Check variable naming conventions for your language".to_string()); 818 } 819 820 suggestions.push("".to_string()); 821 suggestions 822 .push("💡 *For AI-powered detailed review, set up OPENAI_API_KEY*".to_string()); 823 824 return Ok(ChatOpResult::Block(suggestions)); 825 } 826 827 // AI-powered review 828 let ai_service = Arc::clone(&self.ai_service); 829 let prompt = format!( 830 "Please review this code and provide specific, actionable feedback. Focus on: 831 - Code quality and best practices 832 - Potential bugs or issues 833 - Performance considerations 834 - Readability and maintainability 835 - Security concerns if applicable 836 837 Code to review: 838 ``` 839 {} 840 ``` 841 842 Please format your response as a markdown list of specific suggestions.", 843 code 844 ); 845 846 match self.runtime.block_on(async move { 847 ai_service.translate_text(&prompt, "code review").await // Using translate as a general AI completion 848 }) { 849 Some(review) => { 850 let result = vec!["🤖 **AI Code Review:**".to_string(), "".to_string(), review]; 851 Ok(ChatOpResult::Block(result)) 852 } 853 None => Ok(ChatOpResult::Error( 854 "AI review failed. Please try again or use basic review.".to_string(), 855 )), 856 } 857 } 858 }