-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add hackernews project in kittehub (#123)
This PR addresses ENG-1025. Project tracks articles from Hacker News based on user-provided topic and sends updates to a designated Slack channel. The main functionality includes: • Slash Command Integration: Users can specify a topic to monitor directly from Slack. • Real-Time Updates: The bot fetches new articles every two minutes and posts any updates to Slack. • Hacker News API Integration: Uses the Algolia-powered Hacker News API to search for articles by keyword. • Slack Integration: Sends article details (title and URL) to the specified Slack channel. Since we’re updating the README to focus on cloud deployment, I did not place significant emphasis on the README file --------- Co-authored-by: Daniel Abraham <[email protected]> Co-authored-by: Pasha Fateev <[email protected]>
- Loading branch information
1 parent
fb34bd6
commit 4968949
Showing
3 changed files
with
137 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
--- | ||
title: Hacker News Alerts in Slack | ||
description: Track Hacker News articles by topic and send updates to Slack | ||
integrations: ["slack"] | ||
categories: ["Office Automation"] | ||
--- | ||
|
||
# Hacker News Alerts in Slack | ||
|
||
This project monitors Hacker News for new articles matching a specific topic, fetching their details in real-time. It compares the latest results with previously fetched articles to identify new ones and sends their title and URL as notifications to a Slack channel. | ||
|
||
## How It Works | ||
|
||
1. Extract the topic from the Slack app mention. | ||
2. Add the topic to the Hacker News search query (check out [Algolia's REST API](https://www.algolia.com/doc/api-reference/rest-api) for more details). | ||
3. Return all the new articles related to the topic that were published since the last check. | ||
|
||
## Deployment & Configuration | ||
|
||
#### Cloud Usage (Recommended) | ||
|
||
- Initialize your connection with Slack through the UI | ||
|
||
#### Prerequisites | ||
|
||
- [Install AutoKitteh](https://docs.autokitteh.com/get_started/install) | ||
- Set up required integrations: | ||
- [Slack](https://docs.autokitteh.com/integrations/slack) | ||
|
||
#### Installation Steps | ||
|
||
1. Clone the repository: | ||
```shell | ||
git clone https://github.com/autokitteh/kittehub.git | ||
cd kittehub/hackernews | ||
``` | ||
|
||
2. Start the AutoKitteh server: | ||
```shell | ||
ak up --mode dev | ||
``` | ||
|
||
3. Deploy the project: | ||
```shell | ||
ak deploy --manifest autokitteh.yaml | ||
``` | ||
|
||
The output will show your connection IDs, which you'll need for the next step. Look for lines like: | ||
```shell | ||
[exec] create_connection "hackernews_alert/slack_connection": con_01je39d6frfdtshstfg5qpk8sz created | ||
``` | ||
|
||
In this example, `con_01je39d6frfdtshstfg5qpk8sz` is the connection ID. | ||
|
||
4. Initialize your connections using the CLI: | ||
```shell | ||
ak connection init slack_connection <connection ID> | ||
``` | ||
|
||
## Trigger Workflow | ||
|
||
- Type `@your-slack-app topic` in the Slack channel you set in the environment variable, replacing `topic` with what you want to search for, to start tracking articles | ||
- The workflow runs automatically every two minutes after deployment |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
# This YAML file is a declarative manifest that describes the setup of an | ||
# AutoKitteh project that monitors Hacker News for a specific topic. | ||
|
||
version: v1 | ||
|
||
project: | ||
name: hackernews_alert | ||
vars: | ||
- name: POLLING_INTERVAL_SECS | ||
value: 120 | ||
connections: | ||
- name: slack_connection | ||
integration: slack | ||
triggers: | ||
- name: slack_slash_command | ||
connection: slack_connection | ||
event_type: app_mention | ||
call: program.py:on_slack_command |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
"""Monitor Hacker News for new articles on a specific topic, and post updates to a Slack channel.""" | ||
|
||
import os | ||
import requests | ||
import time | ||
import urllib.parse | ||
|
||
from autokitteh.slack import slack_client | ||
|
||
|
||
API_URL = "http://hn.algolia.com/api/v1/search_by_date?tags=story&page=0&query=" | ||
POLLING_INTERVAL_SECS = int(os.getenv("POLLING_INTERVAL_SECS")) | ||
|
||
slack = slack_client("slack_connection") | ||
|
||
|
||
def on_slack_command(event): | ||
"""Workflow's entry-point. | ||
Extracts a topic from a Slack command, monitors for new articles, | ||
and posts updates to `SLACK_CHANNEL`. | ||
""" | ||
topic = event.data.text.split(" ", 1)[-1].strip() | ||
slack.chat_postMessage( | ||
channel=event.data.channel, | ||
text=f"Waiting for new articles on the topic: `{topic}`.", | ||
) | ||
current_articles = set() | ||
fetch_articles(topic, current_articles) | ||
|
||
# NOTE: For low-traffic topics, it might take a while for new articles to be published, | ||
# so users may experience delays in receiving notifications. | ||
while True: | ||
all_articles = set(current_articles) | ||
fetch_articles(topic, all_articles) | ||
new_articles = all_articles - current_articles | ||
|
||
for article in new_articles: | ||
_, title, url = article | ||
slack_message = f"Title: {title}, URL: {url if url else 'No URL'}" | ||
slack.chat_postMessage(channel=event.data.channel, text=slack_message) | ||
current_articles.update(new_articles) | ||
|
||
time.sleep(POLLING_INTERVAL_SECS) | ||
|
||
|
||
def fetch_articles(topic, all_articles): | ||
encoded_query = urllib.parse.quote(topic) | ||
full_url = f"{API_URL}{encoded_query}" | ||
hits = requests.get(full_url).json().get("hits", []) | ||
|
||
# Extract some of the article fields from the API response. | ||
for article in hits: | ||
object_id = article["objectID"] | ||
title = article["title"] | ||
url = article.get("url") | ||
all_articles.add((object_id, title, url)) |