Spaces:
Running
Running
Update app.py
Browse files
app.py
CHANGED
@@ -32,10 +32,17 @@ load_dotenv()
|
|
32 |
|
33 |
SAMPLE_RATE = 24000
|
34 |
|
35 |
-
# Use Persistent Storage path
|
36 |
-
|
|
|
|
|
|
|
|
|
|
|
37 |
os.makedirs(PERSISTENT_DIR, exist_ok=True)
|
38 |
DB_PATH = os.path.join(PERSISTENT_DIR, "personal_assistant.db")
|
|
|
|
|
39 |
|
40 |
# HTML content embedded as a string
|
41 |
HTML_CONTENT = """<!DOCTYPE html>
|
@@ -397,12 +404,12 @@ HTML_CONTENT = """<!DOCTYPE html>
|
|
397 |
background: linear-gradient(135deg, #27ae60, #229954);
|
398 |
}
|
399 |
#end-session-button {
|
400 |
-
background: linear-gradient(135deg, #
|
401 |
padding: 8px 16px;
|
402 |
font-size: 13px;
|
403 |
}
|
404 |
#end-session-button:hover {
|
405 |
-
background: linear-gradient(135deg, #
|
406 |
}
|
407 |
#audio-output {
|
408 |
display: none;
|
@@ -562,7 +569,7 @@ HTML_CONTENT = """<!DOCTYPE html>
|
|
562 |
|
563 |
<div class="controls">
|
564 |
<button id="start-button">๋ํ ์์</button>
|
565 |
-
<button id="end-session-button" style="display: none;"
|
566 |
</div>
|
567 |
</div>
|
568 |
|
@@ -685,7 +692,7 @@ HTML_CONTENT = """<!DOCTYPE html>
|
|
685 |
}
|
686 |
} catch (error) {
|
687 |
console.error('Failed to end session:', error);
|
688 |
-
showError('
|
689 |
}
|
690 |
}
|
691 |
|
@@ -1489,11 +1496,20 @@ async def process_text_chat(message: str, web_search_enabled: bool, session_id:
|
|
1489 |
user_name: str = "", memories: Dict = None) -> Dict[str, str]:
|
1490 |
"""Process text chat using GPT-4o-mini model"""
|
1491 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1492 |
# Build system prompt with memories
|
1493 |
base_prompt = f"""You are a personal AI assistant for {user_name if user_name else 'the user'}.
|
1494 |
You remember all previous conversations and personal information about the user.
|
1495 |
Be friendly, helpful, and personalized in your responses.
|
1496 |
-
Always use the information you remember to make conversations more personal and relevant.
|
|
|
1497 |
|
1498 |
# Add memories to prompt
|
1499 |
if memories:
|
@@ -1577,6 +1593,8 @@ class OpenAIHandler(AsyncStreamHandler):
|
|
1577 |
self.session_id = session_id
|
1578 |
self.user_name = user_name
|
1579 |
self.memories = memories or {}
|
|
|
|
|
1580 |
|
1581 |
print(f"[INIT] Handler created with web_search={web_search_enabled}, session_id={session_id}, user={user_name}")
|
1582 |
|
@@ -1654,7 +1672,8 @@ class OpenAIHandler(AsyncStreamHandler):
|
|
1654 |
base_instructions = f"""You are a personal AI assistant for {self.user_name if self.user_name else 'the user'}.
|
1655 |
You remember all previous conversations and personal information about the user.
|
1656 |
Be friendly, helpful, and personalized in your responses.
|
1657 |
-
Always use the information you remember to make conversations more personal and relevant.
|
|
|
1658 |
|
1659 |
# Add memories to prompt
|
1660 |
if self.memories:
|
@@ -1695,7 +1714,12 @@ Always use the information you remember to make conversations more personal and
|
|
1695 |
model="gpt-4o-mini-realtime-preview-2024-12-17"
|
1696 |
) as conn:
|
1697 |
session_update = {
|
1698 |
-
"turn_detection": {
|
|
|
|
|
|
|
|
|
|
|
1699 |
"instructions": instructions,
|
1700 |
"tools": tools,
|
1701 |
"tool_choice": "auto" if tools else "none",
|
@@ -1710,7 +1734,37 @@ Always use the information you remember to make conversations more personal and
|
|
1710 |
print(f"Connected with tools: {len(tools)} functions")
|
1711 |
|
1712 |
async for event in self.connection:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1713 |
if event.type == "response.audio_transcript.done":
|
|
|
|
|
|
|
|
|
|
|
|
|
1714 |
print(f"[RESPONSE] Transcript: {event.transcript[:100]}...")
|
1715 |
|
1716 |
# Detect language
|
@@ -1731,7 +1785,17 @@ Always use the information you remember to make conversations more personal and
|
|
1731 |
}
|
1732 |
await self.output_queue.put(AdditionalOutputs(output_data))
|
1733 |
|
|
|
|
|
|
|
|
|
|
|
|
|
1734 |
elif event.type == "response.audio.delta":
|
|
|
|
|
|
|
|
|
1735 |
await self.output_queue.put(
|
1736 |
(
|
1737 |
self.output_sample_rate,
|
@@ -1847,6 +1911,17 @@ async def startup_event():
|
|
1847 |
await PersonalAssistantDB.init()
|
1848 |
print(f"Database initialized at: {DB_PATH}")
|
1849 |
print(f"Persistent directory: {PERSISTENT_DIR}")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1850 |
|
1851 |
# Intercept offer to capture settings
|
1852 |
@app.post("/webrtc/offer", include_in_schema=False)
|
|
|
32 |
|
33 |
SAMPLE_RATE = 24000
|
34 |
|
35 |
+
# Use Persistent Storage path for Hugging Face Space
|
36 |
+
# In HF Spaces, persistent storage is at /data
|
37 |
+
if os.path.exists("/data"):
|
38 |
+
PERSISTENT_DIR = "/data"
|
39 |
+
else:
|
40 |
+
PERSISTENT_DIR = "./data"
|
41 |
+
|
42 |
os.makedirs(PERSISTENT_DIR, exist_ok=True)
|
43 |
DB_PATH = os.path.join(PERSISTENT_DIR, "personal_assistant.db")
|
44 |
+
print(f"Using persistent directory: {PERSISTENT_DIR}")
|
45 |
+
print(f"Database path: {DB_PATH}")
|
46 |
|
47 |
# HTML content embedded as a string
|
48 |
HTML_CONTENT = """<!DOCTYPE html>
|
|
|
404 |
background: linear-gradient(135deg, #27ae60, #229954);
|
405 |
}
|
406 |
#end-session-button {
|
407 |
+
background: linear-gradient(135deg, #4a9eff, #3a7ed8);
|
408 |
padding: 8px 16px;
|
409 |
font-size: 13px;
|
410 |
}
|
411 |
#end-session-button:hover {
|
412 |
+
background: linear-gradient(135deg, #3a7ed8, #2a5eb8);
|
413 |
}
|
414 |
#audio-output {
|
415 |
display: none;
|
|
|
569 |
|
570 |
<div class="controls">
|
571 |
<button id="start-button">๋ํ ์์</button>
|
572 |
+
<button id="end-session-button" style="display: none;">๊ธฐ์ต ์
๋ฐ์ดํธ</button>
|
573 |
</div>
|
574 |
</div>
|
575 |
|
|
|
692 |
}
|
693 |
} catch (error) {
|
694 |
console.error('Failed to end session:', error);
|
695 |
+
showError('๊ธฐ์ต ์
๋ฐ์ดํธ ์ค ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค.');
|
696 |
}
|
697 |
}
|
698 |
|
|
|
1496 |
user_name: str = "", memories: Dict = None) -> Dict[str, str]:
|
1497 |
"""Process text chat using GPT-4o-mini model"""
|
1498 |
try:
|
1499 |
+
# Check for stop words
|
1500 |
+
stop_words = ["์ค๋จ", "๊ทธ๋ง", "์คํฑ", "stop", "๋ฅ์ณ", "๋ฉ์ถฐ", "์ค์ง"]
|
1501 |
+
if any(word in message.lower() for word in stop_words):
|
1502 |
+
return {
|
1503 |
+
"response": "๋ํ๋ฅผ ์ค๋จํฉ๋๋ค.",
|
1504 |
+
"detected_language": "ko"
|
1505 |
+
}
|
1506 |
+
|
1507 |
# Build system prompt with memories
|
1508 |
base_prompt = f"""You are a personal AI assistant for {user_name if user_name else 'the user'}.
|
1509 |
You remember all previous conversations and personal information about the user.
|
1510 |
Be friendly, helpful, and personalized in your responses.
|
1511 |
+
Always use the information you remember to make conversations more personal and relevant.
|
1512 |
+
IMPORTANT: Give only ONE response. Do not repeat or give multiple answers."""
|
1513 |
|
1514 |
# Add memories to prompt
|
1515 |
if memories:
|
|
|
1593 |
self.session_id = session_id
|
1594 |
self.user_name = user_name
|
1595 |
self.memories = memories or {}
|
1596 |
+
self.is_responding = False # Track if already responding
|
1597 |
+
self.should_stop = False # Track if conversation should stop
|
1598 |
|
1599 |
print(f"[INIT] Handler created with web_search={web_search_enabled}, session_id={session_id}, user={user_name}")
|
1600 |
|
|
|
1672 |
base_instructions = f"""You are a personal AI assistant for {self.user_name if self.user_name else 'the user'}.
|
1673 |
You remember all previous conversations and personal information about the user.
|
1674 |
Be friendly, helpful, and personalized in your responses.
|
1675 |
+
Always use the information you remember to make conversations more personal and relevant.
|
1676 |
+
IMPORTANT: Give only ONE response per user input. Do not repeat yourself or give multiple answers."""
|
1677 |
|
1678 |
# Add memories to prompt
|
1679 |
if self.memories:
|
|
|
1714 |
model="gpt-4o-mini-realtime-preview-2024-12-17"
|
1715 |
) as conn:
|
1716 |
session_update = {
|
1717 |
+
"turn_detection": {
|
1718 |
+
"type": "server_vad",
|
1719 |
+
"threshold": 0.5,
|
1720 |
+
"prefix_padding_ms": 300,
|
1721 |
+
"silence_duration_ms": 200
|
1722 |
+
},
|
1723 |
"instructions": instructions,
|
1724 |
"tools": tools,
|
1725 |
"tool_choice": "auto" if tools else "none",
|
|
|
1734 |
print(f"Connected with tools: {len(tools)} functions")
|
1735 |
|
1736 |
async for event in self.connection:
|
1737 |
+
# Handle user transcription for stop detection
|
1738 |
+
if event.type == "conversation.item.created":
|
1739 |
+
if hasattr(event, 'item') and hasattr(event.item, 'role') and event.item.role == "user":
|
1740 |
+
if hasattr(event.item, 'content') and event.item.content:
|
1741 |
+
for content_item in event.item.content:
|
1742 |
+
if hasattr(content_item, 'transcript'):
|
1743 |
+
user_text = content_item.transcript.lower()
|
1744 |
+
stop_words = ["์ค๋จ", "๊ทธ๋ง", "์คํฑ", "stop", "๋ฅ์ณ", "๋ฉ์ถฐ", "์ค์ง"]
|
1745 |
+
|
1746 |
+
if any(word in user_text for word in stop_words):
|
1747 |
+
print(f"[STOP DETECTED] User said: {content_item.transcript}")
|
1748 |
+
self.should_stop = True
|
1749 |
+
# Cancel any ongoing response
|
1750 |
+
if self.connection:
|
1751 |
+
try:
|
1752 |
+
await self.connection.response.cancel()
|
1753 |
+
except:
|
1754 |
+
pass
|
1755 |
+
continue
|
1756 |
+
|
1757 |
+
# Save user message to database
|
1758 |
+
if self.session_id:
|
1759 |
+
await PersonalAssistantDB.save_message(self.session_id, "user", content_item.transcript)
|
1760 |
+
|
1761 |
if event.type == "response.audio_transcript.done":
|
1762 |
+
# Prevent multiple responses
|
1763 |
+
if self.is_responding:
|
1764 |
+
print("[DUPLICATE RESPONSE] Skipping duplicate response")
|
1765 |
+
continue
|
1766 |
+
|
1767 |
+
self.is_responding = True
|
1768 |
print(f"[RESPONSE] Transcript: {event.transcript[:100]}...")
|
1769 |
|
1770 |
# Detect language
|
|
|
1785 |
}
|
1786 |
await self.output_queue.put(AdditionalOutputs(output_data))
|
1787 |
|
1788 |
+
elif event.type == "response.done":
|
1789 |
+
# Reset responding flag when response is complete
|
1790 |
+
self.is_responding = False
|
1791 |
+
self.should_stop = False
|
1792 |
+
print("[RESPONSE DONE] Response completed")
|
1793 |
+
|
1794 |
elif event.type == "response.audio.delta":
|
1795 |
+
# Check if we should stop
|
1796 |
+
if self.should_stop:
|
1797 |
+
continue
|
1798 |
+
|
1799 |
await self.output_queue.put(
|
1800 |
(
|
1801 |
self.output_sample_rate,
|
|
|
1911 |
await PersonalAssistantDB.init()
|
1912 |
print(f"Database initialized at: {DB_PATH}")
|
1913 |
print(f"Persistent directory: {PERSISTENT_DIR}")
|
1914 |
+
print(f"DB file exists: {os.path.exists(DB_PATH)}")
|
1915 |
+
|
1916 |
+
# Check if we're in Hugging Face Space
|
1917 |
+
if os.path.exists("/data"):
|
1918 |
+
print("Running in Hugging Face Space with persistent storage")
|
1919 |
+
# List files in persistent directory
|
1920 |
+
try:
|
1921 |
+
files = os.listdir(PERSISTENT_DIR)
|
1922 |
+
print(f"Files in persistent directory: {files}")
|
1923 |
+
except Exception as e:
|
1924 |
+
print(f"Error listing files: {e}")
|
1925 |
|
1926 |
# Intercept offer to capture settings
|
1927 |
@app.post("/webrtc/offer", include_in_schema=False)
|