Skip to content

Commit

Permalink
initial
Browse files Browse the repository at this point in the history
  • Loading branch information
danielgross committed Dec 2, 2022
1 parent 54e7050 commit 7fbb5d4
Show file tree
Hide file tree
Showing 5 changed files with 217 additions and 0 deletions.
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
# whatsapp-gpt
* You'll need to run WhatsApp from a phone number using the golang library I'm using.
* You'll run a dedicated browser in another window that's controlling ChatGPT.
* This this the end of the readme file for now; it is a bit sparse. Will add more later.
16 changes: 16 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module example.com/m

go 1.19

require (
filippo.io/edwards25519 v1.0.0 // indirect
github.com/gorilla/websocket v1.5.0 // indirect
github.com/mattn/go-sqlite3 v1.14.16 // indirect
github.com/mdp/qrterminal v1.0.1 // indirect
github.com/mdp/qrterminal/v3 v3.0.0 // indirect
go.mau.fi/libsignal v0.0.0-20221015105917-d970e7c3c9cf // indirect
go.mau.fi/whatsmeow v0.0.0-20221202110551-e067ee7293b0 // indirect
golang.org/x/crypto v0.0.0-20221012134737-56aed061732a // indirect
google.golang.org/protobuf v1.28.1 // indirect
rsc.io/qr v0.2.0 // indirect
)
27 changes: 27 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek=
filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mdp/qrterminal v1.0.1 h1:07+fzVDlPuBlXS8tB0ktTAyf+Lp1j2+2zK3fBOL5b7c=
github.com/mdp/qrterminal v1.0.1/go.mod h1:Z33WhxQe9B6CdW37HaVqcRKzP+kByF3q/qLxOGe12xQ=
github.com/mdp/qrterminal/v3 v3.0.0 h1:ywQqLRBXWTktytQNDKFjhAvoGkLVN3J2tAFZ0kMd9xQ=
github.com/mdp/qrterminal/v3 v3.0.0/go.mod h1:NJpfAs7OAm77Dy8EkWrtE4aq+cE6McoLXlBqXQEwvE0=
go.mau.fi/libsignal v0.0.0-20221015105917-d970e7c3c9cf h1:mzPxXBgDPHKDHMVV1tIWh7lwCiRpzCsXC0gNRX+K07c=
go.mau.fi/libsignal v0.0.0-20221015105917-d970e7c3c9cf/go.mod h1:XCjaU93vl71YNRPn059jMrK0xRDwVO5gKbxoPxow9mQ=
go.mau.fi/whatsmeow v0.0.0-20221202110551-e067ee7293b0 h1:danzDOlj/KiDi8kNsaHOhwJ7IZdo7V7hXelkZXhJhsc=
go.mau.fi/whatsmeow v0.0.0-20221202110551-e067ee7293b0/go.mod h1:2yweL8nczvtlIxkrvCb0y8xiO13rveX9lJPambwYV/E=
golang.org/x/crypto v0.0.0-20221012134737-56aed061732a h1:NmSIgad6KjE6VvHciPZuNRTKxGhlPfD6OA87W/PLkqg=
golang.org/x/crypto v0.0.0-20221012134737-56aed061732a/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY=
rsc.io/qr v0.2.0/go.mod h1:IF+uZjkb9fqyeF/4tlBoynqmQxUoPfWEKh921coOuXs=
110 changes: 110 additions & 0 deletions main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
package main

import (
"bytes"
"context"
"fmt"
"net/http"
"net/url"
"os"
"os/signal"
"syscall"

_ "github.com/mattn/go-sqlite3"
"github.com/mdp/qrterminal/v3"
"go.mau.fi/whatsmeow"
waProto "go.mau.fi/whatsmeow/binary/proto"
"go.mau.fi/whatsmeow/store/sqlstore"
"go.mau.fi/whatsmeow/types"
"go.mau.fi/whatsmeow/types/events"
waLog "go.mau.fi/whatsmeow/util/log"
"google.golang.org/protobuf/proto"
)

type MyClient struct {
WAClient *whatsmeow.Client
eventHandlerID uint32
}

func (mycli *MyClient) register() {
mycli.eventHandlerID = mycli.WAClient.AddEventHandler(mycli.eventHandler)
}

func (mycli *MyClient) eventHandler(evt interface{}) {
switch v := evt.(type) {
case *events.Message:
newMessage := v.Message
msg := newMessage.GetExtendedTextMessage().GetText()
fmt.Println("Message received:", msg)
// Make a http request to localhost:5001/chat?q= with the message, and send the response
// URL encode the message
urlEncoded := url.QueryEscape(msg)
// Make the request
resp, err := http.Get("http://localhost:5001/chat?q=" + urlEncoded)
if err != nil {
fmt.Println("Error making request:", err)
return
}
// Read the response
buf := new(bytes.Buffer)
buf.ReadFrom(resp.Body)
newMsg := buf.String()
// encode out as a string
response := &waProto.Message{Conversation: proto.String(string(newMsg))}
userJid := types.NewJID(v.Info.Sender.User, types.DefaultUserServer)
mycli.WAClient.SendMessage(context.Background(), userJid, "", response)

}
}

func main() {
dbLog := waLog.Stdout("Database", "DEBUG", true)
// Make sure you add appropriate DB connector imports, e.g. github.com/mattn/go-sqlite3 for SQLite
container, err := sqlstore.New("sqlite3", "file:examplestore.db?_foreign_keys=on", dbLog)
if err != nil {
panic(err)
}
// If you want multiple sessions, remember their JIDs and use .GetDevice(jid) or .GetAllDevices() instead.
deviceStore, err := container.GetFirstDevice()
if err != nil {
panic(err)
}
clientLog := waLog.Stdout("Client", "DEBUG", true)
client := whatsmeow.NewClient(deviceStore, clientLog)
// add the eventHandler
mycli := &MyClient{WAClient: client}
mycli.register()

if client.Store.ID == nil {
// No ID stored, new login
qrChan, _ := client.GetQRChannel(context.Background())
err = client.Connect()
if err != nil {
panic(err)
}
for evt := range qrChan {
if evt.Event == "code" {
// Render the QR code here
// e.g. qrterminal.GenerateHalfBlock(evt.Code, qrterminal.L, os.Stdout)
// or just manually `echo 2@... | qrencode -t ansiutf8` in a terminal
qrterminal.GenerateHalfBlock(evt.Code, qrterminal.L, os.Stdout)
// fmt.Println("QR code:", evt.Code)
} else {
fmt.Println("Login event:", evt.Event)
}
}
} else {
// Already logged in, just connect
err = client.Connect()
if err != nil {
panic(err)
}
}

// Listen to Ctrl+C (you can also do something else that prevents the program from exiting)
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
<-c

client.Disconnect()
}
61 changes: 61 additions & 0 deletions server.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
"""Make some requests to OpenAI's chatbot"""

import time
import os
import flask

from flask import g

from playwright.sync_api import sync_playwright

APP = flask.Flask(__name__)
PLAY = sync_playwright().start()
BROWSER = PLAY.chromium.launch_persistent_context(
user_data_dir="/tmp/playwright",
headless=False,
)
PAGE = BROWSER.new_page()

def get_input_box():
"""Get the child textarea of `PromptTextarea__TextareaWrapper`"""
return PAGE.query_selector("div[class*='PromptTextarea__TextareaWrapper']").query_selector("textarea")

def is_logged_in():
# See if we have a textarea with data-id="root"
return get_input_box() is not None

def send_message(message):
# Send the message
box = get_input_box()
box.click()
box.fill(message)
box.press("Enter")

def get_last_message():
"""Get the latest message"""
page_elements = PAGE.query_selector_all("div[class*='ConversationItem__Message']")
last_element = page_elements[-1]
return last_element.inner_text()

@APP.route("/chat", methods=["GET"])
def chat():
message = flask.request.args.get("q")
print("Sending message: ", message)
send_message(message)
time.sleep(10) # TODO: there are about ten million ways to be smarter than this
response = get_last_message()
print("Response: ", response)
return response

def start_browser():
PAGE.goto("https://chat.openai.com/")
if not is_logged_in():
print("Please log in to OpenAI Chat")
print("Press enter when you're done")
input()
else:
print("Logged in")
APP.run(port=5001, threaded=False)

if __name__ == "__main__":
start_browser()

0 comments on commit 7fbb5d4

Please sign in to comment.