Packages

A Cleverbot API wrapper.

Current section

Files

Jump to
cleverbot lib cleverbot.ex
Raw

lib/cleverbot.ex

defmodule Cleverbot do
@moduledoc """
A genserver implementation of the Cleverbot API to hold conversations with
[Cleverbot].
[Cleverbot]: http://www.cleverbot.com/
## Example
```
{:ok, pid} = Cleverbot.start_link
Cleverbot.think(pid, "Hello, Cleverbot!")
session = Cleverbot.get_session(pid)
IO.puts List.first(session.history)
```
"""
use GenServer
@url "http://www.cleverbot.com/webservicemin"
@doc """
Starts a Cleverbot process. You can pass in an existing `Cleverbot.Session`
as the first argument.
"""
def start_link(session \\ %Cleverbot.Session{}, http \\ HTTPoison) do
GenServer.start_link(__MODULE__, %{session: session, http: http})
end
@doc """
Sends the given message to the Cleverbot process and returns Cleverbot's
reply.
"""
def think(pid, message) do
GenServer.call(pid, {:think, message}, 15000)
end
@doc """
Retreive the current `Cleverbot.Session`.
"""
def get_session(pid) do
GenServer.call(pid, :value)
end
# GenServer
@doc false
def init(session) do
{:ok, session}
end
@doc false
def handle_call(:value, _from, state = %{session: session}) do
{:reply, session, state}
end
@doc false
def handle_call({:think, message}, _from, state = %{session: session, http: http}) do
response = think_about_it(message, session, http)
new_session = Cleverbot.Session.update(session, message, response)
state = Map.put(state, :session, new_session)
{:reply, response.text, state}
end
defp think_about_it(message, session, http) do
form_data = build_query(message, session)
{:ok, response} = http.post(@url, form_data, headers)
Cleverbot.Response.parse(response.body)
end
defp headers do
%{
"Cache-Control" => "no-cache, no-cache",
"Pragma" => "no-cache",
"Referer" => "http://www.cleverbot.com"
}
end
defp build_query(message, session) do
initial_data = build_form_map(message, session)
icognocheck = URI.encode_query(initial_data)
|> String.slice(9..34)
|> md5
List.insert_at(initial_data, 11, {:icognocheck, icognocheck})
initial_data ++ [icognocheck: icognocheck] |> URI.encode_query
end
defp build_form_map(message, session) do
[
stimulus: URI.encode(message),
start: "y",
sessionid: session.session_id,
vText8: Enum.at(session.history, 6),
vText7: Enum.at(session.history, 5),
vText6: Enum.at(session.history, 4),
vText5: Enum.at(session.history, 3),
vText4: Enum.at(session.history, 2),
vText3: Enum.at(session.history, 1),
vText2: Enum.at(session.history, 0),
icognoid: "wsf",
fno: 0,
sub: "Say",
islearning: 1,
cleanslate: false,
]
end
defp md5(string) do
:crypto.hash(:md5, string)
|> :erlang.bitstring_to_list
|> Enum.map(&(:io_lib.format("~2.16.0b", [&1])))
|> List.flatten
|> :erlang.list_to_bitstring
|> to_string
end
end