implement brain api service & implement chatui with gradio & refactor brain class for api and manage.sh

This commit is contained in:
ALIHAN DIKEL
2023-05-18 23:34:55 +03:00
parent c3c05f784e
commit 02924614ad
9 changed files with 266 additions and 90 deletions

1
.gitignore vendored
View File

@@ -6,3 +6,4 @@ logs/
.ipynb_checkpoints
packages
*.ipynb
.idea

View File

@@ -1,11 +1,13 @@
# Preparations before Flight
## Hardware setup
* turn uadis hotpot on
* plugin xiaomi repeater "_plus" to powers source
* connect rpi to power source
* wait for boot and ams vpn connection
* until connected devices @uadis increment +1 with device name "uad"
* manual setup:
### manual cli-rpi setup:
* ssh into
* cd tello-commander
* source venv/bin/activate
@@ -16,3 +18,5 @@
* until repeater lights blue without blinking
* ./manage.sh get-dhcp
* ./manage start-talikng
### auto chatui-rpi setup:

View File

@@ -1,7 +1,10 @@
import ast
import json
import os
from commander.commands import CommandHandler
from loguru import logger
from commander.commands import CommandHandler
class BaseBrain:
@@ -20,13 +23,48 @@ class BaseBrain:
with open(prompt_filepath, "r") as f:
return f.read()
def _is_valid_json(self, answer):
try:
response_json = json.loads(answer)
return True
except ValueError as e:
logger.error(f"chatgpt failed to return json obj: {answer}")
return False
def _gc(self):
self.cmd_prompt = None
self.response = None
def is_emergency(self, input):
if input == "q":
print("##### BASE BRAIN: EMERGENCY STOP DETECTED!!! #####")
msg = "##### BASE BRAIN: EMERGENCY STOP DETECTED!!! #####"
logger.warning(msg)
self.response_to_chatui = msg
self.command_handler.handle({"command": "emergency"})
return True
else:
return False
def listen(self):
def listen(self, channel="cli", prompt=None):
if channel == "cli":
self.cmd_prompt = input("\n\nwhat should I do now?\n(enter q for emergency)\n\t")
elif channel == "api":
self.cmd_prompt = prompt
def command(self):
if self._is_valid_json(self.answer):
command = ast.literal_eval(self.answer)
if command == {}:
msg = f"I failed to understand: {command}"
logger.warning(msg)
self.response_to_chatui = msg
else:
msg = f"I will send this command: {command}"
logger.success(msg)
self.response_to_chatui = msg
self.command_handler.handle(command)
else:
msg = f"\tI will skip this:\n {self.answer}"
logger.warning(msg)
self.response_to_chatui = msg
self._gc()

View File

@@ -1,10 +1,9 @@
import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import json
import ast
import openai
from loguru import logger
from brain_base import BaseBrain
from settings.config import settings
@@ -13,48 +12,25 @@ from settings.config import settings
class CloudSTTBrain:
def __init__(self):
print("not implemented")
logger.error("not implemented")
class CloudChatBrain(BaseBrain):
def __init__(self):
super().__init__()
openai.api_key = settings.OPENAI_API_KEY
def _is_valid_json(self, answer):
try:
response_json = json.loads(answer)
return True
except ValueError as e:
print(f"chatgpt failed to return json obj: {answer}")
return False
def _gc(self):
self.cmd_prompt = None
self.response = None
def understand(self):
## BURADA TRY:EXCEPT BLOCKU GEREKİR
self.response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
temperature=0.2,
temperature=0.3,
messages=[
{"role": "system", "content": self.sys_prompt},
{"role": "user", "content": self.cmd_prompt}
])
def command(self):
answer = self.response.choices[0].message.content
if self._is_valid_json(answer):
command = ast.literal_eval(answer)
if command == {}:
print(f"I failed to understand: {command}")
else:
print(f"I will send this command: {command}")
self.command_handler.handle(command)
else:
print(f"\tI will skip this:\n {command}")
self._gc()
self.answer = self.response.choices[0].message.content

View File

@@ -5,7 +5,7 @@ brain = CloudChatBrain()
while True:
try:
brain.listen()
brain.listen(channel="cli")
if not brain.is_emergency(brain.cmd_prompt):
brain.understand()
brain.command()

View File

@@ -3,31 +3,31 @@ import random
import gradio as gr
from loguru import logger
from brain.brain_openai import CloudChatBrain
def make_completion(history):
return "ok"
def answer(input, history):
history.append({"role": "user", "content": input})
response = random.choice(["How are you?", "I love you", "I'm very hungry"])
history.append({"role": "assistant", "content": response})
def brain_commander(prompt, history):
brain.listen(channel="api", prompt=prompt)
brain.understand()
history.append({"role": "user", "content": prompt})
history.append({"role": "assistant", "content": brain.answer})
messages = [(history[i]["content"], history[i+1]["content"]) for i in range(0, len(history)-1, 2)]
logger.debug(history)
brain.command()
return messages, history
brain = CloudChatBrain()
with gr.Blocks() as demo:
chatbot = gr.Chatbot(label="Fly my drone with chatGPT as copilot")
chatbot_ui = gr.Chatbot(label="drone flight with chatgpt as copilot")
state = gr.State([])
with gr.Row():
prompt = gr.Textbox(
show_label=True,
label="what should I do now?\n(enter q for emergency)",
placeholder="Enter text and press enter")\
label="what should I do now? (enter q for emergency)",
placeholder="Enter flight command and press enter")\
.style(container=True)
prompt.submit(answer, [prompt, state], [chatbot, state])
prompt.submit(brain_commander, [prompt, state], [chatbot_ui, state])
demo.launch(server_name="0.0.0.0", server_port=8890, debug=True)

View File

@@ -5,11 +5,11 @@
######################
## SCRIPT INIT
######################
DRONE_INTERFACE=$(yq '.commander.drone_interface' < settings/admin.yml)
DRONE_WPA_SUPP_CONF=$(yq '.commander.drone_wpa_supp' < settings/admin.yml)
NET_INTERFACE=$(yq '.commander.net_interface' < settings/admin.yml)
NET_WPA_SUPP_CONF=$(yq '.commander.net_wpa_supp' < settings/admin.yml)
#ENV_FOR_DYNACONF=$(yq '.commander.env_for_dynaconf' < settings/admin.yml)
DRONE_INTERFACE=$(yq '.drone_interface' < settings/admin.yml)
DRONE_WPA_SUPP_CONF=$(yq '.drone_wpa_supp' < settings/admin.yml)
NET_INTERFACE=$(yq '.net_interface' < settings/admin.yml)
NET_WPA_SUPP_CONF=$(yq '.net_wpa_supp' < settings/admin.yml)
#ENV_FOR_DYNACONF=$(yq '.env_for_dynaconf' < settings/admin.yml)
pids_dir='./pids'
if [[ ! -d "$pids_dir" ]]; then
@@ -34,13 +34,6 @@ connect_using_wpa_supp() {
sudo wpa_supplicant -D nl80211 -i $DRONE_INTERFACE -c network/$DRONE_WPA_SUPP_CONF
}
#wait_for_drone() {
#while ! ping -c1 192.168.10.1 &>/dev/null; do
# echo "Drone is offline. Waiting.."; sleep 2
#done
#echo "Drone is available, can ask for dhcp"; sleep 1
#}
get_dhcp_ip () {
while true;
do
@@ -70,11 +63,12 @@ start_commander_service() {
}
start_brain_service() {
venv/bin/python brain/service.py $1
venv/bin/python -m gradio brain/service.py $1
}
talk_to_drone() {
ENV_FOR_DYNACONF=$1 python brain/cli.py
talk_to_drone_via_cli() {
commander_host=$1
ENV_FOR_DYNACONF=$commander_host python brain/cli.py
}
kill_everything() {
@@ -172,11 +166,25 @@ elif [ "$1" == "start-commander" ]; then
elif [ "$1" == "stop-commander" ]; then
commander_pid_file="$pids_dir/commander_pid.txt"
if [ -f "$commander_pid_file" ]; then
sudo killport 8889
sudo pkill -15 -P $(cat $commander_pid_file)
sudo killport 8889
echo "stopped commander"
fi
elif [ "$1" == "start-brain" ]; then
start_brain_service $2 > logs/brain.log 2>&1 &
brain_pid=$!
echo "started brain service with PID brain_pid"
echo brain_pid > $pids_dir/brain_pid.txt
elif [ "$1" == "stop-brain" ]; then
brain_pid_file="$pids_dir/brain_pid.txt"
if [ -f "brain_pid_file" ]; then
sudo pkill -15 -P $(cat brain_pid_file)
sudo killport 8890
echo "stopped brain service"
fi
elif [ "$1" == "prepare-flight" ]; then
./manage.sh connect-drone
./manage.sh get-dhcp
@@ -189,8 +197,8 @@ elif [ "$1" == "finish-flight" ]; then
./manage.sh stop-commander
kill_everything
echo "flight finished"
elif [ "$1" == "start-talking" ]; then
talk_to_drone $2
elif [ "$1" == "start-clitalk" ]; then
talk_to_drone_via_cli $2
######################
## INFO
@@ -201,10 +209,11 @@ else
- list-wifis
- connect-/ disconnect-drone
- get-/ kill-dhcp
- start-/ stop-jupyter
- start-/ stop-cs
- start-/ stop-commander [port]
- start-talking tuncel / commander
- start-/ stop-jupyter (8888)
- start-/ stop-cs (8888)
- start-/ stop-commander [port (8889)]
- start-/ stop-brain [port (8890)]
- start-clitalk [host (tuncel/commander)]
- turn-off
- prepare-/ finish-flight"
fi

View File

@@ -0,0 +1,149 @@
aiofiles==22.1.0
aiohttp==3.8.4
aiosignal==1.3.1
aiosqlite==0.19.0
altair==5.0.0
anyio==3.6.2
argon2-cffi==21.3.0
argon2-cffi-bindings==21.2.0
arrow==1.2.3
asttokens==2.2.1
async-timeout==4.0.2
attrs==23.1.0
Babel==2.12.1
backcall==0.2.0
backoff==2.2.1
beautifulsoup4==4.12.2
bleach==6.0.0
certifi==2023.5.7
cffi==1.15.1
charset-normalizer==3.1.0
click==8.1.3
comm==0.1.3
contourpy==1.0.7
cycler==0.11.0
debugpy==1.6.7
decorator==5.1.1
defusedxml==0.7.1
djitellopy==2.4.0
dynaconf==3.1.12
executing==1.2.0
fastapi==0.95.1
fastjsonschema==2.16.3
ffmpy==0.3.0
filelock==3.12.0
fonttools==4.39.4
fqdn==1.5.1
frozenlist==1.3.3
fsspec==2023.5.0
gradio==3.31.0
gradio_client==0.2.5
h11==0.14.0
httpcore==0.17.1
httptools==0.5.0
httpx==0.24.0
huggingface-hub==0.14.1
idna==3.4
ipykernel==6.23.0
ipython==8.13.2
ipython-genutils==0.2.0
isoduration==20.11.0
jedi==0.18.2
Jinja2==3.1.2
json5==0.9.11
jsonpointer==2.3
jsonschema==4.17.3
jupyter-events==0.6.3
jupyter-ydoc==0.2.4
jupyter_client==8.2.0
jupyter_core==5.3.0
jupyter_server==2.5.0
jupyter_server_fileid==0.9.0
jupyter_server_terminals==0.4.4
jupyter_server_ydoc==0.8.0
jupyterlab==3.6.3
jupyterlab-pygments==0.2.2
jupyterlab_server==2.22.1
kiwisolver==1.4.4
linkify-it-py==2.0.2
loguru==0.7.0
markdown-it-py==2.2.0
MarkupSafe==2.1.2
matplotlib==3.7.1
matplotlib-inline==0.1.6
mdit-py-plugins==0.3.3
mdurl==0.1.2
mistune==2.0.5
multidict==6.0.4
nbclassic==1.0.0
nbclient==0.7.4
nbconvert==7.4.0
nbformat==5.8.0
nest-asyncio==1.5.6
notebook==6.5.4
notebook_shim==0.2.3
numpy==1.24.3
openai==0.27.6
opencv-python==4.7.0.72
orjson==3.8.12
packaging==23.1
pandas==2.0.1
pandocfilters==1.5.0
parso==0.8.3
pexpect==4.8.0
pickleshare==0.7.5
Pillow==9.5.0
platformdirs==3.5.0
prometheus-client==0.16.0
prompt-toolkit==3.0.38
psutil==5.9.5
ptyprocess==0.7.0
pure-eval==0.2.2
pycparser==2.21
pydantic==1.10.7
pydub==0.25.1
Pygments==2.15.1
pyparsing==3.0.9
pyrsistent==0.19.3
python-dateutil==2.8.2
python-dotenv==1.0.0
python-json-logger==2.0.7
python-multipart==0.0.6
pytz==2023.3
PyYAML==6.0
pyzmq==25.0.2
regex==2023.5.5
requests==2.30.0
rfc3339-validator==0.1.4
rfc3986-validator==0.1.1
semantic-version==2.10.0
Send2Trash==1.8.2
six==1.16.0
sniffio==1.3.0
soupsieve==2.4.1
stack-data==0.6.2
starlette==0.26.1
terminado==0.17.1
tiktoken==0.3.3
tinycss2==1.2.1
tomli==2.0.1
toolz==0.12.0
tornado==6.3.1
tqdm==4.65.0
traitlets==5.9.0
typing_extensions==4.5.0
tzdata==2023.3
uc-micro-py==1.0.2
uri-template==1.2.0
urllib3==2.0.2
uvicorn==0.22.0
uvloop==0.17.0
watchfiles==0.19.0
wcwidth==0.2.6
webcolors==1.13
webencodings==0.5.1
websocket-client==1.5.1
websockets==11.0.3
y-py==0.5.9
yarl==1.9.2
ypy-websocket==0.8.2

View File

@@ -1,9 +1,8 @@
commander:
drone_interface:
drone_interface:
wlan1
net_interface:
net_interface:
wlan0
drone_wpa_supp:
drone_wpa_supp:
wpa_supp_djituad0_plus.conf
net_wpa_supp:
net_wpa_supp:
wpa_supp_uadis.conf