Browse Source

Oasis release 0.3.8

psy 1 week ago
parent
commit
c1fc03f54f

+ 15 - 1
README.md

@@ -39,7 +39,6 @@ But it has others features that are also really interesting, for example:
     
     
  +  Support for multiple themes.
  +  Support for multiple themes.
  
  
- 
    ![SNH](https://solarnethub.com/git/snh-clear-theme.png "SolarNET.HuB")
    ![SNH](https://solarnethub.com/git/snh-clear-theme.png "SolarNET.HuB")
    ![SNH](https://solarnethub.com/git/snh-purple-theme.png "SolarNET.HuB")
    ![SNH](https://solarnethub.com/git/snh-purple-theme.png "SolarNET.HuB")
    ![SNH](https://solarnethub.com/git/snh-matrix-theme.png "SolarNET.HuB")
    ![SNH](https://solarnethub.com/git/snh-matrix-theme.png "SolarNET.HuB")
@@ -53,6 +52,7 @@ And much more, that we invite you to discover by yourself ;-)
 Oasis is TRULY MODULAR. Here's a list of what comes deployed with the "core".
 Oasis is TRULY MODULAR. Here's a list of what comes deployed with the "core".
 
 
  + Agenda: Module to manage all your assigned items.
  + Agenda: Module to manage all your assigned items.
+ + AI: Module to talk with a LLM called '42'.
  + Audios: Module to discover and manage audios.
  + Audios: Module to discover and manage audios.
  + Bookmarks: Module to discover and manage bookmarks.	
  + Bookmarks: Module to discover and manage bookmarks.	
  + Cipher: Module to encrypt and decrypt your text symmetrically (using a shared password).	
  + Cipher: Module to encrypt and decrypt your text symmetrically (using a shared password).	
@@ -85,6 +85,20 @@ Both the codebase and the inhabitants can generate new modules.
 
 
 ----------
 ----------
 
 
+## C-AI (collective artificial intelligence)
+
+Oasis contains its own AI model called "42". 
+
+The main idea behind this implementation is to enable distributed learning generated through the collective action of many individuals, with the goal of redistributing the necessary processing load, as well as the ecological footprint and corporate bias.
+
+  ![SNH](https://solarnethub.com/git/oasis-ai-example.png "SolarNET.HuB")
+
+Our AI is trained with content from the OASIS network and its purpose is to take action and obtain answers to individual, but also global, problems.
+
+ + https://wiki.solarnethub.com/socialnet/ai
+
+----------
+
 ## ECOin (crypto-economy)
 ## ECOin (crypto-economy)
 
 
 Oasis contains its own cryptocurrency. With it, you can exchange items and services in the marketplace. 
 Oasis contains its own cryptocurrency. With it, you can exchange items and services in the marketplace. 

+ 17 - 0
docs/AI/info.md

@@ -0,0 +1,17 @@
+# Oasis AI General Info
+
+Collective Artificial Intelligence (CAI) model called "42" is based into: llama-2-7b-chat.Q4_K_M.
+
+https://huggingface.co/TheBloke/Llama-2-7B-Chat-GGUF
+
+This is a static model trained in English on an offline dataset with a size of: 3,8 GiB (4.081.004.224 bytes). 
+
+---
+
+The main idea behind this implementation of an GGUF/LLM in the OASIS network is to enable distributed learning generated through the collective action of many individuals, with the goal of redistributing the necessary processing load, as well as the ecological footprint and corporate bias.
+
+Our AI will be trained with content from the OASIS network and its purpose is to take action and obtain answers to individual, but also global, problems.
+
+Future versions of the tuned model will be released as we improve model safety with community feedback.
+
+---

+ 6 - 0
docs/CHANGELOG.md

@@ -13,6 +13,12 @@ All notable changes to this project will be documented in this file.
 ### Security
 ### Security
 -->
 -->
 
 
+## v0.3.8 - 2025-07-21
+
+### Added
+
+- AI model called "42".
+
 ## v0.3.5 - 2025-06-21 (summer solstic)
 ## v0.3.5 - 2025-06-21 (summer solstic)
 
 
 ### Changed
 ### Changed

+ 22 - 2
install.sh

@@ -1,14 +1,34 @@
 #!/bin/bash
 #!/bin/bash
 
 
 cd src/server
 cd src/server
+
 printf "==========================\n"
 printf "==========================\n"
-printf "|| OASIS Installer v0.1 ||\n"
+printf "|| OASIS Installer v0.2 ||\n"
 printf "==========================\n"
 printf "==========================\n"
-sudo apt-get install git curl
+
+sudo apt-get install -y git curl tar
+
 curl -sL http://deb.nodesource.com/setup_22.x | sudo bash -
 curl -sL http://deb.nodesource.com/setup_22.x | sudo bash -
 sudo apt-get install -y nodejs
 sudo apt-get install -y nodejs
 npm install .
 npm install .
 npm audit fix
 npm audit fix
+
+MODEL_DIR="../AI"
+MODEL_FILE="oasis-42-1-chat.Q4_K_M.gguf"
+MODEL_TAR="$MODEL_FILE.tar.gz"
+MODEL_URL="https://solarnethub.com/code/models/$MODEL_TAR"
+
+if [ ! -f "$MODEL_DIR/$MODEL_FILE" ]; then
+    echo ""
+    echo "downloading AI model [size: 3,8 GiB (4.081.004.224 bytes)] ..."
+    curl -L -o "$MODEL_DIR/$MODEL_TAR" "$MODEL_URL"
+    echo ""
+    echo "extracting package: $MODEL_TAR..."
+    echo ""
+    tar -xzf "$MODEL_DIR/$MODEL_TAR" -C "$MODEL_DIR"
+    rm "$MODEL_DIR/$MODEL_TAR"
+fi
+
 printf "==========================\n"
 printf "==========================\n"
 printf "\nOASIS has been correctly deployed! ;)\n\n"
 printf "\nOASIS has been correctly deployed! ;)\n\n"
 printf "Run: 'sh oasis.sh' to start ...\n\n"
 printf "Run: 'sh oasis.sh' to start ...\n\n"

+ 13 - 2
oasis.sh

@@ -2,11 +2,22 @@
 
 
 CURRENT_DIR=$(pwd)
 CURRENT_DIR=$(pwd)
 MODE=$1
 MODE=$1
+MODEL_PATH="$CURRENT_DIR/src/AI/oasis-42-1-chat.Q4_K_M.gguf"
+CONFIG_FILE="$CURRENT_DIR/src/configs/oasis-config.json"
+
+if [ -f "$CONFIG_FILE" ]; then
+  if [ -f "$MODEL_PATH" ]; then
+    sed -i.bak 's/"aiMod": *"off"/"aiMod": "on"/' "$CONFIG_FILE"
+  else
+    sed -i.bak 's/"aiMod": *"on"/"aiMod": "off"/' "$CONFIG_FILE"
+  fi
+  rm -f "$CONFIG_FILE.bak"
+fi
 
 
 if [ "$MODE" = "server" ]; then
 if [ "$MODE" = "server" ]; then
-  cd "$CURRENT_DIR/src/server" || { echo "Directory not found: $CURRENT_DIR/src/server"; exit 1; }
+  cd "$CURRENT_DIR/src/server" || exit 1
   exec node SSB_server.js start
   exec node SSB_server.js start
 else
 else
-  cd "$CURRENT_DIR/src/backend" || { echo "Directory not found: $CURRENT_DIR/src/backend"; exit 1; }
+  cd "$CURRENT_DIR/src/backend" || exit 1
   exec node backend.js
   exec node backend.js
 fi
 fi

+ 48 - 0
src/AI/ai_service.mjs

@@ -0,0 +1,48 @@
+import path from 'path';
+import { fileURLToPath } from 'url';
+import express from '../server/node_modules/express/index.js'; 
+import cors from '../server/node_modules/cors/lib/index.js';   
+import { getLlama, LlamaChatSession } from '../server/node_modules/node-llama-cpp/dist/index.js';
+
+const app = express();
+app.use(cors());
+app.use(express.json());
+
+const __filename = fileURLToPath(import.meta.url);
+const __dirname = path.dirname(__filename);
+
+let llamaInstance, model, context, session;
+
+async function initModel() {
+  if (!model) {
+    llamaInstance = await getLlama({ gpu: false });
+    model = await llamaInstance.loadModel({
+      modelPath: path.join(__dirname, '..', 'AI', 'oasis-42-1-chat.Q4_K_M.gguf')
+    });
+    context = await model.createContext();
+    session = new LlamaChatSession({ contextSequence: context.getSequence() });
+  }
+}
+
+app.post('/ai', async (req, res) => {
+    const userInput = req.body.input;
+
+    await initModel();  
+    const prompt = `
+      Context: You are an AI assistant in Oasis, a distributed, encrypted and federated social network created by old-school hackers.
+
+      Query: "${userInput}"
+
+      Provide an informative and precise response.
+    `;
+
+    const response = await session.prompt(prompt);
+    if (!response) {
+      res.status(500).json({ error: 'Failed to get response from model' });
+      return;
+    }
+    res.json({ answer: response.trim() });
+});
+
+app.listen(4001, () => {
+});

+ 52 - 12
src/backend/backend.js

@@ -11,6 +11,7 @@ const promisesFs = require("fs").promises;
 const SSBconfig = require('../server/SSB_server.js');
 const SSBconfig = require('../server/SSB_server.js');
 const moment = require('../server/node_modules/moment');
 const moment = require('../server/node_modules/moment');
 const FileType = require('../server/node_modules/file-type');
 const FileType = require('../server/node_modules/file-type');
+const ssbRef = require("../server/node_modules/ssb-ref");
 
 
 const defaultConfig = {};
 const defaultConfig = {};
 const defaultConfigFile = path.join(
 const defaultConfigFile = path.join(
@@ -40,6 +41,17 @@ if (config.debug) {
   process.env.DEBUG = "oasis,oasis:*";
   process.env.DEBUG = "oasis,oasis:*";
 }
 }
 
 
+//AI
+const { spawn } = require('child_process');
+function startAI() {
+  const aiPath = path.resolve(__dirname, '../AI/ai_service.mjs');
+  const aiProcess = spawn('node', [aiPath], {
+    detached: false,
+    stdio: 'ignore', //inherit for debug
+  });
+  aiProcess.unref();
+}
+
 const customStyleFile = path.join(
 const customStyleFile = path.join(
   envPaths("oasis", { suffix: "" }).config,
   envPaths("oasis", { suffix: "" }).config,
   "/custom-style.css"
   "/custom-style.css"
@@ -394,8 +406,7 @@ const { imageView, singleImageView } = require("../views/image_view");
 const { settingsView } = require("../views/settings_view");
 const { settingsView } = require("../views/settings_view");
 const { trendingView } = require("../views/trending_view");
 const { trendingView } = require("../views/trending_view");
 const { marketView, singleMarketView } = require("../views/market_view");
 const { marketView, singleMarketView } = require("../views/market_view");
-
-const ssbRef = require("../server/node_modules/ssb-ref");
+const { aiView } = require("../views/AI_view");
 
 
 let sharp;
 let sharp;
 
 
@@ -506,25 +517,40 @@ router
     ctx.body = await publicPopular({ period });
     ctx.body = await publicPopular({ period });
    }) 
    }) 
    
    
-   // pixelArt
-  .get('/pixelia', async (ctx) => {
-    const pixelArt = await pixeliaModel.listPixels();
-    ctx.body = pixeliaView(pixelArt);
-  })
-  // modules
+   // modules
   .get("/modules", async (ctx) => {
   .get("/modules", async (ctx) => {
     const configMods = getConfig().modules;
     const configMods = getConfig().modules;
     const modules = [
     const modules = [
     'popular', 'topics', 'summaries', 'latest', 'threads', 'multiverse', 'invites', 'wallet', 
     'popular', 'topics', 'summaries', 'latest', 'threads', 'multiverse', 'invites', 'wallet', 
     'legacy', 'cipher', 'bookmarks', 'videos', 'docs', 'audios', 'tags', 'images', 'trending', 
     'legacy', 'cipher', 'bookmarks', 'videos', 'docs', 'audios', 'tags', 'images', 'trending', 
     'events', 'tasks', 'market', 'tribes', 'governance', 'reports', 'opinions', 'transfers', 
     'events', 'tasks', 'market', 'tribes', 'governance', 'reports', 'opinions', 'transfers', 
-    'feed', 'pixelia', 'agenda'
+    'feed', 'pixelia', 'agenda', 'ai'
     ];
     ];
     const moduleStates = modules.reduce((acc, mod) => {
     const moduleStates = modules.reduce((acc, mod) => {
       acc[`${mod}Mod`] = configMods[`${mod}Mod`];
       acc[`${mod}Mod`] = configMods[`${mod}Mod`];
       return acc;
       return acc;
     }, {});
     }, {});
     ctx.body = modulesView(moduleStates);
     ctx.body = modulesView(moduleStates);
+  })
+   // AI
+  .get('/ai', async (ctx) => {
+    const aiMod = ctx.cookies.get("aiMod") || 'on';
+    if (aiMod !== 'on') {
+      ctx.redirect('/modules');
+      return;
+    }
+    startAI();
+    ctx.body = aiView();
+  })
+   // pixelArt
+  .get('/pixelia', async (ctx) => {
+    const pixeliaMod = ctx.cookies.get("pixeliaMod") || 'on';
+    if (pixeliaMod !== 'on') {
+      ctx.redirect('/modules');
+      return;
+    }
+    const pixelArt = await pixeliaModel.listPixels();
+    ctx.body = pixeliaView(pixelArt);
   })
   })
   .get("/public/latest", async (ctx) => {
   .get("/public/latest", async (ctx) => {
     const latestMod = ctx.cookies.get("latestMod") || 'on';
     const latestMod = ctx.cookies.get("latestMod") || 'on';
@@ -1260,6 +1286,16 @@ router
   })
   })
 
 
   //POST backend routes   
   //POST backend routes   
+  .post('/ai', koaBody(), async (ctx) => {
+    const axios = require('../server/node_modules/axios').default;
+    const { input } = ctx.request.body;
+    if (!input) {
+      return ctx.status = 400, ctx.body = { error: 'No input provided' };
+    }
+    const response = await axios.post('http://localhost:4001/ai', { input });
+    const aiResponse = response.data.answer;
+    ctx.body = aiView(aiResponse, input);
+  })
   .post('/pixelia/paint', koaBody(), async (ctx) => {
   .post('/pixelia/paint', koaBody(), async (ctx) => {
     const { x, y, color } = ctx.request.body;
     const { x, y, color } = ctx.request.body;
     if (x < 1 || x > 50 || y < 1 || y > 200) {
     if (x < 1 || x > 50 || y < 1 || y > 200) {
@@ -2085,7 +2121,7 @@ router
   })
   })
 
 
   // UPDATE OASIS
   // UPDATE OASIS
- .post("/update", koaBody(), async (ctx) => {
+  .post("/update", koaBody(), async (ctx) => {
     const util = require("node:util");
     const util = require("node:util");
     const exec = util.promisify(require("node:child_process").exec);
     const exec = util.promisify(require("node:child_process").exec);
     async function updateTool() {
     async function updateTool() {
@@ -2093,11 +2129,15 @@ router
       console.log("oasis@version: updating Oasis...");
       console.log("oasis@version: updating Oasis...");
       console.log(stdout);
       console.log(stdout);
       console.log(stderr);
       console.log(stderr);
+      const { stdout: shOut, stderr: shErr } = await exec("sh install.sh");
+      console.log("oasis@version: running install.sh...");
+      console.log(shOut);
+      console.error(shErr);
     }
     }
     await updateTool();
     await updateTool();
     const referer = new URL(ctx.request.header.referer);
     const referer = new URL(ctx.request.header.referer);
     ctx.redirect(referer.href);
     ctx.redirect(referer.href);
-  })
+  }) 
   .post("/settings/theme", koaBody(), async (ctx) => {
   .post("/settings/theme", koaBody(), async (ctx) => {
     const theme = String(ctx.request.body.theme);
     const theme = String(ctx.request.body.theme);
     const currentConfig = getConfig();
     const currentConfig = getConfig();
@@ -2153,7 +2193,7 @@ router
     'popular', 'topics', 'summaries', 'latest', 'threads', 'multiverse', 'invites', 'wallet',
     'popular', 'topics', 'summaries', 'latest', 'threads', 'multiverse', 'invites', 'wallet',
     'legacy', 'cipher', 'bookmarks', 'videos', 'docs', 'audios', 'tags', 'images', 'trending',
     'legacy', 'cipher', 'bookmarks', 'videos', 'docs', 'audios', 'tags', 'images', 'trending',
     'events', 'tasks', 'market', 'tribes', 'governance', 'reports', 'opinions', 'transfers',
     'events', 'tasks', 'market', 'tribes', 'governance', 'reports', 'opinions', 'transfers',
-    'feed', 'pixelia', 'agenda'
+    'feed', 'pixelia', 'agenda', 'ai'
     ];
     ];
     const currentConfig = getConfig();
     const currentConfig = getConfig();
     modules.forEach(mod => {
     modules.forEach(mod => {

+ 2 - 2
src/backend/updater.js

@@ -95,7 +95,7 @@ exports.getRemoteVersion = async () => {
       diffVersion(data, (status) => {
       diffVersion(data, (status) => {
         if (status === "required" && !printed) {
         if (status === "required" && !printed) {
           printed = true; 
           printed = true; 
-          console.log("\noasis@version: new code updates are available:\n\n1) Run Oasis and go to 'Settings' tab\n2) Click at 'Get updates' button to download latest code\n3) Restart Oasis when finished\n");
+          console.log("\noasis@version: new code updates are available!\n\n1) Run Oasis and go to 'Settings' tab\n2) Click at 'Get updates' button to download latest code\n3) Restart Oasis when finished\n");
         } else if (status === "") {
         } else if (status === "") {
           console.log("\noasis@version: no updates requested.\n");
           console.log("\noasis@version: no updates requested.\n");
         }
         }
@@ -108,7 +108,7 @@ exports.getRemoteVersion = async () => {
           diffVersion(data, (status) => {
           diffVersion(data, (status) => {
             if (status === "required" && !printed) {
             if (status === "required" && !printed) {
               printed = true; 
               printed = true; 
-              console.log("\noasis@version: new code updates are available:\n\n1) Run Oasis and go to 'Settings' tab\n2) Click at 'Get updates' button to download latest code\n3) Restart Oasis when finished\n");
+              console.log("\noasis@version: new code updates are available!\n\n1) Run Oasis and go to 'Settings' tab\n2) Click at 'Get updates' button to download latest code\n3) Restart Oasis when finished\n");
             } else {
             } else {
               console.log("oasis@version: no updates requested.\n");
               console.log("oasis@version: no updates requested.\n");
             }
             }

+ 11 - 1
src/client/assets/translations/oasis_en.js

@@ -1296,6 +1296,14 @@ module.exports = {
     statsSize: "Total (size)",
     statsSize: "Total (size)",
     statsBlockchainSize: "Blockchain (size)",
     statsBlockchainSize: "Blockchain (size)",
     statsBlobsSize: "Blobs (size)",
     statsBlobsSize: "Blobs (size)",
+    //AI
+    ai: "AI",
+    aiTitle: "AI",
+    aiDescription: "A Collective Artificial Intelligence (CAI) called '42' that learns from your network.",
+    aiInputPlaceholder: "What's up?",
+    aiUserQuestion: "Your Question",
+    aiResponseTitle: "AI Reply",
+    aiSubmitButton: "Send!",
     //market
     //market
     marketMineSectionTitle: "Your Items",
     marketMineSectionTitle: "Your Items",
     marketCreateSectionTitle: "Create a New Item",
     marketCreateSectionTitle: "Create a New Item",
@@ -1406,7 +1414,9 @@ module.exports = {
     modulesPixeliaLabel: "Pixelia",
     modulesPixeliaLabel: "Pixelia",
     modulesPixeliaDescription: "Module to draw on a collaborative grid.",
     modulesPixeliaDescription: "Module to draw on a collaborative grid.",
     modulesAgendaLabel: "Agenda",
     modulesAgendaLabel: "Agenda",
-    modulesAgendaDescription: "Module to manage all your assigned items."
+    modulesAgendaDescription: "Module to manage all your assigned items.",
+    modulesAILabel: "AI",
+    modulesAIDescription: "Module to talk with a LLM called '42'."   
      
      
      //END
      //END
     }
     }

+ 11 - 1
src/client/assets/translations/oasis_es.js

@@ -1295,6 +1295,14 @@ module.exports = {
     statsSize: "Total (tamaño)",
     statsSize: "Total (tamaño)",
     statsBlockchainSize: "Blockchain (tamaño)",
     statsBlockchainSize: "Blockchain (tamaño)",
     statsBlobsSize: "Blobs (tamaño)",
     statsBlobsSize: "Blobs (tamaño)",
+    //AI
+    ai: "IA",
+    aiTitle: "IA",
+    aiDescription: "Una Inteligencia Artificial Colectiva (IAC) llamada '42' que aprende de tu red.",
+    aiInputPlaceholder: "Qué quieres saber?",
+    aiUserQuestion: "Tu pregunta",
+    aiResponseTitle: "Respuesta",
+    aiSubmitButton: "Enviar!",
     //market
     //market
     marketMineSectionTitle: "Tus Artículos",
     marketMineSectionTitle: "Tus Artículos",
     marketCreateSectionTitle: "Crear un Nuevo Artículo",
     marketCreateSectionTitle: "Crear un Nuevo Artículo",
@@ -1405,7 +1413,9 @@ module.exports = {
     modulesPixeliaLabel: "Pixelia",
     modulesPixeliaLabel: "Pixelia",
     modulesPixeliaDescription: "Módulo para dibujar en una cuadrícula colaborativa.",
     modulesPixeliaDescription: "Módulo para dibujar en una cuadrícula colaborativa.",
     modulesAgendaLabel: "Agenda",
     modulesAgendaLabel: "Agenda",
-    modulesAgendaDescription: "Módulo para gestionar todos tus elementos asignados."
+    modulesAgendaDescription: "Módulo para gestionar todos tus elementos asignados.",
+    modulesAILabel: "AI",
+    modulesAIDescription: "Módulo para hablar con un LLM llamado '42'."   
      
      
      //END
      //END
     }
     }

+ 11 - 1
src/client/assets/translations/oasis_eu.js

@@ -1296,6 +1296,14 @@ module.exports = {
     statsSize: "Guztira (taimaina)",
     statsSize: "Guztira (taimaina)",
     statsBlockchainSize: "Blockchain (tamaina)",
     statsBlockchainSize: "Blockchain (tamaina)",
     statsBlobsSize: "Blob-ak (tamaina)",
     statsBlobsSize: "Blob-ak (tamaina)",
+    //IA
+    ai: "IA",
+    aiTitle: "IA",
+    aiDescription: "Zure saretik ikasten duen '42' izeneko Adimen Artifizial Kolektibo (AIA) bat.",
+    aiInputPlaceholder: "Zer jakin nahi duzu?",
+    aiUserQuestion: "Zure galdera",
+    aiResponseTitle: "Erantzuna",
+    aiSubmitButton: "Bidali!",
     //market
     //market
     marketMineSectionTitle: "Zure Elementuak",
     marketMineSectionTitle: "Zure Elementuak",
     marketCreateSectionTitle: "Sortu Elementu Berria",
     marketCreateSectionTitle: "Sortu Elementu Berria",
@@ -1343,6 +1351,7 @@ module.exports = {
     marketItemSeller: "Saltzailea",
     marketItemSeller: "Saltzailea",
     marketNoItems: "Elementurik ez, oraindik.",
     marketNoItems: "Elementurik ez, oraindik.",
     marketYourBid: "Zeure eskaintza",
     marketYourBid: "Zeure eskaintza",
+    marketCreateFormImageLabel: "Igo Irudia (jpeg, jpg, png, gif) (gehienez: 500px x 400px)",
     //modules
     //modules
     modulesModuleName: "Izena",
     modulesModuleName: "Izena",
     modulesModuleDescription: "Deskribapena",
     modulesModuleDescription: "Deskribapena",
@@ -1406,7 +1415,8 @@ module.exports = {
     modulesPixeliaDescription: "Lauki kolaboratibo batean marrazteko modulua.",
     modulesPixeliaDescription: "Lauki kolaboratibo batean marrazteko modulua.",
     modulesAgendaLabel: "Agenda",
     modulesAgendaLabel: "Agenda",
     modulesAgendaDescription: "Esleitu zaizkizun elementu guztiak kudeatzeko modulua.",
     modulesAgendaDescription: "Esleitu zaizkizun elementu guztiak kudeatzeko modulua.",
-    marketCreateFormImageLabel: "Igo Irudia (jpeg, jpg, png, gif) (gehienez: 500px x 400px)",
+    modulesAILabel: "AI",
+    modulesAIDescription: "'42' izeneko LLM batekin hitz egiteko modulua."
 
 
      //END
      //END
   }
   }

+ 2 - 1
src/configs/config-manager.js

@@ -36,7 +36,8 @@ if (!fs.existsSync(configFilePath)) {
       "transfersMod": "on",
       "transfersMod": "on",
       "feedMod": "on",
       "feedMod": "on",
       "pixeliaMod": "on",
       "pixeliaMod": "on",
-      "agendaMod": "on"
+      "agendaMod": "on",
+      "aiMod": "on"
     },
     },
     "wallet": {
     "wallet": {
       "url": "http://localhost:7474",
       "url": "http://localhost:7474",

+ 2 - 1
src/configs/oasis-config.json

@@ -30,7 +30,8 @@
     "transfersMod": "on",
     "transfersMod": "on",
     "feedMod": "on",
     "feedMod": "on",
     "pixeliaMod": "on",
     "pixeliaMod": "on",
-    "agendaMod": "on"
+    "agendaMod": "on",
+    "aiMod": "on"
   },
   },
   "wallet": {
   "wallet": {
     "url": "http://localhost:7474",
     "url": "http://localhost:7474",

File diff suppressed because it is too large
+ 2645 - 333
src/server/package-lock.json


+ 5 - 2
src/server/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@krakenslab/oasis",
   "name": "@krakenslab/oasis",
-  "version": "0.3.7",
+  "version": "0.3.8",
   "description": "Oasis Social Networking Project Utopia",
   "description": "Oasis Social Networking Project Utopia",
   "repository": {
   "repository": {
     "type": "git",
     "type": "git",
@@ -29,14 +29,16 @@
     "abstract-level": "^2.0.1",
     "abstract-level": "^2.0.1",
     "archiver": "^7.0.1",
     "archiver": "^7.0.1",
     "await-exec": "^0.1.2",
     "await-exec": "^0.1.2",
-    "axios": "^1.7.9",
+    "axios": "^1.10.0",
     "base64-url": "^2.3.3",
     "base64-url": "^2.3.3",
     "broadcast-stream": "^0.2.1",
     "broadcast-stream": "^0.2.1",
     "caller-path": "^4.0.0",
     "caller-path": "^4.0.0",
+    "cors": "^2.8.5",
     "crypto": "^1.0.1",
     "crypto": "^1.0.1",
     "debug": "^4.3.1",
     "debug": "^4.3.1",
     "env-paths": "^2.2.1",
     "env-paths": "^2.2.1",
     "epidemic-broadcast-trees": "^9.0.4",
     "epidemic-broadcast-trees": "^9.0.4",
+    "express": "^5.1.0",
     "file-type": "^16.5.4",
     "file-type": "^16.5.4",
     "gpt-3-encoder": "^1.1.4",
     "gpt-3-encoder": "^1.1.4",
     "has-network": "0.0.1",
     "has-network": "0.0.1",
@@ -63,6 +65,7 @@
     "muxrpc-validation": "^3.0.2",
     "muxrpc-validation": "^3.0.2",
     "muxrpcli": "^3.1.2",
     "muxrpcli": "^3.1.2",
     "node-iframe": "^1.8.5",
     "node-iframe": "^1.8.5",
+    "node-llama-cpp": "^3.10.0",
     "non-private-ip": "^2.2.0",
     "non-private-ip": "^2.2.0",
     "open": "^8.4.2",
     "open": "^8.4.2",
     "packet-stream": "^2.0.6",
     "packet-stream": "^2.0.6",

+ 29 - 0
src/views/AI_view.js

@@ -0,0 +1,29 @@
+const { div, h2, p, section, button, form, textarea, br, span } = require("../server/node_modules/hyperaxe");
+const { template, i18n } = require('./main_views');
+
+exports.aiView = (response = '', userQuestion = '') => {
+  return template(
+    i18n.aiTitle,
+    section(
+      div({ class: "tags-header" },
+        h2(i18n.aiTitle),
+        p(i18n.aiDescription),
+        form({ method: 'POST', action: '/ai' },
+          textarea({ name: 'input', placeholder: i18n.aiInputPlaceholder, required: true }),
+          br(),
+          button({ type: 'submit' }, i18n.aiSubmitButton)
+        ),
+        br(),
+        userQuestion ? div({ class: 'user-question' },
+          h2(`${i18n.aiUserQuestion}:`),
+          userQuestion
+        ) : null,
+
+        response ? div({ class: 'ai-response' },
+          h2(`${i18n.aiResponseTitle}:`),
+          response
+        ) : null
+      )
+    )
+  );
+};

+ 1 - 2
src/views/agenda_view.js

@@ -68,9 +68,8 @@ const renderAgendaItem = (item, userId, filter) => {
 
 
   if (item.type === 'tribe') {
   if (item.type === 'tribe') {
     details = [
     details = [
-      renderCardField(i18n.agendaDescriptionLabel + ":",item.description || i18n.noDescription),
       renderCardField(i18n.agendaAnonymousLabel + ":", item.isAnonymous ? i18n.agendaYes : i18n.agendaNo),
       renderCardField(i18n.agendaAnonymousLabel + ":", item.isAnonymous ? i18n.agendaYes : i18n.agendaNo),
-      renderCardField(i18n.agendaInviteModeLabel + ":", item.inviteMode || i18n.noInviteMode),
+      renderCardField(i18n.agendaInviteModeLabel + ":", item.inviteMode.toUpperCase() || i18n.noInviteMode),
       renderCardField(i18n.agendaLARPLabel + ":", item.isLARP ? i18n.agendaYes : i18n.agendaNo),
       renderCardField(i18n.agendaLARPLabel + ":", item.isLARP ? i18n.agendaYes : i18n.agendaNo),
       renderCardField(i18n.agendaLocationLabel + ":", item.location || i18n.noLocation),
       renderCardField(i18n.agendaLocationLabel + ":", item.location || i18n.noLocation),
       renderCardField(i18n.agendaMembersCount + ":", item.members.length || 0),
       renderCardField(i18n.agendaMembersCount + ":", item.members.length || 0),

+ 10 - 1
src/views/main_views.js

@@ -325,6 +325,15 @@ const renderAgendaLink = () => {
     : '';
     : '';
 };
 };
 
 
+const renderAILink = () => {
+  const aiMod = getConfig().modules.aiMod === 'on';
+  return aiMod 
+    ? [
+      navLink({ href: "/ai", emoji: "ꘜ", text: i18n.ai, class: "ai-link enabled" }),
+      ]
+    : '';
+};
+
 const renderEventsLink = () => {
 const renderEventsLink = () => {
   const eventsMod = getConfig().modules.eventsMod === 'on';
   const eventsMod = getConfig().modules.eventsMod === 'on';
   return eventsMod 
   return eventsMod 
@@ -389,8 +398,8 @@ const template = (titlePrefix, ...elements) => {
              renderCipherLink(),
              renderCipherLink(),
              navLink({ href: "/pm", emoji: "ꕕ", text: i18n.privateMessage }),
              navLink({ href: "/pm", emoji: "ꕕ", text: i18n.privateMessage }),
              navLink({ href: "/publish", emoji: "❂", text: i18n.publish }),
              navLink({ href: "/publish", emoji: "❂", text: i18n.publish }),
-             //navLink({ href: "/ai", emoji: "ꘜ", text: i18n.ai }),
              renderTagsLink(),
              renderTagsLink(),
+             renderAILink(),
              navLink({ href: "/search", emoji: "ꔅ", text: i18n.search })
              navLink({ href: "/search", emoji: "ꔅ", text: i18n.search })
              )
              )
           ),
           ),

+ 1 - 0
src/views/modules_view.js

@@ -6,6 +6,7 @@ const modulesView = () => {
   const config = getConfig().modules;
   const config = getConfig().modules;
   const modules = [
   const modules = [
     { name: 'agenda', label: i18n.modulesAgendaLabel, description: i18n.modulesAgendaDescription },
     { name: 'agenda', label: i18n.modulesAgendaLabel, description: i18n.modulesAgendaDescription },
+    { name: 'ai', label: i18n.modulesAILabel, description: i18n.modulesAIDescription },
     { name: 'audios', label: i18n.modulesAudiosLabel, description: i18n.modulesAudiosDescription },
     { name: 'audios', label: i18n.modulesAudiosLabel, description: i18n.modulesAudiosDescription },
     { name: 'bookmarks', label: i18n.modulesBookmarksLabel, description: i18n.modulesBookmarksDescription },
     { name: 'bookmarks', label: i18n.modulesBookmarksLabel, description: i18n.modulesBookmarksDescription },
     { name: 'cipher', label: i18n.modulesCipherLabel, description: i18n.modulesCipherDescription },
     { name: 'cipher', label: i18n.modulesCipherLabel, description: i18n.modulesCipherDescription },