Spaces:
Sleeping
Sleeping
Dirk Haupt
commited on
Commit
·
480eede
1
Parent(s):
2065479
add timer and game phases
Browse files- app_streamlit_old.py +79 -0
- timer.py +52 -0
app_streamlit_old.py
CHANGED
@@ -3,6 +3,10 @@ import asyncio
|
|
3 |
from quickstart import WebSocketHandler, AsyncHumeClient, ChatConnectOptions, MicrophoneInterface, SubscribeEvent
|
4 |
import os
|
5 |
from dotenv import load_dotenv
|
|
|
|
|
|
|
|
|
6 |
|
7 |
# Page config
|
8 |
st.set_page_config(
|
@@ -21,6 +25,18 @@ if 'messages' not in st.session_state:
|
|
21 |
st.session_state.messages = []
|
22 |
st.session_state.recording = False
|
23 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
24 |
class StreamlitWebSocketHandler(WebSocketHandler):
|
25 |
async def on_message(self, message: SubscribeEvent):
|
26 |
await super().on_message(message)
|
@@ -75,6 +91,21 @@ async def run_chat():
|
|
75 |
|
76 |
await microphone_task
|
77 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
78 |
# Display welcome message
|
79 |
if len(st.session_state.messages) == 0:
|
80 |
st.info("Welcome to the Hume.ai Voice Chat Demo! Click the button below to start chatting.")
|
@@ -98,3 +129,51 @@ with col2:
|
|
98 |
st.session_state.messages = []
|
99 |
st.session_state.recording = False
|
100 |
st.rerun()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3 |
from quickstart import WebSocketHandler, AsyncHumeClient, ChatConnectOptions, MicrophoneInterface, SubscribeEvent
|
4 |
import os
|
5 |
from dotenv import load_dotenv
|
6 |
+
from dataclasses import dataclass, field
|
7 |
+
from typing import List, Dict
|
8 |
+
import time
|
9 |
+
from timer import AsyncTimer
|
10 |
|
11 |
# Page config
|
12 |
st.set_page_config(
|
|
|
25 |
st.session_state.messages = []
|
26 |
st.session_state.recording = False
|
27 |
|
28 |
+
@dataclass
|
29 |
+
class GameState:
|
30 |
+
round: int = 1
|
31 |
+
chat_group_id: str = None
|
32 |
+
user_decisions: List[str] = field(default_factory=list)
|
33 |
+
ai_decisions: List[str] = field(default_factory=list)
|
34 |
+
conversation_history: List[Dict] = field(default_factory=list)
|
35 |
+
emotion_history: List[Dict] = field(default_factory=list)
|
36 |
+
scores: Dict[str, int] = field(default_factory=lambda: {"user": 0, "ai": 0})
|
37 |
+
phase: str = "INIT" # INIT, CONVERSATION, USER_DECISION, AI_DECISION, RESULTS, NEXT_ROUND
|
38 |
+
timer_start: float = None
|
39 |
+
|
40 |
class StreamlitWebSocketHandler(WebSocketHandler):
|
41 |
async def on_message(self, message: SubscribeEvent):
|
42 |
await super().on_message(message)
|
|
|
91 |
|
92 |
await microphone_task
|
93 |
|
94 |
+
async def handle_conversation_phase():
|
95 |
+
"""Handle the CONVERSATION phase with timer and chat"""
|
96 |
+
timer_placeholder = st.empty()
|
97 |
+
|
98 |
+
async def on_timer_complete():
|
99 |
+
st.session_state.game.phase = "USER_DECISION"
|
100 |
+
st.session_state.game.timer_start = None
|
101 |
+
st.rerun()
|
102 |
+
|
103 |
+
timer = AsyncTimer(30, on_timer_complete, timer_placeholder)
|
104 |
+
await asyncio.gather(
|
105 |
+
timer.start(),
|
106 |
+
run_chat()
|
107 |
+
)
|
108 |
+
|
109 |
# Display welcome message
|
110 |
if len(st.session_state.messages) == 0:
|
111 |
st.info("Welcome to the Hume.ai Voice Chat Demo! Click the button below to start chatting.")
|
|
|
129 |
st.session_state.messages = []
|
130 |
st.session_state.recording = False
|
131 |
st.rerun()
|
132 |
+
|
133 |
+
# Initialize session state
|
134 |
+
if 'game' not in st.session_state:
|
135 |
+
st.session_state.game = GameState()
|
136 |
+
|
137 |
+
# Game UI based on phase
|
138 |
+
if st.session_state.game.phase == "INIT":
|
139 |
+
if st.button("Start Game"):
|
140 |
+
st.session_state.game.phase = "CONVERSATION"
|
141 |
+
st.session_state.game.timer_start = time.time()
|
142 |
+
st.rerun()
|
143 |
+
|
144 |
+
elif st.session_state.game.phase == "CONVERSATION":
|
145 |
+
asyncio.run(handle_conversation_phase())
|
146 |
+
|
147 |
+
elif st.session_state.game.phase == "USER_DECISION":
|
148 |
+
col1, col2 = st.columns(2)
|
149 |
+
with col1:
|
150 |
+
if st.button("Cooperate"):
|
151 |
+
st.session_state.game.user_decisions.append("C")
|
152 |
+
st.session_state.game.phase = "AI_DECISION"
|
153 |
+
st.rerun()
|
154 |
+
with col2:
|
155 |
+
if st.button("Defect"):
|
156 |
+
st.session_state.game.user_decisions.append("D")
|
157 |
+
st.session_state.game.phase = "AI_DECISION"
|
158 |
+
st.rerun()
|
159 |
+
|
160 |
+
elif st.session_state.game.phase == "AI_DECISION":
|
161 |
+
# Run AI decision chat
|
162 |
+
asyncio.run(run_chat())
|
163 |
+
|
164 |
+
elif st.session_state.game.phase == "RESULTS":
|
165 |
+
# Display round results
|
166 |
+
# Update scores
|
167 |
+
if st.button("Next Round"):
|
168 |
+
st.session_state.game.round += 1
|
169 |
+
st.session_state.game.phase = "CONVERSATION"
|
170 |
+
st.session_state.game.timer_start = time.time()
|
171 |
+
st.rerun()
|
172 |
+
|
173 |
+
def check_timer():
|
174 |
+
if st.session_state.game.timer_start:
|
175 |
+
elapsed = time.time() - st.session_state.game.timer_start
|
176 |
+
if elapsed >= 30:
|
177 |
+
st.session_state.game.phase = "USER_DECISION"
|
178 |
+
st.session_state.game.timer_start = None
|
179 |
+
st.rerun()
|
timer.py
ADDED
@@ -0,0 +1,52 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import asyncio
|
2 |
+
import time
|
3 |
+
import streamlit as st
|
4 |
+
from typing import Callable, Optional
|
5 |
+
|
6 |
+
class AsyncTimer:
|
7 |
+
def __init__(self, duration: int, on_complete: Callable, placeholder: Optional[st.empty] = None):
|
8 |
+
"""
|
9 |
+
Initialize async timer
|
10 |
+
|
11 |
+
Args:
|
12 |
+
duration: Duration in seconds
|
13 |
+
on_complete: Callback function to run when timer completes
|
14 |
+
placeholder: Optional streamlit placeholder to display timer
|
15 |
+
"""
|
16 |
+
self.duration = duration
|
17 |
+
self.on_complete = on_complete
|
18 |
+
self.placeholder = placeholder or st.empty()
|
19 |
+
self.start_time = None
|
20 |
+
self.is_running = False
|
21 |
+
|
22 |
+
def format_time(self, seconds: int) -> str:
|
23 |
+
"""Format seconds into MM:SS"""
|
24 |
+
mm, ss = seconds//60, seconds%60
|
25 |
+
return f"{mm:02d}:{ss:02d}"
|
26 |
+
|
27 |
+
async def start(self):
|
28 |
+
"""Start the countdown timer"""
|
29 |
+
self.start_time = time.time()
|
30 |
+
self.is_running = True
|
31 |
+
|
32 |
+
while self.is_running:
|
33 |
+
elapsed = int(time.time() - self.start_time)
|
34 |
+
remaining = max(0, self.duration - elapsed)
|
35 |
+
|
36 |
+
# Update display
|
37 |
+
self.placeholder.metric(
|
38 |
+
"Time Remaining",
|
39 |
+
self.format_time(remaining)
|
40 |
+
)
|
41 |
+
|
42 |
+
# Check if timer completed
|
43 |
+
if remaining <= 0:
|
44 |
+
self.is_running = False
|
45 |
+
await self.on_complete()
|
46 |
+
break
|
47 |
+
|
48 |
+
await asyncio.sleep(0.1) # Small delay to prevent excessive updates
|
49 |
+
|
50 |
+
def stop(self):
|
51 |
+
"""Stop the timer"""
|
52 |
+
self.is_running = False
|