diff options
| author | Ben Sima <ben@bensima.com> | 2026-05-18 13:54:55 -0400 |
|---|---|---|
| committer | Ben Sima <ben@bensima.com> | 2026-05-18 13:54:55 -0400 |
| commit | 06b08dbbcb4b234a94be189f855ce5fec4c5c37b (patch) | |
| tree | a42f84919ca1e3ba7e19be634e3fd2e10d0d5bc6 /main.py | |
init: slopbot scaffold
Diffstat (limited to 'main.py')
| -rw-r--r-- | main.py | 67 |
1 files changed, 67 insertions, 0 deletions
@@ -0,0 +1,67 @@ +#!/usr/bin/env python3 +""" +slopbot - Zulip bot that replies with stock prices when it sees $TICKER patterns. + +Usage: + python main.py + +Requires a .zuliprc file in the same directory (see .zuliprc.example). +""" + +import re +import zulip +import yfinance as yf + +# Regex to match stock tickers like $NVDA, $AAPL, $BRK +TICKER_RE = re.compile(r'\$([A-Z]{1,5})') + + +def fetch_price(ticker: str) -> str: + """Return a formatted price string for a ticker, or an error message.""" + try: + info = yf.Ticker(ticker).fast_info + price = info["lastPrice"] + return f"${ticker}: ${price:,.2f}" + except Exception as e: + return f"${ticker}: couldn't fetch price ({e})" + + +def handle_event(event: dict, client: zulip.Client) -> None: + """Process a Zulip event and reply if tickers are found.""" + if event.get("type") != "message": + return + + msg = event["message"] + + # Don't reply to ourselves + if msg["sender_email"] == client.email: + return + + content = msg.get("content", "") + tickers = TICKER_RE.findall(content.upper()) + + if not tickers: + return + + lines = [fetch_price(t) for t in dict.fromkeys(tickers)] # dedup, preserve order + reply = "\n".join(lines) + + client.send_message({ + "type": msg["type"], # "stream" or "private" + "to": msg["stream_id"] if msg["type"] == "stream" else msg["sender_email"], + "topic": msg.get("subject", ""), + "content": reply, + }) + + +def main(): + client = zulip.Client(config_file=".zuliprc") + print(f"slopbot running as {client.email} ...") + client.call_on_each_event( + lambda event: handle_event(event, client), + event_types=["message"], + ) + + +if __name__ == "__main__": + main() |
