updating readme

This commit is contained in:
akdeb 2025-04-21 12:32:39 +01:00
parent f6b4b5a075
commit e85e210ad6
8 changed files with 54 additions and 41 deletions

View file

@ -6,7 +6,7 @@ Realtime AI Speech powered by OpenAI Realtime API, ESP32, Secure WebSockets, and
<div align="center">
[![Discord Follow](https://dcbadge.vercel.app/api/server/KJWxDPBRUj?style=flat)](https://discord.gg/KJWxDPBRUj)
[![License: GPLv3](https://img.shields.io/badge/license-MIT-blue)](https://www.gnu.org/licenses/gpl-3.0.en.html)&ensp;&ensp;&ensp;
[![License: MIT](https://img.shields.io/badge/license-MIT-blue)](https://www.gnu.org/licenses/gpl-3.0.en.html)&ensp;&ensp;&ensp;
![Node.js](https://img.shields.io/badge/Node.js-22.13.0-yellow.svg)
![Next.js](https://img.shields.io/badge/Next.js-14.2.7-brightgreen.svg)
![React](https://img.shields.io/badge/React-18.2.0-blue.svg)
@ -25,8 +25,9 @@ https://github.com/user-attachments/assets/aa60e54c-5847-4a68-80b5-5d6b1a5b9328
## Getting Started
1. Set up your Local Supabase Backend. From the root directory, run:
1. Install [Supabase CLI](https://supabase.com/docs/guides/local-development/cli/getting-started) and set up your Local Supabase Backend. From the root directory, run:
```bash
brew install supabase/tap/supabase
supabase start # Starts your local Supabase server with the default migrations and seed data.
```
@ -34,10 +35,18 @@ supabase start # Starts your local Supabase server with the default migrations a
```bash
cd frontend-nextjs
npm install
# Set your environment variables
cp .env.example .env.local
# NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321
# NEXT_PUBLIC_SUPABASE_ANON_KEY=<your_supabase_anon_key>
# OPENAI_API_KEY=<your_openai_api_key>
# Run the development server
npm run dev
```
3. Add your ESP32-S3 Device MAC Address to the Settings page in the NextJS Frontend. This links your device to your account.
3. Add your ESP32-S3 Device MAC Address to the [Settings page](http://localhost:3000/home/settings) in the NextJS Frontend. This links your device to your account.
To find your ESP32-S3 Device's MAC Address, build and upload `test/print_mac_address_test.cpp` using PlatformIO.
4. Add your OpenAI API Key in the `server-deno/.env` and `frontend-nextjs/.env.local` file.
@ -47,16 +56,27 @@ OPENAI_API_KEY=<your_openai_api_key>
5. Start the Deno server. ([See the Deno server README](server-deno/README.md))
```bash
# Navigate to the server directory
cd server-deno
# Set your environment variables
cp .env.example .env
# NEXT_PUBLIC_SUPABASE_URL=http://127.0.0.1:54321
# NEXT_PUBLIC_SUPABASE_ANON_KEY=<your_supabase_anon_key>
# OPENAI_API_KEY=<your_openai_api_key>
# Run the server at port 8000
deno run -A --env-file=.env main.ts
```
5. Set up your ESP32 Arduino Client. ([See the ESP32 README](firmware-arduino/README.md)) On PlatformIO, first `Build` the project, then `Upload` the project to your ESP32.
6. The ESP32 should open an AP `ELATO-DEVICE` to connect to Wifi. Connect to it and go to `http://192.168.4.1` to configure the device.
6. The ESP32 should open an AP `ELATO-DEVICE` to connect to Wifi. Connect to it and go to `http://192.168.4.1` to configure the device wifi.
7. Once your Wifi is configured, turn the device off and on again and it should connect to your Wifi and the Deno edge server.
8. Now you can talk to your AI Character!
## 📌 Project Architecture
ElatoAI consists of three main components:

View file

@ -36,7 +36,7 @@ This firmware turns your ESP32 device into a WebSocket audio client for Elato, e
1. Install Visual Studio Code and the PlatformIO extension
2. Clone this repository
3. Open the project folder in PlatformIO
3. Open the project folder in PlatformIO. `Open > Open Project > firmware-arduino`
4. Edit `src/Config.cpp` with your server details:
- If using locally: Set your computer's IP address in `ws_server` and `backend_server`
- If using production: Ensure proper certificates are set

View file

@ -27,11 +27,11 @@ bool factory_reset_status = false;
*/
#ifdef DEV_MODE
const char *ws_server = "10.2.1.187";
const char *ws_server = "10.2.1.136";
const uint16_t ws_port = 8000;
const char *ws_path = "/";
// Backend server details
const char *backend_server = "10.2.1.187";
const char *backend_server = "10.2.1.136";
const uint16_t backend_port = 3000;
#else

View file

@ -58,7 +58,7 @@ extern const uint16_t backend_port;
extern const uint32_t SAMPLE_RATE;
// ---------- Development ------------
// #define DEV_MODE
#define DEV_MODE
#define TOUCH_MODE
// ----------------- Pin Definitions -----------------

View file

@ -38,8 +38,7 @@ export default function Footer() {
</Button>
</a>
<Label className={`font-normal text-xs text-gray-500`}>
Elato AI © {new Date().getFullYear()} All rights
reserved.
Made with by Elato AI © {new Date().getFullYear()}
</Label>
</div>
{/* <Separator orientation="vertical" /> */}
@ -77,20 +76,6 @@ export default function Footer() {
</Button>
</Link>
</div>
<a
href="/privacy"
className={`font-normal underline text-gray-500 text-xs`}
>
Privacy Policy
</a>
<a
href="/terms"
className={`font-normal underline text-gray-500 text-xs`}
>
Terms of Service
</a>
</div>
{/* <ThemeSwitcher /> */}

View file

@ -97,7 +97,7 @@ export default async function LandingPage() {
<Image src="/logos/arduino.png" alt="Arduino" width={100} height={24} style={{ height: '36px', width: 'auto' }} />
</a>
<a href="https://espressif.com" target="_blank" rel="noopener noreferrer" className="transition-all">
<Image src="/logos/espressif.png" alt="Espressif ESP32" width={100} height={24} style={{ height: '24px', width: 'auto' }} />
<Image src="/logos/espressif.png" alt="Espressif ESP32" width={100} height={24} style={{ height: '36px', width: 'auto' }} />
</a>
<a href="https://platformio.org" target="_blank" rel="noopener noreferrer" className="transition-all">
<Image src="/logos/platformio.png" alt="PlatformIO" width={100} height={24} style={{ height: '36px', width: 'auto' }} />

View file

@ -1,7 +1,7 @@
# Supabase keys
SUPABASE_URL=<SUPABASE_URL>
SUPABASE_KEY=<SUPABASE_KEY>
JWT_SECRET=<JWT_SECRET>
JWT_SECRET=super-secret-jwt-token-with-at-least-32-characters-long
# Encryption Key (useful for encrypting secrets in the database)
ENCRYPTION_KEY=<ENCRYPTION_KEY>

View file

@ -1,25 +1,27 @@
import * as jose from 'https://deno.land/x/jose@v5.9.6/index.ts';
import { getUserByEmail } from './supabase.ts';
import { SupabaseClient } from '@supabase/supabase-js';
import crypto from 'node:crypto';
import { Buffer } from 'node:buffer';
import * as jose from "https://deno.land/x/jose@v5.9.6/index.ts";
import { getUserByEmail } from "./supabase.ts";
import { SupabaseClient } from "@supabase/supabase-js";
import crypto from "node:crypto";
import { Buffer } from "node:buffer";
export const authenticateUser = async (
supabaseClient: SupabaseClient,
authToken: string,
): Promise<IUser> => {
try {
const jwtSecret = Deno.env.get('JWT_SECRET');
const jwtSecret = Deno.env.get("JWT_SECRET");
console.log("jwtSecret", jwtSecret);
if (!jwtSecret) throw new Error('JWT_SECRET not configured');
if (!jwtSecret) throw new Error("JWT_SECRET not configured");
const secretBytes = new TextEncoder().encode(jwtSecret);
const payload = await jose.jwtVerify(authToken, secretBytes);
const { payload: { email } } = payload;
const user = await getUserByEmail(supabaseClient, email as string);
console.log("user", user);
return user;
} catch (error: any) {
throw new Error(error.message || 'Failed to authenticate user');
throw new Error(error.message || "Failed to authenticate user");
}
};
@ -30,20 +32,26 @@ export const authenticateUser = async (
* @param masterKey - 32-byte string or buffer
* @returns the original plaintext secret
*/
export function decryptSecret(encryptedData: string, iv: string, masterKey: string) {
export function decryptSecret(
encryptedData: string,
iv: string,
masterKey: string,
) {
// Decode the base64 master key
const decodedKey = Buffer.from(masterKey, 'base64');
const decodedKey = Buffer.from(masterKey, "base64");
if (decodedKey.length !== 32) {
throw new Error('ENCRYPTION_KEY must be 32 bytes when decoded from base64.');
throw new Error(
"ENCRYPTION_KEY must be 32 bytes when decoded from base64.",
);
}
const decipher = crypto.createDecipheriv(
'aes-256-cbc',
"aes-256-cbc",
decodedKey, // Use the decoded key instead of raw masterKey
Buffer.from(iv, 'base64'),
Buffer.from(iv, "base64"),
);
let decrypted = decipher.update(encryptedData, 'base64', 'utf8');
decrypted += decipher.final('utf8');
let decrypted = decipher.update(encryptedData, "base64", "utf8");
decrypted += decipher.final("utf8");
return decrypted;
}