diff --git a/extensions/community/AIConnector.json b/extensions/community/AIConnector.json new file mode 100644 index 000000000..2e339dc7a --- /dev/null +++ b/extensions/community/AIConnector.json @@ -0,0 +1,541 @@ +{ + "author": "", + "category": "Third-party", + "dimension": "", + "extensionNamespace": "", + "fullName": "KI Connector", + "gdevelopVersion": "", + "helpPath": "https://github.com/stumblespike/Gdevlop-AI-Connector/blob/main/README.md", + "iconUrl": "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz48IURPQ1RZUEUgc3ZnIFBVQkxJQyAiLS8vVzNDLy9EVEQgU1ZHIDEuMS8vRU4iICJodHRwOi8vd3d3LnczLm9yZy9HcmFwaGljcy9TVkcvMS4xL0RURC9zdmcxMS5kdGQiPjxzdmcgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiBpZD0ibWRpLWxhbi1jb25uZWN0IiB3aWR0aD0iMjQiIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCI+PHBhdGggZD0iTTQsMUMyLjg5LDEgMiwxLjg5IDIsM1Y3QzIsOC4xMSAyLjg5LDkgNCw5SDFWMTFIMTNWOUgxMEMxMS4xMSw5IDEyLDguMTEgMTIsN1YzQzEyLDEuODkgMTEuMTEsMSAxMCwxSDRNNCwzSDEwVjdINFYzTTMsMTNWMThMMywyMEgxMFYxOEg1VjEzSDNNMTQsMTNDMTIuODksMTMgMTIsMTMuODkgMTIsMTVWMTlDMTIsMjAuMTEgMTIuODksMjEgMTQsMjFIMTFWMjNIMjNWMjFIMjBDMjEuMTEsMjEgMjIsMjAuMTEgMjIsMTlWMTVDMjIsMTMuODkgMjEuMTEsMTMgMjAsMTNIMTRNMTQsMTVIMjBWMTlIMTRWMTVaIiAvPjwvc3ZnPg==", + "name": "AIConnector", + "previewIconUrl": "https://asset-resources.gdevelop.io/public-resources/Icons/9d2d99ea2f8ef2782af917d0b20be40f7c21b5eb1eba5f931cb52fc426a617c8_lan-connect.svg", + "shortDescription": "Connect your API and KI models to your Gdevlop Project.", + "version": "1.0.0", + "description": [ + "OpenRouter Connector.", + "Gemini Connector.", + "Groq Connector.", + "Hugging Face Connector.", + "Costume AI Connector." + ], + "tags": [ + "KI", + "AI", + "Hugging Face", + "Gemini", + "Groq", + "OpenRouter" + ], + "authorIds": [ + "thf7ybj62vVOnQqx4jepS3MhyDU2" + ], + "dependencies": [], + "globalVariables": [], + "sceneVariables": [], + "eventsFunctions": [ + { + "description": "Your Fully Costume API for an AI.", + "fullName": "Costume API", + "functionType": "Action", + "name": "Costume_API", + "sentence": "Sends a Text to _PARAM1_ and the API _PARAM2_ send the text _PARAM4_ with the System Prompt _PARAM3_ to the Model _PARAM6_ and save the Answer of the AI in _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const baseUrl = eventsFunctionContext.getArgument(\"URL\").trim();", + "const key = eventsFunctionContext.getArgument(\"API_Key\").trim();", + "const personality = eventsFunctionContext.getArgument(\"Message\");", + "const userQuery = eventsFunctionContext.getArgument(\"TextInput\");", + "const targetVarName = eventsFunctionContext.getArgument(\"Scene_Variable\");", + "const selectedModel = eventsFunctionContext.getArgument(\"Model\").trim();", + "", + "const sceneVariables = runtimeScene.getVariables();", + "", + "if (sceneVariables.has(targetVarName)) {", + " const gdVariable = sceneVariables.get(targetVarName);", + " gdVariable.setString(\"KI antwortet bald...\");", + "", + " fetch(baseUrl, {", + " method: 'POST',", + " headers: {", + " \"Content-Type\": \"application/json\",", + " \"Authorization\": \"Bearer \" + key,", + " \"HTTP-Referer\": \"https://gdevelop.io\", // OpenRouter braucht das!", + " \"X-Title\": \"MyGDevelopGame\"", + " },", + " body: JSON.stringify({", + " model: selectedModel,", + " messages: [", + " { role: \"system\", content: personality },", + " { role: \"user\", content: userQuery }", + " ]", + " })", + " })", + " .then(async response => {", + " const data = await response.json();", + " if (!response.ok) {", + " // Zeigt uns jetzt genau: \"Credit balance too low\" oder \"Model not found\"", + " throw new Error(data.error?.message || \"Fehler \" + response.status);", + " }", + " return data;", + " })", + " .then(data => {", + " if (data.choices && data.choices[0].message) {", + " gdVariable.setString(data.choices[0].message.content.trim());", + " } else {", + " gdVariable.setString(\"Fehler: Provider gab leere Antwort.\");", + " }", + " })", + " .catch(err => {", + " gdVariable.setString(\"API INFO: \" + err.message);", + " });", + " }", + " " + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Your URL example: https://openrouter.ai/api/v1/chat/completions", + "name": "URL", + "type": "string" + }, + { + "description": "Your API Key", + "name": "API_Key", + "type": "string" + }, + { + "description": "System Personality", + "name": "Message", + "type": "string" + }, + { + "description": "Your Text Input to write the Text that gets send to the AI", + "name": "TextInput", + "type": "string" + }, + { + "description": "The Variable the AI answer gets Saved", + "name": "Scene_Variable", + "type": "string" + }, + { + "description": "Your model example: \"google/gemma-4-26b-a4b-it:free\"", + "name": "Model", + "type": "string" + } + ], + "objectGroups": [] + }, + { + "description": "Connect Hugging Face with your Project\nmeta-llama/Llama-3.2-1B-Instruct: Very Fast good for easy Chat Answers.", + "fullName": "Connect Hugging Face", + "functionType": "Action", + "name": "HuggingFace_Connector", + "sentence": "Sends the message from _PARAM3_ and the instructions _PARAM2_ to _PARAM1_ and the result is stored in _PARAM4_ the used Model is _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const key = eventsFunctionContext.getArgument(\"API_Key\");", + "const personality = eventsFunctionContext.getArgument(\"Message\");", + "const userQuery = eventsFunctionContext.getArgument(\"TextInput\");", + "const targetVarName = eventsFunctionContext.getArgument(\"Scene_Variable\");", + "const selectedModel = eventsFunctionContext.getArgument(\"Model\").trim();", + "", + "const sceneVariables = runtimeScene.getVariables();", + "", + "if (sceneVariables.has(targetVarName)) {", + " const gdVariable = sceneVariables.get(targetVarName);", + " gdVariable.setString(\"Verbinde mit HF Router...\");", + "", + " // Der moderne Endpunkt für 2026 (OpenAI-kompatibel)", + " const url = \"https://router.huggingface.co/v1/chat/completions\";", + "", + " const payload = {", + " model: selectedModel,", + " messages: [", + " { role: \"system\", content: personality },", + " { role: \"user\", content: userQuery }", + " ],", + " max_tokens: 300", + " };", + "", + " fetch(url, {", + " method: 'POST',", + " headers: {", + " \"Authorization\": \"Bearer \" + key,", + " \"Content-Type\": \"application/json\"", + " },", + " body: JSON.stringify(payload)", + " })", + " .then(async response => {", + " const data = await response.json();", + " if (!response.ok) {", + " throw new Error(data.error?.message || data.error || \"Server Fehler \" + response.status);", + " }", + " return data;", + " })", + " .then(data => {", + " if (data.choices && data.choices[0].message) {", + " gdVariable.setString(data.choices[0].message.content.trim());", + " } else {", + " gdVariable.setString(\"HF Router: Ungültiges Format erhalten.\");", + " }", + " })", + " .catch(err => {", + " // Wenn es hier immer noch scheitert, ist der Key falsch oder das Modell offline", + " gdVariable.setString(\"Fehler: \" + err.message);", + " console.error(\"HF Router Error:\", err);", + " });", + " }", + " " + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "API Key", + "name": "API_Key", + "type": "string" + }, + { + "description": "\"Personality of AI\" or \"extra instructions\" ", + "name": "Message", + "type": "string" + }, + { + "description": "Your Message Input", + "name": "TextInput", + "type": "string" + }, + { + "description": "This is where the AI's message is stored ", + "name": "Scene_Variable", + "type": "string" + }, + { + "description": "These three models are free, but you can also use others", + "name": "Model", + "supplementaryInformation": "[\"meta-llama/Llama-3.2-1B-Instruct\"]", + "type": "stringWithSelector" + } + ], + "objectGroups": [] + }, + { + "description": "Connect Groq \nllama-3.3-70b versatile (Very smart, almost like GPT-4)\nLama-3.1-8b-instant (Extremely fast, good for easy support)\nmixtral-8x7b-32768 (Good for logic and longer texts).", + "fullName": "Connect GroqAI", + "functionType": "Action", + "name": "Groq_Connector", + "sentence": "Sends the message from _PARAM3_ and the instructions _PARAM2_ to _PARAM1_ and the result is stored in _PARAM4_ the used Model is _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "const key = eventsFunctionContext.getArgument(\"API_Key\");", + "const personality = eventsFunctionContext.getArgument(\"Message\");", + "const userQuery = eventsFunctionContext.getArgument(\"TextInput\");", + "const targetVarName = eventsFunctionContext.getArgument(\"Scene_Variable\");", + "// .trim() entfernt das Leerzeichen, falls du es in GDevelop vergisst", + "const selectedModel = eventsFunctionContext.getArgument(\"Model\").trim(); ", + "", + "const sceneVariables = runtimeScene.getVariables();", + "", + "if (sceneVariables.has(targetVarName)) {", + " const gdVariable = sceneVariables.get(targetVarName);", + " gdVariable.setString(\"Groq wird gerufen...\");", + "", + " fetch(\"https://api.groq.com/openai/v1/chat/completions\", {", + " method: 'POST',", + " headers: {", + " 'Content-Type': 'application/json',", + " 'Authorization': 'Bearer ' + key", + " },", + " body: JSON.stringify({", + " model: selectedModel,", + " messages: [", + " { role: \"system\", content: personality },", + " { role: \"user\", content: userQuery }", + " ]", + " })", + " })", + " .then(response => response.json())", + " .then(data => {", + " if (data.choices && data.choices[0]) {", + " gdVariable.setString(data.choices[0].message.content);", + " } else if (data.error) {", + " // Zeigt uns den Fehler OHNE Leerzeichen-Probleme", + " gdVariable.setString(\"Fehler: \" + data.error.message);", + " }", + " })", + " .catch(err => {", + " gdVariable.setString(\"Verbindungsfehler!\");", + " });", + " }", + " " + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "API Key", + "name": "API_Key", + "type": "string" + }, + { + "description": "\"Personality of AI\" or \"extra instructions\" ", + "name": "Message", + "type": "string" + }, + { + "description": "Your Message Input", + "name": "TextInput", + "type": "string" + }, + { + "description": "This is where the AI's message is stored ", + "name": "Scene_Variable", + "type": "string" + }, + { + "description": "These three models are free, but you can also use others ", + "name": "Model", + "supplementaryInformation": "[\"llama-3.3-70b-versatile\",\"llama-3.1-8b-instant\"]", + "type": "stringWithSelector" + } + ], + "objectGroups": [] + }, + { + "description": "Connect Gemini to your Project what youll need to know :\nGemini 3.1 Flash Lite: Completely free, extremely high limits (many requests per minute).\nGemini 3.1 Flash: Completely free, very fast, up to 1,000 requests a day.", + "fullName": "Connect GeminiAI", + "functionType": "Action", + "name": "Gemini_Connector", + "sentence": "Sends the message from _PARAM3_ and the instructions _PARAM2_ to _PARAM1_ and the result is stored in _PARAM4_ the used Model is _PARAM5_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "// 1. Alle 5 Parameter abrufen", + "const key = eventsFunctionContext.getArgument(\"API_Key\");", + "const personality = eventsFunctionContext.getArgument(\"Message\");", + "const userQuery = eventsFunctionContext.getArgument(\"TextInput\");", + "const targetVarName = eventsFunctionContext.getArgument(\"Scene_Variable\");", + "const selectedModel = eventsFunctionContext.getArgument(\"Model\"); // Der neue Parameter", + "", + "const sceneVariables = runtimeScene.getVariables();", + "", + "if (sceneVariables.has(targetVarName)) {", + " const gdVariable = sceneVariables.get(targetVarName);", + " gdVariable.setString(\"KI (\" + selectedModel + \") antwortet...\");", + "", + " // Die URL nutzt nun das vom User gewählte Modell", + " const url = \"https://generativelanguage.googleapis.com/v1beta/models/\" + selectedModel + \":generateContent?key=\" + key;", + "", + " const payload = {", + " contents: [{", + " parts: [{ ", + " text: \"Rolle/Instruktion: \" + personality + \"\\n\\nSpieler: \" + userQuery ", + " }]", + " }]", + " };", + "", + " fetch(url, {", + " method: 'POST',", + " headers: { 'Content-Type': 'application/json' },", + " body: JSON.stringify(payload)", + " })", + " .then(response => response.json())", + " .then(data => {", + " if (data.error) {", + " gdVariable.setString(\"Fehler (\" + selectedModel + \"): \" + data.error.message);", + " console.error(\"Gemini Error:\", data.error);", + " } else if (data.candidates && data.candidates[0].content) {", + " const aiText = data.candidates[0].content.parts[0].text;", + " gdVariable.setString(aiText);", + " } else {", + " gdVariable.setString(\"Fehler: Das Modell hat keine Antwort geliefert.\");", + " }", + " })", + " .catch(err => {", + " gdVariable.setString(\"Netzwerkfehler!\");", + " console.error(\"Fetch Error:\", err);", + " });", + " }", + " " + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "API Key", + "name": "API_Key", + "type": "string" + }, + { + "description": "\"Personality of AI\" or \"extra instructions\" ", + "name": "Message", + "type": "string" + }, + { + "description": "Your Message Input", + "name": "TextInput", + "type": "string" + }, + { + "description": "This is where the AI's message is stored ", + "name": "Scene_Variable", + "type": "string" + }, + { + "description": "These three models are free, but you can also use others", + "name": "Model", + "supplementaryInformation": "[\"gemini-3-flash-preview\",\"gemini-3.1-flash-lite-preview\"]", + "type": "stringWithSelector" + } + ], + "objectGroups": [] + }, + { + "description": "Sends a Message to OpenRouter and Back to the scene Variable.", + "fullName": "Send Message to OpenRouter", + "functionType": "Action", + "name": "OpenRouter_Connector", + "sentence": "Sends _PARAM3_ and _PARAM4_ to OpenRouter and with the API _PARAM1_ it gets send to _PARAM2_ and the Message gets saved in _PARAM5_ and also in _PARAM6_ and _PARAM7_", + "events": [ + { + "type": "BuiltinCommonInstructions::JsCode", + "inlineCode": [ + "// 1. Parameter holen", + "const apiKey = eventsFunctionContext.getArgument(\"API_Key\");", + "const modelName = eventsFunctionContext.getArgument(\"Model\");", + "const extraInstructions = eventsFunctionContext.getArgument(\"Message\") || \"\";", + "const sceneVarName = eventsFunctionContext.getArgument(\"SceneVariable\");", + "", + "// 2. Text aus dem Eingabefeld holen", + "const textInputObjects = eventsFunctionContext.getObjects(\"Text_Input\");", + "let userMessage = \"\";", + "if (textInputObjects.length > 0) {", + " // Falls .getText() nicht geht, nutzen wir .getString() als Backup", + " userMessage = typeof textInputObjects[0].getText === \"function\" ", + " ? textInputObjects[0].getText() ", + " : textInputObjects[0].getString();", + " }", + "", + " // 3. Variable in der Szene finden", + " const targetVar = runtimeScene.getVariables().get(sceneVarName);", + " if (targetVar) targetVar.setString(\"KI antwortet...\");", + "", + " // 4. API Anfrage", + " fetch(\"https://openrouter.ai/api/v1/chat/completions\", {", + " method: \"POST\",", + " headers: {", + " \"Authorization\": \"Bearer \" + apiKey,", + " \"Content-Type\": \"application/json\"", + " },", + " body: JSON.stringify({", + " \"model\": modelName,", + " \"messages\": [{ \"role\": \"user\", \"content\": extraInstructions + \" \" + userMessage }]", + " })", + " })", + " .then(response => response.json())", + " .then(data => {", + " let result = \"Fehler: Keine Antwort\";", + " if (data.choices && data.choices[0]) {", + " result = data.choices[0].message.content;", + " } else if (data.error) {", + " result = \"API Error: \" + data.error.message;", + " }", + " ", + " // Ergebnis in die Variable schreiben", + " if (targetVar) targetVar.setString(result);", + " })", + " .catch(error => {", + " if (targetVar) targetVar.setString(\"Netzwerk-Fehler: \" + error.message);", + " });", + " " + ], + "parameterObjects": "", + "useStrict": true, + "eventsSheetExpanded": false + } + ], + "parameters": [ + { + "description": "Your API Key", + "name": "API_Key", + "type": "string" + }, + { + "description": "The Model you use", + "name": "Model", + "type": "string" + }, + { + "description": "For extra instructions for the KI", + "name": "Message", + "type": "string" + }, + { + "description": "The TextInput where you write the Messages", + "name": "Text_Input", + "supplementaryInformation": "TextInput::TextInputObject", + "type": "objectList" + }, + { + "description": "The Variable you Use", + "name": "SceneVariable", + "type": "string" + }, + { + "description": "Optional for Rankings on Open Router your Site URL", + "name": "Site_URL", + "type": "string" + }, + { + "description": "Optional Site Title for OpenRouter Rankings", + "name": "Site_Name", + "type": "string" + } + ], + "objectGroups": [] + } + ], + "eventsFunctionsFolderStructure": { + "folderName": "__ROOT", + "children": [ + { + "functionName": "OpenRouter_Connector" + }, + { + "functionName": "Gemini_Connector" + }, + { + "functionName": "Groq_Connector" + }, + { + "functionName": "HuggingFace_Connector" + }, + { + "functionName": "Costume_API" + } + ] + }, + "eventsBasedBehaviors": [], + "eventsBasedObjects": [] +}