Tecnologias Emergentes
-
Cadastro
IBM Academic Initiative
-
Obter promocode para a
IBM Cloud
-
Ativar
IBM Cloud
- Acesso via
postman
- Utilizar a URL
https://api.us-south.language-translator.watson.cloud.ibm.com/instances/INSTANCE_ID/v3/translate?version=2018-05-01
- Autenticação deve ser
Basic Auth
ondeUsername
deve serapikey
ePassword
a chave de API
- Utilizar a URL
-
Acesso via
postman
- Utilizar a URL
https://api.us-south.natural-language-understanding.watson.cloud.ibm.com/instances/INSTANCE_ID/v1/analyze?version=2019-07-12
- Autenticação deve ser
Basic Auth
ondeUsername
deve serapikey
ePassword
a chave de API
- Utilizar a URL
-
Biblioteca
nodejs
-
Instalar a biblioteca
npm init -y npm i --save ibm-watson
-
Categorias
{
url: 'https://www.espm.br/',
features: {
categories: {}
}
}
- Classificações
{
text: 'I feel good today!',
features: {
classifications: { model: 'tone-classifications-en-v1' }
}
}
-
Somente disponível para textos em inglês
- excited: Mostrando entusiasmo e interesse pessoais
- frustrated: Sentindo-se incomodado e irritado
- impolite: Sendo desrespeitoso e rude
- polite: Exibindo um comportamento racional e orientado a objetivos
- sad: Uma emoção passiva desagradável
- satisfied: Uma resposta afetiva à qualidade do serviço percebida
- sympathetic: Um modo afetivo de compreensão que envolve ressonância emocional
-
Referêcia: Análise de Tons
-
Conceitos
{
url: 'www.espm.br',
features: {
concepts: {}
}
}
- Entidades
{
text: 'Eu quero que o meu pedido entregue na cidade de São Paulo, na Rua Antonio da Silva, 123',
features: {
entities: {}
}
}
- Permite a criação de chatbots
-
Efetuar login na IBM Cloud
-
Instanciar o serviço Watson Assistant
-
Utilizar o ChatGPT para gerar os textos
-
Criar uma
Persona
para o chatbot, por exemplo:Crie uma persona para um chatbot que auxilie alunos universitários da faculdade "Belo Diploma" nas questões como: obter nota, faltas, grade de aulas, etc... Essa persona deve ter um ótimo senso de humor e uma linguagem descontraída
-
Criar o diálogo introdutório, o
On boarding
-
Adicionar 3 variações de resposta para quando a pergunta não for compreendida pelo Chatbot (escolhidas aleatoriamente)
- Observar o
No matches count <= 3
;
- Observar o
-
Criar a primeira ação: "Verificar as disciplinas matriculadas";
- Aluno deve infomar o número de matrícula;
- O diálogo deve informar "Estou pesquisando sua matrícula
numero_da_matricula
"; - Criar uma variável de sessão para armazenar o número de matrícula do aluno;
- Ao final, informar a grade de disciplinas e o nome do aluno (sempre o mesmo)
-
Variáveis de sessão:
-
Acessar o
endpoint
para obter a lista de disciplinashttps://sistema-universitario.glitch.me/grade/1000
-
Formato
OpenAPI
Gere um json no formato OpenAPI para o endpoint https://sistema-universitario.glitch.me/grade/:matricula onde :matricula corresponde à matrícula do aluno. O endpoint retorna um JSON no formato {aluno: "nome do aulo", disciplinas: ["disciplina1", "disciplina2"]}
-
Desenvolver um diálogo para que o aluno possa solicitar a nota de uma disciplina informando o número de matrícula e a descrição da disciplina
https://sistema-universitario.glitch.me/nota/1000/Estrutura de Dados
-
Desenvolver um diálogo para que o aluno possa consultar a sala de aula de uma disciplina
https://sistema-universitario.glitch.me/sala/Estrutura de Dados
-
Instalar em uma página HTML
-
Código inicial para exibir o chatbot em um site
<script> window.watsonAssistantChatOptions = { // A UUID like '1d7e34d5-3952-4b86-90eb-7c7232b9b540' included in the embed code provided in IBM watsonx Assistant. integrationID: 'YOUR_INTEGRATION_ID', // Your assistants region e.g. 'us-south', 'us-east', 'jp-tok' 'au-syd', 'eu-gb', 'eu-de', etc. region: 'YOUR_REGION', // A UUID like '6435434b-b3e1-4f70-8eff-7149d43d938b' included in the embed code provided in IBM watsonx Assistant. serviceInstanceID: 'YOUR_SERVICE_INSTANCE_ID', // The callback function that is called after the widget instance has been created. onLoad: async (instance) => { await instance.render(); } }; setTimeout(function(){const t=document.createElement('script');t.src='https://web-chat.global.assistant.watson.appdomain.cloud/versions/' + (window.watsonAssistantChatOptions.clientVersion || 'latest') + '/WatsonAssistantChatEntry.js';document.head.appendChild(t);}); </script>
-
Para obter um exemplo, clicar em
-
E em seguida, clicar na aba superior Embed
-
onLoad
executado quando o chatbot é carregado -
Configurações de layout
layout: { showFrame: true, hasContentMaxWidth: false, }
-
Configurações do tema
themeConfig: { carbonTheme: 'g100', corners: 'round', }
-
Obs:
carbonTheme
podem ser "white", "g10", "g90" ou "g100" ecorner
"square" ou "round" -
Botão para fechar o chatbot
headerConfig: { closeButtonIconType: 'side-panel-left', }
-
Obs: opções "minimize", "close", "side-panel-left" e "side-panel-right".
-
Lista de eventos completa pode ser encontrada Aqui
instance.on({ type: 'receive', handler: (event) => { console.log('I received a message!', event); } });
-
Evento
receive
: executado quando uma mensagem é recebida; -
- Os principais parâmetros recebidos pelas funçõs na varável
event
são:event.data
: mensagem (dados) recebidos pelo chatbot como respostas das intenções do usuário;event.data.output.generic
: itens da resposta recebidos (texto, etc...)
- Os principais parâmetros recebidos pelas funçõs na varável
-
Evento
pre:receive
: executado antes doreceive
;instance.on({ type: 'pre:receive', handler: (event) => { console.log('pre:receive') const message = event.data; if (message.output.generic) { message.output.generic.forEach(messageItem => { console.log(messageItem); if (messageItem.response_type === 'text') { messageItem.response_type = 'teste123'; } }) } } });
-
Evento
customResponse
: permite criar uma resposta personalizada;function customResponseHandler(event) { const { message, element, fullMessage } = event.data; const div = document.createElement('div'); // obtem o texto da mensagem div.innerHTML = message.text; div.style.border = 'solid 1px'; div.style.color = 'red'; // message.options.forEach((messageItem, index) => { // const button = document.createElement('button'); // button.innerHTML = messageItem.label; // button.classList.add('CardButton'); // button.addEventListener('click', () => onClick(messageItem, button, fullMessage, index)); // element.appendChild(button); // }); element.appendChild(div); }
-
Acessar o emulador Arduino Uno ou instalar no VSCode
-
Instalar no VS Code as extensões (e reiniciar o VS Code) - Referência:
- Wokwi
- PlatformIO IDE
- Clicar no ícone PlatformIO: Home (ícone da casa) na barra de ícones na parte inferior da tela do VS Code
- Iniciar um novo projeto (desmarcar a opção Location: use default location!!!!) e selecionar uma pasta para criar o projeto
- Criar dois arquivos
diagram.json
ewokwi.toml
dentro da estrutura do projeto
- Conteúdo dos arquivos (respectivamente
diagram.json
ewokwi.toml
):
{ "version": 1, "author": "Anonymous maker", "editor": "wokwi", "parts": [ { "type": "board-esp32-devkit-c-v4", "id": "esp", "top": 0, "left": 0, "attrs": {} } ], "connections": [ [ "esp:TX", "$serialMonitor:RX", "", [] ], [ "esp:RX", "$serialMonitor:TX", "", [] ] ], "dependencies": {} }
[wokwi] version = 1 firmware = '.pio/build/esp32doit-devkit-v1/firmware.bin' elf = '.pio/build/esp32doit-devkit-v1/firmware.elf'
- Realizar o build da aplicação (pressionar
Control + Shift + P
ouCommand + Shift + P
)
- Executar o emulador
- Editar o código (pressionar
main.cpp
)
- É uma linguagem para progeramação do Arduino Linguagem Arduino
- Código básico
void setup() { // Configurações iniciais } void loop() { // Loop principal }
- Principais funções:
pinMode(pino, modo)
: configura um pino como entrada (INPUT
) ou saída (OUTPUT
)digitalWrite(pino, valor)
: envia um sinal (HIGH
/LOW
) a um determinado pinodelay(ms)
: aguarda o período especificado (em milisegundos)
- Exemplo led piscando no pino 13:
// Defina o pino do LED const int ledPin = 13; void setup() { // Configure o pino do LED como saída pinMode(ledPin, OUTPUT); } void loop() { // Acenda o LED digitalWrite(ledPin, HIGH); // Espere 1 segundo (1000 milissegundos) delay(1000); // Apague o LED digitalWrite(ledPin, LOW); // Espere 1 segundo (1000 milissegundos) delay(1000); }
- Saída serial - permite comunicação com um computador via porta serial
- Imprimir caracteres ASCII
void setup() {
// definir taxa de transmissão (bauds)
Serial.begin(9600);
}
void loop() {
// imprimir mensagem
Serial.println("Arduino is ok");
// Verifica se há dados disponíveis na porta serial
if (Serial.available() > 0) {
// Lê a string digitada pelo usuário
String texto = Serial.readStringUntil('\n'); // Lê até o usuário pressionar Enter
// Imprime o texto lido no monitor serial
Serial.print("Você digitou: ");
Serial.println(texto);
}
}
-
Exemplo 3 leds piscando de forma aleatória
// Defina os pinos dos LEDs const int ledPins[] = {8, 9, 10}; // Pinos aos quais os LEDs estão conectados const int numLeds = 3; // Número de LEDs void setup() { // Configure todos os pinos dos LEDs como saída for (int i = 0; i < numLeds; i++) { pinMode(ledPins[i], OUTPUT); } // Inicialize os LEDs apagados for (int i = 0; i < numLeds; i++) { digitalWrite(ledPins[i], LOW); } } void loop() { // Escolha um LED aleatório para piscar int ledIndex = random(numLeds); // Acenda o LED escolhido digitalWrite(ledPins[ledIndex], HIGH); // Espere um intervalo aleatório entre 500 e 1500 milissegundos delay(random(500, 1501)); // Apague o LED escolhido digitalWrite(ledPins[ledIndex], LOW); // Espere um intervalo aleatório entre 500 e 1500 milissegundos antes de piscar o próximo LED delay(random(500, 1501)); }
-
Exemplo push button
- btn1:2r - uno:7
- btn1:1l - gnd
#define LED_PIN 9 #define BUTTON_PIN 7 void setup() { pinMode(LED_PIN, OUTPUT); pinMode(BUTTON_PIN, INPUT_PULLUP); } void loop() { int button_val = digitalRead(BUTTON_PIN); if (button_val == 0) { digitalWrite(LED_PIN, HIGH); } else { digitalWrite(LED_PIN, LOW); } }
-
Exemplo joystick
- Utilizar portas seriais
- joystick1:VERT - A0 (1023 - cima, 0 - baixo)
- joystick1:HORIZ - A1 (1023 - direita, 0 - esquerda)
- joystick1:SEL - uno:0 (porta digital - true para solto e false para pressionado)
#define LED_L_PIN 9 #define LED_R_PIN 8 #define VERT_PIN A0 #define HORZ_PIN A1 #define SEL_PIN 0 void setup() { pinMode(LED_L_PIN, OUTPUT); pinMode(LED_R_PIN, OUTPUT); pinMode(VERT_PIN, INPUT); pinMode(HORZ_PIN, INPUT); pinMode(SEL_PIN, INPUT_PULLUP); } void loop() { int vert = analogRead(VERT_PIN); int horz = analogRead(HORZ_PIN); int sel = digitalRead(SEL_PIN); if (sel) { digitalWrite(LED_L_PIN, LOW); digitalWrite(LED_R_PIN, LOW); } else { digitalWrite(LED_L_PIN, HIGH); digitalWrite(LED_R_PIN, HIGH); } if (horz == 1023) { digitalWrite(LED_L_PIN, HIGH); digitalWrite(LED_R_PIN, LOW); } else if (horz == 0){ digitalWrite(LED_L_PIN, LOW); digitalWrite(LED_R_PIN, HIGH); } }
- Utilizar portas seriais
-
Exercício: Acender 4 leds conforme o movimento realizado pelo joysctick
-
Exemplo display de 7 segmentos
- P(2) - S(A), P(3) - S(B), P(4) - S(C), P(5) - S(D), P(6) - S(E), P(7) - S(F), P(8) - S(G)
- COM2 - GND
- Diagrama:
{ "version": 1, "author": "Anonymous maker", "editor": "wokwi", "parts": [ { "type": "wokwi-arduino-uno", "id": "uno", "top": 48.6, "left": 18.6, "attrs": {} }, { "type": "wokwi-7segment", "id": "sevseg1", "top": -119.82, "left": 120.28, "attrs": { "common": "cathode", "color": "#00ff00", "digits": "1", "colon": "" } } ], "connections": [ [ "sevseg1:A", "uno:2", "#8f4814", [ "v-18.36", "h105.6" ] ], [ "sevseg1:B", "uno:3", "red", [ "v-18.36", "h19.2", "v9.6", "h57.6" ] ], [ "sevseg1:C", "uno:4", "gold", [ "v9.6", "h76.8" ] ], [ "sevseg1:D", "uno:5", "green", [ "v19.2", "h86.4" ] ], [ "sevseg1:E", "uno:6", "blue", [ "v28.8", "h96" ] ], [ "sevseg1:F", "uno:7", "white", [ "v-18.36", "h-48", "v153.6", "h124.8" ] ], [ "sevseg1:G", "uno:8", "gray", [ "v0.84", "h-9.6", "v115.2", "h76.8" ] ], [ "sevseg1:COM.2", "uno:GND.1", "green", [ "h0", "v-37.56", "h-76.8", "v192", "h67.2" ] ] ], "dependencies": {} }
const int segmentPins[8] = {2, 3, 4, 5, 6, 7, 8}; const byte numbers[11] = { B11111100, // 0 B01100000, // 1 B11011010, // 2 B11110010, // 3 B01100110, // 4 B10110110, // 5 B10111110, // 6 B11100000, // 7 B11111110, // 8 B11110110 // 9 }; void setup() { for (int i = 0; i < 7; i++) { pinMode(segmentPins[i], OUTPUT); } } void loop() { for (int i = 0; i < 10; i++) { displayNumber(i); delay(1000); } } void displayNumber(int num) { for (int i = 0; i < 8; i++) { digitalWrite(segmentPins[i], HIGH); } for (int i = 0; i < 8; i++) { if (bitRead(numbers[num], i) == LOW) { digitalWrite(segmentPins[7-i], LOW); } } }
-
Gerar números aleatórios com a função random
-
Uso de bibliotecas Arduino
-
Exemplo motor
- Definir no
diagram.json
:
{ "version": 1, "author": "Michael Möller", "editor": "wokwi", "parts": [ { "type": "wokwi-arduino-uno", "id": "uno", "top": 160.98, "left": -237.02, "attrs": {} }, { "type": "wokwi-stepper-motor", "id": "sw1", "top": -139.49, "left": -191.12, "attrs": { "gearRatio": "2:1", "display": "steps", "arrow": "orange" } } ], "connections": [ [ "sw1:B-", "uno:8", "green", [ "v0" ] ], [ "sw1:A-", "uno:11", "yellow", [ "v0" ] ], [ "sw1:B+", "uno:9", "red", [ "v0" ] ], [ "sw1:A+", "uno:10", "blue", [ "v0" ] ] ], "dependencies": {} }
- Definir no
-
Utilizar biblioteca
Stepper
do Arduino para controlar o motor de passo#include <Stepper.h> const int stepsPerRevolution = 200; // change this to fit the number of steps per revolution // for your motor // initialize the stepper library on pins 8 through 11: Stepper myStepper(stepsPerRevolution, 8, 9, 10, 11); void setup() { // set the speed at 60 rpm: myStepper.setSpeed(60); // initialize the serial port: Serial.begin(9600); } void loop() { // step one revolution in one direction: Serial.println("clockwise"); myStepper.step(stepsPerRevolution); delay(500); // step one revolution in the other direction: Serial.println("counterclockwise"); myStepper.step(-stepsPerRevolution); delay(500); }
-
Exemplo servo
- Adicionar a biblioteca
Servo
no arquivolibraries.txt
#include <Servo.h> Servo arm; // Create a "Servo" object called "arm" float pos = 0.0; // Variable where the arm's position will be stored (in degrees) float step = 1.0; // Variable used for the arm's position step void setup() { arm.attach(2); // Attache the arm to the pin 2 arm.write(pos); // Initialize the arm's position to 0 (leftmost) } void loop() { arm.write(pos); delay(100); pos++; }
- Adicionar a biblioteca
-
Incluir ium potenciômetro para aumentar ou diminuir o passo do
servo
- Conectado à porta analógica (A0)
#include <Servo.h> Servo arm; // Create a "Servo" object called "arm" float pos = 0.0; // Variable where the arm's position will be stored (in degrees) float step = 1.0; // Variable used for the arm's position step void setup() { arm.attach(2); // Attache the arm to the pin 2 arm.write(pos); // Initialize the arm's position to 0 (leftmost) Serial.begin(115200); pinMode(A0, INPUT); } void loop() { arm.write(pos); delay(100); pos = pos + step; step = analogRead(A0); Serial.println(step); }
-
Exemplo sensor de temperatura (DS 18B20 - pinos: alimentação, leitura e terra)
- Ligar a leitura no pino 10
#include <OneWire.h> #include <DallasTemperature.h> OneWire oneWire(10); DallasTemperature sensor(&oneWire); void setup(void) { Serial.begin(115200); delay(2); sensor.begin(); delay(20); } void loop(void) { sensor.requestTemperatures(); Serial.print("Temperature is: "); delay(10); Serial.println(sensor.getTempCByIndex(0)); delay(1000); }
-
Arduino Uno não possui interface com a internet
-
Utilizar o ESP32 que possui uma placa de rede integrada
-
Conexão com o WiFi
#include <WiFi.h> void setup() { Serial.begin(9600); Serial.print("Conectando-se ao Wi-Fi"); // Wokwi simula uma rede WiFi com acesso total à Internet com o usuário Wokwi-GUEST // não precisa de senha WiFi.begin("Wokwi-GUEST", "", 6); while (WiFi.status() != WL_CONNECTED) { delay(100); Serial.print("."); } Serial.println(" Conectado!"); } void loop() { }
-
Exemplo de requisição POST
- Uso da biblioteca
HttpClient
- Executar um POST no endpoint
https://teste-iot-server.glitch.me/temperatura
- No corpo da requisição, enviar
{"sensor":"ESP32", "temperatura": 30}
#include <WiFi.h> #include <HTTPClient.h> #define TEMPLATE "{\"sensor\":\"ESP32\",\"temperatura\":%d}" void setup() { Serial.begin(9600); Serial.print("Conectando-se ao Wi-Fi"); WiFi.begin("Wokwi-GUEST", "", 6); while (WiFi.status() != WL_CONNECTED) { delay(100); Serial.print("."); } Serial.println(" Conectado!"); Serial.println(WiFi.localIP()); } void loop() { // Realizar a requisição POST if (WiFi.status() == WL_CONNECTED) { HTTPClient http; // Defina o URL do servidor que receberá a requisição POST http.begin("https://teste-iot-server.glitch.me/temperatura"); // Substitua pela URL do servidor // Defina o tipo de conteúdo (JSON, neste caso) http.addHeader("Content-Type", "application/json"); // Dados JSON que serão enviados int temp = random(10, 40); char postData[100]; // Copia a temperatura para o %d definido no template (TEMPLATE) sprintf(postData, TEMPLATE, temp); // Realiza a requisição POST int httpResponseCode = http.POST(postData); // Verifica a resposta do servidor if (httpResponseCode > 0) { String response = http.getString(); // Obtém a resposta Serial.println("Resposta do servidor: " + response); } else { Serial.println("Erro na requisição POST"); } http.end(); // Fecha a conexão } else { Serial.println("Falha na conexão Wi-Fi"); } }
- Uso da biblioteca
-
Ajustar o exemplo acima para enviar dados do sensor de temperatura DS 18B20
-
Obter o status de um led com base na requisição GET de um endpoint
https://teste-iot-server.glitch.me/led
-
Para ligar ou desligar, efetuar um POST na mesma URL com o corpo
{"status":"ligado"}
-
Criar um app em nodejs para alterar o status do led
-
Exemplo Mosquitto Broker para publish
-
Incluir a biblioteca PubSubClient
-
No caso do VS Code a biblioteca deve ser incluída no arquivo
platformio.ini
[env:esp32doit-devkit-v1] platform = espressif32 board = esp32doit-devkit-v1 framework = arduino lib_deps = PubSubClient
-
Exemplo de código para publicar uma mensagem no Mosquitto Broker
#include <WiFi.h> #include <PubSubClient.h> // Substitua pelos detalhes da sua rede WiFi #define SSID "Wokwi-GUEST" #define WIFI_PASSWD "" // Substitua pelos detalhes do broker Mosquitto #define MQTT_SERVER "test.mosquitto.org" #define MQTT_PORT 1883 // Porta padrão MQTT para conexões não seguras WiFiClient espClient; PubSubClient client(espClient); void setup_wifi() { delay(10); Serial.println(); Serial.print("Conectando-se a "); Serial.println(SSID); WiFi.begin(SSID, WIFI_PASSWD); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("Conectado."); Serial.print("IP address: "); Serial.println(WiFi.localIP()); } void connect_mqtt() { while (!client.connected()) { Serial.print("Conectando ao MQTT..."); if (client.connect("WokwiClient")) { Serial.println("Conectado."); } else { Serial.print("Falha, rc="); Serial.print(client.state()); Serial.println(" Tentar novamente em 5 segundos."); delay(5000); } } } void publish_message() { String message = "Hello from ESP!"; if (client.publish("test/topic-esensato", message.c_str())) { Serial.println("Mensagem publicada com sucesso."); } else { Serial.println("Falha ao publicar a mensagem."); } } void setup() { Serial.begin(115200); setup_wifi(); client.setServer(MQTT_SERVER, MQTT_PORT); connect_mqtt(); } void loop() { if (!client.connected()) { connect_mqtt(); } client.loop(); publish_message(); delay(5000); // Aguarda 5 segundos entre publicações }
-
Exemplo de um cliente MQTT em nodejs
- Instalar a biblioteca
npm install mqtt --save
const mqtt = require("mqtt"); const client = mqtt.connect("mqtt://test.mosquitto.org"); client.on("connect", () => { client.subscribe("test/topic-esensato", (err) => { if (err) { console.log("Erro: ", err); } else { console.log("Inscrito") } }); }); client.on("message", (topic, message) => { console.log(message.toString()); client.end(); });
- Instalar a biblioteca
-
Exemplo subscribe
#include <WiFi.h> #include <PubSubClient.h> // Substitua pelos detalhes da sua rede WiFi const char* ssid = "Wokwi-GUEST"; const char* password = ""; // Substitua pelos detalhes do broker Mosquitto const char* mqtt_server = "test.mosquitto.org"; const int mqtt_port = 1883; // Porta padrão MQTT para conexões não seguras WiFiClient espClient; PubSubClient client(espClient); void setup_wifi() { delay(10); Serial.println(); Serial.print("Conectando-se a "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println("Conectado."); Serial.print("IP address: "); Serial.println(WiFi.localIP()); } void connect_mqtt() { while (!client.connected()) { Serial.print("Conectando ao MQTT..."); if (client.connect("WokwiClient")) { Serial.println("Conectado."); } else { Serial.print("Falha, rc="); Serial.print(client.state()); Serial.println(" Tentar novamente em 5 segundos."); delay(5000); } } } void publish_message() { String message = "Hello from ESP!"; if (client.publish("test/topic-esensato", message.c_str())) { Serial.println("Mensagem publicada com sucesso."); } else { Serial.println("Falha ao publicar a mensagem."); } } void callback(char* topic, byte* payload, unsigned int length) { Serial.print("Mensagem recebida no tópico "); Serial.print(topic); Serial.print(": "); for (int i = 0; i < length; i++) { Serial.print((char)payload[i]); } Serial.println(); } void setup() { Serial.begin(115200); setup_wifi(); client.setServer(mqtt_server, mqtt_port); client.setCallback(callback); client.subscribe("test/topic-esensato"); connect_mqtt(); } void loop() { if (!client.connected()) { connect_mqtt(); } client.loop(); }
-
Exemplo publish em nodejs
const mqtt = require("mqtt"); const client = mqtt.connect("mqtt://test.mosquitto.org"); client.on("connect", () => { client.publish("test/topic-esensato", "Teste 123"); });
-
Outro broker conhecido é o HiveMQ
-
Criar cluster e obter dados de acesso:
-
Trabalhando com buffers utilizando o
snprintf
(%s
é string,%d
para decimal)Serial.begin(115200); delay(100); char msg[100]; snprintf(msg, 100, "Valor %s", "Teste"); Serial.println(msg);
-
Publicar uma mensagem em um tópico:
#include <WiFi.h> #include <PubSubClient.h> #include <WiFiClientSecure.h> //---- WiFi settings const char *ssid = "Wokwi-GUEST"; const char *password = ""; //---- HiveMQ Cloud Broker settings const char *mqtt_server = ""; // replace with your HiveMQ Cluster URL const char *mqtt_username = ""; // replace with your Username const char *mqtt_password = ""; // replace with your Password const int mqtt_port = 8883; WiFiClientSecure espClient; PubSubClient client(espClient); unsigned long lastMsg = 0; #define MSG_BUFFER_SIZE (500) char msg[MSG_BUFFER_SIZE]; // HiveMQ Cloud Let's Encrypt CA certificate static const char *root_ca PROGMEM = R"EOF( -----BEGIN CERTIFICATE----- MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ 0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ 3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq 4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= -----END CERTIFICATE----- )EOF"; void setup_wifi() { delay(10); // We start by connecting to a WiFi network Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } randomSeed(micros()); Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } void reconnect() { // Loop until we’re reconnected while (!client.connected()) { Serial.print("Attempting MQTT connection… "); String clientId = "ESP32Client"; // Attempt to connect if (client.connect(clientId.c_str(), mqtt_username, mqtt_password)) { Serial.println("connected!"); } else { Serial.print("failed, rc = "); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); // Wait 5 seconds before retrying delay(5000); } } } void setup() { delay(500); // When opening the Serial Monitor, select 9600 Baud Serial.begin(115200); delay(500); setup_wifi(); espClient.setCACert(root_ca); client.setServer(mqtt_server, mqtt_port); } void loop() { if (!client.connected()) { reconnect(); } // Construct your message with the formatted value snprintf(msg, MSG_BUFFER_SIZE, "%s", "TESTE"); Serial.print("Publish message: "); Serial.println(msg); // Publish the message to the topic client.publish("esp32/teste", msg); delay(10000); }
-
Exemplo com publish e subscribe
```javascript #include <WiFi.h> #include <PubSubClient.h> // Não precisa incluir na biblioteca (libraries.txt)!!! #include <WiFiClientSecure.h> #define MSG_BUFFER_SIZE (500) const char* ssid = "Wokwi-GUEST"; const char* password = ""; const char* mqtt_server = ""; // obter dos dados de acesso do cluster HiveMQ const char* mqtt_username = ""; // usuário criado para o cluster HiveMQ const char* mqtt_password = ""; // senha criada para o cluster HiveMQ const int mqtt_port = 8883; WiFiClientSecure espClient; PubSubClient client(espClient); unsigned long lastMsg = 0; char msg[MSG_BUFFER_SIZE]; int value = 0; // Variables to store received values bool ledValue = false; int brilhoValue = 0; int nivelAguaValue = 0; int umidadeSoloValue = 0; // Obter o certificado do link especificado no link acima static const char *root_ca PROGMEM = R"EOF( -----BEGIN CERTIFICATE----- MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4 WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+ 0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ 3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5 ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq 4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc= -----END CERTIFICATE----- )EOF"; void setup_wifi() { delay(10); // We start by connecting to a WiFi network Serial.println(); Serial.print("Connecting to "); Serial.println(ssid); WiFi.mode(WIFI_STA); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } randomSeed(micros()); Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } void callback(char* topic, byte* payload, unsigned int length) { Serial.print("Message arrived ["); Serial.print(topic); Serial.print("] "); // Convert payload to string String payloadStr; for (int i = 0; i < length; i++) { payloadStr += (char)payload[i]; } // Store values based on topic if (strcmp(topic, "home/alecrim/led") == 0) { if (payloadStr == "true") { ledValue = true; } else { ledValue = false; } } else if (strcmp(topic, "home/alecrim/brilho") == 0) { brilhoValue = payloadStr.toInt(); } Serial.println(payloadStr); } void reconnect() { // Loop until we’re reconnected while (!client.connected()) { Serial.print("Attempting MQTT connection… "); String clientId = "ESP32Client"; // Attempt to connect if (client.connect(clientId.c_str(), mqtt_username, mqtt_password)) { Serial.println("connected!"); // client.publish("testTopic", "Hello World!"); // … and resubscribe client.subscribe("home/alecrim/led"); client.subscribe("home/alecrim/brilho"); client.subscribe("home/alecrim/nivel_agua"); client.subscribe("home/alecrim/umidade_solo"); } else { Serial.print("failed, rc = "); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); // Wait 5 seconds before retrying delay(5000); } } } void setup() { delay(500); // When opening the Serial Monitor, select 9600 Baud Serial.begin(115200); delay(500); setup_wifi(); espClient.setCACert(root_ca); client.setServer(mqtt_server, mqtt_port); client.setCallback(callback); } void loop() { if (!client.connected()) { reconnect(); } client.loop(); unsigned long now = millis(); if (now - lastMsg > 5000) { lastMsg = now; ++value; // Convert integer value to char array char valueStr[10]; // Adjust size based on your integer range snprintf(valueStr, sizeof(valueStr), "%d", value); // Construct your message with the formatted value snprintf(msg, MSG_BUFFER_SIZE, "%s", valueStr); Serial.print("Publish message: "); Serial.println(msg); // Publish the message to the topic client.publish("home/alecrim/nivel_agua", msg); // Publish other values client.publish("home/alecrim/led", ledValue ? "true" : "false"); char brilhoStr[10]; snprintf(brilhoStr, sizeof(brilhoStr), "%d", brilhoValue); client.publish("home/alecrim/brilho", brilhoStr); char umidadeSoloStr[10]; snprintf(umidadeSoloStr, sizeof(umidadeSoloStr), "%d", umidadeSoloValue); client.publish("home/alecrim/umidade_solo", umidadeSoloStr); } } ```
- A plataforma Think Speak possui um mecanismo analítico para analisar os dados coletados pelos sensores
- Efetuar o cadastro na plataforma
- Criar um canal
#include <WiFi.h> #include <OneWire.h> #include <DallasTemperature.h> #define SENSOR_PIN 0 OneWire oneWire(SENSOR_PIN); DallasTemperature sensor(&oneWire); // Network information char* ssid = "Wokwi-GUEST"; const char* password = ""; // ThingSpeak settings char server[] = "api.thingspeak.com"; String writeAPIKey = "45BQ8GHUMYG19C9B"; void setup(){ Serial.begin(115200); delay(2); sensor.begin(); delay(20); connectWiFi(); } void loop(){ sensor.requestTemperatures(); delay(10); float temperatura = sensor.getTempCByIndex(0); delay(3000); httpRequest(temperatura); Serial.print(temperatura); } void connectWiFi(){ while (WiFi.status() != WL_CONNECTED){ WiFi.begin(ssid, password); delay(3000); } Serial.println("Connected"); } void httpRequest(float field1Data) { WiFiClient client; if (!client.connect(server, 80)){ Serial.println("Connection failed"); client.stop(); return; } else{ // Create data string to send to ThingSpeak. String data = "field1=" + String(field1Data); //shows how to include additional field data in http post // POST data to ThingSpeak. if (client.connect(server, 80)) { client.println("POST /update HTTP/1.1"); client.println("Host: api.thingspeak.com"); client.println("Connection: close"); client.println("User-Agent: ESP32WiFi/1.1"); client.println("X-THINGSPEAKAPIKEY: "+writeAPIKey); client.println("Content-Type: application/x-www-form-urlencoded"); client.print("Content-Length: "); client.print(data.length()); client.print("\n\n"); client.print(data); Serial.println("Request efetuado"); delay(250); } } client.stop(); }
- Instalar (iOS) o WebXR Viewer (Android não precisa!)
- Abrir site
threejs.org
e buscar pelo exemplo (abrir em nova tab)ar - cones
- Para instalar no desktop via Chrome
- Pesquisar no Google por webxr emulator chrome extension
- Habilitar via Ferramentas do Desenvolvedor (selecionar Samsumg Galaxy S8+ (AR))
- Atualizar a página
- Criar um projeto no glitch
- Projeto já existente
- Preparação para o projeto:
- Arquivo
style.css
body { margin: 0; background-color: #000000; color: #ffffff; font-family: Monospace; font-size: 16px; line-height: 24px; overscroll-behavior: none; } canvas { display: block; }
- Arquivo
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>WebXR</title> <link rel="stylesheet" href="/style.css" /> <script type="importmap"> { "imports": { "three": "https://cdn.jsdelivr.net/npm/[email protected]/build/three.module.js", "three/addons/": "https://cdn.jsdelivr.net/npm/[email protected]/examples/jsm/" } } </script> </head> <body> <script type="module"> import * as THREE from 'three'; const container = document.createElement('div'); document.body.appendChild(container); </script> </body> </html>
- Scene: container básico para os elementos gráficos
let scene = new THREE.Scene();
- Camera: ponto de vista do observador
let camera = new THREE.PerspectiveCamera(70, window.innerWidth / window.innerHeight, 0.01, 40); scene.add(camera)
- Renderer: exibe a cena utilizando WebGL como base
let renderer = new THREE.WebGLRenderer({ antialias: true, alpha: true }); renderer.setPixelRatio(window.devicePixelRatio); renderer.setSize(window.innerWidth, window.innerHeight); container.appendChild(renderer.domElement);
- Light: fonte de luz posicionada acima da cena
var light = new THREE.HemisphereLight(0xffffff, 0xbbbbff, 1); light.position.set(0.5, 1, 0.25); scene.add(light);
- Geometry: forma geométrica
- Outras formas podem ser consutadas aqui
const geometry = new THREE.IcosahedronGeometry(0.2, 1);
- Material: tipo de material utilizado na superfície
const material = new THREE.MeshPhongMaterial({ color : new THREE.Color("rgb(226,35,213)"), shininess : 6, transparent: 1, opacity : 0.8 });
- Mesh: representa figuras compostas de poígonos triangulares (juntando geometry e material)
let mesh = new THREE.Mesh(geometry, material); mesh.position.set(0, 0, -0.5); scene.add(mesh); renderer.setAnimationLoop(() => { renderer.render(scene, camera); });
- Finalmente, criar o loop principal da animação
renderer.setAnimationLoop(() => { renderer.render(scene, camera); });
- BoxGeometry
const boxGeom = new THREE.BoxGeometry(0.3, 0.3, 0.3); const boxMaterial = new THREE.MeshBasicMaterial({color: 0xe0676767}); const boxMesh = new THREE.Mesh(boxGeom, boxMaterial); scene.add(boxMesh); boxMesh.position.z = -1; boxMesh.position.y = 0.5; boxMesh.name = 'Cubo';
- Torus
const torusGeom = new THREE.TorusGeometry( 0.15, 0.05, 12, 50 ); const torusMaterial = new THREE.MeshBasicMaterial( { color: 0xffff00 } ); const torusMesh = new THREE.Mesh( torusGeom, torusMaterial ); torusMesh.position.set(0.0, 0.0, -1); scene.add(torusMesh);
- Posicionamento (x,y,z): x esquerda / direita, y cima / baixo e z profundidade (distância da câmera)
- Cone
const coneGeom = new THREE.ConeGeometry( 0.2, 0.3, 32 ); const coneMaterial = new THREE.MeshBasicMaterial( {color: 0xffff00} ); const coneMesh = new THREE.Mesh(coneGeom, coneMaterial ); coneMesh.position.set(0.0, 0.3, -1); scene.add( coneMesh );
- Texto
- Importar o
FontLoader
- Alguns exemplos de fontes podem ser obtidos aqui
import { FontLoader } from 'three/addons/loaders/FontLoader.js'; import { TextGeometry } from 'three/addons/geometries/TextGeometry.js'; const loader = new FontLoader(); loader.load( 'https://cdn.jsdelivr.net/npm/[email protected]/examples/fonts/optimer_bold.typeface.json', function ( font ) { let textGeom = new TextGeometry( "WebXR", { font: font, size: 10, depth: 20, hover: 30, curveSegments: 12, bevelEnabled: true, bevelThickness: 10, bevelSize: 8, bevelOffset: 0, bevelSegments: 5 } ); const textMaterial = new THREE.MeshBasicMaterial( {color: 0xffff00} ); const textMesh = new THREE.Mesh(textGeom, textMaterial ); textMesh.position.set(0, 0.0, -100.0); scene.add( textMesh ); } );
- Importar o
- Para alterar o valor do texto exibido deve-se remover o objeto e adicioná-lo novamente
scene.remove(textMesh); textMesh.geometry.dispose(); textMesh.material.dispose();
- Convertendo para AR / WebXR
- Importar o ARButton
import { ARButton } from 'three/addons/webxr/ARButton.js';
- Habilitar o xr eaAdicionar o botão
renderer.xr.enabled = true; const button = ARButton.createButton(renderer); document.body.appendChild(button);
- Modelagem 3D
- Modelos prontos do Khronos Group ou aqui
- Tipos de loades para modelos 3D podem ser obtidos aqui
- Importar o GLTFLoader
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
const gltfLoader = new GLTFLoader();
gltfLoader.load( 'https://raw.githubusercontent.com/KhronosGroup/glTF-Sample-Assets/refs/heads/main/Models/Duck/glTF-Embedded/Duck.gltf',
function ( gltf ) {
gltf.scene.position.x = 0.0;
gltf.scene.position.y = 0.0;
gltf.scene.position.z = -3.0;
scene.add(gltf.scene);
},
function (progress){
console.log('Carregando modelo...');
},
function (err){
console.log('Erro', err);
} );
- Animações podem ser adicionadas sobre os modelos
renderer.setAnimationLoop(() => { boxMesh.rotation.y = boxMesh.rotation.y + 0.01; // radiano renderer.render(scene, camera); });
- Hit test - possibilidade de posicionar objetos sobre suberfícies reais
- Criar um marcador para identificar a área de oposicionamento do objeto
- Remover o
.rotateX( -Math.PI / 2);
para visualizar o objeto Ring
const geometryRing = new THREE.RingGeometry(0.15, 0.2, 32).rotateX( -Math.PI / 2);
const materialRing = new THREE.MeshBasicMaterial();
let reticleMesh = new THREE.Mesh(geometryRing, materialRing);
//reticleMesh.matrixAutoUpdate = false;
//reticleMesh.visible = true;
reticleMesh.position.set(1.0, 0.0, -1.0);
scene.add(reticleMesh);
- Adicionar o hit text como uma feature
const button = ARButton.createButton(renderer, {
requiredFeatures: ["hit-test"]
});
- Alterar a função
setAnimationLoop
let hitTestSource = null;
let localSpace = null;
let hitTestSourceInitialized = false;
renderer.setAnimationLoop((timestamp, frame) => {
if (frame) {
// 1. create a hit test source once and keep it for all the frames
// this gets called only once
if (!hitTestSourceInitialized) {
initializeHitTestSource();
}
// 2. get hit test results
if (hitTestSourceInitialized) {
// we get the hit test results for a particular frame
const hitTestResults = frame.getHitTestResults(hitTestSource);
// XRHitTestResults The hit test may find multiple surfaces. The first one in the array is the one closest to the camera.
if (hitTestResults.length > 0) {
const hit = hitTestResults[0];
// Get a pose from the hit test result. The pose represents the pose of a point on a surface.
const pose = hit.getPose(localSpace);
reticleMesh.visible = true;
// Transform/move the reticle image to the hit test position
reticleMesh.matrix.fromArray(pose.transform.matrix);
} else {
reticleMesh.visible = false;
}
}
renderer.render(scene, camera);
}
});
- Criar a função
initializeHitTestSource
async function initializeHitTestSource() {
const session = renderer.xr.getSession();
const viewerSpace = await session.requestReferenceSpace("viewer");
hitTestSource = await session.requestHitTestSource({
space: viewerSpace,
});
localSpace = await session.requestReferenceSpace("local");
hitTestSourceInitialized = true;
session.addEventListener("end", () => {
hitTestSourceInitialized = false;
hitTestSource = null;
});
}
- Implementar o
onSelect
function onSelect() {
if (reticle.visible) {
const geometry = new THREE.CylinderGeometry(0, 0.05, 0.2, 32);
const material = new THREE.MeshPhongMaterial({
color: 0xffffff * Math.random()
});
const mesh = new THREE.Mesh(geometry, material);
mesh.position.setFromMatrixPosition(reticle.matrix);
mesh.quaternion.setFromRotationMatrix(reticle.matrix);
scene.add(mesh);
}
}
- Verificar se um objeto da cena foi clicado
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
function onMouseClick(event) {
mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
// Atualizar o Raycaster com a câmera e a posição do mouse
raycaster.setFromCamera(mouse, camera);
// Obter os objetos que foram intersectados pelo raio
const intersects = raycaster.intersectObjects(scene.children, true);
if (intersects.length > 0) {
// Se houve intersecção, podemos acessar o primeiro objeto clicado
const clickedObject = intersects[0].object;
console.log("Objeto clicado: ", clickedObject.name);
// Adicionar ou modificar ações no objeto clicado
clickedObject.material.color.set(0xff0000); // Mudar a cor do objeto como exemplo
}
}
window.addEventListener('click', onMouseClick, false);
- Ambiente de desenvolvimento Ethereum Remix
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.2 <0.9.0;
contract Transferencia {
string public nomeorigem;
string public nomedestino;
int public valor;
constructor (string memory novonomeorigem, string memory novonomedstino, int novovalor) {
nomeorigem = novonomeorigem;
nomedestino = novonomedstino;
valor = novovalor;
}
function setNomeOrigem(string memory novonomeorigem) public {
nomeorigem = novonomeorigem;
}
}
- Atributos
public
são apenas de leitura - Necessário criar os métodos
set
para atribuir valor
function setNomeOrigem(string memory novonomeorigem) public {
nomeorigem = novonomeorigem;
}
- Tipos de função:
public
- qualquer um pode acessarprivate
- restrita ao contrato (interna)view
- apenas retorna dados e não altera o conteúdo das variáveis de estadoconstant
- mesma coisa do queview
pure
- nem altera e nem retorna o conteúdo das variáveis de estadopayable
- explicitamente envia ethers quando acionada
- Exemplo:
function teste() public pure returns (int){
return 1 + 1;
}
- Criar também um método construtor
constructor (string memory novonomeorigem, string memory novonomedstino, int novovalor) {
nomeorigem = novonomeorigem;
nomedestino = novonomedstino;
valor = novovalor;
}
- Os principais tipos de dados do solidity podem ser acessados aqui
- Instalar as dependências
npm install -g solc web3 truffle ganache
- Criar uma pasta para conter o projeto, por exemplo,
blockchain-transferencia
- Iniciar o projeto dentro do diretório
blockchain-transferencia
com o comandotruffle init
- Editar o arquivo
truffle-config.js
e no objetonetwork
colar o código abaixo
networks: {
development: {
host: "127.0.0.1",
port: 8545,
network_id: "*"
}
},
compilers: {
solc: {
version: "0.8.24"
}
}
- Criar o contrato na pasta
contracts
com o comandotruffle create contract Transferencia
e incluir o código abaixo
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.8.24;
contract Transferencia {
string public nomeorigem;
string public nomedestino;
int public valor;
constructor (string memory novonomeorigem, string memory novonomedstino, int novovalor) {
nomeorigem = novonomeorigem;
nomedestino = novonomedstino;
valor = novovalor;
}
function setNomeOrigem(string memory novonomeorigem) public {
nomeorigem = novonomeorigem;
}
}
- Para compilar o contrato
truffle compile
que irá gerar a interface ABI e também o bytecode dentro da pastabuild/contracts
- Criar uma migração deploy com o comando
truffle create migration Transferencia
e complementar o código
// indicar o nome do contrato criado na pasta contracts
const Transferencia = artifacts.require('Transferencia');
module.exports = function (_deployer) {
_deployer.deploy(Transferencia, 'Joao', 'Maria', 100);
};
- Em um novo terminal, iniciar o servidor local ganache com
ganache
- Efetuar o deploy com
truffle migrate
- Para interagir com o contrato utilizar o
truffle console
- Obter a instância do contrato
const instancia = await Transferencia.deployed();
- Verificar os valores
const nomeOrigem = await instancia.nomeorigem();
console.log("Nome de origem:", nomeOrigem);
const nomeDestino = await instancia.nomedestino();
console.log("Nome de destino:", nomeDestino);
const valorTransferencia = await instancia.valor();
console.log("Valor da transferência:", valorTransferencia.toString());
- Outras opções interessantes
// Endereço do contrato
console.log("Endereço do contrato:", instancia.address);
// Verificar o endereço da conta que fez o deploy
const deployer = (await web3.eth.getAccounts())[0];
console.log("Deployer:", deployer);
// Obter saldo da conta deployer
const saldo = await web3.eth.getBalance(deployer);
console.log("Saldo do deployer:", web3.utils.fromWei(saldo, 'ether'), "ETH");
// verificar o ultimo bloco
const latestBlock = await web3.eth.getBlock('latest');
console.log(latestBlock);
// verificar o bloco anterior
const previousBlock = await web3.eth.getBlock(latestBlock.number - 1);
console.log(previousBlock);
// buscar os blocos do contrato pelos logs
const logs = await web3.eth.getPastLogs({address: '0x3A198349564862C1Dc9DFd367B26930F9d35D0bD'});
- Para sair do console digitar o comando
.exit
- Um exemplo utilizando o web3
const { Web3 } = require('web3');
const provider = new Web3.providers.HttpProvider('http://localhost:8545');
const web3 = new Web3(provider)
async function getPreviousBlock() {
const latestBlock = await web3.eth.getBlock('latest');
console.log('Bloco atual:', latestBlock);
const previousBlock = await web3.eth.getBlock(latestBlock.number - BigInt(1));
console.log('Bloco anterior:', previousBlock);
}
getPreviousBlock().catch(console.error);
- Observação: existe mais de um tipo de provider
- Criar uma pasta com o nome
blockchain-transferencia-express
- Iniciar o projeto nodejs com
npm init -y
- Instalar as dependências
npm install --save express web3
- Criar o backend da aplicação
const express = require('express');
const { Web3 } = require('web3');
const { abi, bytecode } = require('./build/contracts/Transferencia.json')
const app = express();
const port = 3000;
// Configuração do Web3 com o Ganache (ou endereço RPC)
const provider = new Web3.providers.HttpProvider('http://localhost:8545');
const web3 = new Web3(provider)
// Carregar ABI e endereço do contrato
const contratoEndereco = '0x7c20117358280da996b00bf8d33e531d15b2959c'; // Substitua pelo endereço do contrato implantado
const contrato = new web3.eth.Contract(abi, contratoEndereco);
// Rota para obter os dados do contrato
app.get('/dados', async (req, res) => {
try {
const nomeOrigem = await contrato.methods.nomeorigem().call();
const nomeDestino = await contrato.methods.nomedestino().call();
const valor = await contrato.methods.valor().call();
res.json({ nomeOrigem, nomeDestino, valor: valor.toString()});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
// Rota para atualizar os dados do contrato
app.post('/atualizar', express.json(), async (req, res) => {
const { nomeOrigem, nomeDestino, valor } = req.body;
const accounts = await web3.eth.getAccounts();
try {
await contrato.methods.atualizarTransferencia(nomeOrigem, nomeDestino, valor)
.send({ from: accounts[0], gas: 500000 });
res.json({ message: 'Contrato atualizado com sucesso!' });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
app.listen(port, () => {
console.log(`Servidor rodando em http://localhost:${port}`);
});
- Um simples frontend pode ser criado para interagir com o backend acima
- Criar uma pasta
public
dentro da pasta do projeto - No
server.js
adicionar
const path = require('path'); app.use(express.static(path.join(__dirname, 'public')));
- Criar uma pasta
- Incluir o código abaixo
index.html
na pastapublic
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Meu Projeto</title>
<link rel="stylesheet" href="style.css">
<script>
async function carregarDados() {
try {
const response = await fetch('/dados');
if (!response.ok) {
throw new Error('Network response was not ok');
}
const dados = await response.json();
document.getElementById('nomeOrigem').textContent = dados.nomeOrigem;
document.getElementById('nomeDestino').textContent = dados.nomeDestino;
document.getElementById('valor').textContent = dados.valor;
} catch (error) {
console.error('Houve um problema com a requisição Fetch:', error);
}
}
// Carregar os dados ao carregar a página
window.addEventListener('load', carregarDados);
</script>
</head>
<body>
<h1 id="nomeOrigem"></h1>
<p id="nomeDestino"></p>
<p id="valor"></p>
</body>
</html>
- Criar um arquivo de folha de estilos
style.css
body {
font-family: Arial, sans-serif;
background-color: #f4f4f4;
text-align: center;
padding: 50px;
}
h1 {
color: #333;
}
- Criar uma pasta
blockchain-transferencia-client-truffle
- Dentro da pasta, iniciar o projeto nodejs com
npm init -y
- Adicionar o servidor, por exemplo, lite-server
npm install lite-server --save-dev
- Editar o arquivo
package.json
e adicionar o seguinte script
"scripts": {
"start": "lite-server"
},
- Criar um arquivo
Transferencia.js
com o conteúdo
const Transferencia = {
"abi": [ /* Cole o ABI gerado aqui */ ],
"networks": {
"5777": { "address": "ENDERECO_DO_CONTRATO" }
}
};
export default Transferencia;
- Criar uma carteira virtual no Metamax
- Conversor para Mnemonic Bip39
- Tempo de processamento de blocos pode ser consultado em block time
- Principais modelos utilizados para classificação e/ou predição (regressão)
Modelo | Tipo de Uso | Descrição |
---|---|---|
Random Forest (RF) | Classificação, Regressão | Algoritmo baseado em múltiplas árvores de decisão, útil tanto para classificação quanto para regressão, especialmente em dados ruidosos. |
Gradient Boosting Machine (GBM) | Classificação, Regressão | Método de boosting com árvores de decisão que melhora iterativamente os erros do modelo anterior. Funciona bem com dados não lineares. |
Deep Learning (DL) | Classificação, Regressão | Redes neurais profundas que podem capturar padrões complexos, sendo eficaz para grandes volumes de dados. Comum em tarefas como reconhecimento de imagem e voz. |
Generalized Linear Model (GLM) | Classificação, Regressão | Modelos lineares com diferentes distribuições de erro, usado para problemas como regressão logística ou linear. |
Naive Bayes | Classificação | Modelo probabilístico simples que assume a independência entre as variáveis, frequentemente usado em tarefas de texto como spam filtering. |
Stacked Ensemble | Classificação, Regressão | Combinação de múltiplos modelos para melhorar a performance, sendo uma técnica poderosa para aumentar a precisão geral. |
XGBoost | Classificação, Regressão | Implementação eficiente de gradient boosting, amplamente usado em competições de machine learning, especialmente para dados tabulares. |
LightGBM | Classificação, Regressão | Versão mais eficiente e escalável do Gradient Boosting, projetada para lidar com grandes volumes de dados. |
GLM with Elastic Net | Classificação, Regressão | Modelo linear com regularização L1 e L2 (Lasso + Ridge), que ajuda a prevenir overfitting, especialmente em dados com muitas variáveis. |
Quantile Regression | Regressão | Variante da regressão linear que estima quantis (ex: mediana) em vez de valores médios, útil em modelos robustos a outliers. |
H2O AutoML Stacked Ensemble | Classificação, Regressão | Combinação automática dos melhores modelos gerados pelo AutoML, resultando em um modelo de ensemble final para melhorar a precisão. |
K-means Clustering | Não supervisionado | Algoritmo de agrupamento usado para segmentação de dados em clusters, útil para explorar padrões e agrupamentos em dados não rotulados. |
DBSCAN (Density-Based Spatial Clustering of Applications with Noise) | Não supervisionado | Algoritmo de agrupamento baseado em densidade, útil para encontrar clusters de formas arbitrárias e identificar outliers. |
Principal Component Analysis (PCA) | Não supervisionado | Técnica de redução de dimensionalidade, usada para simplificar dados complexos, mantendo as variações mais significativas. |
t-SNE (t-Distributed Stochastic Neighbor Embedding) | Não supervisionado | Técnica de redução de dimensionalidade usada para visualizar dados em alta dimensão de maneira mais compreensível, muito usada em visualização de dados. |
K-Nearest Neighbors (KNN) | Classificação, Regressão | Modelo simples que classifica ou faz previsões baseadas nos "vizinhos" mais próximos, utilizado tanto para classificação quanto para regressão. |
Support Vector Machine (SVM) | Classificação, Regressão | Algoritmo poderoso para classificação e regressão, que busca maximizar a margem entre as classes. Funciona bem para dados complexos e não linearmente separáveis. |
AdaBoost | Classificação, Regressão | Método de boosting que combina vários modelos fracos (geralmente árvores pequenas) para criar um modelo forte, comumente usado em classificações. |
ElasticNet | Regressão | Combinação de regularização L1 (Lasso) e L2 (Ridge), útil em regressão linear quando há muitas variáveis correlacionadas. |
Ridge Regression | Regressão | Tipo de regressão linear com regularização L2 para evitar overfitting em dados com muitas variáveis. |
Lasso Regression | Regressão | Tipo de regressão linear com regularização L1, que ajuda a realizar seleção de características ao forçar coeficientes a zero. |
- Acessar o Google Colab e criar um novo Notebook
- Importar os pacotes necessários
!pip install h2o
!pip install tpot
!pip install scikit-learn
!pip install ucimlrepo
!pip install pandas
- Os pacotes scikit-learn e ucimlrepo são datasets utilizados em exemplos
- Para listar todos os datasets do pacote scikit-learn
import sklearn.datasets as datasets_sklearn
available_datasets = [func for func in dir(datasets_sklearn) if func.startswith('load_') or func.startswith('fetch_')]
available_datasets
- Listando todos os datasets do pacote ucimlrepo
from ucimlrepo import fetch_ucirepo, list_available_datasets
list_available_datasets()
- Por exemplo, podemos utilizar um dataset para classificação de flores de Iris (um tipo de flor de cores fortes, parecidas com orquídeas)
- As flores de Iris podem ser classificadas em Setosa, Versicolour e Virginica conforme a largura e altura de pétalas e sépalas
- Para carregar o dataset
from sklearn.datasets import load_iris
iris = load_iris()
- Os datasets são formados pelas suas características (atributos) representados pelas features
iris.feature_names
- Os dados das features podem ser vistos no atributo
data
iris.data
- Os targets representam o resultado observado para cada conjunto de feature
iris.target_names
iris.target
- A melhor forma para se trabalhar com esses dados é onvertê-los para dataframes
import pandas as pd
df = pd.DataFrame(iris.data, columns=iris.feature_names)
df['especie'] = iris.target
df.head()
- Outro exemplo para o dataset relacionado ao tipo de câncer de mama (malígno ou benígno)
from sklearn.datasets import load_breast_cancer
cancer = load_breast_cancer()
cancer.target_names
cancer.target_names
dfCancer = pd.DataFrame(cancer.data, columns=cancer.feature_names)
dfCancer['tipo'] = cancer.target
dfCancer['tipo_desc'] = cancer.target_names[cancer.target]
dfCancer.head()
- Selecionar um subconjunto dos dados para testar o modelo
X_train
: sub-conjunto dos dados para o treinamentoy_train
: targets para o treinamento relacionados aoX_train
X_test
: sub-onjunto dos dados para o testey_test
: targets para o teste relacionados aoX_test
test_size=0.2
: indica 20% para o teste e 80% das amostras para o treinamento (no exemplo, total = 569, treino = 455, teste = 114)
from sklearn.model_selection import train_test_split
X_train, X_test, y_train, y_test = train_test_split(cancer.data, cancer.target, test_size=0.2, random_state=42)
df_train = pd.DataFrame(X_train, columns=cancer.feature_names)
df_train['tipo'] = y_train
df_train.head(1000)
- Exibir os dados de teste
df_test = pd.DataFrame(X_test, columns=cancer.feature_names)
df_test['tipo'] = y_test
df_test.head()
- Visualização gráfica da distribuição dos tipos de câncer por malígno(0) e benígno(1)
import matplotlib.pyplot as plt
import seaborn as sns
plt.figure(figsize=(12, 6))
plt.subplot(1, 2, 1)
sns.countplot(x=y_train)
plt.title("Distribuição das Classes - Treinamento")
plt.subplot(1, 2, 2)
sns.countplot(x=y_test)
plt.title("Distribuição das Classes - Teste")
plt.tight_layout()
plt.show()
- Iniciar o servidor H2O
import h2o
h2o.init()
- Importar a bilbioteca
H2OAutoML
e o dataframe específicoH2OFrame
from h2o.automl import H2OAutoML
from h2o import H2OFrame
- Converter o Dataframe para o formato aceito pelo H2O (
H2OFrame
)
train_data = H2OFrame(df_train)
train_data['tipo'] = train_data['tipo'].asfactor()
test_data = H2OFrame(df_test)
train_data
test_data
- Realizar a escolha do melhor modelo (Random Forest, Gradient Boosting, Deep Learning, etc.) para o conjunto de dados
max_models
: quantidade máxima de modelos analisadosmax_runtime_secs
: tempo máximo de análise
aml = H2OAutoML(max_models=10, max_runtime_secs=120)
x = train_data.columns[:-1]
y = 'tipo'
aml.train(x=x, y=y, training_frame=train_data)
- Tabela dos melhores modelos selecionados
aml.leaderboard
- Melhor modelo
aml.leader
- Utilizar o melhor modelo (
leader
) para realizar uma predição
predictions = aml.leader.predict(test_data)
- Considerar a tabela abaixo contendo 10 observações sobre 4 features relacionadas a imóveis em uma cidade
Imóvel | Preço | Tamanho (m²) | Quartos | Idade (anos) | Padrão |
---|---|---|---|---|---|
1 | 250 | 80 | 2 | 10 | Médio |
2 | 450 | 120 | 3 | 5 | Alto |
3 | 350 | 100 | 3 | 8 | Médio |
4 | 200 | 60 | 1 | 15 | Baixo |
5 | 300 | 90 | 2 | 12 | Médio |
6 | 550 | 150 | 4 | 3 | Alto |
7 | 400 | 110 | 3 | 7 | Alto |
8 | 150 | 50 | 1 | 20 | Baixo |
9 | 250 | 85 | 2 | 11 | Médio |
10 | 600 | 160 | 4 | 2 | Alto |
- Instalar o H2O caso ainda não esteja instalado
!pip install h2o
- Importar o pacote e iniciar o servidor
import h2o
h2o.init()
- Criar o dataframe no formato H2O
import pandas as pd
data = {
'Preço': [250, 450, 350, 200, 300, 550, 400, 150, 250, 600],
'Tamanho (m²)': [80, 120, 100, 60, 90, 150, 110, 50, 85, 160],
'Quartos': [2, 3, 3, 1, 2, 4, 3, 1, 2, 4],
'Idade (anos)': [10, 5, 8, 15, 12, 3, 7, 20, 11, 2],
'Padrão': ['Médio', 'Alto', 'Médio', 'Baixo', 'Médio', 'Alto', 'Alto', 'Baixo', 'Médio', 'Alto']
}
df = pd.DataFrame(data)
h2o_df = h2o.H2OFrame(df)
h2o_df
- Dividir os dados para treino (80%) e testes do modelo (20%)
train, test = h2o_df.split_frame(ratios=[0.8], seed=1234)
train
test
- Treinar um modelo, por exemplo, o random forest
x = ['Preço', 'Tamanho (m²)', 'Quartos', 'Idade (anos)']
y = 'Padrão'
from h2o.estimators.random_forest import H2ORandomForestEstimator
model = H2ORandomForestEstimator(ntrees=50, max_depth=20)
model.train(x=x, y=y, training_frame=train)
- Avaliar a performance do modelo selecionado
performance = model.model_performance(test_data=test)
performance
- Efetuar a classificação
predictions = model.predict(test)
predictions.head()
- Agora, efetuar o treinamento para um modelo preditivo, isto é, prever o preço de um imóvel com base nas suas features
train, test = h2o_df.split_frame(ratios=[0.8], seed=1234)
- Definir as variáveis (dependentes - preço e independentes - tamanho, quartos e idade)
x = ['Tamanho (m²)', 'Quartos', 'Idade (anos)']
y = 'Preço'
- Criar o modelo de regressão
model_regressor = H2ORandomForestEstimator(ntrees=50, max_depth=20)
model_regressor.train(x=x, y=y, training_frame=train)
- Avaliar o modelo
performance_regressor = model_regressor.model_performance(test_data=test)
performance_regressor
- Efetuar uma previsão de preço com base no conjunto de teste
predictions_regressor = model_regressor.predict(test)
predictions_regressor.head()
- Avaliar o imóvel abaixo e determinar seu padrão aplicando o modelo Naive Bayes
Preço | Tamanho (m²) | Quartos | Idade (anos) | Padrão |
---|---|---|---|---|
300 | 200 | 5 | 30 | ??? |
from h2o.estimators import H2ONaiveBayesEstimator
nb = H2ONaiveBayesEstimator()
nb.train(x=x, y=y, training_frame=train)
performance = nb.model_performance(test_data=test)
performance
- Criando um novo dado com as características do imóvel e efetuando a predição
new_data = pd.DataFrame({
'Preço': [300],
'Tamanho (m²)': [200],
'Quartos': [5],
'Idade (anos)': [30]
})
new_data_h2o = h2o.H2OFrame(new_data)
prediction = nb.predict(new_data_h2o)
prediction
- Prever agora qual seria o preço do mesmo imóvel, isto é, com as features abaixo utilizando o Generalized Linear Model
Preço | Tamanho (m²) | Quartos | Idade (anos) |
---|---|---|---|
300 | 200 | 5 | 30 |
from h2o.estimators import H2OGeneralizedLinearEstimator
# Criando o DataFrame com os dados de imóveis
data = {
'Preço': [250, 450, 350, 200, 300, 550, 400, 150, 250, 600],
'Tamanho (m²)': [80, 120, 100, 60, 90, 150, 110, 50, 85, 160],
'Quartos': [2, 3, 3, 1, 2, 4, 3, 1, 2, 4],
'Idade (anos)': [10, 5, 8, 15, 12, 3, 7, 20, 11, 2]
}
df = pd.DataFrame(data)
h2o_df = h2o.H2OFrame(df)
train, test = h2o_df.split_frame(ratios=[0.8], seed=1234)
x = ['Tamanho (m²)', 'Quartos', 'Idade (anos)']
y = 'Preço'
glm = H2OGeneralizedLinearEstimator(family="gaussian")
glm.train(x=x, y=y, training_frame=train)
performance = glm.model_performance(test_data=test)
performance.rmse()
new_data = pd.DataFrame({
'Tamanho (m²)': [200],
'Quartos': [5],
'Idade (anos)': [30]
})
new_data_h2o = h2o.H2OFrame(new_data)
prediction = glm.predict(new_data_h2o)
prediction
- Obs: Root Mean Squared Error - RMSE (* Erro Quadrático Médio (EQM)*) é uma métrica utilizada para medir a diferença entre os valores reais e os valores preditos pelo modelo
- Utilizar o conceito de Auto Machine Learning para escolher automaticamente o melhor modelo
aml = H2OAutoML(max_models=20, seed=1, max_runtime_secs=300)
aml.train(x=x, y=y, training_frame=train)
- Modelos selecionados
aml.leaderboard
- Melhor modelo
aml.leader
- Avaliando a performande do melhor modelo
- Model: Nome do modelo treinado (ex. Random Forest, GBM, Deep Learning, etc.)
- AUC: Para classificação, mostra a Área sob a Curva ROC
- LogLoss: Para classificação, mostra a medida da incerteza das previsões
- RMSE: Para regressão, mostra o erro quadrático médio
- MAE: Para regressão, mostra o erro absoluto médio
performance = leader.model_performance(test_data=test)
performance
- Realizando previsões
predictions = leader.predict(test)
predictions.head()
- Esta não é o melhor caso de aplicação de IA para classificação (pois existe uma regra bem definida) mas serve para avaliar facilmente se o modelo está correto
- Considerar a lista de notas de 10 alunos e o seu status final, isto é, Aprovado ou Reprovado
Aluno | Prova 1 | Prova 2 | Prova 3 | Trabalho 1 | Trabalho 2 | Participação | Média | Status |
---|---|---|---|---|---|---|---|---|
A1 | 6 | 7 | 8 | 7 | 6 | 5 | 6.17 | Aprovado |
A2 | 5 | 6 | 4 | 3 | 4 | 6 | 4.67 | Reprovado |
A3 | 9 | 8 | 9 | 8 | 9 | 9 | 8.83 | Aprovado |
A4 | 4 | 3 | 5 | 4 | 5 | 4 | 4.17 | Reprovado |
A5 | 7 | 6 | 7 | 6 | 7 | 8 | 6.83 | Aprovado |
A6 | 6 | 5 | 6 | 5 | 5 | 4 | 5.17 | Reprovado |
A7 | 8 | 8 | 7 | 7 | 6 | 7 | 7.17 | Aprovado |
A8 | 3 | 4 | 3 | 2 | 3 | 2 | 3.00 | Reprovado |
A9 | 10 | 10 | 9 | 10 | 9 | 9 | 9.50 | Aprovado |
A10 | 5 | 5 | 6 | 6 | 6 | 4 | 5.33 | Reprovado |
- Um aluno é aprovado caso a sua média final seja maior ou igual a 6
- A preparação dos dados é a que segue abaixo
# Criando o dataframe com os dados simulados
data = {
'Prova 1': [6, 5, 9, 4, 7, 6, 8, 3, 10, 5],
'Prova 2': [7, 6, 8, 3, 6, 5, 8, 4, 10, 5],
'Prova 3': [8, 4, 9, 5, 7, 6, 7, 3, 9, 6],
'Trabalho 1': [7, 3, 8, 4, 6, 5, 7, 2, 10, 6],
'Trabalho 2': [6, 4, 9, 5, 7, 5, 6, 3, 9, 6],
'Participação': [5, 6, 9, 4, 8, 4, 7, 2, 9, 4]
}
# Convertendo o dicionário para um DataFrame pandas
df = pd.DataFrame(data)
# Calculando a média
df['Média'] = df[['Prova 1', 'Prova 2', 'Prova 3', 'Trabalho 1', 'Trabalho 2', 'Participação']].mean(axis=1)
# Criando a coluna 'Status' com base na média
df['Status'] = df['Média'].apply(lambda x: 'Aprovado' if x > 5 else 'Reprovado')
- Utilizar o AutoML com o H2O para determinar o melhor modelo
- Verificar qual seria o status dos alunos abaixo
Aluno | Prova 1 | Prova 2 | Prova 3 | Trabalho 1 | Trabalho 2 | Participação | Média | Status |
---|---|---|---|---|---|---|---|---|
A1 | 10 | 10 | 10 | 10 | 10 | 10 | 10 | Aprovado |
A2 | 5 | 1 | 0 | 9 | 8 | 10 | 5.5 | Reprovado |
- Observar a Confusion Matrix para os resultados por meio do método
best_model.model_performance()
- Aplicar o PCA para reduzir a dimensão 4D para 2D sobre um conjunto de features relacionadas a imóveis em uma cidade
- O conjunto de dados é criado manualmente com as 4 características dos imóveis: Preço, Tamanho, Quartos e Idade. Normalização
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from sklearn.decomposition import PCA
from sklearn.preprocessing import StandardScaler
data = {
'Preço': [250, 450, 350, 200, 300, 550, 400, 150, 250, 600],
'Tamanho (m²)': [80, 120, 100, 60, 90, 150, 110, 50, 85, 160],
'Quartos': [2, 3, 3, 1, 2, 4, 3, 1, 2, 4],
'Idade (anos)': [10, 5, 8, 15, 12, 3, 7, 20, 11, 2]
}
df = pd.DataFrame(data)
df
- Como as características possuem escalas diferentes (ex: o preço pode variar de centenas de milhares, enquanto a idade varia de poucos anos), usamos o
StandardScaler
para normalizar os dados, o que significa transformá-los para que tenham média 0 e desvio padrão 1. Isso é importante porque o PCA é sensível à escala dos dados
scaler = StandardScaler()
df_scaled = scaler.fit_transform(df)
df_scaled
- O PCA é aplicado com n_components=2, o que significa que vamos reduzir as 4 dimensões originais para 2 componentes principais. O PCA encontra a combinação linear das características que mais explica a variância dos dados
pca = PCA(n_components=2)
df_pca = pca.fit_transform(df_scaled)
df_pca_df = pd.DataFrame(df_pca, columns=['PC1', 'PC2'])
plt.figure(figsize=(8, 6))
plt.scatter(df_pca_df['PC1'], df_pca_df['PC2'], color='blue', marker='o')
plt.title('Redução de Dimensionalidade - Imóveis em uma Cidade (PCA)')
plt.xlabel('Componente Principal 1 (PC1)')
plt.ylabel('Componente Principal 2 (PC2)')
plt.show()
- Instalar os pacotes necessários
!pip install scikit-learn matplotlib seaborn
- Preparar os dados para processamento
import pandas as pd
from sklearn.cluster import KMeans
import matplotlib.pyplot as plt
import seaborn as sns
data = {
'Item': ['Banana', 'Maçã', 'Abacate', 'Alface', 'Rúcula', 'Acelga'],
'Peso (g)': [120, 150, 200, 50, 30, 40],
'Doçura (0-10)': [9, 8, 7, 2, 1, 3],
'Cor (1-fruta, 0-verdura)': [1, 1, 1, 0, 0, 0]
}
df = pd.DataFrame(data)
df.set_index('Item', inplace=True)
df
- Aplicar o k-means
X = df[['Peso (g)', 'Doçura (0-10)', 'Cor (1-fruta, 0-verdura)']]
kmeans = KMeans(n_clusters=2, random_state=42)
df['Cluster'] = kmeans.fit_predict(X)
df
- Visualizar o resultado
sns.scatterplot(data=df, x='Peso (g)', y='Doçura (0-10)', hue='Cluster', palette='Set2', s=100)
plt.title('Classificação de Frutas e Verduras com K-means')
plt.xlabel('Peso (g)')
plt.ylabel('Doçura (0-10)')
plt.legend(title='Cluster')
plt.show()
- Aplicando o k-means em um conjunto de dados mais complexo (wine)
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.datasets import load_wine
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
data = load_wine()
X = data.data
y = data.target
df = pd.DataFrame(X, columns=data.feature_names)
df.head()
- Normalizar os dados
- A normalização transforma as variáveis para a mesma escala, garantindo que cada característica tenha média 0 e desvio padrão 1, o que evita que variáveis com maior amplitude dominem o cálculo das distâncias.
scaler = StandardScaler()
X_scaled = scaler.fit_transform(X)
X_scaled[:5]
- Verificar qual seria o valor inicial ideal aplicando o método do cotovelo
inertia = []
for k in range(1, 11):
kmeans = KMeans(n_clusters=k, random_state=42)
kmeans.fit(X_scaled)
inertia.append(kmeans.inertia_)
plt.plot(range(1, 11), inertia, marker='o')
plt.title('Método do Cotovelo')
plt.xlabel('Número de Clusters (K)')
plt.ylabel('Inércia')
plt.xticks(range(1, 11))
plt.show()
- Aplicar o k-means para k = 3
kmeans = KMeans(n_clusters=3, random_state=42)
y_kmeans = kmeans.fit_predict(X_scaled)
df['Cluster'] = y_kmeans
df.head()
- Visualizar os clusters
from sklearn.decomposition import PCA
pca = PCA(n_components=2)
X_pca = pca.fit_transform(X_scaled)
df_pca = pd.DataFrame(X_pca, columns=['PC1', 'PC2'])
df_pca['Cluster'] = y_kmeans
plt.figure(figsize=(8,6))
sns.scatterplot(x='PC1', y='PC2', hue='Cluster', data=df_pca, palette='Set2', s=100)
plt.title('Clusters de Vinho (K-means com K=3)')
plt.xlabel('Componente Principal 1')
plt.ylabel('Componente Principal 2')
plt.show()
- TPOT - gera programas em python que implementam um pipeline de Machine Learning
!pip install tpot
import pandas as pd
from sklearn.model_selection import train_test_split
from tpot import TPOTClassifier, TPOTRegressor
data = {
'Preço (milhares de R$)': [250, 450, 350, 200, 300, 550, 400, 150, 250, 600],
'Tamanho (m²)': [80, 120, 100, 60, 90, 150, 110, 50, 85, 160],
'Quartos': [2, 3, 3, 1, 2, 4, 3, 1, 2, 4],
'Idade (anos)': [10, 5, 8, 15, 12, 3, 7, 20, 11, 2],
'Padrão': ['Médio', 'Alto', 'Médio', 'Baixo', 'Médio', 'Alto', 'Alto', 'Baixo', 'Médio', 'Alto']
}
df = pd.DataFrame(data)
df['Padrão'] = df['Padrão'].map({'Baixo': 0, 'Médio': 1, 'Alto': 2})
X = df.drop('Padrão', axis=1)
y = df['Padrão']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, random_state=42)
tpot = TPOTClassifier(verbosity=2, generations=5, population_size=20, random_state=42, cv=3)
tpot.fit(X_train, y_train)
print("Acurácia no conjunto de teste:", tpot.score(X_test, y_test))
tpot.export('best_classification_model.py')
- Verificar se os arquivos foram gerados no diretório local
!ls
- Importar o arquivo gerado
from best_classification_model import exported_pipeline
- Exemplo do auto-sklearn
import autosklearn.regression
from sklearn.metrics import mean_squared_error
automl = autosklearn.regression.AutoSklearnRegressor(time_left_for_this_task=60, # tempo total para a busca
per_run_time_limit=30, # tempo máximo por modelo
n_jobs=-1) # Usando todos os núcleos do CPU
automl.fit(X_train, y_train)
y_pred = automl.predict(X_test)
mse = mean_squared_error(y_test, y_pred)
mse
- Voyant Tools é uma plataforma gratuita para análise de textos on-line
- Acessar o Google Colab e criar um novo Notebook
- Em python existe a biblioteca nltk para processamento de linguagem natural (já incluída no colab)
- Necessário instalar alguns pacotes específicos por idioma
import nltk
nltk.download('all')
- Tokenização
tokens = nltk.word_tokenize("Eu gostaria de aprender IA. Acho uma área muito interessante, além de bastante promissora.".lower())
tokens
- Stop words para a língua portuguesa
filtered_tokens = [token for token in tokens if token not in stopwords.words('portuguese')]
filtered_tokens
- Processo de stemming com o algoritmo de Porter para palavras em inglês
from nltk.stem import PorterStemmer
ps = PorterStemmer()
example_words = ["program","programming","programer","programs","programmed"]
for word in example_words:
print(word, ps.stem(word))
- A biblioteca nltk possui um stemmer específico para a língua portuguesa chamado
RSLPStemmer
from nltk.stem import RSLPStemmer
ps = RSLPStemmer()
example_words = ["programa","programador","programação","programável","programar"]
for word in example_words:
print(word, ps.stem(word))
- Lematização
from nltk.stem import WordNetLemmatizer
wnl = WordNetLemmatizer()
example_words = ["program","programming","programer","programs","programmed"]
for word in example_words:
print(word, ps.stem(word))
- Para português utilizar a biblioteca spicy
- Reiniciar o colab com
Control + M + .
- Reiniciar o colab com
!pip install spacy
!python -m spacy download pt_core_news_sm
- Aplicar o processo em um texto de exemplo em português
import spacy
nlp = spacy.load("pt_core_news_sm")
text = "Eu estava correndo quando vi um gato e ele correu rapidamente."
doc = nlp(text)
lemmatized_words = [token.lemma_ for token in doc]
lemmatized_words
- Exemplo de Bag of Words
- Instalar a biblioteca scikit-learn com
!pip install scikit-learn
- Instalar a biblioteca scikit-learn com
from sklearn.feature_extraction.text import CountVectorizer
docs = [
"O cachorro corre rápido",
"O gato corre devagar"
]
vectorizer = CountVectorizer()
X = vectorizer.fit_transform(docs)
vocab = vectorizer.get_feature_names_out()
print("Vocabulário:", vocab)
print("\nMatriz de contagem de palavras (Bag-of-Words):")
print(X.toarray())
- Análise de sentimento
import nltk
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
from nltk.classify import NaiveBayesClassifier
# Baixando recursos necessários do NLTK
nltk.download('punkt')
nltk.download('stopwords')
# Definindo o conjunto de dados de treinamento com frases e rótulos
# 'positivo' ou 'negativo' são os rótulos de sentimento
train_data = [
("O produto é realmente muito bom, estou plenamente satisfeito", "positivo"),
("Vou devolver o produto pois estou muito decepcionado com o seu funcionamento", "negativo"),
("Adorei a compra, super recomendo!", "positivo"),
("O produto não funciona, fiquei muito frustrado", "negativo"),
("Estou muito feliz com o produto, valeu cada centavo", "positivo"),
("O produto é péssimo, não serve para nada", "negativo")
]
# Função para extrair características (features) do texto
def extrair_caracteristicas(texto):
# Tokenizando o texto e removendo stopwords
palavras = word_tokenize(texto.lower()) # Convertendo para minúsculas e tokenizando
stop_words = set(stopwords.words('portuguese')) # Lista de stopwords em português
palavras = [palavra for palavra in palavras if palavra not in stop_words and palavra.isalpha()] # Remover stopwords e não-alfabéticos
# Retorna um dicionário de características (palavras como chaves)
return {palavra: True for palavra in palavras}
# Transformar os dados de treinamento em características
train_features = [(extrair_caracteristicas(texto), sentimento) for texto, sentimento in train_data]
# Treinando o classificador Naive Bayes com o NLTK
classificador = NaiveBayesClassifier.train(train_features)
# Função para classificar novas frases
def classificar_sentimento(frase):
features = extrair_caracteristicas(frase)
return classificador.classify(features)
# Testando com novas frases
novas_frases = [
"O produto é muito bom, super recomendo!", # Sentimento esperado: Positivo
"Não gostei do produto, está muito abaixo das minhas expectativas." # Sentimento esperado: Negativo
]
# Classificando as novas frases
for frase in novas_frases:
sentimento = classificar_sentimento(frase)
print(f"Frase: {frase} -> Sentimento: {sentimento}")
- Para treinar utilizando um conjunto de dados maior
import pandas as pd
import nltk
from nltk.corpus import stopwords
from nltk.tokenize import word_tokenize
from nltk.classify import NaiveBayesClassifier
# Baixando recursos necessários do NLTK
nltk.download('punkt')
nltk.download('stopwords')
# Carregando o CSV diretamente da URL
url = "https://raw.githubusercontent.com/pycaret/pycaret/master/datasets/amazon.csv"
data = pd.read_csv(url)
# Visualizando as primeiras linhas do DataFrame
print(data.head())
# Verificando as colunas do DataFrame
print(f"Colunas disponíveis: {data.columns}")
# Exibindo a distribuição de sentimentos no dataset
print(data['sentiment'].value_counts())
# Função para extrair características (features) do texto
def extrair_caracteristicas(texto):
# Tokenizando o texto e removendo stopwords
palavras = word_tokenize(texto.lower()) # Convertendo para minúsculas e tokenizando
stop_words = set(stopwords.words('english')) # Lista de stopwords em inglês
palavras = [palavra for palavra in palavras if palavra not in stop_words and palavra.isalpha()] # Remover stopwords e não-alfabéticos
# Retorna um dicionário de características (palavras como chaves)
return {palavra: True for palavra in palavras}
# Filtrando dados com sentimentos 'positivo' e 'negativo' (se houver)
data = data[data['sentiment'].isin(['positive', 'negative'])]
# Transformar os dados de treinamento em características
train_features = [(extrair_caracteristicas(texto), sentimento) for texto, sentimento in zip(data['text'], data['sentiment'])]
# Dividindo o conjunto de dados em treino e teste (80% treino, 20% teste)
train_size = int(0.8 * len(train_features))
train_set, test_set = train_features[:train_size], train_features[train_size:]
# Treinando o classificador Naive Bayes com o NLTK
classificador = NaiveBayesClassifier.train(train_set)
# Função para classificar novas frases
def classificar_sentimento(frase):
features = extrair_caracteristicas(frase)
return classificador.classify(features)
# Testando com algumas frases do conjunto de teste
for texto, sentimento_real in test_set[:5]: # Testando as primeiras 5 amostras
texto_original = ' '.join([palavra for palavra, _ in texto.items()]) # Reconstruindo o texto original
sentimento_previsto = classificar_sentimento(texto_original)
print(f"Texto: {texto_original}")
print(f"Sentimento Real: {sentimento_real} | Sentimento Previsto: {sentimento_previsto}\n")
import nltk
from nltk import word_tokenize, pos_tag, ne_chunk
from nltk.tree import Tree
# Baixando os recursos necessários do NLTK
nltk.download('punkt')
nltk.download('maxent_ne_chunker')
nltk.download('words')
nltk.download('averaged_perceptron_tagger')
# Texto jurídico exemplo
texto_juridico = """
No dia 25 de março de 2023, o juiz João Silva, da 5ª Vara Criminal de São Paulo,
proferiu a sentença no processo nº 0012345-67.2023.8.26.0100, em que o réu,
Carlos Alberto Pereira, foi condenado por tráfico de drogas. O Ministério Público,
representado pela promotora Maria Fernanda Souza, afirmou que a pena deveria ser
agravada em razão da reincidência do réu.
"""
# Tokenização e POS Tagging (Marcação de partes do discurso)
tokens = word_tokenize(texto_juridico)
tags = pos_tag(tokens)
# Realizando o NER usando o chunking
entidades = ne_chunk(tags)
# Função para extrair as entidades nomeadas do texto
def extrair_entidades(tree):
entidades_extraidas = []
for subtree in tree:
if isinstance(subtree, Tree):
entidade = " ".join(word for word, tag in subtree.leaves())
tipo = subtree.label()
entidades_extraidas.append((entidade, tipo))
return entidades_extraidas
# Extraindo as entidades
entidades_extraidas = extrair_entidades(entidades)
# Exibindo as entidades extraídas
print("Entidades extraídas:")
for entidade, tipo in entidades_extraidas:
print(f"{entidade} - {tipo}")
- Tipos de classificação
- PERSON: Nome de pessoa (como "João Silva" e "Carlos Alberto Pereira")
- GPE: Localização geopolítica (como "São Paulo").
- TIME: Datas ou períodos de tempo.
- ORGANIZATION: Nome de organizações (como "Ministério Público").
- MISC: Entidades diversas (usado para coisas como títulos, etc.).
- Treinamento do modelo de Reconhecimento de Entidades Nomeadas (NER) com a biblioteca spicy
- Carregar o modelo base
import random
import spacy
from spacy.training.example import Example
nlp = spacy.load("pt_core_news_sm")
- Dados utilizados para o treinamento
train_data = [
("O Art. 5º da Constituição Federal é muito importante", {"entities": [(2, 9, "ARTIGO_LEI")]}),
("No Código Penal, Art. 121 trata do homicídio", {"entities": [(14, 21, "ARTIGO_LEI")]}),
("A decisão foi baseada no Art. 102 da Constituição", {"entities": [(28, 34, "ARTIGO_LEI")]}),
("A cláusula do contrato está no Art. 15", {"entities": [(22, 29, "ARTIGO_LEI")]}),
]
- Adicionar a nova tag ao NER
ner = nlp.get_pipe("ner")
ner.add_label("ARTIGO_LEI")
- Iniciar o treinamento
optimizer = nlp.begin_training()
for epoch in range(30):
print(f"Epoch {epoch + 1}")
random.shuffle(train_data)
losses = {}
for text, annotations in train_data:
doc = nlp.make_doc(text)
example = Example.from_dict(doc, annotations)
nlp.update([example], drop=0.5, losses=losses)
print(losses)
- Testar o modelo
test_text = "O juiz citou o Art. 5º da Constituição Federal como base para sua decisão"
doc = nlp(test_text)
print("Entidades encontradas:")
for ent in doc.ents:
print(f"{ent.text} - {ent.label_}")
- Criar um modelo para reconhecer o CPF de uma pessoa
- Detecção de sentenças Sentence Boundary Detection (SBD)
import spacy
nlp = spacy.load("pt_core_news_sm")
# Texto de exemplo
texto = """
SpaCy é uma excelente biblioteca de processamento de linguagem natural. Ela é rápida, precisa e muito utilizada na indústria.
Muitas pessoas usam o spaCy para tarefas como tokenização, lematização, e, claro, detecção de limites de sentenças.
O spaCy também possui suporte para múltiplos idiomas, tornando-o ideal para projetos globais.
"""
doc = nlp(texto)
print("Sentenças detectadas:")
for sent in doc.sents:
print(f"- {sent.text}")
- Análise de similaridade
- Carregar o modelo de similaridade maior com
!python -m spacy download en_core_web_lg
- Para português
!python -m spacy download pt_core_news_lg
- Carregar o modelo de similaridade maior com
import spacy
nlp = spacy.load("en_core_web_lg")
frase1 = "I love programming in Python"
frase2 = "Python is my favorite programming language"
doc1 = nlp(frase1)
doc2 = nlp(frase2)
similaridade = doc1.similarity(doc2)
print(f"A similaridade entre as duas frases é: {similaridade:.2f}")