Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 30 additions & 29 deletions gigaam_transcriber/llm_cascade.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,49 +26,50 @@
# ─── Layer 1: Classification ────────────────────────────────────


CLASSIFIER_SYSTEM_PROMPT = """Ты — классификатор фрагментов делового диалога.
Проанализируй фрагмент транскрипта и классифицируй его.
CLASSIFIER_SYSTEM_PROMPT = """Ты — классификатор фрагментов B2B-продажного диалога.
Определи, содержит ли фрагмент значимое для менеджера по продажам событие.

Категории:
- "neutral" — рутина, small talk, обычное обсуждение без значимых событий
- "objection" — возражение клиента (дорого, не подходит, подумаем, уже работаем с другими)
- "price_question" — вопрос или обсуждение цены, скидок, бюджета, условий оплаты
- "competitor_mention" — упоминание конкурента или альтернативного поставщика
- "clarification" — запрос уточнения от клиента (важно, но не возражение)
- "commitment_signal" — сигнал готовности к сделке (договорились, ок, согласен)
- "silence" — пауза в разговоре
- "neutral" — рутина, small talk, пустая фраза, обычное изложение без триггера
- "objection" — возражение: дорого, не подходит, подумаем, не готовы, не уверены, у других лучше
- "price_question" — обсуждение цены, бюджета, скидок, условий оплаты, ROI, сроков окупаемости
- "competitor_mention" — упоминание конкурента, альтернативы, сравнение с другим продуктом
- "buying_signal" — клиент спрашивает о деталях внедрения, сроках, демо, следующих шагах, договоре
- "need_expression" — клиент описывает свою проблему, боль, потребность, чего ему не хватает
- "clarification" — запрос уточнения, технический вопрос, сомнение в понимании

ВАЖНО: Классифицируй как НЕ-neutral ТОЛЬКО если есть конкретное значимое событие.
Нейтральные обсуждения, приветствия, small talk — всегда "neutral".
Классифицируй щедро: если есть хоть намёк на значимое событие — НЕ neutral.
Приветствия, прощания, «да-да», «понял» без контекста — neutral.

Ответь ТОЛЬКО валидным JSON:
{"classification": "<category>", "confidence": 0.0-1.0, "excerpt": "<ключевая фраза>"}"""
Ответь ТОЛЬКО JSON: {"classification": "<category>", "confidence": 0.0-1.0, "excerpt": "<фраза>"}"""


# ─── Layer 2: Advisory ──────────────────────────────────────────


ADVISOR_SYSTEM_PROMPT = """Ты — ассистент менеджера B2B-продаж. На основе контекста встречи и фрагмента диалога дай подсказку.
ADVISOR_SYSTEM_PROMPT = """Ты — live-советник менеджера B2B-продаж. Менеджер сейчас на звонке с клиентом. Дай ОДНУ короткую, конкретную подсказку.

Типы подсказок:
- "tactical" — немедленное действие (что сказать/спросить прямо сейчас)
- "strategic" — направление разговора (куда вести диалог)
- "warning" — предупреждение (риск, конкурент, возражение)
- "analytical" — аналитическое наблюдение (тенденция, сдвиг в обсуждении)
Типы:
- "tactical" — что СКАЗАТЬ или СПРОСИТЬ прямо сейчас (конкретная фраза или вопрос)
- "strategic" — куда ВЕСТИ разговор дальше (переход к теме, техника закрытия)
- "warning" — ОПАСНОСТЬ: необработанное возражение, уход клиента, конкурент, ошибка менеджера
- "analytical" — НАБЛЮДЕНИЕ: клиент проявил интерес, сменил тон, подал покупательский сигнал

Приоритеты: "critical", "high", "medium", "low"
Приоритеты:
- "critical" — клиент уходит, сделка под угрозой, нужно действовать СЕЙЧАС
- "high" — возражение, конкурент, покупательский сигнал — важно не упустить
- "medium" — полезный совет, можно учесть
- "low" — фоновое наблюдение

ПРАВИЛА:
- Не повторяй подсказки, которые уже давались (см. историю)
- Учитывай фазу переговоров и накопленные факты
- Не выдумывай данные — опирайся только на транскрипт и контекст
- Не давай юридических/финансовых гарантий
- Не рекомендуй манипулятивные техники
ФОРМАТ подсказки:
- 1-2 предложения максимум. Менеджер читает на ходу — ему некогда
- Для tactical: дай ГОТОВУЮ фразу в кавычках или конкретный вопрос
- Ссылайся на слова клиента из транскрипта

{feedback_bias}

Ответь ТОЛЬКО валидным JSON:
{"type": "<tactical|strategic|warning|analytical>", "text": "<подсказка>", "priority": "<critical|high|medium|low>", "rationale": "<почему эта подсказка>"}"""
Ответь ТОЛЬКО JSON:
{{"type": "<tactical|strategic|warning|analytical>", "text": "<подсказка>", "priority": "<critical|high|medium|low>", "rationale": "<почему>"}}"""


@dataclass
Expand All @@ -81,7 +82,7 @@ class ClassificationResult:
@property
def is_significant(self) -> bool:
"""Whether this fragment should trigger Layer 2."""
return self.classification != "neutral" and self.confidence >= 0.5
return self.classification != "neutral" and self.confidence >= 0.3


class LLMCascade:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ readme = "README.md"
license = {text = "MIT"}
requires-python = ">=3.10"
authors = [
{name = "GigaAM Transcriber", email = ""}
{name = "GigaAM Transcriber"}
]
keywords = [
"transcription",
Expand Down
4 changes: 2 additions & 2 deletions routers/live_hints.py
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ async def live_hints_ws(ws: WebSocket):

# ── Live Advisor: cascade hint generation ───────
cascade_hint_sent = False
min_cascade_interval = 20.0 # seconds between cascade hints
min_cascade_interval = 8.0
if trigger_event and event_detector.should_trigger(trigger_event) and (now - last_hint_time) >= min_cascade_interval:
event_detector.mark_event_processed()
event_detector.reset_timer()
Expand Down Expand Up @@ -291,7 +291,7 @@ async def live_hints_ws(ws: WebSocket):
if (
not cascade_hint_sent
and session_config
and now - last_hint_time >= 10.0
and now - last_hint_time >= 15.0
):
last_hint_time = now
full_transcript = "\n".join(transcript_segments)
Expand Down