{"id":21998255,"url":"https://github.com/simonswine/hacknight-slack-bot","last_synced_at":"2026-04-13T23:31:07.282Z","repository":{"id":75884372,"uuid":"52300520","full_name":"simonswine/hacknight-slack-bot","owner":"simonswine","description":null,"archived":false,"fork":false,"pushed_at":"2016-03-01T23:11:55.000Z","size":876,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-23T05:11:17.988Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/simonswine.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-02-22T19:45:00.000Z","updated_at":"2016-03-01T22:57:29.000Z","dependencies_parsed_at":"2023-04-07T13:03:31.314Z","dependency_job_id":null,"html_url":"https://github.com/simonswine/hacknight-slack-bot","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/simonswine/hacknight-slack-bot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonswine%2Fhacknight-slack-bot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonswine%2Fhacknight-slack-bot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonswine%2Fhacknight-slack-bot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonswine%2Fhacknight-slack-bot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/simonswine","download_url":"https://codeload.github.com/simonswine/hacknight-slack-bot/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/simonswine%2Fhacknight-slack-bot/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31775692,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-13T20:17:16.280Z","status":"ssl_error","status_checked_at":"2026-04-13T20:17:08.216Z","response_time":93,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-29T22:20:51.102Z","updated_at":"2026-04-13T23:31:07.264Z","avatar_url":"https://github.com/simonswine.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Slack Quote Bot\n\nWritten for February 2016's [West London Hack Night](http://www.meetup.com/West-London-Hack-Night/).\n\n## Overview\n\nThis golang project tries to respond all incoming Slack messages with an\nfitting quote. To be able to repsond accordingly it indexes a quote database\nfirst. The indexing/matching is done using elasticsearch\n\n## End of Hacknight state\n\n* We used [tray.io](https://tray.io) for handling the Slack part\n* Indexing was done with golang bleve library (was pretty slow, did not work 100% in the end)\n\n## Example usage\n\n![Screenshot](/screenshots/example_chat.png?raw=true \"Screenshot\")\n\n## Build and run it locally\n\n### Prerequisites\n\n* You'll need [docker](https://docker.io) and [docker-compose](https://docs.docker.com/compose/overview/) installed locally.\n* You need to download this [quote database](http://thewebminer.com/do) (Go to the very bottom of the page, then save to this directory with the name `quotes_all.csv`\n\n### Build go and images\n\n```\n$ docker-compose build\nelasticsearch uses an image, skipping\nBuilding slackbot\nStep 1 : FROM golang:1.5\n ---\u003e 32854d8f16c4\nStep 2 : RUN go get github.com/tools/godep\n ---\u003e Using cache\n ---\u003e 485da879b0cf\nStep 3 : RUN mkdir /slackbot \u0026\u0026 chown nobody /slackbot\n ---\u003e Using cache\n ---\u003e 86de35465fc6\nStep 4 : WORKDIR /slackbot\n ---\u003e Using cache\n ---\u003e dcb368fff2a0\nStep 5 : USER nobody\n ---\u003e Using cache\n ---\u003e 286a290cf9fb\nStep 6 : ADD quotes_all.csv /slackbot/\n ---\u003e Using cache\n ---\u003e aa042e742875\nStep 7 : ADD main.go /slackbot/main.go\n ---\u003e Using cache\n ---\u003e 45127529c7a9\nStep 8 : ADD Godeps/ /slackbot/Godeps/\n ---\u003e Using cache\n ---\u003e 0bb450f8b28f\nStep 9 : RUN godep go build\n ---\u003e Using cache\n ---\u003e b1c4d94a42ca\nStep 10 : CMD /slackbot/slackbot\n ---\u003e Using cache\n ---\u003e 5f8993406a52\nSuccessfully built 5f8993406a52\n```\n\n### Run app and elasticsearch\n\n```\n$ docker-compose up\nCreating hacknightslackbot_elasticsearch_1\nCreating hacknightslackbot_slackbot_1\nAttaching to hacknightslackbot_elasticsearch_1, hacknightslackbot_slackbot_1\nslackbot_1      | time=\"2016-02-23T22:45:05Z\" level=info msg=\"Initializing slack quote bot...\" \nslackbot_1      | time=\"2016-02-23T22:45:05Z\" level=info msg=\"Use slack api token: xoxb-22757066566-LtgYbLxQcDpedIKOe11PPFFH\" \nslackbot_1      | time=\"2016-02-23T22:45:05Z\" level=info msg=\"Use elasticsearch url: http://172.17.0.2:9200\" \nslackbot_1      | time=\"2016-02-23T22:45:05Z\" level=info msg=\"Elasticsearch http://172.17.0.2:9200 is not ready yet (1. try)\" \nelasticsearch_1 | [2016-02-23 22:45:06,003][INFO ][node                     ] [Thinker] version[2.2.0], pid[1], build[8ff36d1/2016-01-27T13:32:39Z]\nelasticsearch_1 | [2016-02-23 22:45:06,005][INFO ][node                     ] [Thinker] initializing ...\nslackbot_1      | time=\"2016-02-23T22:45:06Z\" level=info msg=\"Elasticsearch http://172.17.0.2:9200 is not ready yet (2. try)\" \nelasticsearch_1 | [2016-02-23 22:45:06,664][INFO ][plugins                  ] [Thinker] modules [lang-expression, lang-groovy], plugins [], sites []\nelasticsearch_1 | [2016-02-23 22:45:06,702][INFO ][env                      ] [Thinker] using [1] data paths, mounts [[/usr/share/elasticsearch/data (/dev/disk/by-uuid/85d441f8-cbd3-4f25-87f1-50cf5ec1d94f)]], net usable_space [11.7gb], net total_space [69.1gb], spins? [possibly], types [ext4]\nelasticsearch_1 | [2016-02-23 22:45:06,702][INFO ][env                      ] [Thinker] heap size [990.7mb], compressed ordinary object pointers [true]\nslackbot_1      | time=\"2016-02-23T22:45:07Z\" level=info msg=\"Elasticsearch http://172.17.0.2:9200 is not ready yet (3. try)\" \nslackbot_1      | time=\"2016-02-23T22:45:08Z\" level=info msg=\"Elasticsearch http://172.17.0.2:9200 is not ready yet (4. try)\" \nslackbot_1      | time=\"2016-02-23T22:45:09Z\" level=info msg=\"Elasticsearch http://172.17.0.2:9200 is not ready yet (5. try)\" \nelasticsearch_1 | [2016-02-23 22:45:10,008][INFO ][node                     ] [Thinker] initialized\nelasticsearch_1 | [2016-02-23 22:45:10,008][INFO ][node                     ] [Thinker] starting ...\nelasticsearch_1 | [2016-02-23 22:45:10,166][INFO ][transport                ] [Thinker] publish_address {172.17.0.2:9300}, bound_addresses {[::]:9300}\nelasticsearch_1 | [2016-02-23 22:45:10,179][INFO ][discovery                ] [Thinker] elasticsearch/NVlrQSgDTK6nXcajZfaWTQ\nslackbot_1      | time=\"2016-02-23T22:45:10Z\" level=info msg=\"Elasticsearch http://172.17.0.2:9200 is not ready yet (6. try)\" \nslackbot_1      | time=\"2016-02-23T22:45:11Z\" level=info msg=\"Elasticsearch http://172.17.0.2:9200 is not ready yet (7. try)\" \nslackbot_1      | time=\"2016-02-23T22:45:12Z\" level=info msg=\"Elasticsearch http://172.17.0.2:9200 is not ready yet (8. try)\" \nslackbot_1      | time=\"2016-02-23T22:45:13Z\" level=info msg=\"Elasticsearch http://172.17.0.2:9200 is not ready yet (9. try)\" \nelasticsearch_1 | [2016-02-23 22:45:13,261][INFO ][cluster.service          ] [Thinker] new_master {Thinker}{NVlrQSgDTK6nXcajZfaWTQ}{172.17.0.2}{172.17.0.2:9300}, reason: zen-disco-join(elected_as_master, [0] joins received)\nelasticsearch_1 | [2016-02-23 22:45:13,311][INFO ][http                     ] [Thinker] publish_address {172.17.0.2:9200}, bound_addresses {[::]:9200}\nelasticsearch_1 | [2016-02-23 22:45:13,312][INFO ][node                     ] [Thinker] started\nelasticsearch_1 | [2016-02-23 22:45:13,336][INFO ][gateway                  ] [Thinker] recovered [0] indices into cluster_state\nslackbot_1      | time=\"2016-02-23T22:45:14Z\" level=info msg=\"Established connection to elasticsearch\" \nelasticsearch_1 | [2016-02-23 22:45:14,583][INFO ][cluster.metadata         ] [Thinker] [quotes] creating index, cause [api], templates [], shards [5]/[0], mappings []\nslackbot_1      | time=\"2016-02-23T22:45:14Z\" level=info msg=\"Created index 'quotes' in elasticsearch\" \nelasticsearch_1 | [2016-02-23 22:45:15,294][INFO ][cluster.routing.allocation] [Thinker] Cluster health status changed from [RED] to [GREEN] (reason: [shards started [[quotes][4], [quotes][4]] ...]).\nslackbot_1      | time=\"2016-02-23T22:45:15Z\" level=info msg=\"Indexing bulk 0/759 quotes 0 - 99\" \nelasticsearch_1 | [2016-02-23 22:45:15,865][INFO ][cluster.metadata         ] [Thinker] [quotes] create_mapping [quote]\nslackbot_1      | time=\"2016-02-23T22:45:16Z\" level=info msg=\"Indexing bulk 1/759 quotes 100 - 199\" \n[...]\nslackbot_1      | time=\"2016-02-23T22:45:53Z\" level=info msg=\"Indexing bulk 759/759 quotes 75900 - 75965\" \nslackbot_1      | time=\"2016-02-23T22:45:53Z\" level=info msg=\"Connecting to slack\" \nslackbot_1      | time=\"2016-02-23T22:46:09Z\" level=info msg=\"Incoming message 'what?'\" \nslackbot_1      | time=\"2016-02-23T22:46:09Z\" level=info msg=\"query elasticsearch for 'what?' hits=6500\" \n```\n\nTo integrate it with Slack, we built a (tray.io)[https://tray.io] flow that uses Slack outgoing webhook on a specific channel. \n\n1. Each messages posted to the channel is sent to the flow's trigger. \n2. After checking if it's a valid user message (not from a bot), an http request is sent to golang part containing the full text of the message. \n3. If the response is positive, the flow finally posts it (the quote) in Slack.\n\n![Screenshot](/screenshots/tray_flow.png?raw=true \"Screenshot\")\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimonswine%2Fhacknight-slack-bot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsimonswine%2Fhacknight-slack-bot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsimonswine%2Fhacknight-slack-bot/lists"}