Spaces:
Running
Running
File size: 7,571 Bytes
a31f556 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | """
modules/conversation.py β FRIDAY Continuous Conversation Engine
REMOVES THE WAKE WORD BARRIER:
- Free-talk mode - no "hey FRIDAY" needed
- Context carries across turns
- Intent detection, not just commands
- Seamless multi-turn conversations
"""
import time
import json
import os
from config import DATA_DIR
CONV_FILE = os.path.join(DATA_DIR, "conversation.json")
def _load() -> dict:
if not os.path.exists(CONV_FILE):
return {"mode": "command", "context": {}, "last_intent": "", "free_talk": False}
try:
with open(CONV_FILE, "r") as f:
return json.load(f)
except Exception:
return {"mode": "command", "context": {}, "last_intent": "", "free_talk": False}
def _save(data: dict):
os.makedirs(DATA_DIR, exist_ok=True)
try:
with open(CONV_FILE, "w") as f:
json.dump(data, f, indent=2)
except Exception:
pass
# ββ Mode Control ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
def enable_free_talk(enabled: bool = True):
"""Enable/disable free-talk mode."""
data = _load()
data["free_talk"] = enabled
data["mode"] = "free_talk" if enabled else "command"
_save(data)
def is_free_talk() -> bool:
"""Check if free-talk is enabled."""
return _load().get("free_talk", False)
def get_mode() -> str:
"""Get current conversation mode."""
return _load().get("mode", "command")
# ββ Intent Detection ββββββββββββββββββββββββββββββββββββββββββββ
def detect_intent(text: str) -> str:
"""Detect intent from text."""
t = (text or "").lower()
# Question intents
if any(w in t for w in ["what", "how", "why", "when", "where", "which", "?"]):
return "question"
# Command intents
if any(t.startswith(w) for w in ["open", "close", "start", "stop", "play", "pause", "set", "turn"]):
return "command"
# Request intents
if any(w in t for w in ["can you", "please", "would you", "could", "help me"]):
return "request"
# Statement intents
if any(w in t for w in ["i am", "i'm", "feeling", "working on", "doing"]):
return "statement"
# Opinion intents
if any(w in t for w in ["think", "believe", "opinion", "should i"]):
return "opinion"
# Greeting intents
if any(w in t for w in ["hey", "hi", "hello", "yo", "bro"]):
return "greeting"
# Emotional intents
if any(w in t for w in ["frustrated", "annoyed", "happy", "excited", "sad", "tired"]):
return "emotion"
return "statement"
# ββ Context Management ββββββββββββββββββββββββββββββββββββββββββββ
def set_context(key: str, value):
"""Set conversation context."""
data = _load()
data.setdefault("context", {})[key] = value
_save(data)
def get_context(key: str):
"""Get conversation context."""
return _load().get("context", {}).get(key)
def clear_context():
"""Clear conversation context."""
data = _load()
data["context"] = {}
_save(data)
# ββ Multi-turn Continuation βββββββββββββββββββββββββββββββββββββββββ
def is_follow_up(text: str) -> bool:
"""Check if this is a follow-up to previous turn."""
t = (text or "").lower()
# Follow-up words
follow_ups = ["that", "it", "them", "this", "also", "and", "but", "again", "more", "yes", "no", "ok", "sure"]
# Pronouns that need context
pronouns = ["it", "that", "this", "them", "they", "he", "she", "you", "we"]
# Check for follow-up patterns
first_word = t.split()[0] if t.split() else ""
if first_word in follow_ups:
return True
# Short responses that need context
if len(t.split()) <= 3 and first_word in pronouns:
return True
return False
def get_follow_up_context() -> dict:
"""Get context needed for follow-up."""
data = _load()
return data.get("context", {})
# ββ Should Respond βββββββββββββββββββββββββββββββββββββββββββββββββ
def should_respond(text: str) -> bool:
"""Decide if FRIDAY should respond without wake word."""
# Check free-talk mode
if not is_free_talk():
return False
t = (text or "").strip()
if not t:
return False
# Check for name mentions
if "friday" in t.lower() or "jarvis" in t.lower():
return True
# Check for direct address
if any(t.lower().startswith(w) for w in ["hey", "hi", "yo", "bro", "ok"]):
return True
# Follow-ups always respond
if is_follow_up(t):
return True
# Check for question
if "?" in t:
return True
# Short commands without wake word
if detect_intent(t) == "command" and len(t.split()) <= 4:
return True
return False
# ββ Natural Response Generation ββββββββββββββββββββββββββββββββββββββββ
def get_natural_response(intent: str, context: dict) -> str:
"""Generate natural response based on intent."""
responses = {
"question": [
"Good question. Let me think.",
"Here's what I know:",
"Let me look into that.",
],
"command": [
"On it.",
"Done.",
"Consider it done.",
],
"request": [
"Got it.",
"Sure thing.",
"I'll handle it.",
],
"statement": [
"Interesting.",
"Got it.",
"Noted.",
],
"emotion": [
"I hear you.",
"Got it.",
"I'm here.",
],
}
intents = responses.get(intent, responses["statement"])
import random
return random.choice(intents)
# ββ Brain Integration βββββββββββββββββββββββββββββββββββββββββ
def prepare_for_brain(text: str) -> dict:
"""Prepare conversation context for brain."""
intent = detect_intent(text)
data = _load()
# Update context
data["last_intent"] = intent
data["last_text"] = text
data["last_time"] = time.time()
_save(data)
return {
"mode": get_mode(),
"intent": intent,
"context": get_follow_up_context(),
"is_follow_up": is_follow_up(text),
"should_respond": should_respond(text),
}
# ββ Toggle via Command ββββββββββββββββββββββββββββββββββββββββββ
def toggle_free_talk_command(enable: bool = None) -> str:
"""Toggle free-talk mode via voice command."""
if enable is None:
enable = not is_free_talk()
enable_free_talk(enable)
if enable:
return "Free talk enabled. Just talk to me."
else:
return "Free talk disabled. Say my name to get my attention." |