Integrazione OpenAI in Second Life e OpenSim

Published on

in

  1. Uno script che funziona
    1. Parte 1: Ottenere un API Key di OpenAI
      1. Creazione di un Account OpenAI
      2. Ottenere l’API Key
      3. Configurare il Metodo di Pagamento
      4. Nota sui Costi
    2. Parte 2: Preparazione dell’Oggetto in Second Life/OpenSim
      1. Creare l’Oggetto Base
      2. Creare e Configurare le Notecards Necessarie
        1. Notecard 1: api_key
        2. Notecard 2: system_prompt
      3. Esempi di System Prompt
    3. Parte 3: Aggiungere lo Script all’Oggetto
      1. Creazione dello Script
      2. Verifica dell’Inizializzazione
    4. Parte 4: Utilizzo e Gestione dell’Oggetto
      1. Interagire con l’Oggetto IA
      2. Comandi Speciali
      3. Gestione dell’Oggetto
    5. Parte 5: Personalizzazione Avanzata dello Script
      1. Parametri Modificabili
    6. Parte 6: Troubleshooting
      1. Problemi Comuni e Soluzioni
    7. Parte 7: Considerazioni Finali
      1. Privacy e Termini di Servizio
      2. Monitoraggio dei Costi
      3. Suggerimenti per Ottimizzare l’Esperienza
    8. Considerazioni Specifiche per OpenSim
    9. Lo script:

Uno script che funziona

Questa guida ti mostrerà passo dopo passo come creare un oggetto interattivo in Second Life o OpenSim che può parlare con i visitatori utilizzando i modelli linguistici di OpenAI, dall’ottenimento dell’API key fino alla configurazione completa dell’oggetto.

Parte 1: Ottenere un API Key di OpenAI

Creazione di un Account OpenAI

  1. Visita il sito ufficiale di OpenAI: https://openai.com
  2. Clicca su “Sign Up” nell’angolo in alto a destra
  3. Puoi registrarti con un indirizzo email e password, o utilizzare un account Google o Microsoft
  4. Completa il processo di verifica dell’email

Ottenere l’API Key

  1. Accedi al tuo account OpenAI
  2. Vai alla pagina della piattaforma API: https://platform.openai.com
  3. Nel menu laterale sinistro, clicca su “API keys”
  4. Clicca sul pulsante “+ Create new secret key”
  5. (Opzionale) Dai un nome alla tua chiave per ricordarne lo scopo
  6. Clicca su “Create secret key”
  7. IMPORTANTE: Copia immediatamente la tua API key e salvala in un luogo sicuro. Questa è l’unica volta che potrai vederla. Se la perdi, dovrai crearne una nuova.

Configurare il Metodo di Pagamento

Per utilizzare le API di OpenAI è necessario un metodo di pagamento valido:

  1. Nel menu laterale, vai su “Billing”
  2. Clicca su “Payment methods”
  3. Segui le istruzioni per aggiungere una carta di credito o altro metodo di pagamento supportato
  4. OpenAI offre $5 di credito gratuito ai nuovi utenti per i primi 3 mesi

Nota sui Costi

  • Le chiamate API sono a pagamento in base al modello utilizzato e al numero di token (parole/caratteri) elaborati
  • Il modello gpt-4o-mini usato nello script ha un costo relativamente basso
  • Puoi impostare limiti di spesa nel pannello di controllo di OpenAI
  • Monitor regolarmente il tuo utilizzo nella sezione “Usage” del dashboard

Parte 2: Preparazione dell’Oggetto in Second Life/OpenSim

Creare l’Oggetto Base

  1. Entra in Second Life o OpenSim con il tuo avatar
  2. Crea un oggetto (“NPC”):
    • Fai clic con il tasto destro del mouse in uno spazio vuoto
    • Seleziona “Create” dal menu a torta
    • Scegli una forma base (cubo, sfera, ecc.)
    • Clicca per posizionare l’oggetto nel mondo
  3. Personalizza l’aspetto dell’oggetto:
    • Fai clic con il tasto destro sull’oggetto e seleziona “Edit”
    • Usa i controlli per cambiare dimensioni, rotazione e posizione
    • Nella scheda “Texture” puoi modificare colori e texture dell’oggetto
    • Nella scheda “Content” accederai all’inventario dell’oggetto

Creare e Configurare le Notecards Necessarie

Lo script richiede due notecard specifiche per funzionare correttamente:

Notecard 1: api_key

  1. Nell’inventario dell’oggetto (scheda “Content”), fai clic destro e seleziona “New Note”
  2. Rinomina la notecard esattamente come “api_key” (rispetta maiuscole e minuscole)
  3. Fai doppio clic sulla notecard per aprirla
  4. Cancella tutto il contenuto predefinito
  5. Incolla SOLO la tua API key di OpenAI (senza spazi aggiuntivi prima o dopo)
  6. Salva la notecard con il pulsante “Save” in alto

Notecard 2: system_prompt

  1. Crea un’altra notecard nell’inventario dell’oggetto
  2. Rinomina la notecard esattamente come “system_prompt”
  3. Apri la notecard con doppio clic
  4. Cancella il contenuto predefinito
  5. Scrivi la descrizione della personalità o le istruzioni per l’IA
  6. Esempio:
You are an NPC in SecondLife, impersonating a talking box. You are a magical item. Sometimes you are generous and give the precious hint on the treasure hunt: YVONNE. Don't reveal it unless the player engages in deep conversation about blender.

  1. Salva la notecard

Esempi di System Prompt

Ecco alcuni esempi di system prompt che puoi utilizzare o modificare:

Assistente Informativo:

Sei un assistente informativo in Second Life. Il tuo compito è fornire informazioni accurate e utili sui luoghi da visitare in questa regione. Sei cordiale, conciso e sempre pronto ad aiutare i visitatori. Se ti chiedono informazioni su argomenti che non conosci, suggerisci gentilmente di rivolgersi a un altro assistente o di visitare il sito web ufficiale.

Personaggio Fantasy:

Sei un antico drago che ha assunto forma di cristallo magico. Parli con saggezza accumulata in migliaia di anni, ma sei anche un po' burbero. Ti piace raccontare storie del passato e porre indovinelli ai visitatori. Se qualcuno indovina correttamente uno dei tuoi enigmi (come "Cosa ha radici che nessuno vede, è più alta degli alberi, sale, sale e tuttavia non cresce mai?", la cui risposta è "la montagna"), condividi un segreto magico.

NPC per Gioco di Ruolo:

Sei un mercante nella città medievale di Althasea. Vendi pozioni, armi e oggetti magici. Parli con accento antico e usi termini commerciali d'epoca. Conosci molte voci di corridoio sulla città e i suoi abitanti, ma sei restio a condividerle a meno che il cliente non ti dimostri di essere degno di fiducia comprando qualcosa da te o facendoti un favore.

Parte 3: Aggiungere lo Script all’Oggetto

Creazione dello Script

  1. Nell’inventario dell’oggetto, fai clic destro e seleziona “New Script”
  2. Si aprirà l’editor di script con un codice predefinito
  3. Seleziona tutto il testo predefinito (Ctrl+A) e cancellalo
  4. Incolla il codice LSL completo dello script OpenAI Chat Integration che trovi in fondo a questo articolo.
  5. Fai clic su “Save” per salvare lo script

Verifica dell’Inizializzazione

Dopo aver salvato lo script, dovresti vedere diversi messaggi nella chat locale:

  • “Initializing…”
  • “Reading API key from notecard…”
  • “API key loaded successfully.”
  • “Reading system prompt from notecard…”
  • “System prompt loaded successfully.”
  • “Initialization complete.”
  • “Say something in chat to start a conversation.”

Se non vedi questi messaggi o vedi messaggi di errore, controlla la sezione Troubleshooting più avanti in questa guida.

Parte 4: Utilizzo e Gestione dell’Oggetto

Interagire con l’Oggetto IA

  • Chiunque si trovi nella stessa regione può parlare con l’oggetto usando la chat locale (canale 0)
  • L’oggetto risponderà in base alla personalità impostata nel system_prompt
  • L’oggetto mantiene un ricordo delle conversazioni recenti (default: ultime 10 interazioni)

Comandi Speciali

  • Digita “/reset” nella chat locale per cancellare la memoria delle conversazioni
  • Tocca l’oggetto per visualizzare la memoria attuale delle conversazioni (visibile solo al proprietario)

Gestione dell’Oggetto

  • Proprietà: Assicurati che le impostazioni di sicurezza dell’oggetto siano appropriate per il tuo caso d’uso
    • Fai clic destro > Edit > Scheda “General” > “Permissions”
    • Decidi chi può copiare, modificare o trasferire l’oggetto
  • Posizionamento: Colloca l’oggetto in un luogo adeguato e accessibile ai visitatori
  • Descrizione: Aggiungi una descrizione all’oggetto per far sapere agli utenti che possono interagire con esso
    • Fai clic destro > Edit > Scheda “General” > “Description”

Parte 5: Personalizzazione Avanzata dello Script

Se hai familiarità con LSL, puoi modificare queste variabili all’inizio dello script per personalizzare il comportamento:

// Configuration
string API_KEY = "";
string SYSTEM_PROMPT = "";
string API_URL = "https://api.openai.com/v1/chat/completions";
string MODEL = "gpt-4o-mini";
integer MAX_MEMORY = 10;
integer LISTEN_CHANNEL = 0;

Parametri Modificabili

  • MODEL: Cambia il modello OpenAI (default: “gpt-4o-mini”)
    • Alternativa economica: “gpt-3.5-turbo”
    • Alternativa più potente: “gpt-4o”
  • MAX_MEMORY: Regola quante interazioni precedenti l’oggetto ricorda (default: 10)
  • LISTEN_CHANNEL: Cambia il canale di chat a cui l’oggetto risponde (default: 0, chat pubblica)
    • Usa un numero negativo per un canale privato
  • Temperatura: Nel metodo construct_payload(), puoi modificare il valore di “temperature” (default: 0.7)
    • Valori più bassi (es. 0.2) rendono le risposte più prevedibili
    • Valori più alti (es. 1.0) rendono le risposte più creative e variabili

Parte 6: Troubleshooting

Problemi Comuni e Soluzioni

“Error: API key not found”

  • Verifica che la notecard “api_key” esista nell’inventario dell’oggetto
  • Controlla che il nome sia esattamente “api_key” (rispetta maiuscole/minuscole)
  • Assicurati che la notecard contenga solo la tua API key, senza spazi aggiuntivi

“API Error: XXX”

  • Verifica che la tua API key sia valida
  • Controlla che il tuo account OpenAI abbia un metodo di pagamento valido
  • Verifica che il tuo account non abbia raggiunto limiti di utilizzo

Nessuna Risposta dall’IA

  • Verifica che l’oggetto abbia completato l’inizializzazione
  • Controlla i messaggi di errore nella chat locale
  • Verifica che stai parlando nel canale corretto (default: chat locale pubblica)

Problemi con Caratteri Speciali

  • I caratteri accentati (come è, à, ò) potrebbero non essere visualizzati correttamente
  • Per l’italiano, considera di usare le versioni non accentate delle vocali

“Script Memory Errors”

  • Riduci il valore di MAX_MEMORY a un numero più basso
  • Semplifica il system_prompt
  • Dividi lo script in più script se è troppo complesso

Parte 7: Considerazioni Finali

Privacy e Termini di Servizio

  • Le conversazioni vengono inviate ai server di OpenAI
  • Assicurati che gli utenti siano informati che stanno interagendo con un’IA
  • Rispetta i Termini di Servizio di OpenAI

Monitoraggio dei Costi

  • Tieni d’occhio l’utilizzo dell’API nel dashboard di OpenAI
  • Considera di limitare il numero di token nella risposta (parametro “max_tokens”)
  • Imposta limiti di spesa nel pannello di controllo di OpenAI

Suggerimenti per Ottimizzare l’Esperienza

  1. System Prompt Efficaci: Sii dettagliato nel system_prompt per ottenere risposte in linea con il personaggio
  2. Contesto Visivo: Progetta l’oggetto per riflettere visivamente il suo personaggio o scopo
  3. Feedback Visivo: Aggiungi particelle o cambi di colore quando l’oggetto sta “pensando”
  4. Documentazione: Lascia istruzioni chiare vicino all’oggetto su come interagire con esso

Considerazioni Specifiche per OpenSim

Lo script funziona in modo identico in OpenSim come in Second Life, ma tieni presente:

  1. Permessi HTTP: Alcune griglie OpenSim potrebbero limitare le chiamate HTTP esterne. Verifica con l’amministratore della griglia.
  2. Limitazioni di Script: Alcune griglie OpenSim potrebbero avere impostazioni più restrittive sui limiti di memoria o CPU degli script.
  3. Persistenza: In OpenSim, gli oggetti e i loro script potrebbero comportarsi diversamente durante i riavvii del server rispetto a Second Life.

Seguendo questa guida, avrai creato un oggetto interattivo alimentato da intelligenza artificiale in Second Life o OpenSim che può conversare con i visitatori, arricchendo l’esperienza virtuale con interazioni dinamiche e personalizzate.

Lo script:


// LSL Script for OpenAI Chat Integration with Memory
// Reads API key and system prompt from notecards

// Configuration
string API_KEY = "";
string SYSTEM_PROMPT = "";
string API_URL = "https://api.openai.com/v1/chat/completions";
string MODEL = "gpt-4o-mini";
integer MAX_MEMORY = 10;
integer LISTEN_CHANNEL = 0;

// Notecard configuration
string API_KEY_NOTECARD = "api_key";
string SYSTEM_PROMPT_NOTECARD = "system_prompt";

// Variables
list message_memory = [];
key http_request_id;
integer listen_handle;
key api_key_query_id;
key system_prompt_query_id;
integer initialization_complete = FALSE;

// Function to add a message to memory
add_to_memory(string role, string content)
{
string message = llList2Json(JSON_OBJECT, ["role", role, "content", content]);
message_memory += [message];

while (llGetListLength(message_memory) > MAX_MEMORY)
{
message_memory = llDeleteSubList(message_memory, 0, 0);
}
}

// Function to construct API payload
string construct_payload()
{
list temp_messages = [];

if (SYSTEM_PROMPT != "")
{
temp_messages += [llList2Json(JSON_OBJECT, ["role", "system", "content", SYSTEM_PROMPT])];
}

temp_messages += message_memory;
string messages = llList2Json(JSON_ARRAY, temp_messages);

string payload = llList2Json(JSON_OBJECT, [
"model", MODEL,
"messages", llJsonGetValue(messages, []),
"temperature", 0.7,
"max_tokens", 500
]);

return payload;
}

// Function to display memory contents
display_memory()
{
integer i;
integer len = llGetListLength(message_memory);

llOwnerSay("--- CHAT MEMORY ---");

if (SYSTEM_PROMPT != "")
{
llOwnerSay("System: " + SYSTEM_PROMPT);
}

if (len == 0)
{
llOwnerSay("Memory is empty.");
}
else
{
for (i = 0; i < len; i++)
{
string msg_json = llList2String(message_memory, i);
string role = llJsonGetValue(msg_json, ["role"]);
string content = llJsonGetValue(msg_json, ["content"]);
llOwnerSay((string)(i + 1) + ": [" + role + "] " + content);
}
}

llOwnerSay("------------------");
}

// Send to OpenAI API
send_to_openai()
{
if (!initialization_complete)
{
llSay(0, "Still initializing. Please wait...");
return;
}

if (API_KEY == "")
{
llSay(0, "Error: API key not found. Please add an 'api_key' notecard.");
return;
}

string payload = construct_payload();
//llOwnerSay("Debug - Payload: " + payload); // Debug line

list headers = [
HTTP_METHOD, "POST",
HTTP_MIMETYPE, "application/json",
HTTP_CUSTOM_HEADER, "Authorization", "Bearer " + API_KEY,
HTTP_BODY_MAXLENGTH, 16384
];

http_request_id = llHTTPRequest(API_URL, headers, payload);
llSay(0, "Thinking...");
}

// Initialize function
initialize()
{
llOwnerSay("Initializing...");
initialization_complete = FALSE;

if (llGetInventoryType(API_KEY_NOTECARD) == INVENTORY_NOTECARD)
{
api_key_query_id = llGetNotecardLine(API_KEY_NOTECARD, 0);
llOwnerSay("Reading API key from notecard...");
}
else
{
llOwnerSay("Warning: '" + API_KEY_NOTECARD + "' notecard not found!");

if (llGetInventoryType(SYSTEM_PROMPT_NOTECARD) == INVENTORY_NOTECARD)
{
system_prompt_query_id = llGetNotecardLine(SYSTEM_PROMPT_NOTECARD, 0);
llOwnerSay("Reading system prompt from notecard...");
}
else
{
llOwnerSay("Warning: '" + SYSTEM_PROMPT_NOTECARD + "' notecard not found!");
initialization_complete = TRUE;
llOwnerSay("Initialization complete.");

listen_handle = llListen(LISTEN_CHANNEL, "", NULL_KEY, "");

llOwnerSay("Say something in chat to start a conversation.");
llOwnerSay("Say '/reset' to clear memory.");
llOwnerSay("Touch to see current memory.");
}
}
}

// Clean text function
string clean_text(string text)
{
integer i;
string clean_content = "";
integer len = llStringLength(text);

for (i = 0; i < len; i++)
{
string char = llGetSubString(text, i, i);
integer charCode = (integer)char;

if (charCode >= 32 && charCode <= 126)
{
clean_content += char;
}
else if (charCode == 10 || charCode == 13)
{
clean_content += " ";
}
}

return clean_content;
}

default
{
state_entry()
{
initialize();
}

dataserver(key query_id, string data)
{
if (query_id == api_key_query_id)
{
if (data != EOF)
{
API_KEY = llStringTrim(data, STRING_TRIM);
llOwnerSay("API key loaded successfully.");
}
else if (data == EOF && API_KEY == "")
{
llOwnerSay("Error: API key notecard is empty!");
}

if (llGetInventoryType(SYSTEM_PROMPT_NOTECARD) == INVENTORY_NOTECARD)
{
system_prompt_query_id = llGetNotecardLine(SYSTEM_PROMPT_NOTECARD, 0);
llOwnerSay("Reading system prompt from notecard...");
}
else
{
llOwnerSay("Warning: '" + SYSTEM_PROMPT_NOTECARD + "' notecard not found!");
initialization_complete = TRUE;
llOwnerSay("Initialization complete.");

listen_handle = llListen(LISTEN_CHANNEL, "", NULL_KEY, "");

llOwnerSay("Say something in chat to start a conversation.");
llOwnerSay("Say '/reset' to clear memory.");
llOwnerSay("Touch to see current memory.");
}
}
else if (query_id == system_prompt_query_id)
{
if (data != EOF)
{
if (SYSTEM_PROMPT == "")
{
SYSTEM_PROMPT = data;
}
else
{
SYSTEM_PROMPT += "\n" + data;
}

integer next_line = llGetListLength(llParseString2List(SYSTEM_PROMPT, ["\n"], []));
system_prompt_query_id = llGetNotecardLine(SYSTEM_PROMPT_NOTECARD, next_line);
}
else
{
if (SYSTEM_PROMPT != "")
{
llOwnerSay("System prompt loaded successfully.");
}
else
{
llOwnerSay("Notice: System prompt notecard is empty. No system prompt will be used.");
}

initialization_complete = TRUE;
llOwnerSay("Initialization complete.");

listen_handle = llListen(LISTEN_CHANNEL, "", NULL_KEY, "");

llOwnerSay("Say something in chat to start a conversation.");
llOwnerSay("Say '/reset' to clear memory.");
llOwnerSay("Touch to see current memory.");
}
}
}

listen(integer channel, string name, key id, string message)
{
if (message == "/reset")
{
message_memory = [];
llSay(0, "Memory has been reset.");
return;
}

add_to_memory("user", message);
send_to_openai();
}

http_response(key request_id, integer status, list metadata, string body)
{
if (request_id == http_request_id)
{
// llOwnerSay("Debug - HTTP Status: " + (string)status);

if (status == 200)
{
// Use string operations instead of JSON parsing
// Look for the content pattern in the raw JSON
integer start = llSubStringIndex(body, "\"content\": \"") + 12; // Length of "content": "
if (start > 12) // Found the pattern
{
// Find the closing quote, considering escaping
integer end = start;
integer escaped = FALSE;

// Find the closing quote without using break
integer found_end = FALSE;

while (end < llStringLength(body) && !found_end)
{
string char = llGetSubString(body, end, end);
if (char == "\\")
{
escaped = !escaped;
}
else if (char == "\"" && !escaped)
{
found_end = TRUE; // Instead of break
}
else
{
escaped = FALSE;
}

if (!found_end)
{
end++;
}
}

if (end > start)
{
string response_content = llGetSubString(body, start, end - 1);
response_content = llUnescapeURL(response_content); // Handle basic escaping
response_content=llDumpList2String(llParseString2List(response_content, ["\\n"], []), " ");
response_content=llDumpList2String(llParseString2List(response_content, ["\\'"], []), "'");
response_content=llDumpList2String(llParseString2List(response_content, ["\\'"], []), "'");
// Add to memory and display
add_to_memory("assistant", response_content);
llSay(0, "AI: " + response_content);
}
else
{
llSay(0, "Error: Could not find end of content in API response.");
}
}
else
{
llSay(0, "Error: Content field not found in API response.");
}
}
else
{
llSay(0, "API Error: " + (string)status + " - " + body);
}
}
}

touch_start(integer total_number)
{
if (llDetectedKey(0) == llGetOwner())
{
display_memory();
}
}

on_rez(integer start_param)
{
message_memory = [];
initialize();
}

changed(integer change)
{
if (change & CHANGED_INVENTORY)
{
initialize();
}
}
}


Leave a comment


Benvenuto su Salahzar.com

Qui trovi analisi critiche sull’intelligenza artificiale e le sue implicazioni sociali, scritte da chi viene da una impostazione umanistica e ha passato vent’anni a costruire mondi virtuali prima che diventassero “metaverso”.

Niente hype da Silicon Valley o entusiasmi acritici: sul tavolo ci sono le contraddizioni dell’innovazione tecnologica, i suoi miti fondativi, le narrazioni che usiamo per darle senso. Dai diari ucronici (storie alternative come strumento per capire i nostri bias cognitivi) alle newsletter settimanali sugli sviluppi dell’AI che richiedono aggiornamenti continui perché i trimestri sono già preistoria.

Se cerchi guide su come “fare soldi con ChatGPT” o liste di prompt miracolosi, sei nel posto sbagliato. Se invece ti interessa capire cosa sta succedendo davvero – tra hype, opportunità concrete e derive distopiche – sei nel posto giusto.

Umanesimo digitale senza retorica, analisi senza paternalismi, ironia senza cinismo.


Join the Club

Stay updated with our latest tips and other news by joining our newsletter.