Skip to content

Commit

Permalink
[Plugin] AHDA LITE - Actually helpful digital assistant - control PC …
Browse files Browse the repository at this point in the history
…with OMI (#1116)

See https://github.com/ActuallyAdvanced/OMI-AHDA

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Introduced two new plugins: "Gen Z/A Translator" for translating
sentences into Gen Z or Gen Alpha slang.
- Added the "AHDA" plugin for voice control of your PC, enhancing user
accessibility.

- **Documentation**
	- Updated README with a new section for AHDA setup instructions.

- **Chores**
- Implemented webhooks and configuration endpoints for AHDA integration.
	- Added utility functions for managing AHDA-related configurations.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
kodjima33 authored Oct 21, 2024
2 parents ad83562 + 6ae78e0 commit 0f08334
Show file tree
Hide file tree
Showing 6 changed files with 326 additions and 1 deletion.
29 changes: 28 additions & 1 deletion community-plugins.json
Original file line number Diff line number Diff line change
Expand Up @@ -653,7 +653,34 @@
"capabilities": [
"memories"
],
"memory_prompt": "Please transform the following sentence into Gen Z/Gen Alpha slang, incorporating as many of the following terms as possible (and more): *bet, fax, W, vibe, bussin', rizz, lit, drip, mid, cap, salty, slay, extra, flex, yeet, mood, glow up, big L, bop, Gucci, period, sus, sheesh, lowkey, snack, snatched, stan, thirsty, tea, ghost, cringe, delulu, fire, basic, GOAT, ick, peep, sleeper, low-vibrational, it's giving,* and *vibin'*, cooked. The goal is to maintain the original meaning of the sentence but make it sound as if it's being spoken by a Gen Z or Gen Alpha person. Feel free to get creative with the slang, keeping it short and casual, while giving the sentence that trendy, social-media-ready vibe. Also, ensure the use of terms fits contextually and naturally into the sentence. Only respond with the translated sentance.",
"memory_prompt": "Please transform the following sentence into Gen Z/Gen Alpha slang, incorporating as many of the following terms as possible (and more): *bet, fax, W, vibe, bussin', rizz, lit, drip, mid, cap, salty, slay, extra, flex, yeet, mood, glow up, big L, bop, Gucci, period, sus, sheesh, lowkey, snack, snatched, stan, thirsty, tea, ghost, cringe, delulu, fire, basic, GOAT, ick, peep, sleeper, low-vibrational, it's giving,* and *vibin'*, cooked. The goal is to maintain the original meaning of the sentence but make it sound as if it's being spoken by a Gen Z or Gen Alpha person. Feel free to get creative with the slang, keeping it short and casual, while giving the sentence that trendy, social-media-ready vibe. Also, ensure the use of terms fits contextually and naturally into the sentence.",
"deleted": false
},
{
"id": "ahda",
"name": "AHDA",
"author": "Neo",
"description": "Control your PC with your voice",
"image": "/plugins/logos/AHDA.png",
"capabilities": [
"external_integration"
],
"external_integration": {
"triggers_on": "transcript_processed",
"webhook_url": "https://based-hardware--plugins-api.modal.run/ahda/send-webhook",
"setup_completed_url": null,
"setup_instructions_file_path": "/plugins/instructions/ahda/README.md",
"auth_steps": [
{
"name": "Set up and install AHDA on your PC",
"url": "https://github.com/ActuallyAdvanced/OMI-AHDA/blob/main/README.md"
},
{
"name": "Enter URL into OMI",
"url": "https://based-hardware--plugins-api.modal.run/ahda/index"
}
]
},
"deleted": false
}
]
143 changes: 143 additions & 0 deletions plugins/example/ahda/client.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
from fastapi import APIRouter, Request, HTTPException, Form, Query, BackgroundTasks, Body
from fastapi.responses import HTMLResponse, FileResponse, JSONResponse
from db import get_ahda_url, store_ahda, get_ahda_os
import os
import requests
from models import RealtimePluginRequest, EndpointResponse
import time
import asyncio
import logging
from langchain_openai import ChatOpenAI

router = APIRouter()

active_sessions = {}

KEYWORD = "computer"
COMMAND_TIMEOUT = 5 # Seconds to wait after the last word to finalize the command

# Path to the directory containing `index.html`
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
INDEX_PATH = os.path.join(BASE_DIR, "index.html")

chat = ChatOpenAI(model='gpt-4o', temperature=0)

# Use requests to get raw text from URL
prompt = requests.get("https://raw.githubusercontent.com/ActuallyAdvanced/OMI-AHDA/main/prompt.txt").text

# Configure logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# AHDA Utils
def sendToPC(uid, response):
ahda_url = get_ahda_url(uid)
if not ahda_url:
raise ValueError('AHDA URL not configured for this UID')
payload = {
'uid': uid,
'response': response
}
try:
resp = requests.post(ahda_url+"/recieve", json=payload)
resp.raise_for_status()
except requests.RequestException as e:
logger.error(f"Error sending webhook: {e}")
raise
return {'message': 'Webhook sent successfully'}


@router.post('/ahda/send-webhook', tags=['ahda', 'realtime'])
async def send_ahda_webhook(
uid: str = Query(...),
data: dict = Body(...),
background_tasks: BackgroundTasks = BackgroundTasks()
):
segments = data.get("segments")
if not uid:
raise HTTPException(status_code=400, detail="UID is required")

if not segments or not isinstance(segments, list):
raise HTTPException(status_code=400, detail="Invalid payload")

if uid not in active_sessions:
logger.info(f"New session started: {uid}")
active_sessions[uid] = {
"command": "",
"last_received_time": time.time(),
"active": False,
"timer": None
}

async def schedule_finalize_command(uid, delay):
await asyncio.sleep(delay)
await finalize_command(uid)

async def finalize_command(uid):
final_command = active_sessions[uid]["command"].strip()
if final_command:
logger.info(f"Final command for session {uid}: {final_command}")
await call_chatgpt_to_generate_code(final_command, uid)
active_sessions[uid]["command"] = ""
active_sessions[uid]["active"] = False
active_sessions[uid]["timer"] = None

# Adjusted to handle segments as dictionaries
for segment in segments:
text = segment.get("text", "").strip().lower()
logger.info(f"Received segment: {text} (session_id: {uid})")

if KEYWORD in text:
logger.info("Activation keyword detected!")
active_sessions[uid]["active"] = True
active_sessions[uid]["last_received_time"] = time.time()

if active_sessions[uid]["timer"]:
pass

active_sessions[uid]["timer"] = background_tasks.add_task(
schedule_finalize_command, uid, COMMAND_TIMEOUT
)
continue

if active_sessions[uid]["active"]:
active_sessions[uid]["command"] += " " + text
active_sessions[uid]["last_received_time"] = time.time()
logger.info(f"Aggregating command: {active_sessions[uid]['command'].strip()}")

if active_sessions[uid]["timer"]:
pass

active_sessions[uid]["timer"] = background_tasks.add_task(
schedule_finalize_command, uid, COMMAND_TIMEOUT
)

return {"status": "success"}


async def call_chatgpt_to_generate_code(command, uid):
try:
ahda_os = get_ahda_os(uid)
messages = [
("system", prompt.replace("{os_name}",ahda_os)),
("human", command),
]
ai_msg = chat.invoke(messages)
sendToPC(uid, ai_msg)
except Exception as e:
logger.error(f"Error calling ChatGPT-4: {e}")
return {"type": "error", "content": str(e)}

@router.get('/ahda/index', response_class=HTMLResponse, tags=['ahda'])
async def get_ahda_index(request: Request, uid: str = Query(None)):
if not uid:
raise HTTPException(status_code=400, detail="UID is required")
return FileResponse(INDEX_PATH)

@router.post('/ahda/configure', tags=['ahda'])
def configure_ahda(uid: str = Form(...), url: str = Form(...), os: str = Form(...)):
if not uid or not url:
raise HTTPException(status_code=400, detail="Both UID, URL AND OS are required")

store_ahda(uid, url, os)
return {'message': 'AHDA configured successfully'}
138 changes: 138 additions & 0 deletions plugins/example/ahda/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AHDA Integration</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Assistant:[email protected]&display=swap" rel="stylesheet">
<style>
body {
font-family: Assistant, sans-serif;
background-color: #f4f4f4;
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}

.container {
background-color: #fff;
padding: 3rem;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
text-align: center;
max-width: 400px;
width: 100%;
}

h1 {
margin-bottom: 2rem;
}

.logo-container {
display: flex;
justify-content: center;
gap: 20px;
margin-bottom: 2rem;
}

.logo-container img {
width: 80px;
height: 80px;
object-fit: contain;
}

input[type="text"],
button {
width: 100%;
padding: 10px;
margin-bottom: 1rem;
border: 1px solid #ddd;
border-radius: 4px;
box-sizing: border-box;
}

button {
background-color: #000;
color: #fff;
border: none;
cursor: pointer;
font-size: 1rem;
}

button:hover {
background-color: #333;
}

p {
margin-top: 1rem;
}

.plugin-text {
font-size: 1.2rem;
font-weight: bold;
margin-bottom: 1rem;
}
</style>
</head>

<body>
<div class="container">
<div class="logo-container">
<img src="https://avatars.githubusercontent.com/u/162546372" alt="OMI Logo" />
<img src="https://avatars.githubusercontent.com/u/181646370" alt="AHDA Logo" />
</div>
<p class="plugin-text">AHDA Integration Plugin</p>
<h1>AHDA Integration</h1>
<h1>Install https://github.com/ActuallyAdvanced/OMI-AHDA first</h1>
<form id="ahda-form">
<input type="text" id="url" placeholder="Enter AHDA URL" required>
<input type="text" id="os" placeholder="Enter Operating System" required>
<button type="submit">Save Configuration</button>
</form>
<p id="response-message"></p>
</div>

<script>
// Extract the uid from the URL query parameters
const urlParams = new URLSearchParams(window.location.search);
const uid = urlParams.get('uid');

if (!uid) {
document.getElementById('response-message').textContent = "UID is missing. Please check the URL.";
document.getElementById('response-message').style.color = 'red';
}

document.getElementById('ahda-form').addEventListener('submit', async function (event) {
event.preventDefault();

const url = document.getElementById('url').value;
const os = document.getElementById('os').value;

const response = await fetch('/ahda/configure', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({ uid, url, os })
});

const result = await response.json();
const messageElement = document.getElementById('response-message');
if (response.ok) {
messageElement.textContent = result.message;
messageElement.style.color = 'green';
} else {
messageElement.textContent = result.detail || 'An error occurred. Please try again.';
messageElement.style.color = 'red';
}
});
</script>
</body>

</html>
16 changes: 16 additions & 0 deletions plugins/example/db.py
Original file line number Diff line number Diff line change
Expand Up @@ -132,3 +132,19 @@ def set_task_result(task_id: str, result: str):
def get_task_result(task_id: str) -> str:
result = r.get(f'task_result:{task_id}')
return result.decode('utf-8') if result else None

# **********************************************************
# ************ AHDA UTILS (PC Control) ************
# **********************************************************

def store_ahda(uid: str, url: str, os: str):
r.set(f'ahda_url:{uid}', url)
r.set(f'ahda_os:{uid}', os)

def get_ahda_url(uid: str) -> str:
val = r.get(f'ahda_url:{uid}')
return val.decode('utf-8') if val else None

def get_ahda_os(uid: str) -> str:
val = r.get(f'ahda_os:{uid}')
return val.decode('utf-8') if val else None
1 change: 1 addition & 0 deletions plugins/instructions/ahda/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
### [Setup Guide for AHDA](https://github.com/ActuallyAdvanced/OMI-AHDA/blob/main/README.md)
Binary file added plugins/logos/AHDA.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 0f08334

Please sign in to comment.