Spaces:
Sleeping
Sleeping
Commit
·
c29d5e6
1
Parent(s):
1596990
Enhance response generation and add lead history check
Browse filesImproved the generate_response and generate_greeting functions to better tailor responses and greetings based on lead context (cold, warm, follow-up) and archetype, with more concise and context-aware instructions. Added a UI feature to check client history in Google Sheets during setup, automatically updating context if a previous interaction is found.
app.py
CHANGED
|
@@ -156,38 +156,40 @@ def analyze_full_context(model, user_input, current_node, chat_history):
|
|
| 156 |
except:
|
| 157 |
return {"archetype": "UNKNOWN", "intent": "STAY", "reasoning": "Error"}
|
| 158 |
|
| 159 |
-
def generate_response(model,
|
| 160 |
-
#
|
| 161 |
-
|
| 162 |
|
| 163 |
-
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
style_instruction = "STYLE: Logical, detailed. Use facts, numbers, and technical terms. Prove your point."
|
| 167 |
-
elif archetype == "EXPRESSIVE":
|
| 168 |
-
style_instruction = "STYLE: Energetic, inspiring. Use metaphors, exclamation marks. Focus on the 'Future Success'."
|
| 169 |
-
elif archetype == "CONSERVATIVE":
|
| 170 |
-
style_instruction = "STYLE: Calm, supportive, safe. Emphasize low risk, support, and ease of use. Don't push."
|
| 171 |
else:
|
| 172 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 173 |
|
| 174 |
if intent == "STAY":
|
| 175 |
prompt = f"""
|
| 176 |
-
ROLE:
|
| 177 |
-
|
|
|
|
| 178 |
|
| 179 |
-
SITUATION: Step "{
|
| 180 |
-
TASK: Handle objection
|
| 181 |
-
CONSTRAINT: Speak naturally in Ukrainian. Output ONLY the response.
|
| 182 |
"""
|
| 183 |
else:
|
| 184 |
prompt = f"""
|
| 185 |
-
ROLE:
|
| 186 |
-
|
|
|
|
| 187 |
|
| 188 |
-
GOAL: Transition to "{
|
| 189 |
-
TASK: Bridge to the next step
|
| 190 |
-
CONSTRAINT: Speak naturally in Ukrainian. Output ONLY the response.
|
| 191 |
"""
|
| 192 |
|
| 193 |
try:
|
|
@@ -195,32 +197,58 @@ def generate_response(model, context, user_input, intent, lead_info, archetype):
|
|
| 195 |
except: return "..."
|
| 196 |
|
| 197 |
def generate_greeting(model, start_node_text, lead_info):
|
| 198 |
-
"""
|
| 199 |
-
|
| 200 |
-
|
| 201 |
bot_name = lead_info.get('bot_name', 'Олексій')
|
| 202 |
-
client_name = lead_info.get('name', 'Клієнт')
|
| 203 |
company = lead_info.get('company', 'Компанія')
|
|
|
|
| 204 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 205 |
prompt = f"""
|
| 206 |
-
ROLE: Professional Sales Rep
|
| 207 |
CLIENT: {client_name} from {company}.
|
| 208 |
-
|
| 209 |
-
|
| 210 |
-
GOAL: Start conversation based on instruction: "{start_node_text}".
|
| 211 |
|
| 212 |
-
|
| 213 |
-
|
| 214 |
-
- If B2B: Be formal.
|
| 215 |
-
- If B2C: Be friendly.
|
| 216 |
-
- Language: Ukrainian.
|
| 217 |
-
|
| 218 |
-
OUTPUT: Just the spoken greeting.
|
| 219 |
"""
|
| 220 |
try:
|
| 221 |
return model.generate_content(prompt).text.strip()
|
| 222 |
except:
|
| 223 |
-
return f"
|
| 224 |
|
| 225 |
|
| 226 |
# --- UI COMPONENTS ---
|
|
@@ -343,6 +371,30 @@ elif st.session_state.page == "setup":
|
|
| 343 |
type_ = c1.selectbox("Тип бізнесу", ["B2B", "B2C"])
|
| 344 |
context = c2.selectbox("Контекст", ["Холодний дзвінок", "Теплий лід (заявка)", "Повторний дзвінок"])
|
| 345 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 346 |
submitted = st.form_submit_button("🚀 Почати розмову")
|
| 347 |
|
| 348 |
if submitted:
|
|
|
|
| 156 |
except:
|
| 157 |
return {"archetype": "UNKNOWN", "intent": "STAY", "reasoning": "Error"}
|
| 158 |
|
| 159 |
+
def generate_response(model, context_text, user_input, intent, lead_info, archetype):
|
| 160 |
+
# Визначаємо, наскільки детальним має бути спіч
|
| 161 |
+
call_context = lead_info.get('context', 'Cold')
|
| 162 |
|
| 163 |
+
verbosity_instruction = ""
|
| 164 |
+
if "Cold" in call_context or "Холодний" in call_context:
|
| 165 |
+
verbosity_instruction = "LENGTH: VERY SHORT. Elevator Pitch style. The client has no patience."
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 166 |
else:
|
| 167 |
+
verbosity_instruction = "LENGTH: Detailed and explanatory. The client is interested."
|
| 168 |
+
|
| 169 |
+
# Інструкція по стилю (з попередніх кроків)
|
| 170 |
+
style_instruction = ""
|
| 171 |
+
if archetype == "DRIVER": style_instruction = "STYLE: Direct, ROI-focused."
|
| 172 |
+
elif archetype == "ANALYST": style_instruction = "STYLE: Data-driven, precise."
|
| 173 |
+
elif archetype == "EXPRESSIVE": style_instruction = "STYLE: Visionary, exciting."
|
| 174 |
+
elif archetype == "CONSERVATIVE": style_instruction = "STYLE: Safe, supportive."
|
| 175 |
|
| 176 |
if intent == "STAY":
|
| 177 |
prompt = f"""
|
| 178 |
+
ROLE: Adaptive Sales Rep.
|
| 179 |
+
CONTEXT: {verbosity_instruction}
|
| 180 |
+
ARCHETYPE: {style_instruction}
|
| 181 |
|
| 182 |
+
SITUATION: Step "{context_text}". Client Objected: "{user_input}".
|
| 183 |
+
TASK: Handle objection.
|
|
|
|
| 184 |
"""
|
| 185 |
else:
|
| 186 |
prompt = f"""
|
| 187 |
+
ROLE: Adaptive Sales Rep.
|
| 188 |
+
CONTEXT: {verbosity_instruction}
|
| 189 |
+
ARCHETYPE: {style_instruction}
|
| 190 |
|
| 191 |
+
GOAL: Transition to "{context_text}". User said: "{user_input}".
|
| 192 |
+
TASK: Bridge to the next step naturally.
|
|
|
|
| 193 |
"""
|
| 194 |
|
| 195 |
try:
|
|
|
|
| 197 |
except: return "..."
|
| 198 |
|
| 199 |
def generate_greeting(model, start_node_text, lead_info):
|
| 200 |
+
"""
|
| 201 |
+
Генерує привітання залежно від КОНТЕКСТУ (Холодний vs Теплий).
|
| 202 |
+
"""
|
| 203 |
bot_name = lead_info.get('bot_name', 'Олексій')
|
| 204 |
+
client_name = lead_info.get('name', 'Клієнт')
|
| 205 |
company = lead_info.get('company', 'Компанія')
|
| 206 |
+
context = lead_info.get('context', 'Cold Call')
|
| 207 |
|
| 208 |
+
# Спеціальні інструкції для різних типів дзвінків
|
| 209 |
+
if "Cold" in context or "Холодний" in context:
|
| 210 |
+
# ХОЛОДНИЙ ДЗВІНОК: Жодних "я представляю компанію". Коротко, зухвало.
|
| 211 |
+
strategy = f"""
|
| 212 |
+
STRATEGY: COLD CALL (High Risk of Hangup).
|
| 213 |
+
RULES:
|
| 214 |
+
1. NO generic intros ("Hello, my name is... I represent...").
|
| 215 |
+
2. Use a "Pattern Interrupt" or "Permission-based opener".
|
| 216 |
+
3. Be brief (under 10 seconds).
|
| 217 |
+
|
| 218 |
+
Example format: "{client_name}? Це {bot_name}. Ми не знайомі, але я дзвоню щодо [Topic]. Маєте 30 секунд?"
|
| 219 |
+
"""
|
| 220 |
+
elif "Warm" in context or "Теплий" in context:
|
| 221 |
+
# ТЕПЛИЙ ЛІД: Клієнт чекає дзвінка.
|
| 222 |
+
strategy = """
|
| 223 |
+
STRATEGY: WARM LEAD (Inbound Request).
|
| 224 |
+
RULES:
|
| 225 |
+
1. Acknowledge their request immediately.
|
| 226 |
+
2. Verify it's a good time to talk.
|
| 227 |
+
3. Tone: Helpful, responsive.
|
| 228 |
+
|
| 229 |
+
Example format: "Вітаю, {client_name}! Це {bot_name} з SellMe. Ви залишали заявку на сайті, зручно зараз?"
|
| 230 |
+
"""
|
| 231 |
+
else:
|
| 232 |
+
# FOLLOW-UP: Ми вже говорили.
|
| 233 |
+
strategy = """
|
| 234 |
+
STRATEGY: FOLLOW-UP.
|
| 235 |
+
RULES:
|
| 236 |
+
1. Remind who you are immediately.
|
| 237 |
+
2. Reference previous context.
|
| 238 |
+
"""
|
| 239 |
+
|
| 240 |
prompt = f"""
|
| 241 |
+
ROLE: Professional Sales Rep ({bot_name}).
|
| 242 |
CLIENT: {client_name} from {company}.
|
| 243 |
+
CONTEXT: {strategy}
|
|
|
|
|
|
|
| 244 |
|
| 245 |
+
TASK: Generate the opening phrase based on the instruction: "{start_node_text}".
|
| 246 |
+
LANGUAGE: Ukrainian.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 247 |
"""
|
| 248 |
try:
|
| 249 |
return model.generate_content(prompt).text.strip()
|
| 250 |
except:
|
| 251 |
+
return f"{client_name}? Це {bot_name}."
|
| 252 |
|
| 253 |
|
| 254 |
# --- UI COMPONENTS ---
|
|
|
|
| 371 |
type_ = c1.selectbox("Тип бізнесу", ["B2B", "B2C"])
|
| 372 |
context = c2.selectbox("Контекст", ["Холодний дзвінок", "Теплий лід (заявка)", "Повторний дзвінок"])
|
| 373 |
|
| 374 |
+
# --- ПЕРЕВІРКА ІСТОРІЇ ---
|
| 375 |
+
# Спробуємо знайти клієнта в базі (якщо підключено Google Sheets)
|
| 376 |
+
if st.checkbox("🔍 Перевірити в базі (за ім'ям)"):
|
| 377 |
+
try:
|
| 378 |
+
# Це працює, якщо у нас є leads_manager з Google Sheets
|
| 379 |
+
from leads_manager import connect_to_gsheet
|
| 380 |
+
sheet = connect_to_gsheet()
|
| 381 |
+
if sheet:
|
| 382 |
+
records = sheet.get_all_records()
|
| 383 |
+
found = [r for r in records if str(r['Name']).lower() == name.lower()]
|
| 384 |
+
|
| 385 |
+
if found:
|
| 386 |
+
last_interaction = found[-1] # Останній запис
|
| 387 |
+
st.info(f"📜 Знайдено історію! Останній контакт: {last_interaction['Date']}")
|
| 388 |
+
st.warning(f"Результат минулого разу: {last_interaction['Outcome']}")
|
| 389 |
+
st.caption(f"Нотатки: {last_interaction.get('Summary', '')}")
|
| 390 |
+
|
| 391 |
+
# Можна автоматично змінити контекст на "Повторний"
|
| 392 |
+
context = "Повторний дзвінок"
|
| 393 |
+
else:
|
| 394 |
+
st.success("✨ Новий клієнт")
|
| 395 |
+
except Exception as e:
|
| 396 |
+
st.error("База даних недоступна.")
|
| 397 |
+
|
| 398 |
submitted = st.form_submit_button("🚀 Почати розмову")
|
| 399 |
|
| 400 |
if submitted:
|