Greetings and welcome to Sue, a chatbot for iMessage, Discord, and Telegram written in Elixir. Now with ChatGPT and Stable Diffusion!
Feedback is greatly appreciated!
Platform | |
---|---|
iMessage | send !help to sue@robertism.com |
Telegram | send /help to @ImSueBot |
Discord | send !help after adding to your server |
Sue has a long history. You'll have to ask me about it, because I'm not writing it. I made a YouTube Video about an earlier version. Some things have been added since then, some things have been removed since then.
The following commands are currently supported:
!1984
!8ball
!box
!choose
!cringe
!define
!doog
!emoji
!flip
!fortune
!gpt
!gpt4
!motivate
!phrases
!ping
!poll
!qt
!random
!rub
!sd
!uptime
!vote
Telegram uses the slash (/) prefix instead. Sue will not respond to you unless you use the proper prefix. Do not just message her "hi", expecting a miracle. You would be amazed how many people do. Discord uses exclamation mark same as iMessage.
Firstly, I aplogize. I used to use Elixir's built-in database, Mnesia, which was great because you didn't have to install anything. Sadly, I had to write many features myself and it has a 2GB storage limit, so I recently switched to ArangoDB.
- If you want to use iMessage, you need a mac with iMessage. You may be asked to enable disk access and Message control for this program (or, rather, Terminal/iTerm). I've been primarily testing this on Catalina, but it should work on Monterrey and some older versions.
- If you want to use Telegram, you should make a Telegram API key. Look up how, it's pretty straightforward. Similarly if you want to use ChatGPT, make an OpenAI account and generate an API key.
- If you want to use Discord, again, make an API key, a bot, and under gateway intents enable message content intent.
- If you wish to disable any platforms such as Telegram or iMessage, modify the platform list under
config/config.exs
to what you wish to keep. - If you want to be able to use commands that write text atop images (currently only !motivate does this), you will need to install imagemagick with pango. If you don't care about this command, feel free to ignore the rest of this. If you already have imagemagick installed, you can run
$ convert -list format | grep -i pango
to see if you can at least read it. If you don't seer--
, you can't read it and need to do the following: If you're on Mac, you're probably using homebrew, in which case you'll need to edit the install file (they removed pango because it depends on cairo which has many dependencies). After running$ brew edit imagemagick
, you should be in an editor. Add adepends_on "pango"
near its friends. Remove the--without-pango
, adding a--with-pango
near its friends. Save and quit.$ brew reinstall imagemagick --build-from-source
(orinstall
if you hadn't installed to begin with). Run that-list format
command now and you should see it. - Download and install ArangoDB. Make a user account and remember the password. You'll later enter it in the config described below. Create three databases:
- subaru_test
- subaru_dev
- subaru_prod
Make sure the user you created has access to the databases. You can edit user permissions by being in the _system
database, clicking the Users
sidebar, selecting a user, then navigating to the Permissions
tab.
$ git clone https://github.com/inculi/Sue
$ cd Sue
- Make a
config/config.secret.exs
file, here is an example:
import Config
# Telegram API
config :ex_gram, token: "mytoken"
# Discord API
config :nostrum,
gateway_intents: [
:guilds,
:guild_messages,
:guild_message_reactions,
:direct_messages,
:direct_message_reactions,
:message_content
],
token: "mytoken"
config :desu_web, DesuWeb.Endpoint,
secret_key_base: "Run this command: $ mix phx.gen.secret"
config :arangox,
endpoints: "tcp://localhost:8529",
username: "myuser",
password: "mypass"
config :openai,
api_key: "myapikey",
http_options: [recv_timeout: 40_000]
config :replicate,
replicate_api_token: "myapikey"
- Install Elixir if you don't already have it. I recommend using asdf to install.
# Use whatever version tag it recommends on the website:
# https://asdf-vm.com/guide/getting-started.html#official-download
# For me, this is:
$ git clone https://github.com/asdf-vm/asdf.git ~/.asdf --branch v0.13.1
# add ~/.asdf/bin to path
# Install erlang dependencies
# Discussed in https://github.com/asdf-vm/asdf-erlang
$ brew install autoconf openssl wxwidgets libxslt fop
# Add erlang and elixir plugins, install and set a version.
$ asdf plugin add erlang https://github.com/asdf-vm/asdf-erlang.git
$ asdf plugin-add elixir https://github.com/asdf-vm/asdf-elixir.git
$ asdf install erlang 26.1.2
$ asdf install elixir 1.15.7
$ asdf global erlang 26.1.2
$ asdf global elixir 1.15.7
# add to path: ~/.asdf/shims
$ mix deps.get
- To create a prod build, run
$ MIX_ENV=prod mix release
It should then tell you the path to the newly created executable. - To run in interactive dev mode, you can run
$ iex -S mix
. If you want to Telegram to autocomplete your commands, runSue.post_init()
from within this interactive prompt. Sorry this part is a little scuffed.
- When Sue loads (see
sue.ex
), it iterates through the modules underSue.Commands
, reading the methods defined in them. If a method name starts withc_
, it is saved as a callable command. For example, seerand.ex
:
@doc """
Flip a coin. Will return heads or tails.
Usage: !flip
"""
def c_flip(_msg) do
%Response{body: ["heads", "tails"] |> Enum.random()}
end
If your command takes args, these are found in the Message's args
field. Another example from rand:
@doc """
Returns a random object in your space-delimited argument.
Usage: !choose up down left right
"""
def c_choose(%Message{args: ""}) do
%Response{body: "Please provide a list of things to select. See !help choose"}
end
def c_choose(%Message{args: args}) do
%Response{
body:
args
|> String.split(" ")
|> Enum.random()
}
end
- Submit an issue and I'll put together some instructions. Basically, just look at the tests. They do a good job of explaining most of Sue's major components, even if there isn't a test for everything.
- Image functions stopped working in Telegram. I think there's a new Telegram client for Elixir that I'll probably switch to.
Before you update to the new version, go to your current mnesia/
directory and drill down to the final level where your .DAT files and what-not are stored. Move this last level directory to your project root directory and call it mydir/
or something. Then create a new file called export.exs
with this code:
# export.exs
alias :mnesia, as: Mnesia
:ok = Mnesia.start([dir: String.to_charlist("mydir")])
:ok = Mnesia.wait_for_tables(Mnesia.system_info(:local_tables), 5_000)
record = {:edges, :_, :_, :_, :_, :_}
{:atomic, edges} = fn -> Mnesia.match_object(record) end |> Mnesia.transaction()
:file.write_file("edges.bin", :erlang.term_to_binary(edges))
{:atomic, defns} = fn -> Mnesia.match_object({:defn, :_, :_}) end |> Mnesia.transaction()
:file.write_file("defns.bin", :erlang.term_to_binary(defns))
Run it: $ elixir export.exs
This will generate two files (edges.bin
and defns.bin
). Update to the latest version of Sue, keeping these two new files and nothing else. Once you're in the new version of Sue, enter an interactive shell and perform the following:
iex(1)> Sue.DB.import_mnesia_dump("path/to/edges.bin", "path/to/defns.bin")
There you go! I'm hoping this DB switch will be the last. Arango is pretty solid and should support all the future ideas I have for Sue + Desu + Kiku. Mnesia was neat, though.
- Thanks for Zeke's work on Jared. Your applescript files were cleaner than mine. Good thinking with sqlite.
- Peter's work on Otto, whose applescript handler was instrumental in Sue V1.
- Multiple bloggers who wrote about iMessage's sqlite schema.
- Rick for popping a shell in Sue V1, prompting the development of V2.
- All the random people that have messaged and broken Sue, pushing me ever forward in its development.