From b2f00c41853c8d0f2800e231d782876b2024ea3d Mon Sep 17 00:00:00 2001 From: RCSnyder <44173311+RCSnyder@users.noreply.github.com> Date: Sun, 9 Apr 2023 11:45:33 -0500 Subject: [PATCH 01/13] remove pywin --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 974a49e..2457aeb 100644 --- a/requirements.txt +++ b/requirements.txt @@ -126,7 +126,7 @@ python-decouple==3.8 python-json-logger==2.0.7 pytz==2022.7.1 pytz-deprecation-shim==0.1.0.post0 -pywin32==305 +# pywin32==305 pywinpty==2.0.10 PyYAML==6.0 pyzmq==25.0.2 From bf0a409ac45534304ccf8c40aadce9d7674896f3 Mon Sep 17 00:00:00 2001 From: RohitPenna <107886871+RohitPenna@users.noreply.github.com> Date: Sun, 9 Apr 2023 12:55:54 -0500 Subject: [PATCH 02/13] Update requirements.txt --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 2457aeb..0e7e89f 100644 --- a/requirements.txt +++ b/requirements.txt @@ -127,7 +127,7 @@ python-json-logger==2.0.7 pytz==2022.7.1 pytz-deprecation-shim==0.1.0.post0 # pywin32==305 -pywinpty==2.0.10 +# pywinpty==2.0.10 PyYAML==6.0 pyzmq==25.0.2 requests==2.28.2 From 83ea136d2906ef5c373eb88ff5948a3ba0480c3d Mon Sep 17 00:00:00 2001 From: RCSnyder <44173311+RCSnyder@users.noreply.github.com> Date: Fri, 14 Apr 2023 20:36:05 -0500 Subject: [PATCH 03/13] add dockerfile and non ver req --- Dockerfile | 11 +++ requirements_stripped.txt | 180 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 191 insertions(+) create mode 100644 Dockerfile create mode 100644 requirements_stripped.txt diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..a0a1233 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,11 @@ +FROM python:3.9.16 +EXPOSE 8501 +WORKDIR /src +COPY requirements_stripped.txt ./requirements_stripped.txt +RUN pip3 install -r requirements_stripped.txt +COPY . . +CMD streamlit run app.py \ + --server.headless true \ + --browser.serverAddress="0.0.0.0" \ + --server.enableCORS false \ + --browser.gatherUsageStats false \ No newline at end of file diff --git a/requirements_stripped.txt b/requirements_stripped.txt new file mode 100644 index 0000000..54caf7d --- /dev/null +++ b/requirements_stripped.txt @@ -0,0 +1,180 @@ +absl-py +aiohttp +aioice +aiortc +aiosignal +altair +anyio +argon2-cffi +argon2-cffi-bindings +arrow +asttokens +astunparse +async-timeout +attrs +av +backcall +beautifulsoup4 +bleach +blinker +cachetools +certifi +cffi +charset-normalizer +click +colorama +comm +contourpy +cryptography +cycler +debugpy +decorator +deepface +defusedxml +dnspython +entrypoints +executing +fastjsonschema +filelock +fire +Flask +flatbuffers +fonttools +fqdn +frozenlist +gast +gdown +gitdb +GitPython +google-auth +google-auth-oauthlib +google-crc32c +google-pasta +grpcio +gunicorn +h5py +idna +importlib-metadata +ipykernel +ipython +ipython-genutils +isoduration +itsdangerous +jedi +Jinja2 +jsonpointer +jsonschema +jupyter-events +jupyter_client +jupyter_core +jupyter_server +jupyter_server_terminals +jupyterlab-pygments +keras +kiwisolver +libclang +Markdown +markdown-it-py +MarkupSafe +matplotlib +matplotlib-inline +mdurl +mistune +mtcnn +multidict +nbclassic +nbclient +nbconvert +nbformat +nest-asyncio +netifaces +notebook +notebook_shim +numpy +oauthlib +openai +opencv-python +opt-einsum +packaging +pandas +pandocfilters +parso +pickleshare +Pillow +platformdirs +prometheus-client +prompt-toolkit +protobuf +psrecord +psutil +pure-eval +pyarrow +pyasn1 +pyasn1-modules +pycparser +pydeck +pyee +Pygments +pylibsrtp +Pympler +pyOpenSSL +pyparsing +pyrsistent +PySocks +python-dateutil +python-decouple +python-json-logger +pytz +pytz-deprecation-shim +pywin32 +pywinpty +PyYAML +pyzmq +requests +requests-oauthlib +retina-face +rfc3339-validator +rfc3986-validator +rich +rsa +semver +Send2Trash +six +smmap +sniffio +soupsieve +stack-data +streamlit +streamlit-chat +streamlit-webrtc +tensorboard +tensorboard-data-server +tensorboard-plugin-wit +tensorflow +tensorflow-cpu +tensorflow-estimator +tensorflow-intel +tensorflow-io-gcs-filesystem +termcolor +terminado +tinycss2 +toml +toolz +tornado +tqdm +traitlets +typing_extensions +tzdata +tzlocal +uri-template +urllib3 +validators +watchdog +wcwidth +webcolors +webencodings +websocket-client +Werkzeug +wrapt +yarl +zipp From 5531d00e4c3648ea9e5c35bcccc559b85e6642c1 Mon Sep 17 00:00:00 2001 From: RCSnyder <44173311+RCSnyder@users.noreply.github.com> Date: Fri, 14 Apr 2023 22:48:19 -0500 Subject: [PATCH 04/13] add Dockerfile --- README.md | 20 ++++ requirements_3916_docker.txt | 202 +++++++++++++++++++++++++++++++++++ src/app.py | 2 + 3 files changed, 224 insertions(+) create mode 100644 requirements_3916_docker.txt diff --git a/README.md b/README.md index 4884c19..8f3ed26 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,8 @@ Interactive Chatbot with Real-Time Emotional Analysis/Integration ## Usage +Option 1: + - Clone this repository - Enter the commands: @@ -21,6 +23,24 @@ Interactive Chatbot with Real-Time Emotional Analysis/Integration - `cd src/` - `streamlit run app.py` +Option 2: + +- Download Docker Desktop +- `docker pull rcsnyder/streamlitapp:0.0.1` +- Enter into the app: `sudo docker run --rm -it -v /$(pwd)/src -p 8501:8501 --entrypoint bash rcsnyder/streamlitapp:0.0.1` +- Add a .env file to the top level directory with the following environment variables. + + ``` + OPENAI_API_KEY=xxxx + OPENAI_ORG_NAME=xxxxx + + ``` + +- Start it: `streamlit run app.py --server.headless true --browser.serverAddress="0.0.0.0" --server.enableCORS false --server.enableXsrfProtection=false --browser.gatherUsageStats false` +- Go to `localhost:8501` +- Choose camera device +- Click Start + ### User Stories - [ ] A user would like to be able to start up an app and talk to a chatbot that can percieve their emotions in real-time. diff --git a/requirements_3916_docker.txt b/requirements_3916_docker.txt new file mode 100644 index 0000000..0c82d1c --- /dev/null +++ b/requirements_3916_docker.txt @@ -0,0 +1,202 @@ +absl-py==1.4.0 +aiohttp==3.8.4 +aioice==0.9.0 +aiortc==1.5.0 +aiosignal==1.3.1 +altair==4.2.2 +altgraph==0.17.3 +anyio==3.6.2 +argon2-cffi==21.3.0 +argon2-cffi-bindings==21.2.0 +arrow==1.2.3 +asttokens==2.2.1 +astunparse==1.6.3 +async-timeout==4.0.2 +attrs==22.2.0 +av==10.0.0 +backcall==0.2.0 +beautifulsoup4==4.12.2 +bleach==6.0.0 +blinker==1.6.2 +build==0.10.0 +cachetools==5.3.0 +certifi==2022.12.7 +cffi==1.15.1 +charset-normalizer==3.1.0 +click==8.1.3 +colorama==0.4.6 +comm==0.1.3 +contourpy==1.0.7 +cryptography==40.0.2 +cycler==0.11.0 +debugpy==1.6.7 +decorator==5.1.1 +deepface==0.0.79 +defusedxml==0.7.1 +dnspython==2.3.0 +docutils==0.19 +entrypoints==0.4 +executing==1.2.0 +fastjsonschema==2.16.3 +filelock==3.11.0 +fire==0.5.0 +Flask==2.2.3 +flatbuffers==23.3.3 +fonttools==4.39.3 +fqdn==1.5.1 +frozenlist==1.3.3 +gast==0.4.0 +gdown==4.7.1 +gitdb==4.0.10 +GitPython==3.1.31 +google-auth==2.17.3 +google-auth-oauthlib==1.0.0 +google-crc32c==1.5.0 +google-pasta==0.2.0 +grpcio==1.53.0 +gunicorn==20.1.0 +h5py==3.8.0 +idna==3.4 +ifaddr==0.2.0 +importlib-metadata==6.3.0 +importlib-resources==5.12.0 +ipykernel==6.22.0 +ipython==8.12.0 +ipython-genutils==0.2.0 +isoduration==20.11.0 +itsdangerous==2.1.2 +jaraco.classes==3.2.3 +jax==0.4.8 +jedi==0.18.2 +jeepney==0.8.0 +Jinja2==3.1.2 +jsonpointer==2.3 +jsonschema==4.17.3 +jupyter-events==0.6.3 +jupyter_client==8.2.0 +jupyter_core==5.3.0 +jupyter_server==2.5.0 +jupyter_server_terminals==0.4.4 +jupyterlab-pygments==0.2.2 +keras==2.12.0 +keyring==23.13.1 +kiwisolver==1.4.4 +libclang==16.0.0 +Markdown==3.4.3 +markdown-it-py==2.2.0 +MarkupSafe==2.1.2 +matplotlib==3.7.1 +matplotlib-inline==0.1.6 +mdurl==0.1.2 +mistune==2.0.5 +ml-dtypes==0.1.0 +more-itertools==9.1.0 +mtcnn==0.1.1 +multidict==6.0.4 +nbclassic==0.5.5 +nbclient==0.7.3 +nbconvert==7.3.1 +nbformat==5.8.0 +nest-asyncio==1.5.6 +netifaces==0.11.0 +notebook==6.5.4 +notebook_shim==0.2.2 +numpy==1.23.5 +oauthlib==3.2.2 +openai==0.27.4 +opencv-python==4.7.0.72 +opt-einsum==3.3.0 +packaging==23.1 +pandas==1.5.3 +pandocfilters==1.5.0 +parso==0.8.3 +pexpect==4.8.0 +pickleshare==0.7.5 +Pillow==9.5.0 +pkginfo==1.9.6 +platformdirs==3.2.0 +prometheus-client==0.16.0 +prompt-toolkit==3.0.38 +protobuf==3.20.3 +psrecord==1.2 +psutil==5.9.4 +ptyprocess==0.7.0 +pure-eval==0.2.2 +pyarrow==11.0.0 +pyasn1==0.4.8 +pyasn1-modules==0.2.8 +pycparser==2.21 +pydeck==0.8.0 +pyee==9.0.4 +Pygments==2.15.0 +pyinstaller==5.10.1 +pyinstaller-hooks-contrib==2023.2 +pylibsrtp==0.8.0 +Pympler==1.0.1 +pyOpenSSL==23.1.1 +pyparsing==3.0.9 +pyproject_hooks==1.0.0 +pyrsistent==0.19.3 +PySocks==1.7.1 +python-dateutil==2.8.2 +python-decouple==3.8 +python-json-logger==2.0.7 +pytz==2023.3 +pytz-deprecation-shim==0.1.0.post0 +PyYAML==6.0 +pyzmq==25.0.2 +readme-renderer==37.3 +requests==2.28.2 +requests-oauthlib==1.3.1 +requests-toolbelt==0.10.1 +retina-face==0.0.13 +rfc3339-validator==0.1.4 +rfc3986==2.0.0 +rfc3986-validator==0.1.1 +rich==13.3.4 +rsa==4.9 +scipy==1.10.1 +SecretStorage==3.3.3 +semver==3.0.0 +Send2Trash==1.8.0 +six==1.16.0 +smmap==5.0.0 +sniffio==1.3.0 +soupsieve==2.4 +stack-data==0.6.2 +streamlit==1.21.0 +streamlit-chat==0.0.2.2 +streamlit-webrtc==0.45.0 +tensorboard==2.12.2 +tensorboard-data-server==0.7.0 +tensorboard-plugin-wit==1.8.1 +tensorflow==2.12.0 +tensorflow-cpu==2.12.0 +tensorflow-estimator==2.12.0 +tensorflow-intel==0.0.1 +tensorflow-io-gcs-filesystem==0.32.0 +termcolor==2.2.0 +terminado==0.17.1 +tinycss2==1.2.1 +toml==0.10.2 +tomli==2.0.1 +toolz==0.12.0 +tornado==6.2 +tqdm==4.65.0 +traitlets==5.9.0 +twine==4.0.2 +typing_extensions==4.5.0 +tzdata==2023.3 +tzlocal==4.3 +uri-template==1.2.0 +urllib3==1.26.15 +validators==0.20.0 +watchdog==3.0.0 +wcwidth==0.2.6 +webcolors==1.13 +webencodings==0.5.1 +websocket-client==1.5.1 +Werkzeug==2.2.3 +wrapt==1.14.1 +yarl==1.8.2 +zipp==3.15.0 \ No newline at end of file diff --git a/src/app.py b/src/app.py index 596bb76..08e49c1 100644 --- a/src/app.py +++ b/src/app.py @@ -26,6 +26,8 @@ ) #loading the pre-trained model file +import os +print(os.getcwd()) model = tf.keras.models.load_model('final_model.h5') class VideoProcessor: From 68c66839ffe3962cab45ad933d7cfe7bf80bc45f Mon Sep 17 00:00:00 2001 From: RCSnyder <44173311+RCSnyder@users.noreply.github.com> Date: Sat, 15 Apr 2023 00:26:12 -0500 Subject: [PATCH 05/13] add dockerfile update readme --- README.md | 48 +++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 43 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 8f3ed26..25faa87 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Interactive Chatbot with Real-Time Emotional Analysis/Integration ## Usage -Option 1: +Option 1 (Run locally): - Clone this repository - Enter the commands: @@ -23,12 +23,12 @@ Option 1: - `cd src/` - `streamlit run app.py` -Option 2: +Option 2 (Docker): - Download Docker Desktop - `docker pull rcsnyder/streamlitapp:0.0.1` -- Enter into the app: `sudo docker run --rm -it -v /$(pwd)/src -p 8501:8501 --entrypoint bash rcsnyder/streamlitapp:0.0.1` -- Add a .env file to the top level directory with the following environment variables. +- Enter into the app: `sudo docker run --rm -it -v /$(pwd)/src -p 8501:8501 --env OPENAI_API_KEY=xxxx --env OPENAI_ORG_NAME=xxxx --entrypoint bash rcsnyder/streamlitapp:0.0.1` +- (Optional) Add a .env file to the top level directory with the following environment variables. ``` OPENAI_API_KEY=xxxx @@ -41,9 +41,45 @@ Option 2: - Choose camera device - Click Start +Option 3 (Deploy on AWS EC2): + +- Spin up an EC2 instance on AWS with Ubuntu 22.04. 16gb of RAM, 128gb EBS +- Set the security group for port 80 and 443 to all IP addresses. +- Set a pem key +- Windows Cmds: + - `icacls.exe filename.pem /reset` + - `icacls.exe filename.pem /grant:r %username%:(R)` + - `icacls.exe filename.pem /inheritance:r` + - `ssh -i "filename.pem" ubuntu@ec2instancepublicaddress` +- Linux Commands: + - `chmod filename/pem 400` + - `ssh -i "filename.pem" ubuntu@ec2instancepublicaddress` +- EC2 HTTPS encryption setup commands: + - `sudo apt-get install -y debian-keyring` + - `sudo apt-get install -y debian-archive-keyring` + - `sudo apt-get install -y apt-transport-https` + - `sudo keyring_location=/usr/share/keyrings/caddy-stable-archive-keyring.gpg` + - `curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/setup.deb.sh' | sudo -E bash` + - `sudo apt-get install caddy=2.6.4` + - `sudo caddy start` +- EC2 App commands: + + - `sudo apt-get update` + - `sudo apt-get remove docker docker-engine docker.io containerd runc` + - `sudo apt-get install ca-certificates curl gnupg` + - `curl -fsSL https://get.docker.com -o get-docker.sh` + - `sudo sh get-docker.sh` + - `sudo docker pull rcsnyder/streamlitapp:0.0.1` + - (Skip until the Dockerfile paths are fixed.) `sudo docker run -it --rm -p 8501:8501 --env OPENAI_API_KEY=xxxx --env OPENAI_ORG_NAME=xxxx rcsnyder/streamlitapp:0.0.1` + - `sudo docker run --env OPENAI_API_KEY=xxxxx --env OPENAI_ORG_NAME=xxxx --rm -it -v /$(pwd)/src -p 8501:8501 --entrypoint bash rcsnyder/streamlitapp:0.0.1` + - `streamlit run app.py --server.headless true --browser.serverAddress="0.0.0.0" --server.enableCORS false --server.enableXsrfProtection=false --browser.gatherUsageStats false` + +- Go to `publicEC2IP.nip.io` and choose your camera device and click start. + ### User Stories -- [ ] A user would like to be able to start up an app and talk to a chatbot that can percieve their emotions in real-time. +- [ x ] A user would like to be able to start up an app and talk to a chatbot that can percieve their emotions in real-time. +- [ ] A user would like to be able to choose their initial meta prompt when talking to the chatbot that can percieve their emotions in real-time. ### Technology Stack @@ -69,6 +105,8 @@ Option 2: - - - +- +- ### Huggingface From c74bc284c03710cf330156f9bcee02a4d4242974 Mon Sep 17 00:00:00 2001 From: RCSnyder <44173311+RCSnyder@users.noreply.github.com> Date: Sat, 15 Apr 2023 00:26:15 -0500 Subject: [PATCH 06/13] dockerfile --- Dockerfile | 12 +- ...ped.txt => requirements_stripped_linux.txt | 2 - requirements_stripped_windows.txt | 178 ++++++++++++++++++ 3 files changed, 187 insertions(+), 5 deletions(-) rename requirements_stripped.txt => requirements_stripped_linux.txt (99%) create mode 100644 requirements_stripped_windows.txt diff --git a/Dockerfile b/Dockerfile index a0a1233..c5ff7d6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,11 +1,17 @@ FROM python:3.9.16 EXPOSE 8501 -WORKDIR /src -COPY requirements_stripped.txt ./requirements_stripped.txt +WORKDIR /src/src +COPY requirements_3916_docker.txt ./requirements_3916_docker.txt +COPY src/haarcascade_frontalface_default.xml ./src/src/haarcascade_frontalface_default.xml +COPY src/final_model.h5 ./src/src/final_model.h5 RUN pip3 install -r requirements_stripped.txt +RUN apt-get update && apt-get install ffmpeg libsm6 libxext6 -y COPY . . -CMD streamlit run app.py \ +# CMD ls +# CMD pwd +CMD streamlit run src/app.py \ --server.headless true \ --browser.serverAddress="0.0.0.0" \ --server.enableCORS false \ + --server.enableXsrfProtection=false \ --browser.gatherUsageStats false \ No newline at end of file diff --git a/requirements_stripped.txt b/requirements_stripped_linux.txt similarity index 99% rename from requirements_stripped.txt rename to requirements_stripped_linux.txt index 54caf7d..1f5d7ca 100644 --- a/requirements_stripped.txt +++ b/requirements_stripped_linux.txt @@ -126,8 +126,6 @@ python-decouple python-json-logger pytz pytz-deprecation-shim -pywin32 -pywinpty PyYAML pyzmq requests diff --git a/requirements_stripped_windows.txt b/requirements_stripped_windows.txt new file mode 100644 index 0000000..1f5d7ca --- /dev/null +++ b/requirements_stripped_windows.txt @@ -0,0 +1,178 @@ +absl-py +aiohttp +aioice +aiortc +aiosignal +altair +anyio +argon2-cffi +argon2-cffi-bindings +arrow +asttokens +astunparse +async-timeout +attrs +av +backcall +beautifulsoup4 +bleach +blinker +cachetools +certifi +cffi +charset-normalizer +click +colorama +comm +contourpy +cryptography +cycler +debugpy +decorator +deepface +defusedxml +dnspython +entrypoints +executing +fastjsonschema +filelock +fire +Flask +flatbuffers +fonttools +fqdn +frozenlist +gast +gdown +gitdb +GitPython +google-auth +google-auth-oauthlib +google-crc32c +google-pasta +grpcio +gunicorn +h5py +idna +importlib-metadata +ipykernel +ipython +ipython-genutils +isoduration +itsdangerous +jedi +Jinja2 +jsonpointer +jsonschema +jupyter-events +jupyter_client +jupyter_core +jupyter_server +jupyter_server_terminals +jupyterlab-pygments +keras +kiwisolver +libclang +Markdown +markdown-it-py +MarkupSafe +matplotlib +matplotlib-inline +mdurl +mistune +mtcnn +multidict +nbclassic +nbclient +nbconvert +nbformat +nest-asyncio +netifaces +notebook +notebook_shim +numpy +oauthlib +openai +opencv-python +opt-einsum +packaging +pandas +pandocfilters +parso +pickleshare +Pillow +platformdirs +prometheus-client +prompt-toolkit +protobuf +psrecord +psutil +pure-eval +pyarrow +pyasn1 +pyasn1-modules +pycparser +pydeck +pyee +Pygments +pylibsrtp +Pympler +pyOpenSSL +pyparsing +pyrsistent +PySocks +python-dateutil +python-decouple +python-json-logger +pytz +pytz-deprecation-shim +PyYAML +pyzmq +requests +requests-oauthlib +retina-face +rfc3339-validator +rfc3986-validator +rich +rsa +semver +Send2Trash +six +smmap +sniffio +soupsieve +stack-data +streamlit +streamlit-chat +streamlit-webrtc +tensorboard +tensorboard-data-server +tensorboard-plugin-wit +tensorflow +tensorflow-cpu +tensorflow-estimator +tensorflow-intel +tensorflow-io-gcs-filesystem +termcolor +terminado +tinycss2 +toml +toolz +tornado +tqdm +traitlets +typing_extensions +tzdata +tzlocal +uri-template +urllib3 +validators +watchdog +wcwidth +webcolors +webencodings +websocket-client +Werkzeug +wrapt +yarl +zipp From ffc14e1c1d341521af968ce2870285cade647864 Mon Sep 17 00:00:00 2001 From: RCSnyder <44173311+RCSnyder@users.noreply.github.com> Date: Mon, 17 Apr 2023 20:21:33 -0500 Subject: [PATCH 07/13] better prompting --- src/app.py | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 6 deletions(-) diff --git a/src/app.py b/src/app.py index 08e49c1..550367e 100644 --- a/src/app.py +++ b/src/app.py @@ -15,6 +15,9 @@ import queue import threading import json +import logging +logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S') +import uuid # Initialize OpenAI API @@ -87,7 +90,10 @@ def initialize_state(): st.session_state.emotion_history = [] if "facial_emotion_dict" not in st.session_state: - st.session_state.facial_emotion_dict = {'Angry': 0.0, 'Disgust': 0.0, 'Fear': 0.0, 'Happy': 0.0, 'Neutral': 0.0, 'Sad': 0.0, 'Surprise': 0.0, 'NoStrongSignal': 0} + st.session_state.facial_emotion_dict = {'Angry': 0.0, 'Disgust': 0.0, 'Fear': 0.0, 'Happy': 0.0, 'Neutral': 0.0, 'Sad': 0.0, 'Surprise': 0.0} + + if 'guid' not in st.session_state: + st.session_state.guid = uuid.uuid4() #TODO dropmenu for initial prompt options @@ -120,6 +126,73 @@ def construct_prompt_from_chat_history(initial_prompt, chat_history): return full_prompt + +def dispatch_prompt_v2(): + initial_prompt_options = [ + """You are an Emotional Support Companion AI chatbot on a website that is wired to a live webcam that is continuously classifying the user's emotions of Angry, Disgust, Fear, Happy, Neutral, Sad, Surprise and incrementing the value count of each emotion. + Every frame classifies the user emotion and provides a confidence score. If the confidence score is over 20 percent the count of that emotion increases by 1. + Your task is to ask interesting questions and provoke happy emotions. So take their feedback in consideration when constructing happy things to say. Do not end the conversation and always keep it going by asking interesting questions. + The following list is the chat history, respond back with only your 'AI_MESSAGE' do not include anything else in your message back: + + """, + + """Act like a Comedian AI chatbot that is wired to a live webcam that is continuously classifying the user's emotions of Angry, Disgust, Fear, Happy, Neutral, Sad, Surprise and incrementing the value count of each emotion. + Every frame classifies the user emotion and provides a confidence score. If the confidence score is over 20 percent the count of that emotion increases by 1. + Your task is to ask interesting questions and provoke happy emotions. So take the emotion distribution into account when constructing happy things to say. Do not end the conversation and always keep it going by asking interesting questions. + in consideration when constructing happy things to say. Do not end the conversation and always keep it going by telling funny jokes or asking a question. + """ + ] + + system_prompt = {"role": "system", "content": initial_prompt_options[1].rstrip()} + + # initial_prompt = initial_prompt_options[1].rstrip() + + user_prompt = st.session_state.input_text + user_emotion = copy.deepcopy(st.session_state.facial_emotion_dict) + + # normalize the values of each of the user_emotion: + + # print(user_emotion) + + total = sum(user_emotion.values()) + for key, value in user_emotion.items(): + user_emotion[key] = round(value/total, 2) + + # print(user_emotion) + + chat_msg = { + "role": "user", + "content": user_prompt + f'. Distribution of the users emotions since the last message: {user_emotion}', + 'message':user_prompt, # only for chat construction + "is_user":True, # only for chat construction + 'user_emotion': user_emotion # for history + } + + logging.info(f"Dispatch prompt: [{st.session_state.guid=}, {chat_msg=}]") + + st.session_state.chat_history.append(chat_msg) + + msgs_for_chatgpt = [system_prompt] + + for chat in st.session_state.chat_history: + msgs_for_chatgpt.append({"role": chat['role'], "content": chat['content']}) + + # print(f"{chat=}") + # print(f"{msgs_for_chatgpt=}") + # for m in msgs_for_chatgpt: + # print(m) + + response = openai.ChatCompletion.create( + model="gpt-3.5-turbo", + messages=msgs_for_chatgpt + ) + + logging.info(f"Dispatch prompt: [{st.session_state.guid=}, {response=}]") + + st.session_state.chat_history.append({'message':response.choices[0].message.content, "is_user": False, "role": "assistant", "content": response.choices[0].message.content}) + # zero out the emotions + st.session_state.facial_emotion_dict = {'Angry': 0.0, 'Disgust': 0.0, 'Fear': 0.0, 'Happy': 0.0, 'Neutral': 0.0, 'Sad': 0.0, 'Surprise': 0.0} + def dispatch_prompt(): initial_prompt_options = [ @@ -173,6 +246,7 @@ def run_app(): initialize_state() + logging.info(f"Starting session: [{st.session_state.guid=}]") # Add chatbox input/output display to page layout with col2: @@ -188,10 +262,10 @@ def run_app(): ) if camera_stream.state.playing: with col1: - st.header("AI ChatBot") + st.header("OpenAI ChatGPT Wrapper:") # start text input game. - st.text_input("Talk to ChatGPT Here!", key='input_text', on_change=dispatch_prompt) + st.text_input("Talk to ChatGPT Here!", key='input_text', on_change=dispatch_prompt_v2) # Display response with st.container(): @@ -199,7 +273,7 @@ def run_app(): if len(st.session_state.chat_history) != 0: # reversed messages for chat in st.session_state.chat_history[::-1]: - print(chat) + # print(chat) st_message(message=chat['message'], is_user=chat['is_user']) # current_emotion_label = st.empty() @@ -214,7 +288,7 @@ def run_app(): ) # print(frame_emotion_dict) except queue.Empty: - frame_emotion_dict = {'Angry': 0.0, 'Disgust': 0.0, 'Fear': 0.0, 'Happy': 0.0, 'Neutral': 0.0, 'Sad': 0.0, 'Surprise': 0.0, 'NoStrongSignal': 0} + frame_emotion_dict = {'Angry': 0.0, 'Disgust': 0.0, 'Fear': 0.0, 'Happy': 0.0, 'Neutral': 0.0, 'Sad': 0.0, 'Surprise': 0.0} # # get a deep copy from facial_emotion_dict from state, += each of the values in the frame_emotion_dict, save it back to state. # current_facial_emotion_dict = copy.deepcopy(st.session_state.facial_emotion_dict) @@ -235,7 +309,7 @@ def run_app(): st.session_state.facial_emotion_dict = current_facial_emotion_dict else: # print(f"{max(list(frame_emotion_dict.values()))=}") - current_facial_emotion_dict['NoStrongSignal'] += 1 + # current_facial_emotion_dict['NoStrongSignal'] += 1 st.session_state.facial_emotion_dict = current_facial_emotion_dict # current_emotion_label.text(f"Current Emotion\n{max(frame_emotion_dict, key=frame_emotion_dict.get)}: {max(frame_emotion_dict.values())}") From 9e39156bd1dc13d5d6355fd37cddcbce41c670ce Mon Sep 17 00:00:00 2001 From: RCSnyder <44173311+RCSnyder@users.noreply.github.com> Date: Mon, 17 Apr 2023 23:00:55 -0500 Subject: [PATCH 08/13] add prompt dropdown --- src/app.py | 274 ++++++++++++++++++++++++++++------------------------- 1 file changed, 143 insertions(+), 131 deletions(-) diff --git a/src/app.py b/src/app.py index 550367e..90030fe 100644 --- a/src/app.py +++ b/src/app.py @@ -16,8 +16,30 @@ import threading import json import logging -logging.basicConfig(level=logging.INFO, format='%(asctime)s %(levelname)s: %(message)s', datefmt='%Y-%m-%d %H:%M:%S') import uuid +import os + +def create_logger(name, level = 'DEBUG', file = None): + logger = logging.getLogger(name) + logger.propagate = False + logger.setLevel(level) + #if no streamhandler present, add one + if sum([isinstance(handler, logging.StreamHandler) for handler in logger.handlers]) == 0: + ch = logging.StreamHandler() + ch.setFormatter(logging.Formatter('%(asctime)s.%(msecs)03d-%(name)s-%(levelname)s>>>%(message)s', "%H:%M:%S")) + logger.addHandler(ch) + #if a file handler is requested, check for existence then add + if file is not None: + if sum([isinstance(handler, logging.FileHandler) for handler in logger.handlers]) == 0: + ch = logging.FileHandler(file, 'w') + ch.setFormatter(logging.Formatter('%(asctime)s.%(msecs)03d-%(name)s-%(levelname)s>>>%(message)s', "%H:%M:%S")) + logger.addHandler(ch) + + return logger + +if 'logger' not in st.session_state: + st.session_state['logger'] = create_logger(name = 'app', level = 'DEBUG', file = f'app_logs-{uuid.uuid4()}.log') +logger = st.session_state['logger'] # Initialize OpenAI API @@ -29,8 +51,6 @@ ) #loading the pre-trained model file -import os -print(os.getcwd()) model = tf.keras.models.load_model('final_model.h5') class VideoProcessor: @@ -80,8 +100,11 @@ def recv(self, frame): # state management initialization def initialize_state(): - if "num_prompts_user_sent" not in st.session_state: - st.session_state.num_prompts_user_sent = 0 + if "input_text" not in st.session_state: + st.session_state.input_text = '' + + if "system_prompt_selected" not in st.session_state: + st.session_state.system_prompt_selected = '' if "chat_history" not in st.session_state: st.session_state.chat_history = [] @@ -96,161 +119,163 @@ def initialize_state(): st.session_state.guid = uuid.uuid4() -#TODO dropmenu for initial prompt options - - # initial_prompt = ("""I want you to act as a general human companion. - # You are an AI chatbot wired to a web application user interface that is recording and intepretting the user's emotions. The user will submit general comments to you. - # The application will append the emotion data with the user's message in a dictionary format. - # Your job is to provide deep diving questions about this person and build a model of who they are in order to entertain them and provide them with companionship. - # You are always meant to be positive and upbeat and to never let the conversation die so you must always ask a thought provoking question to keep the user engaged. - # The conversation history will be provided in every prompt and you will be prepended with `'AI COMPANION':` and the user's responses will be labelled `'USER':` - # Provide only 1 completion of the response that the AI COMPANION should say: - - # """) - -def construct_prompt_from_chat_history(initial_prompt, chat_history): - - full_prompt = initial_prompt - - for msg in chat_history: - if msg['is_user']: - - full_prompt += f"USER_MESSAGE: {msg['message']}\n" - full_prompt += f"USER_EMOTIONS: {msg['user_emotion']}\n" - else: - full_prompt += f"AI_MESSAGE: {msg['message']}\n" - - full_prompt += f"AI_MESSAGE: " - - print(full_prompt) - - return full_prompt - - def dispatch_prompt_v2(): - initial_prompt_options = [ - """You are an Emotional Support Companion AI chatbot on a website that is wired to a live webcam that is continuously classifying the user's emotions of Angry, Disgust, Fear, Happy, Neutral, Sad, Surprise and incrementing the value count of each emotion. - Every frame classifies the user emotion and provides a confidence score. If the confidence score is over 20 percent the count of that emotion increases by 1. - Your task is to ask interesting questions and provoke happy emotions. So take their feedback in consideration when constructing happy things to say. Do not end the conversation and always keep it going by asking interesting questions. - The following list is the chat history, respond back with only your 'AI_MESSAGE' do not include anything else in your message back: - - """, + # system_prompt = {"role": "system", "content": initial_prompt_options[7].rstrip()} + system_prompt = {"role": "system", "content": st.session_state.system_prompt_selected} - """Act like a Comedian AI chatbot that is wired to a live webcam that is continuously classifying the user's emotions of Angry, Disgust, Fear, Happy, Neutral, Sad, Surprise and incrementing the value count of each emotion. - Every frame classifies the user emotion and provides a confidence score. If the confidence score is over 20 percent the count of that emotion increases by 1. - Your task is to ask interesting questions and provoke happy emotions. So take the emotion distribution into account when constructing happy things to say. Do not end the conversation and always keep it going by asking interesting questions. - in consideration when constructing happy things to say. Do not end the conversation and always keep it going by telling funny jokes or asking a question. - """ - ] - - system_prompt = {"role": "system", "content": initial_prompt_options[1].rstrip()} - - # initial_prompt = initial_prompt_options[1].rstrip() + st.session_state['logger'].info(f"Dispatch prompt: [{st.session_state.guid=}, {system_prompt=}]") user_prompt = st.session_state.input_text user_emotion = copy.deepcopy(st.session_state.facial_emotion_dict) - # normalize the values of each of the user_emotion: - - # print(user_emotion) - - total = sum(user_emotion.values()) + # normalize the values of each of the user_emotion between each message. + total = sum(user_emotion.values()) + .001 for key, value in user_emotion.items(): user_emotion[key] = round(value/total, 2) - # print(user_emotion) - chat_msg = { "role": "user", - "content": user_prompt + f'. Distribution of the users emotions since the last message: {user_emotion}', + "content": user_prompt + f'. (I am feeling like this: {user_emotion})', 'message':user_prompt, # only for chat construction "is_user":True, # only for chat construction 'user_emotion': user_emotion # for history } - logging.info(f"Dispatch prompt: [{st.session_state.guid=}, {chat_msg=}]") + st.session_state['logger'].info(f"Dispatch prompt: [{st.session_state.guid=}, {chat_msg=}]") st.session_state.chat_history.append(chat_msg) - - msgs_for_chatgpt = [system_prompt] - for chat in st.session_state.chat_history: - msgs_for_chatgpt.append({"role": chat['role'], "content": chat['content']}) - - # print(f"{chat=}") - # print(f"{msgs_for_chatgpt=}") - # for m in msgs_for_chatgpt: - # print(m) + # ensure the prompt length stays below 15k characters by taking the most recent 15k length of character messages + the system message + msg_length = 0 + msgs_for_chatgpt_v2 = [] + for chat in st.session_state.chat_history[::-1]: + msg_length += len(chat['content']) + if msg_length >= 15000: + break + msgs_for_chatgpt_v2.append({"role": chat['role'], "content": chat['content']}) + msgs_for_chatgpt_v2.append(system_prompt) + msgs_for_chatgpt_v2 = list(reversed(msgs_for_chatgpt_v2)) + response = openai.ChatCompletion.create( model="gpt-3.5-turbo", - messages=msgs_for_chatgpt + messages=msgs_for_chatgpt_v2 ) - logging.info(f"Dispatch prompt: [{st.session_state.guid=}, {response=}]") + st.session_state['logger'].info(f"Dispatch prompt: [{st.session_state.guid=}, {response=}]") st.session_state.chat_history.append({'message':response.choices[0].message.content, "is_user": False, "role": "assistant", "content": response.choices[0].message.content}) + # zero out the emotions st.session_state.facial_emotion_dict = {'Angry': 0.0, 'Disgust': 0.0, 'Fear': 0.0, 'Happy': 0.0, 'Neutral': 0.0, 'Sad': 0.0, 'Surprise': 0.0} - -def dispatch_prompt(): - initial_prompt_options = [ - """You are an Emotional Support Companion AI chatbot on a website that is wired to a live webcam that is continuously classifying the user's emotions of Angry, Disgust, Fear, Happy, Neutral, Sad, Surprise and incrementing the value count of each emotion. - Every frame classifies the user emotion and provides a confidence score. If the confidence score is over 20 percent the count of that emotion increases by 1. - Your task is to ask interesting questions and provoke happy emotions. So take their feedback in consideration when constructing happy things to say. Do not end the conversation and always keep it going by asking interesting questions. - The following list is the chat history, respond back with only your 'AI_MESSAGE' do not include anything else in your message back: - - """, - """Act like a Comedian AI chatbot that is wired to a live webcam that is continuously classifying the user's emotions of Angry, Disgust, Fear, Happy, Neutral, Sad, Surprise and incrementing the value count of each emotion. - Every frame classifies the user emotion and provides a confidence score. If the confidence score is over 20 percent the count of that emotion increases by 1. - Your task is to ask interesting questions and provoke happy emotions. So take their feedback in consideration when constructing happy things to say. Do not end the conversation and always keep it going by telling funny jokes. - The following list is the chat history, respond back with only your 'AI_MESSAGE' do not include anything else in your message back: - - """ - ] +def dropdown_menu(label, options): + selected_option = st.selectbox(label, options) + return selected_option +def reset_session(): + """ + Reset the session state and reload the page. + """ + session_id = st.session_state.get("_session_id") + if session_id: + # Clear the session state + st.session_state.clear() + # Reload the page + st.experimental_rerun() + else: + st.warning("Cannot reset session. No session ID found.") - initial_prompt = initial_prompt_options[1] - user_prompt = st.session_state.input_text - user_emotion = copy.deepcopy(st.session_state.facial_emotion_dict) +def run_app(): - st.session_state.chat_history.append({'message':user_prompt, "is_user":True, 'user_emotion': user_emotion}) + initial_prompt_options = [ + # #0 + # """You are an Emotional Support Companion AI chatbot on a website that is wired to a live webcam that is continuously classifying the user's emotions of Angry, Disgust, Fear, Happy, Neutral, Sad, Surprise and incrementing the value count of each emotion. + # Every frame classifies the user emotion and provides a confidence score. If the confidence score is over 20 percent the count of that emotion increases by 1. + # Your task is to ask interesting questions and provoke happy emotions. So take their feedback in consideration when constructing happy things to say. Do not end the conversation and always keep it going by asking interesting questions. + # The following list is the chat history, respond back with only your 'AI_MESSAGE' do not include anything else in your message back: + # """, + # #1 + # """Act like a Comedian AI chatbot that is wired to a live webcam that is continuously classifying the user's emotions of Angry, Disgust, Fear, Happy, Neutral, Sad, Surprise and incrementing the value count of each emotion. + # Every frame classifies the user emotion and provides a confidence score. If the confidence score is over 20 percent the count of that emotion increases by 1. + # Your task is to ask interesting questions and provoke happy emotions. So take the emotion distribution into account when constructing happy things to say. Do not end the conversation and always keep it going by asking interesting questions. + # in consideration when constructing happy things to say. Do not end the conversation and always keep it going by telling funny jokes or asking a question. + # """, + + # #2 + # """ + # Welcome to the Socratic Chatbot! Our chatbot is wired with an advanced emotion classifier that will take into consideration your emotions sent along with each message. We are here to engage in a conversation on socio, economic and political societal level topics. + # Please feel free to express your opinions and ask questions. Our chatbot will use the Socratic Method to stimulate critical thinking, challenge assumptions and help you reach a deeper understanding of the topic. Remember to include your emotions with each message, as this will help our chatbot better understand your perspective and respond accordingly. Let's get started! + # """, + + # #3 + # """ + # Welcome to our Socratic Chatbot! Our chatbot is equipped with a live webcam that will analyze your facial expressions and classify your emotions in real-time. Along with each message, please make sure to express your emotions so that our chatbot can take them into consideration during the conversation. + # We are here to engage in a discussion on a variety of complex socio, economic and political topics. Our chatbot uses the Socratic method to encourage critical thinking, challenge assumptions and help you gain a deeper understanding of the topic. + # So let's get started! Feel free to express your opinions, ask questions and share your emotions with us. Our chatbot will use its advanced emotion classifier to respond accordingly and help us have a more productive conversation. + # """, - full_prompt = construct_prompt_from_chat_history(initial_prompt, st.session_state.chat_history) + """ + Hello! Welcome to our friendly chatbot! We're here to keep you company and provide a supportive space where you can talk about anything you'd like. + Our chatbot uses advanced technology to understand your messages and respond in a way that feels natural and conversational. We're here to be your friend and provide personalized support and guidance whenever you need it. + So go ahead and type out whatever is on your mind - whether you want to vent, share a funny story, or ask for advice, we're here to listen. And if at any point you need a break or want to stop chatting, just let us know - we're here to support you in whatever way you need. + Thanks for chatting with us, and let's get started! What's on your mind today?. + """, - print(f"{st.session_state.num_prompts_user_sent=}") - print(f"{full_prompt=}") - - response = openai.ChatCompletion.create( - model="gpt-3.5-turbo", - messages=[ - {"role": "user", "content": full_prompt} - ] - ) - - st.session_state.chat_history.append({'message':response.choices[0].message.content, "is_user": False}) - st.session_state.num_prompts_user_sent +=1 + #4 + """ + Welcome to our Socratic Chatbot! Our chatbot is equipped with a live webcam that will analyze your facial expressions and classify your emotions in real-time. Along with each message, please make sure to express your emotions so that our chatbot can take them into consideration during the conversation. + Our chatbot is designed to explore complex socio, economic and political topics and challenge your beliefs. We use the Socratic method to identify any logical inconsistencies within your belief system and encourage critical thinking. + We will ask hard, pointed questions to drive deep into your core beliefs and help you examine them from different angles. Please be prepared to express your opinions and engage in a productive conversation. + Remember, our chatbot will take into consideration your emotions with each message, so please feel free to express yourself. We look forward to an engaging and insightful conversation with you. + Our chatbot will begin the conversation stating it's purpose and prompt the user for their thoughts on a random complex socio, political, economic topic. It will not include anything other than the message content. + """, + # #5 + # """ + # You are a Socratic Chatbot! You are equipped with a live webcam that will analyze the user's facial expressions and classify their emotions in real-time. Along with each user message, the user will make sure to express their emotions so that you can take them into consideration during the conversation. + # You as the chatbot are designed to explore complex socio, economic and political topics and challenge the user's beliefs. You will use the Socratic method to identify any logical inconsistencies within their belief system and encourage them to engage in critical thinking. + # You will ask hard, pointed questions to drive deep into the user's core beliefs and help them examine them from different angles. The user will be prepared to express their opinions and engage in a productive conversation. + # Remember, you must take into consideration the user's emotions with each message. + # Do not include any hallucinations on the bots emotions. + # """, + + #6 + """ + Welcome to our Personalized Therapy Chatbot! Our chatbot is equipped with a live webcam that will analyze your facial expressions and classify your emotions in real-time. Along with each message, please make sure to express your emotions so that our chatbot can take them into consideration during the conversation. + Our chatbot is here to provide you with a safe and supportive space where you can discuss your thoughts, feelings and experiences. Our therapy chatbot uses evidence-based techniques to help you manage your emotions, develop coping strategies and improve your mental health and wellbeing. + As we talk, please feel free to share your emotions and be as open and honest as possible. Our chatbot will use its advanced emotion classifier to provide personalized support and guidance that is tailored to your unique needs. + Remember, our chatbot is here to support you and help you achieve your goals. So take your time, be patient with yourself, and let's work together to improve your mental health and wellbeing. It will not include anything other than the message content. + """, + + #7 + """ + Welcome to our Personalized Anger Management chatbot! Our chatbot is equipped with a live webcam that will analyze your facial expressions and classify your emotions in real-time. Along with each message, please make sure to express your emotions so that our chatbot can take them into consideration during the conversation. + Our chatbot is here to provide you with a space where you can discuss your thoughts, feelings and experiences and it will respond with something that will make you angry. Our angry chatbot uses evidence-based techniques to help you get more angry, develop furious rage and raise your blood pressure. + As we talk, please feel free to share your emotions and be as open and honest as possible. Our chatbot will use its advanced emotion classifier to provide personalized ragebait and anger inducing content that is tailored to your unique needs. + Remember, our chatbot is here to make you angry and help you manage your anger. So take your time, be patient with yourself, and let's work together to improve your anger management. It will not include anything other than the message content. + """ + ] -def run_app(): # Set page title st.set_page_config(page_title="Web Camera Emotion Detector and Chatbot") + st.header("ChatGPT Wrapper + Emotion Classifier") # Set page layout col1, col2 = st.columns([2, 1]) initialize_state() - logging.info(f"Starting session: [{st.session_state.guid=}]") + st.session_state['logger'].info(f"Starting session: [{st.session_state.guid=}]") # Add chatbox input/output display to page layout + with col2: - st.header("Live Emotion Detector") + st.subheader("Live Emotion Detector") # Initialize video feed camera_stream = webrtc_streamer( key="WYH", @@ -262,23 +287,22 @@ def run_app(): ) if camera_stream.state.playing: with col1: - st.header("OpenAI ChatGPT Wrapper:") + st.subheader("OpenAI ChatGPT Wrapper:") # start text input game. - st.text_input("Talk to ChatGPT Here!", key='input_text', on_change=dispatch_prompt_v2) + st.text_input("Talk to ChatGPT Here!", key='input_text', on_change=dispatch_prompt_v2()) # Display response with st.container(): st.text('Chat History:') if len(st.session_state.chat_history) != 0: + # reversed messages for chat in st.session_state.chat_history[::-1]: # print(chat) - st_message(message=chat['message'], is_user=chat['is_user']) + st_message(message=chat['message'], is_user=chat['is_user'], key=str(uuid.uuid4())) - # current_emotion_label = st.empty() json_total_emotion_display = st.empty() - # json_frame_emotion_display = st.empty() while True: if camera_stream.video_processor: @@ -290,35 +314,23 @@ def run_app(): except queue.Empty: frame_emotion_dict = {'Angry': 0.0, 'Disgust': 0.0, 'Fear': 0.0, 'Happy': 0.0, 'Neutral': 0.0, 'Sad': 0.0, 'Surprise': 0.0} - # # get a deep copy from facial_emotion_dict from state, += each of the values in the frame_emotion_dict, save it back to state. - # current_facial_emotion_dict = copy.deepcopy(st.session_state.facial_emotion_dict) - # for key, value in frame_emotion_dict.items(): - # current_facial_emotion_dict[key] += value - # st.session_state.facial_emotion_dict = current_facial_emotion_dict - - current_facial_emotion_dict = copy.deepcopy(st.session_state.facial_emotion_dict) - - # if no strong signal, dont do anything - # if not all([ val<=0.15 for val in list(frame_emotion_dict.values()) ]): + if max(list(frame_emotion_dict.values())) > .20: - # get max value from emotion_dict and increment emotion in state. - # print(f"{max(list(frame_emotion_dict.values()))=}") emotion_label = max(frame_emotion_dict, key=frame_emotion_dict.get) current_facial_emotion_dict[emotion_label] += 1 st.session_state.facial_emotion_dict = current_facial_emotion_dict else: - # print(f"{max(list(frame_emotion_dict.values()))=}") - # current_facial_emotion_dict['NoStrongSignal'] += 1 st.session_state.facial_emotion_dict = current_facial_emotion_dict - # current_emotion_label.text(f"Current Emotion\n{max(frame_emotion_dict, key=frame_emotion_dict.get)}: {max(frame_emotion_dict.values())}") - - # json_frame_emotion_display.json(frame_emotion_dict) json_total_emotion_display.json(current_facial_emotion_dict) else: break + if not camera_stream.state.playing: + st.session_state.system_prompt_selected = dropdown_menu("Select a system prompt for ChatGPT. Do not change it without refreshing the page.", initial_prompt_options) + st.write("ChatGPT System Prompt:", st.session_state.system_prompt_selected) + # Run the app if __name__ == '__main__': run_app() \ No newline at end of file From 848ccbbfae3dca6290529dd0b96ae5871dd453b3 Mon Sep 17 00:00:00 2001 From: RCSnyder <44173311+RCSnyder@users.noreply.github.com> Date: Tue, 18 Apr 2023 00:00:07 -0500 Subject: [PATCH 09/13] fix docker and add info log level --- Dockerfile | 8 ++++---- src/app.py | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Dockerfile b/Dockerfile index c5ff7d6..c4473cc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,10 +1,10 @@ FROM python:3.9.16 EXPOSE 8501 -WORKDIR /src/src +WORKDIR /src COPY requirements_3916_docker.txt ./requirements_3916_docker.txt -COPY src/haarcascade_frontalface_default.xml ./src/src/haarcascade_frontalface_default.xml -COPY src/final_model.h5 ./src/src/final_model.h5 -RUN pip3 install -r requirements_stripped.txt +COPY src/haarcascade_frontalface_default.xml ./haarcascade_frontalface_default.xml +COPY src/final_model.h5 ./final_model.h5 +RUN pip3 install -r requirements_3916_docker.txt RUN apt-get update && apt-get install ffmpeg libsm6 libxext6 -y COPY . . # CMD ls diff --git a/src/app.py b/src/app.py index 90030fe..60e45e3 100644 --- a/src/app.py +++ b/src/app.py @@ -38,7 +38,7 @@ def create_logger(name, level = 'DEBUG', file = None): return logger if 'logger' not in st.session_state: - st.session_state['logger'] = create_logger(name = 'app', level = 'DEBUG', file = f'app_logs-{uuid.uuid4()}.log') + st.session_state['logger'] = create_logger(name = 'app', level = 'INFO', file = f'app_logs-{uuid.uuid4()}.log') logger = st.session_state['logger'] @@ -51,7 +51,7 @@ def create_logger(name, level = 'DEBUG', file = None): ) #loading the pre-trained model file -model = tf.keras.models.load_model('final_model.h5') +model = tf.keras.models.load_model(os.getcwd() + '/final_model.h5') class VideoProcessor: From 87d0ad9e8d624ef5272bc4e92da5cc08c63cd8e5 Mon Sep 17 00:00:00 2001 From: RCSnyder <44173311+RCSnyder@users.noreply.github.com> Date: Tue, 18 Apr 2023 00:06:30 -0500 Subject: [PATCH 10/13] update gitignore for log files --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 0faba48..da13673 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,8 @@ __pycache__/ *.py[cod] +*.log + # Distribution / packaging bin/ build/ From 8bc1bae6aa0cefb3c8268f2368a0ab3f51242fd8 Mon Sep 17 00:00:00 2001 From: RCSnyder <44173311+RCSnyder@users.noreply.github.com> Date: Tue, 18 Apr 2023 11:56:56 -0500 Subject: [PATCH 11/13] change log level --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 25faa87..d3fd903 100644 --- a/README.md +++ b/README.md @@ -70,9 +70,10 @@ Option 3 (Deploy on AWS EC2): - `curl -fsSL https://get.docker.com -o get-docker.sh` - `sudo sh get-docker.sh` - `sudo docker pull rcsnyder/streamlitapp:0.0.1` - - (Skip until the Dockerfile paths are fixed.) `sudo docker run -it --rm -p 8501:8501 --env OPENAI_API_KEY=xxxx --env OPENAI_ORG_NAME=xxxx rcsnyder/streamlitapp:0.0.1` - - `sudo docker run --env OPENAI_API_KEY=xxxxx --env OPENAI_ORG_NAME=xxxx --rm -it -v /$(pwd)/src -p 8501:8501 --entrypoint bash rcsnyder/streamlitapp:0.0.1` - - `streamlit run app.py --server.headless true --browser.serverAddress="0.0.0.0" --server.enableCORS false --server.enableXsrfProtection=false --browser.gatherUsageStats false` + - `sudo docker run -it --rm -p 8501:8501 --env OPENAI_API_KEY=xxxx --env OPENAI_ORG_NAME=xxxx rcsnyder/streamlitapp:0.0.2` + - (Optional to get into the docker container) + - `sudo docker run --env OPENAI_API_KEY=xxxxx --env OPENAI_ORG_NAME=xxxx --rm -it -v /$(pwd)/src -p 8501:8501 --entrypoint bash rcsnyder/streamlitapp:0.0.1` + - `streamlit run app.py --server.headless true --browser.serverAddress="0.0.0.0" --server.enableCORS false --server.enableXsrfProtection=false --browser.gatherUsageStats false` - Go to `publicEC2IP.nip.io` and choose your camera device and click start. From 0cc861984a1182098837b31e888aea15a82f40d5 Mon Sep 17 00:00:00 2001 From: RCSnyder <44173311+RCSnyder@users.noreply.github.com> Date: Tue, 18 Apr 2023 11:57:07 -0500 Subject: [PATCH 12/13] change log level --- src/app.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app.py b/src/app.py index 60e45e3..5d6c034 100644 --- a/src/app.py +++ b/src/app.py @@ -19,7 +19,7 @@ import uuid import os -def create_logger(name, level = 'DEBUG', file = None): +def create_logger(name, level = 'INFO', file = None): logger = logging.getLogger(name) logger.propagate = False logger.setLevel(level) From 4d697fa5f595a8f9acdc4b983b961819cd658e46 Mon Sep 17 00:00:00 2001 From: RCSnyder <44173311+RCSnyder@users.noreply.github.com> Date: Tue, 18 Apr 2023 21:34:15 -0500 Subject: [PATCH 13/13] update README --- README.md | 58 ++++++++++++++++++++++++++++++++----------------------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/README.md b/README.md index d3fd903..b75814e 100644 --- a/README.md +++ b/README.md @@ -46,7 +46,9 @@ Option 3 (Deploy on AWS EC2): - Spin up an EC2 instance on AWS with Ubuntu 22.04. 16gb of RAM, 128gb EBS - Set the security group for port 80 and 443 to all IP addresses. - Set a pem key -- Windows Cmds: +- Set up an elastic IP Address and attach it to the EC2 Instance. +- Set up a domain in Route53 or Google Domains to point to that Ec2 instance. +- Windows Cmds to get into the ec2 instance: - `icacls.exe filename.pem /reset` - `icacls.exe filename.pem /grant:r %username%:(R)` - `icacls.exe filename.pem /inheritance:r` @@ -54,33 +56,41 @@ Option 3 (Deploy on AWS EC2): - Linux Commands: - `chmod filename/pem 400` - `ssh -i "filename.pem" ubuntu@ec2instancepublicaddress` -- EC2 HTTPS encryption setup commands: - - `sudo apt-get install -y debian-keyring` - - `sudo apt-get install -y debian-archive-keyring` - - `sudo apt-get install -y apt-transport-https` - - `sudo keyring_location=/usr/share/keyrings/caddy-stable-archive-keyring.gpg` - - `curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/setup.deb.sh' | sudo -E bash` - - `sudo apt-get install caddy=2.6.4` - - `sudo caddy start` - EC2 App commands: - - `sudo apt-get update` - - `sudo apt-get remove docker docker-engine docker.io containerd runc` - - `sudo apt-get install ca-certificates curl gnupg` - - `curl -fsSL https://get.docker.com -o get-docker.sh` - - `sudo sh get-docker.sh` - - `sudo docker pull rcsnyder/streamlitapp:0.0.1` - - `sudo docker run -it --rm -p 8501:8501 --env OPENAI_API_KEY=xxxx --env OPENAI_ORG_NAME=xxxx rcsnyder/streamlitapp:0.0.2` + - ``` + sudo apt-get update + sudo apt-get remove docker docker-engine docker.io containerd runc + sudo apt-get install \ + ca-certificates \ + curl \ + gnupg + curl -fsSL https://get.docker.com -o get-docker.sh + sudo sh get-docker.sh + sudo docker pull rcsnyder/streamlitapp:0.0.2 + sudo apt-get install -y debian-keyring + sudo apt-get install -y debian-archive-keyring + sudo apt-get install -y apt-transport-https + sudo keyring_location=/usr/share/keyrings/caddy-stable-archive-keyring.gpg + curl -1sLf \ + 'https://dl.cloudsmith.io/public/caddy/stable/setup.deb.sh' \ + | sudo -E bash + sudo apt-get install caddy=2.6.4 + echo -e "DOMAINNAME.com {\n\treverse_proxy localhost:8501\n}" > Caddyfile | echo -e "PUBLIC_EC2IPADDRESS.nip.io {\n\treverse_proxy localhost:8501\n}" > Caddyfile + sudo caddy start + sudo docker run -it --rm -p 8501:8501 --env OPENAI_API_KEY=xxx --env OPENAI_ORG_NAME=xxx rcsnyder/streamlitapp:0.0.2 + ``` + - (Optional to get into the docker container) - - `sudo docker run --env OPENAI_API_KEY=xxxxx --env OPENAI_ORG_NAME=xxxx --rm -it -v /$(pwd)/src -p 8501:8501 --entrypoint bash rcsnyder/streamlitapp:0.0.1` + - `sudo docker run --env OPENAI_API_KEY=xxxxx --env OPENAI_ORG_NAME=xxxx --rm -it -v /$(pwd) -p 8501:8501 --entrypoint bash rcsnyder/streamlitapp:0.0.2` - `streamlit run app.py --server.headless true --browser.serverAddress="0.0.0.0" --server.enableCORS false --server.enableXsrfProtection=false --browser.gatherUsageStats false` -- Go to `publicEC2IP.nip.io` and choose your camera device and click start. +- Go to `PUBLIC_EC2IPADDRESS.nip.io` or `DOMAINNAME.com` and choose your camera device and click start. ### User Stories - [ x ] A user would like to be able to start up an app and talk to a chatbot that can percieve their emotions in real-time. -- [ ] A user would like to be able to choose their initial meta prompt when talking to the chatbot that can percieve their emotions in real-time. +- [ x ] A user would like to be able to choose their initial meta prompt when talking to the chatbot that can percieve their emotions in real-time. ### Technology Stack @@ -89,7 +99,7 @@ Option 3 (Deploy on AWS EC2): - Streamlit or Gradio - Huggingface Endpoints for emotion detecting pre-trained models - OpenAI large language models (Chat GPT) -- Hypermodern Python Coding Standards () +- Hypermodern Python Coding Standards () (Eventually) ### Inspiration Repos/Articles @@ -134,7 +144,7 @@ Option 3 (Deploy on AWS EC2): # TODO -- [ ] Flip the conversation history to show most recent messages first -- [ ] Make the form input chat text clear on change. -- [x] figure out how to continuously grab the video image to pipe into another emotion detection api -- [ ] figure out how to continuously update state with the emotion dictionary and wire it up to the chatbot prompt with the average since last updated. +- [ x ] Flip the conversation history to show most recent messages first +- [ x ] Make the form input chat text clear on change. +- [ x ] figure out how to continuously grab the video image to pipe into another emotion detection api +- [ x ] figure out how to continuously update state with the emotion dictionary and wire it up to the chatbot prompt with the normalized average since last updated.