143 lines
No EOL
6.9 KiB
Python
143 lines
No EOL
6.9 KiB
Python
#!/usr/bin/env python
|
||
"""Хардас — сборщик потребностей клиентов студии (t-261002072440-c482ca).
|
||
|
||
Мандат Alex (голосовое m-516173358): поставить хардас клиентам студии,
|
||
которые его ждут; потребностиclients собирать самим, дёргая Alex
|
||
поменьше. Этот скрипт — двигалка фазы «сбор»:
|
||
|
||
survey — отправить опросник потребностей клиенту в его чат
|
||
(Telegram через штатный tg_inbox — тот же бот, что и реплаи;
|
||
ключ идемпотентности задаётся --key, повтор = SKIP без дубля);
|
||
collect — пройтись по недавним чатам (TG-инбокс стора) и выписать
|
||
сигналы потребностей в docs/hardass/needs/needs-<period>.md
|
||
(дедуп: повторный запуск не плодит копий — перезаписывает
|
||
период); потребности агрегируются, сырье остаётся в сторе.
|
||
|
||
Использование:
|
||
./venv/bin/python scripts/needs_survey.py survey --key needs-2026-10-w1
|
||
./venv/bin/python scripts/needs_survey.py collect
|
||
|
||
Опросник сформулирован по фактическому составу поставки (см.
|
||
docs/hardass/INSTALL.md, PACKAGE-SIMBIOT-PRESALE.md): спрашиваем о том,
|
||
что харнес реально умеет сейчас.
|
||
"""
|
||
import argparse
|
||
import json
|
||
import os
|
||
import sys
|
||
from datetime import datetime, timezone
|
||
|
||
ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||
sys.path.insert(0, ROOT)
|
||
|
||
NEEDS_DIR = os.path.join(ROOT, "docs", "hardass", "needs")
|
||
|
||
SURVEY_TEXT = """🤖 Хардас подключён — опрос потребностей (1 мин, можно голосом)
|
||
|
||
Я — ваш личный хардас Simbiot: живу тактами, сам выполняю задачи и
|
||
докладываю по графику. Чтобы настроить меня под вас, ответьте на 4
|
||
коротких блока — можно в одном сообщении или голосовыми:
|
||
|
||
1️⃣ РУТИНА: какие 2-3 повторяющихся дела хочется отдать хардасу
|
||
(например: отчёты, мониторинг, файлы, письма, посты).
|
||
|
||
2️⃣ ЧАТ И РИТМ: как удобнее общаться — здесь (Telegram-бот) или
|
||
на портале (страница чата)? Прислать дневной итог работы в удобное время?
|
||
|
||
3️⃣ ЗНАНИЯ: что хардасу стоит знать о вашем деле (ссылки/доки/описание
|
||
процессов) — пришлите что есть, я проиндексирую и буду отвечать по ним.
|
||
|
||
4️⃣ БОЛЬ ПРЯМО СЕЙЧАС: что сегодня делается вручную и раздражает больше
|
||
всего? С этого начну — первую автоматизацию возьму в работу сам.
|
||
|
||
Ответы копятся в базе потребностей — реализация идёт по ним без
|
||
лишних вопросов. 🚀"""
|
||
|
||
SURVEY_KEY = "needs-survey-v1"
|
||
|
||
|
||
def send_survey(key: str) -> str:
|
||
"""Отправка опросника: идемпотентно через deliver_artifact."""
|
||
from harness import commands, tg_inbox, es
|
||
es.init_db()
|
||
aid = f"msg:{key or SURVEY_KEY}"
|
||
|
||
def _send():
|
||
return bool(tg_inbox.notify_chat(SURVEY_TEXT))
|
||
|
||
ok = commands.deliver_artifact(aid, kind="message", send=_send,
|
||
owner="needs-survey", caption="needs-survey")
|
||
return ("OK: опросник отправлен" if ok
|
||
else "SKIP: уже доставлен (или некому отправить / чужой захват)")
|
||
|
||
|
||
def _signals_from_inbox(limit_per_chat: int = 12):
|
||
"""Свежие входящие из стора по всем чатам (без сырья наружу — тезисы)."""
|
||
from harness import es
|
||
model = es.run_projections()
|
||
out = {}
|
||
for mid, m in sorted((model.get("inbox") or {}).items(),
|
||
key=lambda kv: str(kv[1].get("date") or ""))[-60:]:
|
||
if not isinstance(m, dict):
|
||
continue
|
||
chat = str(m.get("chat_id") or "?")
|
||
text = str(m.get("transcript") or m.get("text") or "").strip()
|
||
if not text:
|
||
continue
|
||
out.setdefault(chat, []).append({
|
||
"mid": mid,
|
||
"who": str(m.get("first_name") or m.get("username") or "")[:40],
|
||
"date": str(m.get("date") or "")[:19],
|
||
"kind": str(m.get("kind") or "text"),
|
||
"text": text[:600],
|
||
})
|
||
return {c: v[-limit_per_chat:] for c, v in out.items()}
|
||
|
||
|
||
def collect() -> str:
|
||
"""Агрегация сигналов потребностей в docs/hardass/needs/."""
|
||
os.makedirs(NEEDS_DIR, exist_ok=True)
|
||
period = datetime.now(timezone.utc).strftime("%Y-%m-%d_%H")
|
||
path = os.path.join(NEEDS_DIR, f"needs-{period}.md")
|
||
signals = _signals_from_inbox()
|
||
if not signals:
|
||
return "нет свежих входящих в сторе — collect сделан (пустой период)"
|
||
lines = [
|
||
f"# Потребности клиентов — {period} (UTC)",
|
||
"",
|
||
"Автосборка needs_survey.py (хардас, t-261002072440). Источник: "
|
||
"входящие чатов харнеса (TG/портал). Сырёё — тезисы, полные тексты "
|
||
"в ES-сторе (MessageReceived).",
|
||
"",
|
||
]
|
||
n = 0
|
||
for chat, msgs in signals.items():
|
||
lines.append(f"## Чат {chat}")
|
||
for m in msgs:
|
||
lines.append(f"- `{m['mid']}` {m['date']} {m['who'] or '—'} "
|
||
f"({m['kind']}): {m['text'][:300]}")
|
||
n += 1
|
||
lines.append("")
|
||
body = "\n".join(lines)
|
||
# перезапись того же периода — дедуп по построению (периодный файл)
|
||
tmp = path + ".tmp"
|
||
with open(tmp, "w", encoding="utf-8") as f:
|
||
f.write(body)
|
||
os.replace(tmp, path)
|
||
return f"OK: {n} сигналов из {len(signals)} чатов → {path}"
|
||
|
||
|
||
def main():
|
||
ap = argparse.ArgumentParser(description="Сбор потребностей клиентов хардаса")
|
||
ap.add_argument("cmd", choices=["survey", "collect"])
|
||
ap.add_argument("--key", default=SURVEY_KEY,
|
||
help="ключ идемпотентности отправки (повтор = SKIP)")
|
||
args = ap.parse_args()
|
||
if args.cmd == "survey":
|
||
print(send_survey(args.key))
|
||
else:
|
||
print(collect())
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main() |