/**************************************************************************/ /* ai_assistant.cpp */ /**************************************************************************/ #include "ai_assistant.h" #include "core/config/project_settings.h" #include "core/io/json.h" AIAssistant *AIAssistant::singleton = nullptr; void AIAssistant::_bind_methods() { // Methods ClassDB::bind_method(D_METHOD("initialize", "api_key"), &AIAssistant::initialize, DEFVAL("")); ClassDB::bind_method(D_METHOD("is_initialized"), &AIAssistant::is_initialized); ClassDB::bind_method(D_METHOD("get_code_completion", "context", "recent_code"), &AIAssistant::get_code_completion); ClassDB::bind_method(D_METHOD("explain_code", "code_block"), &AIAssistant::explain_code); ClassDB::bind_method(D_METHOD("fix_error", "error_message", "code_context"), &AIAssistant::fix_error); ClassDB::bind_method(D_METHOD("generate_function_docs", "function_signature"), &AIAssistant::generate_function_docs); ClassDB::bind_method(D_METHOD("natural_language_to_code", "description", "context"), &AIAssistant::natural_language_to_code); ClassDB::bind_method(D_METHOD("set_api_key", "key"), &AIAssistant::set_api_key); ClassDB::bind_method(D_METHOD("get_api_key"), &AIAssistant::get_api_key); ClassDB::bind_method(D_METHOD("clear_cache"), &AIAssistant::clear_cache); // Properties ADD_PROPERTY(PropertyInfo(Variant::STRING, "api_key", PROPERTY_HINT_PASSWORD), "set_api_key", "get_api_key"); // Enums BIND_ENUM_CONSTANT(COMPLETION_TYPE_CODE); BIND_ENUM_CONSTANT(COMPLETION_TYPE_DOCUMENTATION); BIND_ENUM_CONSTANT(COMPLETION_TYPE_EXPLANATION); BIND_ENUM_CONSTANT(COMPLETION_TYPE_FIX); } Error AIAssistant::initialize(const String &p_api_key) { if (initialized) { return OK; } // Set API key if (!p_api_key.is_empty()) { api_key = p_api_key; } else { // Try to get from project settings or environment if (ProjectSettings::get_singleton()->has_setting("aethex/ai/api_key")) { api_key = ProjectSettings::get_singleton()->get_setting("aethex/ai/api_key"); } } if (api_key.is_empty()) { ERR_PRINT("AIAssistant: No API key provided. Set it via initialize() or project settings."); return ERR_UNCONFIGURED; } // Initialize API client api_client.instantiate(); api_client->set_api_key(api_key); Error err = api_client->initialize(); if (err != OK) { ERR_PRINT("AIAssistant: Failed to initialize API client."); return err; } initialized = true; print_line("AIAssistant initialized successfully!"); return OK; } String AIAssistant::get_code_completion(const String &p_context, const PackedStringArray &p_recent_code) { if (!initialized) { ERR_PRINT("AIAssistant: Not initialized. Call initialize() first."); return ""; } // Build prompt String prompt = "You are an expert GDScript developer. Complete the following code:\n\n"; // Add recent code context if (p_recent_code.size() > 0) { prompt += "Recent code:\n"; for (int i = 0; i < p_recent_code.size(); i++) { prompt += p_recent_code[i] + "\n"; } prompt += "\n"; } prompt += "Current context:\n" + p_context + "\n\n"; prompt += "Provide only the code completion, no explanations:"; // Check cache String cached = _get_cached_response(prompt); if (!cached.is_empty()) { return cached; } // Make API call (sync for now) String response = api_client->send_completion_sync(prompt, 5.0); // Cache the response if (!response.is_empty()) { _cache_response(prompt, response); } return response; } String AIAssistant::explain_code(const String &p_code_block) { if (!initialized) { return ""; } String prompt = "Explain this GDScript code clearly and concisely:\n\n"; prompt += p_code_block; String cached = _get_cached_response(prompt); if (!cached.is_empty()) { return cached; } String response = api_client->send_completion_sync(prompt, 10.0); if (!response.is_empty()) { _cache_response(prompt, response); } return response; } String AIAssistant::fix_error(const String &p_error_message, const String &p_code_context) { if (!initialized) { return ""; } String prompt = "Fix this GDScript error. Provide the corrected code:\n\n"; prompt += "Error: " + p_error_message + "\n\n"; prompt += "Code:\n" + p_code_context; String response = api_client->send_completion_sync(prompt, 10.0); return response; } String AIAssistant::generate_function_docs(const String &p_function_signature) { if (!initialized) { return ""; } String prompt = "Generate documentation for this GDScript function:\n\n"; prompt += p_function_signature + "\n\n"; prompt += "Format: Brief description, parameters, returns."; String cached = _get_cached_response(prompt); if (!cached.is_empty()) { return cached; } String response = api_client->send_completion_sync(prompt, 5.0); if (!response.is_empty()) { _cache_response(prompt, response); } return response; } String AIAssistant::generate_class_docs(const String &p_class_code) { if (!initialized) { return ""; } String prompt = "Generate complete documentation for this GDScript class:\n\n"; prompt += p_class_code; String response = api_client->send_completion_sync(prompt, 15.0); return response; } String AIAssistant::natural_language_to_code(const String &p_description, const String &p_context) { if (!initialized) { return ""; } String prompt = "Convert this description to GDScript code:\n\n"; prompt += p_description + "\n\n"; if (!p_context.is_empty()) { prompt += "Context:\n" + p_context + "\n\n"; } prompt += "Provide clean, working GDScript code:"; String response = api_client->send_completion_sync(prompt, 10.0); return response; } void AIAssistant::set_api_key(const String &p_key) { api_key = p_key; if (api_client.is_valid()) { api_client->set_api_key(p_key); } } String AIAssistant::get_api_key() const { return api_key; } void AIAssistant::clear_cache() { response_cache.clear(); print_line("AIAssistant: Cache cleared."); } String AIAssistant::_get_cached_response(const String &p_prompt) { if (response_cache.has(p_prompt)) { return response_cache[p_prompt]; } return ""; } void AIAssistant::_cache_response(const String &p_prompt, const String &p_response) { // Simple cache with size limit if (response_cache.size() > 100) { response_cache.clear(); // Simple eviction } response_cache[p_prompt] = p_response; } AIAssistant *AIAssistant::get_singleton() { return singleton; } AIAssistant::AIAssistant() { singleton = this; } AIAssistant::~AIAssistant() { singleton = nullptr; }