在sillytavern(酒馆)上接入自己DIY的AI玩具(一)

前段时间在群里整活,说要做一个杯子和振动器,把这些设备接入sillytavern。

但吹出来的牛,肯定要说到做到。于是早上刚把demo做了出来,代码什么的还没来得及整理。

这篇文章将介绍整个开发流程,以及设计思路。

目前是在制作振动器。

硬件设备使用esp32进行开发,sillytavern上使用js做蓝牙驱动。

这里先把单片机和js上的代码发出来。

esp32这块使用arduino的C++开发(后面版本估计要改成纯C)。

#include "NimBLEDevice.h"
#include <string.h>

#include "picojson.h"



#define SERVICE_UUID "b408e1a0-3d8a-11ed-b878-0242ac120002"         //服务UUID
#define CONTROL_UUID "de045162-3d97-11ed-b878-0242ac120002"         //控制特征UUID


NimBLECharacteristic controlCharacteristic(CONTROL_UUID, NIMBLE_PROPERTY::READ |NIMBLE_PROPERTY::WRITE);

//设置服务器所需要的配置
void setup() {
  Serial.begin(115200);
  NimBLEDevice::init("Esp32test");
  NimBLEServer *pServer = NimBLEDevice::createServer();
  NimBLEService *pService = pServer->createService(SERVICE_UUID);                         //创建设备
  // 添加一个带有对象名(官方UUID)的特征,不带对象,这个特征不会改变               //显示特征名
  pService->addCharacteristic(&controlCharacteristic);  //增加一个控制LED的特性

  controlCharacteristic.setValue("\0");

  NimBLECharacteristic *pCharacteristic = pService->createCharacteristic(CONTROL_UUID);
  Serial.println("what fuck!");
  pService->start();
  Serial.println("a?");
  NimBLEAdvertising *pAdvertising = NimBLEDevice::getAdvertising();
  pAdvertising->addServiceUUID(SERVICE_UUID); // advertise the UUID of our service
  pAdvertising->setName("why"); // advertise the device name
  pAdvertising->start(); 


  Serial.println("Characteristic defined! Now you can read it in your phone!");  //提示消息


}


char test[100];
long int a;
void loop() {
  
  delay(300);
  strcpy(test,controlCharacteristic.getValue().c_str());
  a++;
  Serial.printf("haha:%s  %ld  %d \n",test,a,(int)test[0]);  
  dacWrite(25,(int)test[0]);

}

sillytavern插件的js这块的代码如下

// The main script for the extension
// 以下是一些基本扩展功能的示例

// 你可能需要从extensions.js中导入extension_settings、getContext和loadExtensionSettings
import { extension_settings, getContext, loadExtensionSettings } from "../../../extensions.js";

// 您可能需要从主脚本导入一些其他函数
import { saveSettingsDebounced } from "../../../../script.js";

// 跟踪您的扩展所在的位置,名称应与repo名称匹配
const extensionName = "SillyTavern_ConnectPeripherals-main";
const extensionFolderPath = `scripts/extensions/third-party/${extensionName}`;
const extensionSettings = extension_settings[extensionName];
const defaultSettings = {};


 
// 如果存在扩展设置,则加载它们,否则将它们初始化为默认值。
async function loadSettings() {
  // 如果设置不存在,则创建这些设置
  extension_settings[extensionName] = extension_settings[extensionName] || {};
  if (Object.keys(extension_settings[extensionName]).length === 0) {
    Object.assign(extension_settings[extensionName], defaultSettings);
  }

  // 更新UI中的设置
  $("#example_setting").prop("checked", extension_settings[extensionName].example_setting).trigger("input");
}





// 在UI中更改扩展设置时调用此函数
function onExampleInput(event) {
  const value = Boolean($(event.target).prop("checked"));
  extension_settings[extensionName].example_setting = value;
  saveSettingsDebounced();
}

// 正则读字符串标签,这里有问题,日后要改
function extractDeviceContent(str) {
  const regex = /<device>([\s\S]*?)<\/device>/g;
  const contents = [];
  let match;

  while ((match = regex.exec(str)) !== null) {
    contents.push(match[1]);
  }

  return contents;
}

// 示例用法


let characteristic;

function wtf1(){
	let device = navigator.bluetooth.requestDevice({
	filters: [ 
		{ namePrefix: 'why' } 
	],
	optionalServices: [ "b408e1a0-3d8a-11ed-b878-0242ac120002" ]
  });
  return device;
}

function wtf2(device){
	let server= device.gatt.connect();
	return server;
}

function wtf3(server){
	let service = server.getPrimaryService("b408e1a0-3d8a-11ed-b878-0242ac120002");
	return service;
}

function wtf4(service){
	let characteristic = service.getCharacteristic("de045162-3d97-11ed-b878-0242ac120002");
	return characteristic;
}

function send_value(characteristic,value){
	characteristic.writeValue(
    new Uint8Array([value])
  );
	
}

async function send_while(characteristic){
	// 获取整个消息文本
	
	
	const context = await getContext();
	  
	// 获取最新消息
	let inputString = context.chat[context.chat.length-1].mes;
	  
	// 通过正则读要传输设备的值
	let result = await extractDeviceContent(inputString);
	
	if(result!=''){
		console.log(result);
		// 发送设备来设置
		result=result[result.length-1];
		result= await parseInt(result);
		console.log(result);
		await send_value(characteristic,result);
	}
}

// 这个函数在按钮被点击时被调用
async function onButtonClick() {
  // 在这里你想做什么就做什么
  // 让我们用选中的设置创建一个弹出窗口
  
  
  // 连接蓝牙
  let device=await wtf1();
  let server=await wtf2(device);
  let service=await wtf3(server);
  let characteristic=await wtf4(service);
  
  
  setInterval(send_while, 1000,characteristic);
  
 // toastr.info(
  //  `The checkbox is ${extension_settings[extensionName].example_setting ? "checked" : "not checked"}`,
    "A popup appeared because you clicked the button!"
 // );
}

// 此函数在加载扩展时调用
jQuery(async () => {
  // 这是一个从文件加载HTML的示例
  const settingsHtml = await $.get(`${extensionFolderPath}/example.html`);

  // 将settingsHtml附加到extensions_settings后
  // Extension_settings和extensions_settings2是Settings菜单的左列和右列
  // 左边应该是处理系统功能的扩展,右边应该是与视觉/UI相关的
  $("#extensions_settings").append(settingsHtml);

  // 这些都是监听事件的例子
  $("#my_button").on("click", onButtonClick);
  $("#example_setting").on("input", onExampleInput);
  $("#text_test").on("input",onExampleInput);
  // 启动时加载设置(如果有的话)
  loadSettings();
});

用法就是让AI发送消息带<device>1~255</device>标签,js程序会读取上下文消息中的的标签中的数值。

js程序会连接esp32的蓝牙服务,并通过蓝牙服务向esp32发送振动程度的数值。

esp32程序读取该数值,然后通过dac引脚,设置引脚的输出电压。通过一个8050三极管,驱动振动马达产生振动。

整个过程很简单,代码也没有多少行。

后续还需要重新设计和测试代码,设计电路并打印PCB(以前还真没设计过稳压芯片之类的),以及3D打印出来个外壳。

等这一切都完成之后,再详细的介绍一下整个开发流程和设计细节,帮助AI爱好者们,diy自己的AI玩具。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值