├── .sample_env ├── whatgpt.service ├── .gitignore ├── go.mod ├── types.go ├── Dockerfile ├── go.sum ├── README.md ├── aigen.go └── main.go /.sample_env: -------------------------------------------------------------------------------- 1 | OPENAIKEY="" 2 | IMGAIKEY="" 3 | IMGAISECRET="" -------------------------------------------------------------------------------- /whatgpt.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=WhatChatGPT 3 | After=network.target 4 | 5 | [Service] 6 | Type=simple 7 | User=your_username 8 | WorkingDirectory=/path/to/your/app 9 | ExecStart=/path/to/your/app/your_app_name 10 | Restart=always 11 | 12 | [Install] 13 | WantedBy=multi-user.target -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.dll 4 | 5 | # Executable 6 | *.out 7 | 8 | # Packages 9 | /vendor/ 10 | /node_modules/ 11 | 12 | # Compiled Object Files 13 | *.o 14 | *.obj 15 | 16 | # Image files 17 | *.jpg 18 | *.png 19 | *.jpeg 20 | 21 | # Test binary, Subdirectories 22 | **/testbin/ 23 | **/tests/ 24 | 25 | # Log files 26 | *.log 27 | 28 | # OS generated files 29 | .DS_Store 30 | *.db -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module ChatGPT 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/joho/godotenv v1.5.1 7 | github.com/mattn/go-sqlite3 v1.14.16 8 | github.com/mdp/qrterminal/v3 v3.0.0 9 | go.mau.fi/whatsmeow v0.0.0-20230222131820-858ec581c8c5 10 | google.golang.org/protobuf v1.33.0 11 | ) 12 | 13 | require ( 14 | filippo.io/edwards25519 v1.0.0 // indirect 15 | github.com/gorilla/websocket v1.5.0 // indirect 16 | go.mau.fi/libsignal v0.1.0 // indirect 17 | golang.org/x/crypto v0.17.0 // indirect 18 | rsc.io/qr v0.2.0 // indirect 19 | ) 20 | -------------------------------------------------------------------------------- /types.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | type ChatRequest struct { 4 | Model string `json:"model"` 5 | Messages []map[string]string `json:"messages"` 6 | Temperature float64 `json:"temperature"` 7 | TopP float64 `json:"top_p"` 8 | N int `json:"n"` 9 | PresencePenalty float64 `json:"presence_penalty"` 10 | FrequencyPenalty float64 `json:"frequency_penalty"` 11 | } 12 | 13 | type ChatResponse struct { 14 | Choices []struct { 15 | Message struct { 16 | Role string `json:"role"` 17 | Content string `json:"content"` 18 | } `json:"message"` 19 | } `json:"choices"` 20 | } 21 | 22 | type envs struct { 23 | OpenAIKey string 24 | AiImgSecret string 25 | AiImgKey string 26 | } 27 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Set the base image to Ubuntu 2 | FROM ubuntu:latest 3 | 4 | # Install packages required for WhatChatGPT application 5 | RUN apt-get update && \ 6 | apt-get install -y build-essential git wget gcc &&\ 7 | apt-get clean 8 | 9 | # Download and install Go 10 | ENV GO_VERSION 1.19 11 | RUN wget https://dl.google.com/go/go$GO_VERSION.linux-amd64.tar.gz &&\ 12 | tar -xzf go$GO_VERSION.linux-amd64.tar.gz &&\ 13 | chown -R root:root ./go &&\ 14 | mv go /usr/local 15 | 16 | ENV GOPATH /go 17 | ENV PATH $GOPATH/bin:/usr/local/go/bin:$PATH 18 | 19 | # Clone source code from github repository 20 | RUN git clone https://github.com/TAMILVIP007/WhatChatGPT.git 21 | 22 | WORKDIR /WhatChatGPT 23 | 24 | # Run Go mod tidy and install dependencies 25 | RUN go mod tidy && \ 26 | go install github.com/TAMILVIP007/WhatChatGPT 27 | 28 | # Compile the Go application 29 | RUN go build -o whatchatgpt main.go 30 | 31 | # Make executable file 32 | RUN chmod +x whatchatgpt 33 | 34 | # Run the executable 35 | CMD ["./whatchatgpt"] -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= 2 | filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= 3 | github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= 4 | github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= 5 | github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= 6 | github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= 7 | github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 8 | github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= 9 | github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= 10 | github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= 11 | github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= 12 | github.com/mdp/qrterminal v1.0.1/go.mod h1:Z33WhxQe9B6CdW37HaVqcRKzP+kByF3q/qLxOGe12xQ= 13 | github.com/mdp/qrterminal/v3 v3.0.0 h1:ywQqLRBXWTktytQNDKFjhAvoGkLVN3J2tAFZ0kMd9xQ= 14 | github.com/mdp/qrterminal/v3 v3.0.0/go.mod h1:NJpfAs7OAm77Dy8EkWrtE4aq+cE6McoLXlBqXQEwvE0= 15 | go.mau.fi/libsignal v0.1.0 h1:vAKI/nJ5tMhdzke4cTK1fb0idJzz1JuEIpmjprueC+c= 16 | go.mau.fi/libsignal v0.1.0/go.mod h1:R8ovrTezxtUNzCQE5PH30StOQWWeBskBsWE55vMfY9I= 17 | go.mau.fi/whatsmeow v0.0.0-20230222131820-858ec581c8c5 h1:MWVwmVf1RhwU8qQ/cW/OWny4AFW2JxKuAg2CGAmsYC4= 18 | go.mau.fi/whatsmeow v0.0.0-20230222131820-858ec581c8c5/go.mod h1:zoTtv1CupGEyTew7TOwnBmTbHB4pVad2OzjTf5CVwa0= 19 | golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= 20 | golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= 21 | golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 22 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= 23 | google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= 24 | google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 25 | rsc.io/qr v0.2.0 h1:6vBLea5/NRMVTz8V66gipeLycZMl/+UlFmk8DvqQ6WY= 26 | rsc.io/qr v0.2.0/go.mod h1:IF+uZjkb9fqyeF/4tlBoynqmQxUoPfWEKh921coOuXs= 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WhatChatGPT 2 | 3 | ## Whatsapp Chatbot with Golang and Whatsmeow 4 | This project is an open-source chatbot for Whatsapp, built with Golang and the Whatsmeow library. It uses OpenAI to generate responses, enabling it to have complex conversations. This repo provides you with all the tools required for getting your own chatbot up and running. 5 | 6 | ## Overview 7 | The Whatsapp Chatbot with Golang & OpenAI is a project that enables users to create their own conversational AI bot for Whatsapp. It takes advantage of the OpenAI platform to train its own model and use it to generate responses based on user inputs. This project also features an advanced image recognition component that can identify objects in images sent by the user. The Whatsmeow library simplifies the entire process by providing users with all the necessary tools to create powerful chatbots. 8 | 9 | ## Features 10 | * Send message as input, receive response as output 11 | * Send image as input, receive AI generated anime image as output 12 | 13 | ## Hosting Options 14 | You can deploy your chatbot on any hosting provider of your choice. For example, if you're using Amazon Web Services (AWS), you can host your chatbot using AWS Lambda. Additionally, you can also host your chatbot using a .service file format. To do this, you will need to add your code to the .service file, configure your environment and set up the appropriate permissions to allow the service to run. You may also need to adjust the configuration settings of your operating system. 15 | 16 | Once all the setup and configurations are complete, you can then run your chatbot using the .service file and start interacting with users. 17 | 18 | We hope that this tutorial helps you get started with creating your own Whatsapp chatbot application. For more information and other tutorials, please check out our website. Thanks! 19 | 20 | 21 | ### Requirements 22 | - Golang (1.18 or higher) 23 | - Whatsmeow library 24 | - A hosting provider for deployment 25 | 26 | 27 | ### Prerequisites 28 | You'll need access to Golang, the Whatsmeow library, an access token from https://mtlab.meitu.com/ and an API Key from https://platform.openai.com/account/api-keys. 29 | 30 | ### Setting Up Variables 31 | Add the following variables to your code: 32 | 33 | * `OPENAIKEY` - the API key obtained from OpenAI 34 | * `IMGAIKEY` - the access token obtained from mtlab.meitu.com 35 | * `IMGAISECRET` - the secret associated with the access token obtained from mtlab.meitu.com 36 | 37 | ### Obtaining Access Token and API Key 38 | To obtain the access token from mtlab.meitu.com, go to the website, log in to your Meitu account and follow their instructions. 39 | 40 | To obtain the API key from OpenAI, you must register for an OpenAI account. Then, you can locate and copy the API key from the Keys & Tokens tab in the account settings page. 41 | 42 | 43 | ## Installation 44 | 1. Clone the repository: `git clone https://github.com/TAMILVIP007/WhatChatGPT` 45 | 2. Navigate to the project directory: `cd WhatChatGPT` 46 | 3. Install Whatsmeow: `go mod tidy` 47 | 4. Build the project: `go build .` 48 | 5. Deploy the bot to your chosen hosting provider 49 | 50 | ## Documentation 51 | For more detailed instructions and documentation, please refer to the README file in the project repo. 52 | 53 | ## Hosting with a .service File 54 | If you want to host this chatbot as a service running in the background, you can create a .service file that contains all the information needed to start the chatbot. This file will be installed in /etc/systemd/system/, where it will be run automatically when the system starts. 55 | 56 | You will need to include the following information in the file: 57 | • The path to the executable of your chatbot. 58 | • The user and group that will own the process. 59 | • Any environment variables needed by the chatbot. 60 | • Any other settings or flags that are required. 61 | 62 | Once the .service file is created, you can enable it to start up at boot time by running the command ‘sudo systemctl enable [service name]’. You can then start or stop the service with the commands ‘sudo systemctl start [service name]’ and ‘sudo systemctl stop [service name]’. 63 | 64 | 65 | ## Live Demo 66 | You can try out a live demo of the chatbot [here](https://wa.me/+18739002988). 67 | 68 | ## Support 69 | If you encounter any issues when setting up or running this repository, please contact us for support via our support chat at [Bots Realm](https://t.me/mybotsrealm). 70 | 71 | ## License & Credits 72 | The code in this repo has been written under the MIT license and all credit for the code should be attributed to the original author. Additionally, credit should be given to [Whatsmeow](https://github.com/tulir/whatsmeow) and OpenAI for their respective technologies used within the application. 73 | 74 | -------------------------------------------------------------------------------- /aigen.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bytes" 5 | "encoding/base64" 6 | "encoding/json" 7 | "fmt" 8 | "log" 9 | "io" 10 | "net/http" 11 | ) 12 | 13 | // GenAIimg function is used to generate anime images based on the input image bytes 14 | func GenAIimg(imageBytes []byte) ([]byte, error) { 15 | // Encode image in base64 string 16 | encodedString := base64.StdEncoding.EncodeToString(imageBytes) 17 | // Create payload with all the required info into a map 18 | payload := map[string]interface{}{ 19 | "parameter": map[string]string{ 20 | "rsp_media_type": "jpg", 21 | }, 22 | "extra": map[string]interface{}{}, 23 | "media_info_list": []map[string]interface{}{ 24 | { 25 | "media_data": encodedString, 26 | "media_profiles": map[string]string{ 27 | "media_data_type": "jpg", 28 | }, 29 | "media_extra": map[string]interface{}{}, 30 | }, 31 | }, 32 | } 33 | // Marshal payload map into json bytes 34 | payloadBytes, err := json.Marshal(payload) 35 | if err != nil { 36 | log.Printf("Couldn't marshal json data: %s", err.Error()) 37 | } 38 | // Initialize http client to send requests 39 | client := &http.Client{} 40 | // Create a http POST request and set headers 41 | req, err := http.NewRequest("POST", fmt.Sprintf("https://openapi.mtlab.meitu.com/v1/stable_diffusion_anime?api_key=%s&api_secret=%s", env.AiImgKey, env.AiImgSecret), nil) 42 | if err != nil { 43 | log.Printf("Can't Send http req: %s", err.Error()) 44 | } 45 | req.Header.Set("Content-Type", "application/json") 46 | // Set request body to the payload we created earlier 47 | req.Body = io.NopCloser(bytes.NewReader(payloadBytes)) 48 | // Send the request and set the response to res variable 49 | resp, err := client.Do(req) 50 | if err != nil { 51 | return nil, err 52 | } 53 | // Close the response body when the function returns 54 | defer resp.Body.Close() 55 | 56 | // Read all bytes from the response body 57 | respBytes, err := io.ReadAll(resp.Body) 58 | if err != nil { 59 | return nil, err 60 | } 61 | // Unmarshal response to a map 62 | var respMap map[string]interface{} 63 | err = json.Unmarshal(respBytes, &respMap) 64 | if err != nil { 65 | return nil, err 66 | } 67 | 68 | // Get media data from the repose and convert it back to bytes 69 | mediaList, ok := respMap["media_info_list"].([]interface{}) 70 | if !ok || len(mediaList) == 0 { 71 | return nil, fmt.Errorf("invalid response format: media_info_list field is missing or has an invalid format") 72 | } 73 | mediaData, ok := mediaList[0].(map[string]interface{})["media_data"].(string) 74 | if !ok { 75 | return nil, fmt.Errorf("invalid response format: media_data field is missing or has an invalid format") 76 | } 77 | decodedBytes, err := base64.StdEncoding.DecodeString(mediaData) 78 | if err != nil { 79 | return nil, err 80 | } 81 | return decodedBytes, nil 82 | } 83 | 84 | // GetAiTextResponse function is used to get AI text response for the given input message 85 | func GetAiTextResponse(msg string) (string, error) { 86 | // Define URL and payload structure 87 | url := "https://api.openai.com/v1/chat/completions" 88 | payload := ChatRequest{ 89 | Model: "gpt-3.5-turbo", 90 | Messages: []map[string]string{ 91 | { 92 | "role": "user", 93 | "content": msg, 94 | }, 95 | }, 96 | Temperature: 1.0, 97 | TopP: 1.0, 98 | N: 1, 99 | PresencePenalty: 0, 100 | FrequencyPenalty: 0, 101 | } 102 | 103 | // Marshall structure into JSON 104 | jsonPayload, err := json.Marshal(payload) 105 | if err != nil { 106 | return "", fmt.Errorf("error marshalling payload: %v", err.Error()) 107 | } 108 | 109 | // Create new http post request 110 | req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonPayload)) 111 | if err != nil { 112 | return "", fmt.Errorf("error creating request: %v", err.Error()) 113 | } 114 | // Set required headers 115 | req.Header.Set("Content-Type", "application/json") 116 | req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", env.OpenAIKey)) 117 | 118 | // Initialize the client and send the request 119 | client := &http.Client{} 120 | resp, err := client.Do(req) 121 | if err != nil { 122 | return "", fmt.Errorf("error sending request: %v", err.Error()) 123 | } 124 | 125 | // Close response body after it is read 126 | defer resp.Body.Close() 127 | responseBody, err := io.ReadAll(resp.Body) 128 | if err != nil { 129 | return "", fmt.Errorf("error reading response body: %v", err.Error()) 130 | } 131 | 132 | // Unmarshal the chat response from bytes 133 | var chatResponse ChatResponse 134 | if err = json.Unmarshal(responseBody, &chatResponse); err != nil { 135 | return "", fmt.Errorf("error unmarshalling response body: %v", err.Error()) 136 | } 137 | if len(chatResponse.Choices) == 0 { 138 | log.Printf("Resp From OpenAi: %s", responseBody) 139 | return "", fmt.Errorf("error getting response from OpenAI") 140 | } 141 | content := chatResponse.Choices[0].Message.Content 142 | return content, nil 143 | } 144 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | ctx "context" 5 | "fmt" 6 | "log" 7 | "net/http" 8 | "os" 9 | "os/signal" 10 | "syscall" 11 | "time" 12 | 13 | "github.com/joho/godotenv" 14 | _ "github.com/mattn/go-sqlite3" 15 | "github.com/mdp/qrterminal/v3" 16 | "go.mau.fi/whatsmeow" 17 | wp "go.mau.fi/whatsmeow/binary/proto" 18 | "go.mau.fi/whatsmeow/store/sqlstore" 19 | "go.mau.fi/whatsmeow/types/events" 20 | waLog "go.mau.fi/whatsmeow/util/log" 21 | "google.golang.org/protobuf/proto" 22 | ) 23 | 24 | var client *whatsmeow.Client 25 | 26 | func loadenv() *envs { 27 | // Load environment variables from .env file 28 | err := godotenv.Load(".env") 29 | if err != nil { 30 | log.Fatalf("Error loading .env file: %v", err) 31 | } 32 | log.Println("Loaded environment variables from .env file") 33 | // Create struct containing environment variables 34 | env := envs{ 35 | OpenAIKey: os.Getenv("OPENAIKEY"), 36 | AiImgKey: os.Getenv("IMGAIKEY"), 37 | AiImgSecret: os.Getenv("IMGAISECRET"), 38 | } 39 | 40 | return &env 41 | } 42 | 43 | var env = loadenv() 44 | 45 | // eventHandler handles incoming events and dispatches them to the appropriate functions 46 | func eventHandler(evt interface{}) { 47 | // Check if event is a message 48 | if evt, ok := evt.(*events.Message); ok { 49 | // Handle image messages 50 | if evt.Message.ImageMessage != nil { 51 | go handleImageMessage(evt) 52 | } 53 | // Handle text messages 54 | if evt.Message.GetConversation() != "" { 55 | go handleConversation(evt) 56 | } 57 | } 58 | } 59 | 60 | // handleImageMessage handles incoming image messages by generating an AI-generated image response and sending it back 61 | func handleImageMessage(evt *events.Message) { 62 | // Download image data from the message 63 | imageData, _ := client.Download(evt.Message.GetImageMessage()) 64 | // Generate an AI-generated image using the downloaded data 65 | imageBytes, err := GenAIimg(imageData) 66 | if err != nil { 67 | // Send an error message if there was an error generating the image 68 | client.SendMessage(ctx.Background(), evt.Info.Chat, &wp.Message{ 69 | Conversation: proto.String(err.Error()), 70 | }) 71 | return 72 | } 73 | // Upload the generated image to WhatsApp 74 | uploadedImage, err := client.Upload(ctx.Background(), imageBytes, whatsmeow.MediaImage) 75 | if err != nil { 76 | // Send an error message if there was an error uploading the image 77 | client.SendMessage(ctx.Background(), evt.Info.Chat, &wp.Message{ 78 | Conversation: proto.String(err.Error()), 79 | }) 80 | return 81 | } 82 | // Create a message to send back containing the uploaded image 83 | msgToSend := &wp.Message{ 84 | ImageMessage: &wp.ImageMessage{ 85 | Caption: proto.String("AI-generated image"), 86 | Url: proto.String(uploadedImage.URL), 87 | DirectPath: proto.String(uploadedImage.DirectPath), 88 | MediaKey: uploadedImage.MediaKey, 89 | MediaKeyTimestamp: proto.Int64(time.Now().Unix()), 90 | Mimetype: proto.String(http.DetectContentType(imageBytes)), 91 | FileEncSha256: uploadedImage.FileEncSHA256, 92 | FileSha256: uploadedImage.FileSHA256, 93 | FileLength: proto.Uint64(uint64(len(imageBytes))), 94 | Height: proto.Uint32(uint32(evt.Message.GetImageMessage().GetHeight())), 95 | Width: proto.Uint32(uint32(evt.Message.GetImageMessage().GetWidth())), 96 | }, 97 | } 98 | // Send the message back to the chat 99 | _, err = client.SendMessage(ctx.Background(), evt.Info.Chat, msgToSend) 100 | if err != nil { 101 | // Send an error message if there was an error sending the message 102 | client.SendMessage(ctx.Background(), evt.Info.Chat, &wp.Message{ 103 | Conversation: proto.String(err.Error()), 104 | }) 105 | } 106 | } 107 | 108 | // handleConversation handles incoming text messages by generating an AI-generated text response and sending it back 109 | func handleConversation(evt *events.Message) { 110 | // Generate an AI-generated text response using the message text 111 | msg, err := GetAiTextResponse(evt.Message.GetConversation()) 112 | if err != nil { 113 | // Send an error message if there was an error generating the text response 114 | client.SendMessage(ctx.Background(), evt.Info.Chat, &wp.Message{ 115 | Conversation: proto.String(err.Error()), 116 | }) 117 | return 118 | } 119 | // Create a message to send back containing the generated text 120 | client.SendMessage(ctx.Background(), evt.Info.Chat, &wp.Message{ 121 | ExtendedTextMessage: &wp.ExtendedTextMessage{ 122 | Text: proto.String(msg), 123 | ContextInfo: &wp.ContextInfo{ 124 | QuotedMessage: &wp.Message{ 125 | Conversation: proto.String(evt.Message.GetConversation()), 126 | }, 127 | StanzaId: proto.String(evt.Info.ID), 128 | Participant: proto.String(evt.Info.Sender.ToNonAD().String()), 129 | }, 130 | }, 131 | }) 132 | } 133 | 134 | func main() { 135 | // Set up logging for the database 136 | dbLog := waLog.Stdout("Database", "INFO", true) 137 | // Create a new SQL store container 138 | container, err := sqlstore.New("sqlite3", "file:whatgpt.db?_foreign_keys=on", dbLog) 139 | if err != nil { 140 | panic(err) 141 | } 142 | 143 | // Get the first device from the container 144 | deviceStore, err := container.GetFirstDevice() 145 | if err != nil { 146 | panic(err) 147 | } 148 | 149 | // Set up logging for the client 150 | clientLog := waLog.Stdout("Client", "INFO", true) 151 | 152 | client = whatsmeow.NewClient(deviceStore, clientLog) 153 | 154 | client.AddEventHandler(eventHandler) 155 | 156 | // Check if client is already logged in 157 | if client.Store.ID == nil { 158 | qrChan, _ := client.GetQRChannel(ctx.Background()) 159 | // Connect to WhatsApp 160 | err = client.Connect() 161 | if err != nil { 162 | panic(err) 163 | } 164 | // Print the QR code to the console 165 | for evt := range qrChan { 166 | if evt.Event == "code" { 167 | qrterminal.GenerateHalfBlock(evt.Code, qrterminal.L, os.Stdout) 168 | } else { 169 | fmt.Println("Login event:", evt.Event) 170 | } 171 | } 172 | } else { 173 | // Connect to WhatsApp if already logged in 174 | err = client.Connect() 175 | if err != nil { 176 | panic(err) 177 | } 178 | } 179 | 180 | c := make(chan os.Signal, 1) 181 | signal.Notify(c, os.Interrupt, syscall.SIGTERM) 182 | <-c 183 | 184 | client.Disconnect() 185 | } 186 | --------------------------------------------------------------------------------