feat: /help command, atm.bat launcher, tzdata fix pentru Windows
- Telegram /h /help — listă comenzi în română - atm.bat — pornire cu venv local automat, pip install la primul run - tzdata adăugat în deps principale cu marker sys_platform==win32 - README: secțiuni dev, instalare Windows, flow-uri calibrare Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
51
README.md
51
README.md
@@ -43,20 +43,60 @@ atm/
|
||||
|
||||
Python 3.11+.
|
||||
|
||||
```bash
|
||||
pip install -e ".[windows]" # Windows: capture live + focus fereastră
|
||||
pip install -e ".[dev]" # Linux/macOS/WSL: doar dev + teste (fără capture)
|
||||
### Windows (producție)
|
||||
|
||||
```powershell
|
||||
python -m venv .venv
|
||||
.venv\Scripts\activate
|
||||
pip install -e ".[windows]"
|
||||
# → creează .venv\Scripts\atm.exe
|
||||
atm --help
|
||||
```
|
||||
|
||||
**WSL/Linux:** recomandat să folosești un virtualenv local:
|
||||
`[windows]` aduce `mss`, `pygetwindow`, `pywin32`. Fără venv, `pip install -e ".[windows]"` direct în Python-ul global funcționează la fel.
|
||||
|
||||
Pornire rapidă cu scriptul inclus — instalează automat la primul run:
|
||||
```powershell
|
||||
atm.bat # prima rulare: pip install + atm run
|
||||
atm.bat run --stop-at 23:00
|
||||
atm.bat debug
|
||||
```
|
||||
|
||||
### WSL / Linux (dev + teste)
|
||||
|
||||
```bash
|
||||
python3 -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install -e ".[dev]"
|
||||
```
|
||||
|
||||
`[windows]` aduce `mss`, `pygetwindow`, `pywin32` (nu le pune pe WSL).
|
||||
`[dev]` aduce `pytest`, `pytest-cov`, `pytest-asyncio`. Nu include dependențele Windows (`mss`, `pygetwindow`, `pywin32`) — nu rulează capture live.
|
||||
|
||||
---
|
||||
|
||||
## Dev
|
||||
|
||||
```bash
|
||||
pytest -q # toate testele (184+)
|
||||
pytest tests/test_commands.py # un modul specific
|
||||
pytest -q --cov=atm --cov-report=term-missing # cu coverage
|
||||
```
|
||||
|
||||
Smoke-test fără Windows (stub de captură din `samples/`):
|
||||
```bash
|
||||
atm run --capture-stub --duration 0.05
|
||||
```
|
||||
|
||||
Structura testelor:
|
||||
|
||||
| Fișier | Ce acoperă |
|
||||
|---|---|
|
||||
| `test_commands.py` | parsing comenzi Telegram |
|
||||
| `test_config.py` | loader TOML, attach_screenshots |
|
||||
| `test_handle_tick.py` | loop principal, snapshot, FSM |
|
||||
| `test_main.py` | lifecycle, operating hours, canary, dispatcher |
|
||||
| `test_validate.py` | gate offline clasificare culori |
|
||||
| `test_canary.py` | drift + callback pauză |
|
||||
|
||||
---
|
||||
|
||||
@@ -299,6 +339,7 @@ Trimiți în chat-ul bot-ului:
|
||||
| `/resume force` | Elimină și drift-pause-ul canary (după recalibrare) |
|
||||
| `/3` sau `/interval 3` | Interval auto-screenshot = 3 min |
|
||||
| `/stop` | Oprește scheduler-ul de screenshot |
|
||||
| `/h` sau `/help` | Listă scurtă a tuturor comenzilor disponibile |
|
||||
|
||||
Doar `allowed_chat_ids` sunt acceptate. După 3 `401` consecutive, poller-ul intră în mod degradat.
|
||||
|
||||
|
||||
15
atm.bat
Normal file
15
atm.bat
Normal file
@@ -0,0 +1,15 @@
|
||||
@echo off
|
||||
cd /d "%~dp0"
|
||||
|
||||
if not exist ".venv\Scripts\atm.exe" (
|
||||
echo Instalez atm in venv local...
|
||||
python -m venv .venv
|
||||
call .venv\Scripts\activate.bat
|
||||
pip install -e ".[windows]"
|
||||
)
|
||||
|
||||
if "%~1"=="" (
|
||||
.venv\Scripts\atm.exe run
|
||||
) else (
|
||||
.venv\Scripts\atm.exe %*
|
||||
)
|
||||
@@ -14,6 +14,7 @@ dependencies = [
|
||||
"requests>=2.31",
|
||||
"rich>=13.0",
|
||||
"httpx>=0.27",
|
||||
"tzdata>=2024.1; sys_platform == 'win32'",
|
||||
]
|
||||
|
||||
[project.optional-dependencies]
|
||||
|
||||
@@ -17,7 +17,7 @@ if TYPE_CHECKING:
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
CommandAction = Literal["set_interval", "stop", "status", "ss", "pause", "resume"]
|
||||
CommandAction = Literal["set_interval", "stop", "status", "ss", "pause", "resume", "help"]
|
||||
|
||||
_BASE = "https://api.telegram.org/bot{token}/{method}"
|
||||
|
||||
@@ -148,6 +148,8 @@ class TelegramPoller:
|
||||
t = text.lstrip("/").strip()
|
||||
if not t:
|
||||
return None
|
||||
if t in ("h", "help"):
|
||||
return Command(action="help")
|
||||
if t == "stop":
|
||||
return Command(action="stop")
|
||||
if t == "status":
|
||||
|
||||
@@ -1065,6 +1065,18 @@ async def _dispatch_command(ctx: RunContext, cmd) -> None:
|
||||
title = "Monitorizare reluată"
|
||||
body = ""
|
||||
ctx.notifier.send(Alert(kind="status", title=title, body=body))
|
||||
elif cmd.action == "help":
|
||||
body = (
|
||||
"/status — stare FSM, uptime, ultima detecție\n"
|
||||
"/ss — screenshot acum\n"
|
||||
"/pause — oprește detecția (heartbeat continuă)\n"
|
||||
"/resume — reia detecția (doar pauza user)\n"
|
||||
"/resume force — reia + anulează drift-pause canary\n"
|
||||
"/3 — screenshot automat la fiecare 3 min (sau orice număr)\n"
|
||||
"/stop — oprește screenshot-urile automate\n"
|
||||
"/h — acest mesaj"
|
||||
)
|
||||
ctx.notifier.send(Alert(kind="status", title="Comenzi ATM", body=body))
|
||||
|
||||
|
||||
async def _drain_cmd_queue(ctx: RunContext) -> None:
|
||||
|
||||
@@ -36,6 +36,14 @@ def test_parse_resume_force():
|
||||
assert cmd.value == 1
|
||||
|
||||
|
||||
def test_parse_help():
|
||||
p = _make_poller()
|
||||
assert p._parse_command("h") == Command(action="help")
|
||||
assert p._parse_command("/h") == Command(action="help")
|
||||
assert p._parse_command("help") == Command(action="help")
|
||||
assert p._parse_command("/help") == Command(action="help")
|
||||
|
||||
|
||||
def test_parse_existing_commands_still_work():
|
||||
"""Regression: adding pause/resume must not break stop/status/ss/interval."""
|
||||
p = _make_poller()
|
||||
|
||||
Reference in New Issue
Block a user