Dirk Haupt commited on
Commit
b67dc9d
·
1 Parent(s): 234ceb7

init hf commit

Browse files
Files changed (5) hide show
  1. .gitignore +3 -0
  2. README.md +12 -4
  3. app.py +50 -0
  4. quickstart.py +220 -0
  5. requirements.txt +23 -0
.gitignore CHANGED
@@ -169,3 +169,6 @@ cython_debug/
169
 
170
  # PyPI configuration file
171
  .pypirc
 
 
 
 
169
 
170
  # PyPI configuration file
171
  .pypirc
172
+
173
+ .DS_Store
174
+ /llm
README.md CHANGED
@@ -1,8 +1,8 @@
1
  ---
2
- title: Emotional Game Theory Ai
3
- emoji: 📊
4
- colorFrom: pink
5
- colorTo: yellow
6
  sdk: streamlit
7
  sdk_version: 1.41.1
8
  app_file: app.py
@@ -12,3 +12,11 @@ short_description: Emotional Game Theory AI
12
  ---
13
 
14
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: Emotional Game Theory AI
3
+ emoji: 🎤
4
+ colorFrom: green
5
+ colorTo: purple
6
  sdk: streamlit
7
  sdk_version: 1.41.1
8
  app_file: app.py
 
12
  ---
13
 
14
  Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
15
+
16
+ # AI Safety Game Theory Experiment
17
+
18
+ An experimental application exploring how emotional data impacts AI decision-making in game-theoretic scenarios.
19
+
20
+ ## Setup
21
+
22
+ 1. Install dependencies:
app.py ADDED
@@ -0,0 +1,50 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import asyncio
3
+ from quickstart import WebSocketHandler, AsyncHumeClient, ChatConnectOptions, MicrophoneInterface
4
+ import os
5
+ from dotenv import load_dotenv
6
+
7
+ # Page config
8
+ st.set_page_config(
9
+ page_title="Hume.ai Voice Chat",
10
+ page_icon="🎤",
11
+ layout="centered"
12
+ )
13
+
14
+ st.title("Hume.ai Voice Chat Demo")
15
+
16
+ # Load environment variables
17
+ load_dotenv()
18
+
19
+ async def run_chat():
20
+ # Initialize client and handlers
21
+ client = AsyncHumeClient(api_key=st.secrets["HUME_API_KEY"])
22
+ options = ChatConnectOptions(
23
+ config_id=st.secrets["HUME_CONFIG_ID"],
24
+ secret_key=st.secrets["HUME_SECRET_KEY"]
25
+ )
26
+
27
+ websocket_handler = WebSocketHandler()
28
+
29
+ async with client.empathic_voice.chat.connect_with_callbacks(
30
+ options=options,
31
+ on_open=websocket_handler.on_open,
32
+ on_message=websocket_handler.on_message,
33
+ on_close=websocket_handler.on_close,
34
+ on_error=websocket_handler.on_error
35
+ ) as socket:
36
+ websocket_handler.set_socket(socket)
37
+
38
+ # Create microphone interface task
39
+ microphone_task = asyncio.create_task(
40
+ MicrophoneInterface.start(
41
+ socket,
42
+ allow_user_interrupt=False,
43
+ byte_stream=websocket_handler.byte_strs
44
+ )
45
+ )
46
+
47
+ await microphone_task
48
+
49
+ if st.button("Start Chat"):
50
+ asyncio.run(run_chat())
quickstart.py ADDED
@@ -0,0 +1,220 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # from https://github.com/HumeAI/hume-api-examples/blob/main/evi-python-example/quickstart.py
2
+
3
+ import asyncio
4
+ import base64
5
+ import datetime
6
+ import os
7
+ from dotenv import load_dotenv
8
+ from hume.client import AsyncHumeClient
9
+ from hume.empathic_voice.chat.socket_client import ChatConnectOptions, ChatWebsocketConnection
10
+ from hume.empathic_voice.chat.types import SubscribeEvent
11
+ from hume.empathic_voice.types import UserInput
12
+ from hume.core.api_error import ApiError
13
+ from hume import MicrophoneInterface, Stream
14
+
15
+ class WebSocketHandler:
16
+ """Handler for containing the EVI WebSocket and associated socket handling behavior."""
17
+
18
+ def __init__(self):
19
+ """Construct the WebSocketHandler, initially assigning the socket to None and the byte stream to a new Stream object."""
20
+ self.socket = None
21
+ self.byte_strs = Stream.new()
22
+
23
+ def set_socket(self, socket: ChatWebsocketConnection):
24
+ """Set the socket.
25
+
26
+ This method assigns the provided asynchronous WebSocket connection
27
+ to the instance variable `self.socket`. It is invoked after successfully
28
+ establishing a connection using the client's connect method.
29
+
30
+ Args:
31
+ socket (ChatWebsocketConnection): EVI asynchronous WebSocket returned by the client's connect method.
32
+ """
33
+ self.socket = socket
34
+
35
+ async def on_open(self):
36
+ """Logic invoked when the WebSocket connection is opened."""
37
+ print("WebSocket connection opened.")
38
+
39
+ async def on_message(self, message: SubscribeEvent):
40
+ """Callback function to handle a WebSocket message event.
41
+
42
+ This asynchronous method decodes the message, determines its type, and
43
+ handles it accordingly. Depending on the type of message, it
44
+ might log metadata, handle user or assistant messages, process
45
+ audio data, raise an error if the message type is "error", and more.
46
+
47
+ This method interacts with the following message types to demonstrate logging output to the terminal:
48
+ - [chat_metadata](https://dev.hume.ai/reference/empathic-voice-interface-evi/chat/chat#receive.Chat%20Metadata.type)
49
+ - [user_message](https://dev.hume.ai/reference/empathic-voice-interface-evi/chat/chat#receive.User%20Message.type)
50
+ - [assistant_message](https://dev.hume.ai/reference/empathic-voice-interface-evi/chat/chat#receive.Assistant%20Message.type)
51
+ - [audio_output](https://dev.hume.ai/reference/empathic-voice-interface-evi/chat/chat#receive.Audio%20Output.type)
52
+
53
+ Args:
54
+ data (SubscribeEvent): This represents any type of message that is received through the EVI WebSocket, formatted in JSON. See the full list of messages in the API Reference [here](https://dev.hume.ai/reference/empathic-voice-interface-evi/chat/chat#receive).
55
+ """
56
+
57
+ # Create an empty dictionary to store expression inference scores
58
+ scores = {}
59
+
60
+ if message.type == "chat_metadata":
61
+ message_type = message.type.upper()
62
+ chat_id = message.chat_id
63
+ chat_group_id = message.chat_group_id
64
+ text = f"<{message_type}> Chat ID: {chat_id}, Chat Group ID: {chat_group_id}"
65
+ elif message.type in ["user_message", "assistant_message"]:
66
+ role = message.message.role.upper()
67
+ message_text = message.message.content
68
+ text = f"{role}: {message_text}"
69
+ if message.from_text is False:
70
+ scores = dict(message.models.prosody.scores)
71
+ elif message.type == "audio_output":
72
+ message_str: str = message.data
73
+ message_bytes = base64.b64decode(message_str.encode("utf-8"))
74
+ await self.byte_strs.put(message_bytes)
75
+ return
76
+ elif message.type == "error":
77
+ error_message: str = message.message
78
+ error_code: str = message.code
79
+ raise ApiError(f"Error ({error_code}): {error_message}")
80
+ else:
81
+ message_type = message.type.upper()
82
+ text = f"<{message_type}>"
83
+
84
+ # Print the formatted message
85
+ self._print_prompt(text)
86
+
87
+ # Extract and print the top 3 emotions inferred from user and assistant expressions
88
+ if len(scores) > 0:
89
+ top_3_emotions = self._extract_top_n_emotions(scores, 3)
90
+ self._print_emotion_scores(top_3_emotions)
91
+ print("")
92
+ else:
93
+ print("")
94
+
95
+ async def on_close(self):
96
+ """Logic invoked when the WebSocket connection is closed."""
97
+ print("WebSocket connection closed.")
98
+
99
+ async def on_error(self, error):
100
+ """Logic invoked when an error occurs in the WebSocket connection.
101
+
102
+ See the full list of errors [here](https://dev.hume.ai/docs/resources/errors).
103
+
104
+ Args:
105
+ error (Exception): The error that occurred during the WebSocket communication.
106
+ """
107
+ print(f"Error: {error}")
108
+
109
+ def _print_prompt(self, text: str) -> None:
110
+ """Print a formatted message with a timestamp.
111
+
112
+ Args:
113
+ text (str): The message text to be printed.
114
+ """
115
+ now = datetime.datetime.now(tz=datetime.timezone.utc)
116
+ now_str = now.strftime("%H:%M:%S")
117
+ print(f"[{now_str}] {text}")
118
+
119
+ def _extract_top_n_emotions(self, emotion_scores: dict, n: int) -> dict:
120
+ """
121
+ Extract the top N emotions based on confidence scores.
122
+
123
+ Args:
124
+ emotion_scores (dict): A dictionary of emotions and their corresponding confidence scores.
125
+ n (int): The number of top emotions to extract.
126
+
127
+ Returns:
128
+ dict: A dictionary containing the top N emotions as keys and their raw scores as values.
129
+ """
130
+ # Convert the dictionary into a list of tuples and sort by the score in descending order
131
+ sorted_emotions = sorted(emotion_scores.items(), key=lambda item: item[1], reverse=True)
132
+
133
+ # Extract the top N emotions
134
+ top_n_emotions = {emotion: score for emotion, score in sorted_emotions[:n]}
135
+
136
+ return top_n_emotions
137
+
138
+ def _print_emotion_scores(self, emotion_scores: dict) -> None:
139
+ """
140
+ Print the emotions and their scores in a formatted, single-line manner.
141
+
142
+ Args:
143
+ emotion_scores (dict): A dictionary of emotions and their corresponding confidence scores.
144
+ """
145
+ # Format the output string
146
+ formatted_emotions = ' | '.join([f"{emotion} ({score:.2f})" for emotion, score in emotion_scores.items()])
147
+
148
+ # Print the formatted string
149
+ print(f"|{formatted_emotions}|")
150
+
151
+
152
+ async def sending_handler(socket: ChatWebsocketConnection):
153
+ """Handle sending a message over the socket.
154
+
155
+ This method waits 3 seconds and sends a UserInput message, which takes a `text` parameter as input.
156
+ - https://dev.hume.ai/reference/empathic-voice-interface-evi/chat/chat#send.User%20Input.type
157
+
158
+ See the full list of messages to send [here](https://dev.hume.ai/reference/empathic-voice-interface-evi/chat/chat#send).
159
+
160
+ Args:
161
+ socket (ChatWebsocketConnection): The WebSocket connection used to send messages.
162
+ """
163
+ # Wait 3 seconds before executing the rest of the method
164
+ await asyncio.sleep(3)
165
+
166
+ # Construct a user input message
167
+ # user_input_message = UserInput(text="Hello there!")
168
+
169
+ # Send the user input as text to the socket
170
+ # await socket.send_user_input(user_input_message)
171
+
172
+ async def main() -> None:
173
+ # Retrieve any environment variables stored in the .env file
174
+ load_dotenv()
175
+
176
+ # Retrieve the API key, Secret key, and EVI config id from the environment variables
177
+ HUME_API_KEY = os.getenv("HUME_API_KEY")
178
+ HUME_SECRET_KEY = os.getenv("HUME_SECRET_KEY")
179
+ HUME_CONFIG_ID = os.getenv("HUME_CONFIG_ID")
180
+
181
+ # Initialize the asynchronous client, authenticating with your API key
182
+ client = AsyncHumeClient(api_key=HUME_API_KEY)
183
+
184
+ # Define options for the WebSocket connection, such as an EVI config id and a secret key for token authentication
185
+ # See the full list of query parameters here: https://dev.hume.ai/reference/empathic-voice-interface-evi/chat/chat#request.query
186
+ options = ChatConnectOptions(config_id=HUME_CONFIG_ID, secret_key=HUME_SECRET_KEY)
187
+
188
+ # Instantiate the WebSocketHandler
189
+ websocket_handler = WebSocketHandler()
190
+
191
+ # Open the WebSocket connection with the configuration options and the handler's functions
192
+ async with client.empathic_voice.chat.connect_with_callbacks(
193
+ options=options,
194
+ on_open=websocket_handler.on_open,
195
+ on_message=websocket_handler.on_message,
196
+ on_close=websocket_handler.on_close,
197
+ on_error=websocket_handler.on_error
198
+ ) as socket:
199
+
200
+ # Set the socket instance in the handler
201
+ websocket_handler.set_socket(socket)
202
+
203
+ # Create an asynchronous task to continuously detect and process input from the microphone, as well as play audio
204
+ microphone_task = asyncio.create_task(
205
+ MicrophoneInterface.start(
206
+ socket,
207
+ allow_user_interrupt=False,
208
+ byte_stream=websocket_handler.byte_strs
209
+ )
210
+ )
211
+
212
+ # Create an asynchronous task to send messages over the WebSocket connection
213
+ message_sending_task = asyncio.create_task(sending_handler(socket))
214
+
215
+ # Schedule the coroutines to occur simultaneously
216
+ await asyncio.gather(microphone_task, message_sending_task)
217
+
218
+ # Execute the main asynchronous function using asyncio's event loop
219
+ if __name__ == "__main__":
220
+ asyncio.run(main())
requirements.txt ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ streamlit
2
+ python-dotenv
3
+ hume[microphone]
4
+
5
+ aiofiles==24.1.0
6
+ annotated-types==0.7.0
7
+ anyio==4.8.0
8
+ certifi==2025.1.31
9
+ cffi==1.17.1
10
+ eval-type-backport==0.2.2
11
+ h11==0.14.0
12
+ httpcore==1.0.7
13
+ httpx==0.28.1
14
+ idna==3.10
15
+ pycparser==2.22
16
+ pydantic==2.10.6
17
+ pydantic-core==2.27.2
18
+ pydub==0.25.1
19
+ simpleaudio==1.0.4
20
+ sniffio==1.3.1
21
+ sounddevice==0.4.7
22
+ typing-extensions==4.12.2
23
+ websockets==12.0