chore: import local project into Gitea
This commit is contained in:
30
.gitignore
vendored
Normal file
30
.gitignore
vendored
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
# OS / tooling
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
|
||||||
|
# Editors
|
||||||
|
.cursor/
|
||||||
|
|
||||||
|
# Secrets
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.example
|
||||||
|
!.env.template
|
||||||
|
|
||||||
|
# Python
|
||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
.venv/
|
||||||
|
venv/
|
||||||
|
|
||||||
|
# Node / frontend
|
||||||
|
node_modules/
|
||||||
|
dist/
|
||||||
|
|
||||||
|
# Typical embedded / tooling noise
|
||||||
|
*.log
|
||||||
|
|
||||||
|
# Builds (adjust per subtree if needed)
|
||||||
|
**/build/.ninja_deps
|
||||||
|
**/build/.ninja_log
|
||||||
|
|
||||||
18
.vscode/c_cpp_properties.json
vendored
Normal file
18
.vscode/c_cpp_properties.json
vendored
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "windows-gcc-x64",
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/**"
|
||||||
|
],
|
||||||
|
"compilerPath": "gcc",
|
||||||
|
"cStandard": "${default}",
|
||||||
|
"cppStandard": "${default}",
|
||||||
|
"intelliSenseMode": "windows-gcc-x64",
|
||||||
|
"compilerArgs": [
|
||||||
|
""
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
||||||
24
.vscode/launch.json
vendored
Normal file
24
.vscode/launch.json
vendored
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "C/C++ Runner: Debug Session",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"args": [],
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"externalConsole": true,
|
||||||
|
"cwd": "f:/dev_shit/p4 pannel",
|
||||||
|
"program": "f:/dev_shit/p4 pannel/build/Debug/outDebug",
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"miDebuggerPath": "gdb",
|
||||||
|
"setupCommands": [
|
||||||
|
{
|
||||||
|
"description": "Enable pretty-printing for gdb",
|
||||||
|
"text": "-enable-pretty-printing",
|
||||||
|
"ignoreFailures": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
59
.vscode/settings.json
vendored
Normal file
59
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
{
|
||||||
|
"C_Cpp_Runner.cCompilerPath": "gcc",
|
||||||
|
"C_Cpp_Runner.cppCompilerPath": "g++",
|
||||||
|
"C_Cpp_Runner.debuggerPath": "gdb",
|
||||||
|
"C_Cpp_Runner.cStandard": "",
|
||||||
|
"C_Cpp_Runner.cppStandard": "",
|
||||||
|
"C_Cpp_Runner.msvcBatchPath": "C:/Program Files/Microsoft Visual Studio/VR_NR/Community/VC/Auxiliary/Build/vcvarsall.bat",
|
||||||
|
"C_Cpp_Runner.useMsvc": false,
|
||||||
|
"C_Cpp_Runner.warnings": [
|
||||||
|
"-Wall",
|
||||||
|
"-Wextra",
|
||||||
|
"-Wpedantic",
|
||||||
|
"-Wshadow",
|
||||||
|
"-Wformat=2",
|
||||||
|
"-Wcast-align",
|
||||||
|
"-Wconversion",
|
||||||
|
"-Wsign-conversion",
|
||||||
|
"-Wnull-dereference"
|
||||||
|
],
|
||||||
|
"C_Cpp_Runner.msvcWarnings": [
|
||||||
|
"/W4",
|
||||||
|
"/permissive-",
|
||||||
|
"/w14242",
|
||||||
|
"/w14287",
|
||||||
|
"/w14296",
|
||||||
|
"/w14311",
|
||||||
|
"/w14826",
|
||||||
|
"/w44062",
|
||||||
|
"/w44242",
|
||||||
|
"/w14905",
|
||||||
|
"/w14906",
|
||||||
|
"/w14263",
|
||||||
|
"/w44265",
|
||||||
|
"/w14928"
|
||||||
|
],
|
||||||
|
"C_Cpp_Runner.enableWarnings": true,
|
||||||
|
"C_Cpp_Runner.warningsAsError": false,
|
||||||
|
"C_Cpp_Runner.compilerArgs": [],
|
||||||
|
"C_Cpp_Runner.linkerArgs": [],
|
||||||
|
"C_Cpp_Runner.includePaths": [],
|
||||||
|
"C_Cpp_Runner.includeSearch": [
|
||||||
|
"*",
|
||||||
|
"**/*"
|
||||||
|
],
|
||||||
|
"C_Cpp_Runner.excludeSearch": [
|
||||||
|
"**/build",
|
||||||
|
"**/build/**",
|
||||||
|
"**/.*",
|
||||||
|
"**/.*/**",
|
||||||
|
"**/.vscode",
|
||||||
|
"**/.vscode/**"
|
||||||
|
],
|
||||||
|
"C_Cpp_Runner.useAddressSanitizer": false,
|
||||||
|
"C_Cpp_Runner.useUndefinedSanitizer": false,
|
||||||
|
"C_Cpp_Runner.useLeakSanitizer": false,
|
||||||
|
"C_Cpp_Runner.showCompilationTime": false,
|
||||||
|
"C_Cpp_Runner.useLinkTimeOptimization": false,
|
||||||
|
"C_Cpp_Runner.msvcSecureNoWarnings": false
|
||||||
|
}
|
||||||
13
README.md
Normal file
13
README.md
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# P4 voice panel
|
||||||
|
|
||||||
|
Bundles **`voice_assistant/`** firmware plus `.vscode`/`.cursor` configs and **`example.code`**.
|
||||||
|
|
||||||
|
Treat this as companion UI work to **`p4 chatbot 83125/`** unless you refactor modules.
|
||||||
|
|
||||||
|
Recommended flow:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd voice_assistant
|
||||||
|
```
|
||||||
|
|
||||||
|
Follow manifests inside (`CMakeLists.txt`, `sdkconfig.defaults`, Arduino project files, etc.—whichever framework that folder uses). Keep generated `build/` / `.pio/` directories excluded from commits.
|
||||||
128
example.code
Normal file
128
example.code
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
#include <WiFi.h>
|
||||||
|
#include <HTTPClient.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <Adafruit_GFX.h>
|
||||||
|
#include <Adafruit_SSD1306.h>
|
||||||
|
|
||||||
|
// OLED config
|
||||||
|
#define SCREEN_WIDTH 128
|
||||||
|
#define SCREEN_HEIGHT 64
|
||||||
|
#define OLED_RESET -1
|
||||||
|
#define I2C_SDA 21
|
||||||
|
#define I2C_SCL 22
|
||||||
|
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
|
||||||
|
|
||||||
|
// WiFi
|
||||||
|
const char* ssid = "your wifi id";
|
||||||
|
const char* password = "your wifi password";
|
||||||
|
const String gemini_api_key = "your api key";
|
||||||
|
|
||||||
|
// MAX9814 microphone input pin
|
||||||
|
#define MIC_PIN 34
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
Wire.begin(I2C_SDA, I2C_SCL);
|
||||||
|
if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) {
|
||||||
|
Serial.println("OLED init failed!");
|
||||||
|
while (1);
|
||||||
|
}
|
||||||
|
|
||||||
|
displayMessage("Connecting WiFi...");
|
||||||
|
WiFi.begin(ssid, password);
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
delay(500);
|
||||||
|
Serial.print(".");
|
||||||
|
}
|
||||||
|
|
||||||
|
displayMessage("WiFi connected!");
|
||||||
|
pinMode(MIC_PIN, INPUT);
|
||||||
|
delay(500);
|
||||||
|
displayMessage("Ready! Speak loud...");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
static unsigned long lastTrigger = 0;
|
||||||
|
|
||||||
|
int micValue = analogRead(MIC_PIN);
|
||||||
|
Serial.println(micValue);
|
||||||
|
|
||||||
|
if (micValue > 1500 && millis() - lastTrigger > 5000) {
|
||||||
|
lastTrigger = millis();
|
||||||
|
|
||||||
|
displayMessage("Detecting...");
|
||||||
|
|
||||||
|
String response = askGemini("who are you.");
|
||||||
|
displayMultilineText(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayMessage(String msg) {
|
||||||
|
display.clearDisplay();
|
||||||
|
display.setTextSize(1);
|
||||||
|
display.setTextColor(SSD1306_WHITE);
|
||||||
|
display.setCursor(0, 0);
|
||||||
|
display.println(msg);
|
||||||
|
display.display();
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayMultilineText(String text) {
|
||||||
|
display.clearDisplay();
|
||||||
|
display.setTextSize(1);
|
||||||
|
display.setTextColor(SSD1306_WHITE);
|
||||||
|
display.setCursor(0, 0);
|
||||||
|
|
||||||
|
int maxCharsPerLine = 21;
|
||||||
|
int lineHeight = 10;
|
||||||
|
int y = 0;
|
||||||
|
|
||||||
|
while (text.length() > 0 && y < SCREEN_HEIGHT) {
|
||||||
|
String line = text.substring(0, maxCharsPerLine);
|
||||||
|
text = text.substring(min((unsigned int)maxCharsPerLine, text.length()));
|
||||||
|
display.setCursor(0, y);
|
||||||
|
display.println(line);
|
||||||
|
y += lineHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
display.display();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Gemini API call
|
||||||
|
String askGemini(String prompt) {
|
||||||
|
HTTPClient http;
|
||||||
|
String endpoint = "https://generativelanguage.googleapis.com/v1/models/gemini-1.5-flash-002:generateContent?key=" + gemini_api_key;
|
||||||
|
http.begin(endpoint);
|
||||||
|
http.addHeader("Content-Type", "application/json");
|
||||||
|
|
||||||
|
prompt.replace("\"", "\\\"");
|
||||||
|
|
||||||
|
String requestBody = "{ \"contents\": [ { \"parts\": [ { \"text\": \"" + prompt + "\" } ] } ] }";
|
||||||
|
int code = http.POST(requestBody);
|
||||||
|
String reply = "";
|
||||||
|
|
||||||
|
if (code == 200) {
|
||||||
|
String payload = http.getString();
|
||||||
|
StaticJsonDocument<2048> doc;
|
||||||
|
DeserializationError error = deserializeJson(doc, payload);
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
reply = doc["candidates"][0]["content"]["parts"][0]["text"].as<String>();
|
||||||
|
reply.replace("\\n", "\n");
|
||||||
|
} else {
|
||||||
|
Serial.println("JSON Error: " + String(error.c_str()));
|
||||||
|
reply = "I am Gemini, your AI assistant.";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Serial.println("Gemini API error: " + String(code));
|
||||||
|
// Fallback reply when API fails
|
||||||
|
reply = "I am Gemini, your AI assistant.";
|
||||||
|
}
|
||||||
|
|
||||||
|
http.end();
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
148
voice_assistant/voice_assistant.ino
Normal file
148
voice_assistant/voice_assistant.ino
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
// Include necessary libraries
|
||||||
|
#include <WiFi.h>
|
||||||
|
#include <HTTPClient.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <Adafruit_GFX.h>
|
||||||
|
#include <Adafruit_ILI9341.h>
|
||||||
|
|
||||||
|
// WiFi credentials
|
||||||
|
const char* ssid = "thetempleofdoom";
|
||||||
|
const char* password = "myhandsonmyself";
|
||||||
|
|
||||||
|
// Gemini API key
|
||||||
|
const char* geminiApiKey = "AIzaSyAzFzg_MAcwoH3O-nfriBjlFw5x6UBU5hk";
|
||||||
|
|
||||||
|
// Pin for the button
|
||||||
|
// IMPORTANT: Please verify the pin number for your button and update the value below.
|
||||||
|
const int buttonPin = 0;
|
||||||
|
|
||||||
|
// Display pins
|
||||||
|
// IMPORTANT: Please verify the pin numbers for your display and update the values below.
|
||||||
|
#define TFT_CS 5
|
||||||
|
#define TFT_DC 4
|
||||||
|
#define TFT_RST -1 // Reset pin (often not needed)
|
||||||
|
|
||||||
|
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// Initialize serial communication
|
||||||
|
Serial.begin(115200);
|
||||||
|
|
||||||
|
// Initialize the button pin
|
||||||
|
pinMode(buttonPin, INPUT_PULLUP);
|
||||||
|
|
||||||
|
// Connect to WiFi
|
||||||
|
WiFi.begin(ssid, password);
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
delay(1000);
|
||||||
|
Serial.println("Connecting to WiFi...");
|
||||||
|
}
|
||||||
|
Serial.println("Connected to WiFi");
|
||||||
|
Serial.print("IP Address: ");
|
||||||
|
Serial.println(WiFi.localIP());
|
||||||
|
|
||||||
|
// Initialize the display
|
||||||
|
tft.begin();
|
||||||
|
tft.setRotation(3);
|
||||||
|
tft.fillScreen(ILI9341_BLACK);
|
||||||
|
tft.setTextColor(ILI9341_GREEN);
|
||||||
|
tft.setTextSize(2);
|
||||||
|
tft.println("Hacker Voice Assistant");
|
||||||
|
tft.println("--------------------");
|
||||||
|
tft.setTextSize(1);
|
||||||
|
tft.print("IP: ");
|
||||||
|
tft.println(WiFi.localIP());
|
||||||
|
tft.setTextSize(2);
|
||||||
|
tft.println("\nReady for command...");
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// Check if the button is pressed
|
||||||
|
if (digitalRead(buttonPin) == LOW) {
|
||||||
|
// Start a voice session
|
||||||
|
startVoiceSession();
|
||||||
|
// After the session, clear the screen and show the ready message again
|
||||||
|
tft.fillScreen(ILI9341_BLACK);
|
||||||
|
tft.setCursor(0,0);
|
||||||
|
tft.setTextSize(2);
|
||||||
|
tft.println("Hacker Voice Assistant");
|
||||||
|
tft.println("--------------------");
|
||||||
|
tft.setTextSize(1);
|
||||||
|
tft.print("IP: ");
|
||||||
|
tft.println(WiFi.localIP());
|
||||||
|
tft.setTextSize(2);
|
||||||
|
tft.println("\nReady for command...");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void startVoiceSession() {
|
||||||
|
// Clear the screen for the new session
|
||||||
|
tft.fillScreen(ILI9341_BLACK);
|
||||||
|
tft.setCursor(0,0);
|
||||||
|
tft.setTextSize(2);
|
||||||
|
|
||||||
|
// TODO: Add voice recording and processing code here
|
||||||
|
Serial.println("Button pressed, starting voice session...");
|
||||||
|
displayHackerText("Listening...");
|
||||||
|
|
||||||
|
// For now, we'll just send a test query to Gemini
|
||||||
|
delay(2000); // Simulate recording time
|
||||||
|
displayHackerText("Processing...");
|
||||||
|
String query = "Hello, Gemini!";
|
||||||
|
String response = sendToGemini(query);
|
||||||
|
|
||||||
|
// Display the response
|
||||||
|
displayHackerText("User: " + query);
|
||||||
|
displayHackerText("Gemini: " + response);
|
||||||
|
Serial.println("Gemini response: " + response);
|
||||||
|
}
|
||||||
|
|
||||||
|
String sendToGemini(String query) {
|
||||||
|
HTTPClient http;
|
||||||
|
String url = "https://generativelanguage.googleapis.com/v1beta/models/gemini-pro:generateContent?key=";
|
||||||
|
url += geminiApiKey;
|
||||||
|
|
||||||
|
http.begin(url);
|
||||||
|
http.addHeader("Content-Type", "application/json");
|
||||||
|
|
||||||
|
StaticJsonDocument<200> doc;
|
||||||
|
JsonObject content = doc.createNestedObject("contents");
|
||||||
|
JsonArray parts = content.createNestedArray("parts");
|
||||||
|
JsonObject part = parts.createNestedObject();
|
||||||
|
part["text"] = query;
|
||||||
|
|
||||||
|
String requestBody;
|
||||||
|
serializeJson(doc, requestBody);
|
||||||
|
|
||||||
|
int httpResponseCode = http.POST(requestBody);
|
||||||
|
|
||||||
|
if (httpResponseCode > 0) {
|
||||||
|
String payload = http.getString();
|
||||||
|
StaticJsonDocument<1024> responseDoc;
|
||||||
|
DeserializationError error = deserializeJson(responseDoc, payload);
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
Serial.print(F("deserializeJson() failed: "));
|
||||||
|
Serial.println(error.f_str());
|
||||||
|
return "Error: Failed to parse response.";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (responseDoc.containsKey("candidates")) {
|
||||||
|
const char* responseText = responseDoc["candidates"][0]["content"]["parts"][0]["text"];
|
||||||
|
return String(responseText);
|
||||||
|
} else {
|
||||||
|
return "Error: Invalid response from Gemini.";
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Serial.print("Error on sending POST: ");
|
||||||
|
Serial.println(httpResponseCode);
|
||||||
|
return "Error: Unable to get response from Gemini.";
|
||||||
|
}
|
||||||
|
|
||||||
|
http.end();
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayHackerText(String text) {
|
||||||
|
tft.println(text);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user