Commit Graph

114 Commits

Author SHA1 Message Date
prosolis
23fffdda3c README: document !post on-demand command 2026-05-23 15:09:10 -07:00
prosolis
689dc4ef92 Add !post command to force-publish next queued story
Typed in a configured channel room, !post pops the head of that channel's
queue and sends immediately, bypassing min-interval, burst cap, and daily
cap. Canonical-URL dedup still applies. Empty queue gets a threaded reply.
2026-05-23 14:47:37 -07:00
prosolis
f29c056171 README: document round-robin posting mode 2026-05-22 19:59:29 -07:00
prosolis
3baec4c8bc Add round-robin posting mode
One story per interval_hours (default 4), cycling through enabled sources
in config order. Empty sources are skipped and the pointer advances to
whichever source actually posted. State persists across restarts.

Duplicate-flagged stories now get a _duplicate sentinel channel so they
stay out of the rotation pool alongside _discarded.
2026-05-22 19:58:46 -07:00
prosolis
69967b25c6 Plumb ctx through classifier and Ollama HTTP path
OllamaClient.Generate/GenerateText/call now take ctx and build the HTTP
request via NewRequestWithContext, so an in-flight LLM call is aborted
when the parent context is cancelled (Ctrl-C). Classifier.Classify and
its tier helpers take ctx too. ProcessFunc gets a ctx parameter so the
poller can forward its cancellable context down to classification.

Explainer.summarize manages its own 60s context since reaction-driven
flow has no parent ctx to inherit.
2026-05-22 18:55:43 -07:00
prosolis
c9318d7bb0 Hard daily cap, no-flood shutdown, ctx-aware poller, double-image fix
Four related fixes after Pete flooded a channel and ignored Ctrl-C:

1. Global daily cap (posting.daily_cap_total, default 5): hard ceiling on
   posts across ALL channels in a rolling 24h window. Checked before the
   per-channel min-interval and burst-cap.

2. Shutdown no longer flushes the queue. Previous drainAll posted every
   remaining item with rate limits disabled — which was literally the
   flood. Replaced with dropOnShutdown that clears queues and logs
   the count.

3. Poller respects ctx mid-loop. pollOnceWithErr now takes ctx and bails
   between items, so Ctrl-C doesn't have to wait for ~30s of network
   per pending story before shutdown can complete.

4. Double-image fix. PostStory now reports imageSent; the queue clears
   ImageURL before retry so a text-send failure after a successful
   image upload doesn't re-post the image.
2026-05-22 18:51:33 -07:00
prosolis
8d1e6ed568 Update README: !explain, paywall/Wayback fallback, explainer package 2026-05-22 18:38:37 -07:00
prosolis
d41eaa6504 Test bullet parser; fix marker-less passthrough
The previous parser treated any non-empty non-header line as a bullet,
so 'plain paragraph' answers were silently rewrapped as <ul><li>. Now
we only count a line if it had a recognized bullet marker (- * • ·);
if none did, fall back to raw + <pre> as originally intended.

Tests cover dash/asterisk/unicode bullets, blank-line tolerance,
Summary:/TL;DR header stripping, HTML escaping, single-bullet output,
the no-marker passthrough path, and the IsQuestionReaction set.
2026-05-22 18:31:26 -07:00
prosolis
dd324c0317 Accept more question-mark reactions as explain triggers
Now triggers on  ⁉️ 🤔 ? ? — covers the obvious red/white/thinking
variants, the exclamation-question combo (with and without VS16), and
plain ascii / fullwidth question marks for keyboard users.
2026-05-22 18:29:32 -07:00
prosolis
3537e073e9 !explain via reaction: thread-reply with a 3-bullet TL;DR
When a user reacts  on one of Pete's posts, fetch the article body,
ask Ollama for a 3-bullet summary, and post it as a threaded reply
rooted at the original story event. Per-process cooldown of 5min per
story keeps repeated reactions from re-summarizing.

- ingestion.FetchArticleBody: visible <p> text capped at 8000 chars
- classifier.OllamaClient.GenerateText: non-JSON variant
- storage.GetStoryByGUID: full row lookup
- matrix.PostThreadedReply: m.thread + m.in_reply_to fallback
- poster.SetReactionCallback: optional hook fired after recording
- New package: internal/explainer
2026-05-22 18:27:11 -07:00
prosolis
e26b69e43f Paywall detection: swap to Wayback snapshot when article body is gated
Fetch each new article once and measure visible <p> text. If body is below
500 chars (or fetch fails), resolve a Wayback snapshot via the
archive.org/wayback/available API and use that URL for both the og:image
fallback and the posted link. Dedup keys stay derived from the original
URL so paywalled/non-paywalled hits collide as before.

- New: internal/ingestion/article.go (FetchArticleMeta via goquery)
- New: internal/ingestion/wayback.go (ResolveWayback)
- Removed: internal/ingestion/og.go (folded into article.go)
- poller.go: dedup first, then one article fetch, then snapshot fallback
2026-05-22 17:53:54 -07:00
prosolis
ca6663c051 Update mautrix version reference in README 2026-05-22 17:27:40 -07:00
prosolis
310950e722 Bump indirect deps: x/crypto 0.52, x/net 0.55, x/sys 0.45 2026-05-22 17:27:00 -07:00
prosolis
652d6dfa38 Initial commit 2026-05-22 17:25:27 -07:00