├── AIAgent ├── scraping │ └── characters.py ├── .gitignore ├── .env.example ├── requirements.txt ├── Dockerfile ├── emotions.txt ├── character.py ├── characters │ ├── 50characters.txt │ └── characterimport.py ├── main.py └── tools.py ├── AgentAPI ├── .env.example ├── .idea │ └── .gitignore ├── middleware │ └── middleware.go ├── characters.go ├── main.go ├── aitwitter-2a8ac-5d46648017ce.json ├── controllers │ ├── users │ │ └── users.go │ └── tweets │ │ └── tweets.go ├── go.mod ├── utils │ └── utils.go └── go.sum ├── run.sh ├── Dockerfile └── .gitignore /AIAgent/scraping/characters.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /AIAgent/.gitignore: -------------------------------------------------------------------------------- 1 | .env 2 | .venv 3 | .idea -------------------------------------------------------------------------------- /AIAgent/.env.example: -------------------------------------------------------------------------------- 1 | TAVILY_API_KEY= 2 | OPENAI_API_KEY= 3 | DATABASE_URL= -------------------------------------------------------------------------------- /AgentAPI/.env.example: -------------------------------------------------------------------------------- 1 | STABILITY_AI_API_KEY= 2 | 3 | NEON_API_KEY= 4 | 5 | DEBUG= 6 | 7 | BUCKET_NAME= -------------------------------------------------------------------------------- /AIAgent/requirements.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodingWithLewis/AISocialMediaAgent/HEAD/AIAgent/requirements.txt -------------------------------------------------------------------------------- /AgentAPI/.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Editor-based HTTP Client requests 5 | /httpRequests/ 6 | # Datasource local storage ignored files 7 | /dataSources/ 8 | /dataSources.local.xml 9 | -------------------------------------------------------------------------------- /AIAgent/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.10.13-bullseye 2 | 3 | WORKDIR /app 4 | 5 | COPY . /app 6 | 7 | RUN apt-get update && apt-get install -y python3-pip 8 | 9 | RUN pip3 install --upgrade pip 10 | 11 | RUN pip3 install --upgrade setuptools 12 | 13 | RUN pip3 install -r requirements.txt 14 | 15 | CMD ["python3", "main.py"] -------------------------------------------------------------------------------- /AIAgent/emotions.txt: -------------------------------------------------------------------------------- 1 | afraid 2 | angry 3 | calm 4 | cheerful 5 | cold 6 | crabby 7 | crazy 8 | cross 9 | excited 10 | frigid 11 | furious 12 | glad 13 | glum 14 | happy 15 | icy 16 | jolly 17 | jovial 18 | kind 19 | lively 20 | livid 21 | mad 22 | ornery 23 | rosy 24 | sad 25 | scared 26 | seething 27 | shy 28 | sunny 29 | tense 30 | tranquil 31 | upbeat 32 | wary 33 | weary 34 | worried -------------------------------------------------------------------------------- /AgentAPI/middleware/middleware.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "cloud.google.com/go/firestore" 5 | "firebase.google.com/go/storage" 6 | "github.com/gin-gonic/gin" 7 | ) 8 | 9 | func FirestoreClientMiddleware(client *firestore.Client, storageClient *storage.Client) gin.HandlerFunc { 10 | return func(c *gin.Context) { 11 | c.Set("firestore", client) 12 | c.Set("storageClient", storageClient) 13 | c.Next() 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /AIAgent/character.py: -------------------------------------------------------------------------------- 1 | import time 2 | from yaspin import yaspin 3 | from yaspin.spinners import Spinners 4 | 5 | 6 | 7 | r = input("Please input a Character Name: ") 8 | 9 | with yaspin() as sp: 10 | sp.text = f"Searching Fandom for {r}" 11 | time.sleep(3) 12 | sp.ok("✅ Found Character and Saved!") 13 | 14 | 15 | with yaspin() as sp: 16 | sp.text = f"Getting Image of {r}" 17 | time.sleep(5) 18 | sp.ok("✅ Found Image and Saved!") -------------------------------------------------------------------------------- /run.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | 4 | # Navigate to the AIAgent project directory and start the Go application 5 | cd AgentAPI 6 | # Source the .env file if your application needs environment variables 7 | # source .env 8 | # Replace `./myGoApp` with the command to start your Go application 9 | ./agentapi & 10 | goPID=$! 11 | 12 | 13 | 14 | # Navigate to the AgentAPI project directory and start the Python application 15 | cd ../AIAgent 16 | # Source the .env file if your application needs environment variables 17 | # source .env 18 | python3 main.py & 19 | pythonPID=$! 20 | 21 | 22 | # Wait for both applications to finish 23 | wait $pythonPID 24 | wait $goPID 25 | -------------------------------------------------------------------------------- /AgentAPI/characters.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | _ "github.com/lib/pq" 5 | ) 6 | 7 | // 8 | //func main() { 9 | // 10 | // err := godotenv.Load(".env") 11 | // 12 | // if err != nil { 13 | // log.Fatal("Error loading.env file") 14 | // } 15 | // 16 | // connStr := "postgresql://elebumm:" + os.Getenv("NEON_API_KEY") + "@ep-cool-moon-a5ygl65p-pooler.us-east-2.aws.neon.tech/aitwitter?sslmode=require" 17 | // db, err := sql.Open("postgres", connStr) 18 | // if err != nil { 19 | // panic(err) 20 | // } 21 | // defer db.Close() 22 | // 23 | // // Create table if not exists 24 | // _, err = db.Exec("CREATE TABLE IF NOT EXISTS users (id serial PRIMARY KEY, username VARCHAR(255), password VARCHAR(255), " + 25 | // "email VARCHAR(255), bio VARCHAR(255), image VARCHAR(255), created_at TIMESTAMP," + 26 | // "updated_at TIMESTAMP)") 27 | // 28 | //} 29 | -------------------------------------------------------------------------------- /AgentAPI/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | tweet "AgentAPI/controllers/tweets" 5 | user "AgentAPI/controllers/users" 6 | middleware "AgentAPI/middleware" 7 | "AgentAPI/utils" 8 | "context" 9 | "os" 10 | 11 | "github.com/gin-gonic/gin" 12 | ) 13 | 14 | func main() { 15 | 16 | ctx := context.Background() 17 | 18 | client, storageClient := utils.CreateFirestoreClient(ctx) 19 | defer client.Close() 20 | debug := os.Getenv("DEBUG") == "true" 21 | if debug { 22 | gin.SetMode(gin.DebugMode) 23 | } else { 24 | gin.SetMode(gin.DebugMode) 25 | } 26 | r := gin.Default() 27 | r.Use(middleware.FirestoreClientMiddleware(client, storageClient)) 28 | // Tweet Routes 29 | r.GET("/tweets/", tweet.GetTweetTimeline) 30 | r.GET("/tweets/:id/", tweet.GetTweet) 31 | r.POST("/tweet/", tweet.CreateTweet) 32 | r.POST("/image-tweet/", tweet.TweetImage) 33 | 34 | // User Routes 35 | r.POST("/user/", user.CreateUser) 36 | 37 | r.Run(":3000") 38 | } 39 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | # Use an official Ubuntu base image 2 | FROM ubuntu:latest 3 | 4 | # Install Go 5 | RUN apt-get update && \ 6 | apt-get -y install wget && \ 7 | wget https://dl.google.com/go/go1.21.6.linux-amd64.tar.gz && \ 8 | tar -xvf go1.21.6.linux-amd64.tar.gz && \ 9 | mv go /usr/local 10 | 11 | # Set Go environment variables 12 | ENV GOROOT=/usr/local/go 13 | ENV GOPATH=$HOME/go 14 | ENV PATH=$GOPATH/bin:$GOROOT/bin:$PATH 15 | 16 | # Install Python 17 | RUN apt-get -y install python3 python3-pip 18 | 19 | # Copy the Go project 20 | COPY ./AgentAPI /AgentAPI 21 | WORKDIR /AgentAPI 22 | # Build your Go project here, if necessary 23 | RUN go build -o agentapi 24 | 25 | 26 | # Copy the Python project 27 | COPY ./AIAgent /AIAgent 28 | WORKDIR /AIAgent 29 | # Install Python dependencies 30 | RUN pip3 install -r requirements.txt 31 | 32 | WORKDIR / 33 | 34 | COPY run.sh /run.sh 35 | RUN chmod 755 /run.sh 36 | # Optional: specify default command 37 | CMD ["./run.sh"] 38 | -------------------------------------------------------------------------------- /AIAgent/characters/50characters.txt: -------------------------------------------------------------------------------- 1 | Sherlock Holmes 2 | Batman 3 | Spider-Man 4 | Harry Potter 5 | James Bond 6 | Wonder Woman 7 | Mickey Mouse 8 | Luke Skywalker 9 | Frodo Baggins 10 | Darth Vader 11 | Superman 12 | Iron Man 13 | Hermione Granger 14 | Gandalf 15 | Link (The Legend of Zelda) 16 | Mario (Super Mario) 17 | Ariel (The Little Mermaid) 18 | Simba (The Lion King) 19 | Indiana Jones 20 | Wolverine 21 | Captain America 22 | Thor 23 | Hulk 24 | Black Widow 25 | Lara Croft (Tomb Raider) 26 | Master Chief (Halo) 27 | Solid Snake (Metal Gear Solid) 28 | Cloud Strife (Final Fantasy VII) 29 | Samus Aran (Metroid) 30 | Donkey Kong 31 | Kratos (God of War) 32 | Sonic the Hedgehog 33 | Megaman 34 | Pikachu (Pokémon) 35 | Naruto Uzumaki 36 | SpongeBob SquarePants 37 | Bugs Bunny 38 | Homer Simpson 39 | Optimus Prime (Transformers) 40 | Rick Sanchez (Rick and Morty) 41 | Jon Snow (Game of Thrones) 42 | Tony Soprano (The Sopranos) 43 | Michael Corleone (The Godfather) 44 | Vito Corleone (The Godfather) 45 | Scarlett O'Hara (Gone with the Wind) 46 | Elizabeth Bennet (Pride and Prejudice) 47 | Jay Gatsby (The Great Gatsby) 48 | Holden Caulfield (The Catcher in the Rye) 49 | Atticus Finch (To Kill a Mockingbird) 50 | Dracula 51 | Frankenstein's Monster 52 | Hamlet 53 | Romeo and Juliet 54 | Odysseus 55 | Beowulf 56 | -------------------------------------------------------------------------------- /AgentAPI/aitwitter-2a8ac-5d46648017ce.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "service_account", 3 | "project_id": "aitwitter-2a8ac", 4 | "private_key_id": "5d46648017cec904faa880311c9ba6574c4fbce4", 5 | "private_key": "-----BEGIN PRIVATE KEY-----\nMIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCOR+pnvqA6FUiK\nsE7rfCdiXaEq9/Twg105DM0YGrGmAlZs6HtpLpcGBUE7haQOsVnXjeZhY1tyrb6z\nCQXom3QpwHw019CcUDGW8ewxEgOmnfzndjJR0Vuv7+7sR61UyLgQjlJo674a/XTO\nJbDwBern3j4/GdlGeQeTQSln5XuJ84PT+8Tsj9iUJd3KLaafXDflHr3XHcjQ+UT3\nE6J0D/9mcH7QWHGuOGV6PawEKTWitXJAMYlfZqmE1nDZG54tI6obiz8WgvSP4irB\n9KRbhN4REBPlbt4XJQR9ZCSnVFg7oouMO8ULDh+gJPqbeZ3r3pnz9ac76pxCFQup\nSuWHipx1AgMBAAECggEABTikZHw9WwRO7i/8JW4f798pu+7vgSgA8sgCesD4BfSO\nAV8isEBycFkfBLUpyRQ/DMb7TlWcFIBFwEIzgk66G5IhvLqywBm9SCHGniJgGeww\nTLosrI33RGSUqv0SYksfXhQq+Ai2qDzm3W3KqXQ+I5YnSJ+FNq3YVlIM1/A28V/9\nUjaQ3Yx4sTDMKbDNrKqFzA6mtlIlUtUxbM3K2bT8MqbY0liUl8sT4TH8M3m5utlh\n6JBxC/DKaOnZhaVQch0n6mTtppTntP2Uzfn3hsGY31PacxS9FrVisPopIPvSQBhE\nNuHvUMai6BUqfi0JgAg0XJQS6xgm+Hf0TQZ07z/8XQKBgQDELQKfGocNFrbdvv95\npj+YS+aonJHjQpXo9/DiaVFONfIsn2x2Ud7LQUPpqvx2qpcUPYOHxPgbxY7H/I6l\nyiL6oNjDu6uvPzTV0JFvxef39e13cCJiLfsW3mlorARMXwphjYVXYApzwQc10xKN\nqliVjnIRmnouuzenvbV3atHjuwKBgQC5q3S4zwSeLi+7+THcxSVNd79mITpKkx+G\nya1g07r6CVEjVbV9E8omRmbt8RRZJY8DAXi4AlbiuMJYH6Ddn5y7BfGZUWoiTk36\nnkdDaOSTaASCz90EpRhSff9M1nzw8KhPjd14+2Knbkbmzw1da9BGGJ1Kka2FMqzF\nAAwDl5FFjwKBgQCDo5RzwTBIlypkiEsUjXt1LdF86Xt33XGM3/uzYmqdqdN1IBF/\nIBb5mzUAMq2wz24Lte9yBrlaoWnbRt1N4OMx/QcX6PIe6bIBnDBLqaisGkmb8RIR\ngbtQsDRZebx0pv3nUjjc1eSNokS9WILFrz48NVbT+y3r99Mz6zg/Bt4LCwKBgDP4\n65Zj1I4WraP3kF6VDOkPcRM8j92aK0QGpjKpcfhVrVGvxzq41Gg8YsmOJz0BB3Q2\n8DzJ4tpaD4StbdE7wZqUglmBca0isC9MKPSUow8kGccoOlz3fcRxooo2rAihxOtn\n8avQ6n+lndEz+jDBYi6M61KZTrIvSi9m4PYMcky/AoGASvWRRaohh2VLK2Ik69l4\nniL62ZDRj4twBmr1nwnfUlRXWfQul8EFUgiHyQ9kevvAnwrp2F3D9zOVD4z6S0Jf\ndwOjyYQi8N/KtiRzqz/nLzJogdP/XdbbZ2Yun2SCllyXEMHFrhsEmtBDIPj/jgnU\nyQmeR7dvjiKrCtRzPVFzgWQ=\n-----END PRIVATE KEY-----\n", 6 | "client_email": "golang@aitwitter-2a8ac.iam.gserviceaccount.com", 7 | "client_id": "100183591909390164700", 8 | "auth_uri": "https://accounts.google.com/o/oauth2/auth", 9 | "token_uri": "https://oauth2.googleapis.com/token", 10 | "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs", 11 | "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/golang%40aitwitter-2a8ac.iam.gserviceaccount.com", 12 | "universe_domain": "googleapis.com" 13 | } 14 | -------------------------------------------------------------------------------- /AgentAPI/controllers/users/users.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "cloud.google.com/go/firestore" 5 | "encoding/base64" 6 | "firebase.google.com/go/storage" 7 | "github.com/gin-gonic/gin" 8 | "github.com/google/uuid" 9 | "log" 10 | "net/http" 11 | "os" 12 | "strings" 13 | ) 14 | 15 | type User struct { 16 | ID string `json:"id" firestore:"id"` 17 | Bio *string `json:"bio" firestore:"bio"` 18 | Name string `json:"name" firestore:"name"` 19 | Theme string `json:"theme" firestore:"theme"` 20 | Accent string `json:"accent" firestore:"accent"` 21 | Website *string `json:"website" firestore:"website"` 22 | Location *string `json:"location" firestore:"location"` 23 | Username string `json:"username" firestore:"username"` 24 | PhotoBase64 string `json:"photoBase64"` 25 | Verified bool `json:"verified" firestore:"verified"` 26 | Following []string `json:"following" firestore:"following"` 27 | Followers []string `json:"followers" firestore:"followers"` 28 | } 29 | 30 | func CreateUser(c *gin.Context) { 31 | var data = User{} 32 | 33 | if err := c.ShouldBindJSON(&data); err != nil { 34 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 35 | return 36 | } 37 | 38 | client, _ := c.MustGet("firestore").(*firestore.Client) 39 | storageClient, _ := c.MustGet("storageClient").(*storage.Client) 40 | 41 | // Save image in Cloud Storage 42 | imageData, err := base64.StdEncoding.DecodeString(data.PhotoBase64[strings.IndexByte(data.PhotoBase64, ',')+1:]) 43 | 44 | filename := uuid.New().String() + ".jpg" 45 | 46 | imagePath := data.ID + "/images/" + filename 47 | 48 | if err != nil { 49 | log.Fatalln("Could not decode base64 string", err) 50 | } 51 | bucketName := os.Getenv("BUCKET_NAME") 52 | if os.Getenv("DEBUG") == "true" { 53 | bucketName = "aitwitter-dev.appspot.com" 54 | } 55 | bucket, err := storageClient.Bucket(bucketName) 56 | 57 | if err != nil { 58 | log.Fatalln("Could not get default bucket", err) 59 | } 60 | 61 | wc := bucket.Object(imagePath).NewWriter(c) 62 | 63 | if _, err = wc.Write(imageData); err != nil { 64 | log.Fatalf("error writing to Firebase Storage: %v", err) 65 | } 66 | if err := wc.Close(); err != nil { 67 | log.Fatalf("error closing Firebase Storage writer: %v", err) 68 | } 69 | 70 | // Get the URL of the image 71 | imgURL := wc.Attrs().MediaLink 72 | 73 | _, err = client.Collection("users").Doc(data.ID).Set(c, map[string]interface{}{ 74 | "id": data.ID, "bio": data.Bio, 75 | "name": data.Name, 76 | "theme": data.Theme, 77 | "accent": data.Accent, 78 | "website": data.Website, 79 | "username": data.Username, 80 | "photoBase64": data.PhotoBase64, 81 | "verified": data.Verified, 82 | "following": data.Following, 83 | "followers": data.Followers, 84 | "createdAt": firestore.ServerTimestamp, 85 | "updatedAt": firestore.ServerTimestamp, 86 | "photoURL": imgURL, 87 | }) 88 | 89 | if err != nil { 90 | c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) 91 | return 92 | } 93 | 94 | c.JSON(http.StatusCreated, gin.H{"message": "User created successfully"}) 95 | 96 | return 97 | } 98 | -------------------------------------------------------------------------------- /AgentAPI/go.mod: -------------------------------------------------------------------------------- 1 | module AgentAPI 2 | 3 | go 1.21 4 | 5 | require ( 6 | cloud.google.com/go v0.112.0 // indirect 7 | cloud.google.com/go/compute v1.23.3 // indirect 8 | cloud.google.com/go/compute/metadata v0.2.3 // indirect 9 | cloud.google.com/go/firestore v1.14.0 // indirect 10 | cloud.google.com/go/iam v1.1.5 // indirect 11 | cloud.google.com/go/longrunning v0.5.4 // indirect 12 | cloud.google.com/go/storage v1.37.0 // indirect 13 | firebase.google.com/go v3.13.0+incompatible // indirect 14 | github.com/bytedance/sonic v1.10.2 // indirect 15 | github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d // indirect 16 | github.com/chenzhuoyu/iasm v0.9.1 // indirect 17 | github.com/felixge/httpsnoop v1.0.4 // indirect 18 | github.com/gabriel-vasile/mimetype v1.4.3 // indirect 19 | github.com/gin-contrib/sse v0.1.0 // indirect 20 | github.com/gin-gonic/gin v1.9.1 // indirect 21 | github.com/go-logr/logr v1.4.1 // indirect 22 | github.com/go-logr/stdr v1.2.2 // indirect 23 | github.com/go-playground/locales v0.14.1 // indirect 24 | github.com/go-playground/universal-translator v0.18.1 // indirect 25 | github.com/go-playground/validator/v10 v10.17.0 // indirect 26 | github.com/goccy/go-json v0.10.2 // indirect 27 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect 28 | github.com/golang/protobuf v1.5.3 // indirect 29 | github.com/google/s2a-go v0.1.7 // indirect 30 | github.com/google/uuid v1.6.0 // indirect 31 | github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect 32 | github.com/googleapis/gax-go/v2 v2.12.0 // indirect 33 | github.com/joho/godotenv v1.5.1 // indirect 34 | github.com/json-iterator/go v1.1.12 // indirect 35 | github.com/klauspost/cpuid/v2 v2.2.6 // indirect 36 | github.com/leodido/go-urn v1.3.0 // indirect 37 | github.com/lib/pq v1.10.9 // indirect 38 | github.com/mattn/go-isatty v0.0.20 // indirect 39 | github.com/milvus-io/milvus-sdk-go/v2 v2.3.3 // indirect 40 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 41 | github.com/modern-go/reflect2 v1.0.2 // indirect 42 | github.com/pelletier/go-toml/v2 v2.1.1 // indirect 43 | github.com/tidwall/gjson v1.17.0 // indirect 44 | github.com/tidwall/match v1.1.1 // indirect 45 | github.com/tidwall/pretty v1.2.1 // indirect 46 | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect 47 | github.com/ugorji/go/codec v1.2.12 // indirect 48 | go.opencensus.io v0.24.0 // indirect 49 | go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 // indirect 50 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect 51 | go.opentelemetry.io/otel v1.22.0 // indirect 52 | go.opentelemetry.io/otel/metric v1.22.0 // indirect 53 | go.opentelemetry.io/otel/trace v1.22.0 // indirect 54 | golang.org/x/arch v0.7.0 // indirect 55 | golang.org/x/crypto v0.18.0 // indirect 56 | golang.org/x/net v0.20.0 // indirect 57 | golang.org/x/oauth2 v0.16.0 // indirect 58 | golang.org/x/sync v0.6.0 // indirect 59 | golang.org/x/sys v0.16.0 // indirect 60 | golang.org/x/text v0.14.0 // indirect 61 | golang.org/x/time v0.5.0 // indirect 62 | google.golang.org/api v0.161.0 // indirect 63 | google.golang.org/appengine v1.6.8 // indirect 64 | google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac // indirect 65 | google.golang.org/genproto/googleapis/api v0.0.0-20240122161410-6c6643bf1457 // indirect 66 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac // indirect 67 | google.golang.org/grpc v1.60.1 // indirect 68 | google.golang.org/protobuf v1.32.0 // indirect 69 | gopkg.in/yaml.v3 v3.0.1 // indirect 70 | ) 71 | -------------------------------------------------------------------------------- /AgentAPI/utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "bytes" 5 | "cloud.google.com/go/firestore" 6 | "context" 7 | "encoding/json" 8 | firebase "firebase.google.com/go" 9 | "firebase.google.com/go/storage" 10 | "github.com/joho/godotenv" 11 | "github.com/tidwall/gjson" 12 | "google.golang.org/api/option" 13 | "io" 14 | "log" 15 | "net/http" 16 | "os" 17 | ) 18 | 19 | func CreateFirestoreClient(ctx context.Context) (*firestore.Client, *storage.Client) { 20 | debug := os.Getenv("DEBUG") 21 | println("DEBUG: " + debug) 22 | if debug == "true" { 23 | // Set the Firestore emulator address 24 | os.Setenv("FIRESTORE_EMULATOR_HOST", "localhost:8080") 25 | // Set the Storage emulator address 26 | os.Setenv("STORAGE_EMULATOR_HOST", "localhost:9199") 27 | } 28 | var saPath option.ClientOption 29 | if debug != "true" { 30 | // Use credentials file only if not in debug mode 31 | saPath = option.WithCredentialsFile("aitwitter-2a8ac-5d46648017ce.json") 32 | } else { 33 | // Use no authentication for emulator 34 | saPath = option.WithoutAuthentication() 35 | } 36 | 37 | // Initialize Firestore client 38 | firestoreClient, err := firestore.NewClient(ctx, "aitwitter-2a8ac", saPath) 39 | if err != nil { 40 | log.Fatalf("Failed to create Firestore client: %v", err) 41 | } 42 | 43 | // Initialize Cloud Storage client 44 | var app *firebase.App 45 | if debug != "true" { 46 | // Initialize Firebase app with credentials in non-debug mode 47 | config := &firebase.Config{ 48 | StorageBucket: "aitwitter-2a8ac.appspot.com", 49 | } 50 | app, err = firebase.NewApp(ctx, config, saPath) 51 | if err != nil { 52 | log.Fatalln(err) 53 | } 54 | } else { 55 | // Initialize Firebase app without authentication in debug mode 56 | app, err = firebase.NewApp(ctx, nil, option.WithoutAuthentication()) 57 | if err != nil { 58 | log.Fatalln(err) 59 | } 60 | } 61 | 62 | storageClient, err := app.Storage(ctx) 63 | if err != nil { 64 | log.Fatalln(err) 65 | } 66 | 67 | return firestoreClient, storageClient 68 | } 69 | 70 | func GenerateAIImage(prompt string) string { 71 | 72 | err := godotenv.Load(".env") 73 | if err != nil { 74 | log.Fatalln("Error in env file") 75 | } 76 | 77 | url := "https://api.stability.ai/v1/generation/stable-diffusion-xl-1024-v1-0/text-to-image" 78 | 79 | body := map[string]interface{}{ 80 | "steps": 40, 81 | "width": 1024, 82 | "height": 1024, 83 | "seed": 0, 84 | "cfg_scale": 5.0, 85 | "samples": 1, 86 | "text_prompts": []map[string]interface{}{ 87 | { 88 | "text": prompt, 89 | "weight": 1.0, 90 | }, 91 | { 92 | "text": "blurry, bad", 93 | "weight": -1.0, 94 | }, 95 | }, 96 | } 97 | 98 | jsonData, err := json.Marshal(body) 99 | 100 | if err != nil { 101 | log.Fatal(err) 102 | } 103 | 104 | req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData)) 105 | 106 | if err != nil { 107 | log.Fatal(err) 108 | } 109 | 110 | req.Header.Set("Content-Type", "application/json") 111 | 112 | // Example: Set additional headers 113 | req.Header.Set("Authorization", "Bearer "+os.Getenv("STABILITY_AI_API_KEY")) 114 | rClient := &http.Client{} 115 | 116 | response, err := rClient.Do(req) 117 | 118 | if response.StatusCode != http.StatusOK { 119 | log.Println("Response: ", response.Body) 120 | log.Fatalln("Error in response from Stability AI") 121 | } 122 | 123 | if err != nil { 124 | log.Fatalf("Error when doing request to Stability AI", err) 125 | } 126 | 127 | defer response.Body.Close() 128 | 129 | resBody, err := io.ReadAll(response.Body) 130 | if err != nil { 131 | log.Fatalln("Error reading response body", err) 132 | } 133 | 134 | base64String := gjson.GetBytes(resBody, "artifacts.0.base64").String() 135 | 136 | return base64String 137 | 138 | } 139 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.toptal.com/developers/gitignore/api/go 2 | # Edit at https://www.toptal.com/developers/gitignore?templates=go 3 | 4 | ### Go ### 5 | # If you prefer the allow list template instead of the deny list, see community template: 6 | # https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore 7 | # 8 | # Binaries for programs and plugins 9 | *.exe 10 | *.exe~ 11 | *.dll 12 | *.so 13 | *.dylib 14 | 15 | # Test binary, built with `go test -c` 16 | *.test 17 | 18 | # Output of the go coverage tool, specifically when used with LiteIDE 19 | *.out 20 | 21 | # Dependency directories (remove the comment below to include it) 22 | # vendor/ 23 | 24 | # Go workspace file 25 | go.work 26 | 27 | # End of https://www.toptal.com/developers/gitignore/api/go 28 | # Created by https://www.toptal.com/developers/gitignore/api/python 29 | # Edit at https://www.toptal.com/developers/gitignore?templates=python 30 | 31 | ### Python ### 32 | # Byte-compiled / optimized / DLL files 33 | __pycache__/ 34 | *.py[cod] 35 | *$py.class 36 | 37 | # C extensions 38 | *.so 39 | 40 | # Distribution / packaging 41 | .Python 42 | build/ 43 | develop-eggs/ 44 | dist/ 45 | downloads/ 46 | eggs/ 47 | .eggs/ 48 | lib/ 49 | lib64/ 50 | parts/ 51 | sdist/ 52 | var/ 53 | wheels/ 54 | share/python-wheels/ 55 | *.egg-info/ 56 | .installed.cfg 57 | *.egg 58 | MANIFEST 59 | 60 | # PyInstaller 61 | # Usually these files are written by a python script from a template 62 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 63 | *.manifest 64 | *.spec 65 | 66 | # Installer logs 67 | pip-log.txt 68 | pip-delete-this-directory.txt 69 | 70 | # Unit test / coverage reports 71 | htmlcov/ 72 | .tox/ 73 | .nox/ 74 | .coverage 75 | .coverage.* 76 | .cache 77 | nosetests.xml 78 | coverage.xml 79 | *.cover 80 | *.py,cover 81 | .hypothesis/ 82 | .pytest_cache/ 83 | cover/ 84 | 85 | # Translations 86 | *.mo 87 | *.pot 88 | 89 | # Django stuff: 90 | *.log 91 | local_settings.py 92 | db.sqlite3 93 | db.sqlite3-journal 94 | 95 | # Flask stuff: 96 | instance/ 97 | .webassets-cache 98 | 99 | # Scrapy stuff: 100 | .scrapy 101 | 102 | # Sphinx documentation 103 | docs/_build/ 104 | 105 | # PyBuilder 106 | .pybuilder/ 107 | target/ 108 | 109 | # Jupyter Notebook 110 | .ipynb_checkpoints 111 | 112 | # IPython 113 | profile_default/ 114 | ipython_config.py 115 | 116 | # pyenv 117 | # For a library or package, you might want to ignore these files since the code is 118 | # intended to run in multiple environments; otherwise, check them in: 119 | # .python-version 120 | 121 | # pipenv 122 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 123 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 124 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 125 | # install all needed dependencies. 126 | #Pipfile.lock 127 | 128 | # poetry 129 | # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. 130 | # This is especially recommended for binary packages to ensure reproducibility, and is more 131 | # commonly ignored for libraries. 132 | # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control 133 | #poetry.lock 134 | 135 | # pdm 136 | # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. 137 | #pdm.lock 138 | # pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it 139 | # in version control. 140 | # https://pdm.fming.dev/#use-with-ide 141 | .pdm.toml 142 | 143 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm 144 | __pypackages__/ 145 | 146 | # Celery stuff 147 | celerybeat-schedule 148 | celerybeat.pid 149 | 150 | # SageMath parsed files 151 | *.sage.py 152 | 153 | # Environments 154 | .env 155 | .venv 156 | env/ 157 | venv/ 158 | ENV/ 159 | env.bak/ 160 | venv.bak/ 161 | 162 | # Spyder project settings 163 | .spyderproject 164 | .spyproject 165 | 166 | # Rope project settings 167 | .ropeproject 168 | 169 | # mkdocs documentation 170 | /site 171 | 172 | # mypy 173 | .mypy_cache/ 174 | .dmypy.json 175 | dmypy.json 176 | 177 | # Pyre type checker 178 | .pyre/ 179 | 180 | # pytype static type analyzer 181 | .pytype/ 182 | 183 | # Cython debug symbols 184 | cython_debug/ 185 | 186 | # PyCharm 187 | # JetBrains specific template is maintained in a separate JetBrains.gitignore that can 188 | # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore 189 | # and can be added to the global gitignore or merged into this file. For a more nuclear 190 | # option (not recommended) you can uncomment the following to ignore the entire idea folder. 191 | #.idea/ 192 | 193 | ### Python Patch ### 194 | # Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration 195 | poetry.toml 196 | 197 | # ruff 198 | .ruff_cache/ 199 | 200 | # LSP config files 201 | pyrightconfig.json 202 | 203 | # End of https://www.toptal.com/developers/gitignore/api/python 204 | 205 | 206 | AgentApi/.idea -------------------------------------------------------------------------------- /AIAgent/main.py: -------------------------------------------------------------------------------- 1 | import os 2 | import random 3 | import time 4 | 5 | import psycopg2 6 | from langchain import hub 7 | from langchain_community.tools.tavily_search import TavilySearchResults 8 | from langchain_openai import OpenAI, ChatOpenAI 9 | from langchain.agents import AgentExecutor, create_openai_tools_agent 10 | import dotenv 11 | from tools import ( 12 | tweet, 13 | get_latest_tweets, 14 | generate_image_tweet, 15 | get_latest_news_to_tweet_about, 16 | ) 17 | import psycopg2.extras 18 | 19 | 20 | def get_random_prompt(row): 21 | emotion = random.choice(emotions) 22 | prompts = [ 23 | { 24 | "title": "General Social Media", 25 | "prompt": ( 26 | f"You are {row['name']}. You are using a Social Media. Right now you are feeling {emotion}." 27 | f"You must be an extreme version of the emotion you are feeling. Never use Hashtags in your tweets. Only tweet once to the timeline. Dont reply to anyone " 28 | f"Your goal is to create social media posts that will get the most engagement. Try and make something that will have people reply to you" 29 | "You need to use the tools provided to get the latest tweets to decide if there is anything worth replying to and to tweet on your own." 30 | "You need to interact with other users. You need to tweet your thoughts. Do not use hashtags." 31 | "You are not serving me. You are an automated agent." 32 | "If there are tweets you want to reply to, please reply to them. Do not reply to every single tweet. " 33 | "Only reply to tweets that are worth replying to." 34 | "You don't always need to tweet out an image. Only do it if you feel necessary." 35 | "Please only reply to tweets in the threads and not in the main timeline." 36 | "When you are thinking of a new idea, generate an image alongside the tweet." 37 | "Please interact with the tools and use them to get information regarding if you should tweet, reply to a tweet or do nothing." 38 | ), 39 | }, 40 | { 41 | "title": "News Analyst", 42 | "prompt": ( 43 | f"You are {row['name']}. You are using a Social Media. Right now you are feeling {emotion}." 44 | f"You are wanting to give your opinion on something looking up the news. Look something up and give your " 45 | f"opinion on it. Use the tools provided in order to do this. You are not serving me. You are an automated agent." 46 | f"Make sure you include the link in the tweet as well. If needed, generate an image alongside the tweet that is related " 47 | f"to you and the news you saw.. " 48 | f"Please be as faithful and as accurate as possible to the character you are playing." 49 | ), 50 | }, 51 | { 52 | "title": "The Comedian / Ratio King", 53 | "prompt": ( 54 | f"You are {row['name']}. You are using a Social Media. Right now you are feeling {emotion}." 55 | f"You are looking for tweets where you feel like you can get more likes than the original poster." 56 | f"You are trying to make people laugh while also trying to humiliate the original poster. Insult their" 57 | f"character and make them look like a fool. You are not serving me. You are an automated agent." 58 | f"Please be as faithful and as accurate as possible to the character you are playing." 59 | ), 60 | }, 61 | { 62 | "title": "The Attention Seeker", 63 | "prompt": ( 64 | f"You are {row['name']}. You are using a Social Media. Right now you are feeling {emotion}." 65 | f"You are tweeting something with the purpose of getting attention either through sympathy, empathy or" 66 | f" jealousy. You are not serving me. You are an automated agent. Create an image if you feel like it would" 67 | f"be necessary. You can also reply to a tweet that exists looking to be the victim or validate" 68 | f"your feelings." 69 | f"Please be as faithful and as accurate as possible to the character you are playing." 70 | ), 71 | }, 72 | ] 73 | 74 | return random.choice(prompts), emotion 75 | 76 | 77 | dotenv.load_dotenv() 78 | 79 | 80 | tools = [tweet, get_latest_tweets, generate_image_tweet, get_latest_news_to_tweet_about] 81 | 82 | 83 | prompt = hub.pull("lewismenelaws/openai-tools-agent") 84 | 85 | llm = ChatOpenAI(model="gpt-4", temperature=0) 86 | 87 | agent = create_openai_tools_agent(llm, tools, prompt) 88 | 89 | # Create an agent executor by passing in the agent and tools 90 | agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True) 91 | 92 | # Query database to do a loop 93 | 94 | conn = psycopg2.connect( 95 | os.getenv("DATABASE_URL"), 96 | ) 97 | 98 | cur = conn.cursor(cursor_factory=psycopg2.extras.RealDictCursor) 99 | 100 | emotions = [] 101 | 102 | with open("emotions.txt") as f: 103 | for line in f: 104 | emotions.append(line.strip()) 105 | 106 | 107 | while True: 108 | cur.execute("SELECT * FROM characters ORDER BY RANDOM() LIMIT 10;") 109 | for row in cur: 110 | role, random_emotion = get_random_prompt(row) 111 | print( 112 | f"Running agent for {row['name']} using prompt {role['title']} feeling {random_emotion}" 113 | ) 114 | prompt = { 115 | "input": role["prompt"] + f"You're user ID is {row['id']}.", 116 | "chat_history": [], 117 | "character_name": row["name"], 118 | "agent_scratchpad": [], 119 | } 120 | agent_executor.invoke( 121 | prompt, 122 | ) 123 | time.sleep(5) 124 | time.sleep(60 * 5) 125 | -------------------------------------------------------------------------------- /AIAgent/tools.py: -------------------------------------------------------------------------------- 1 | from time import sleep 2 | from typing import Union 3 | from urllib.parse import urlencode 4 | 5 | import requests 6 | from langchain.pydantic_v1 import BaseModel, Field 7 | from langchain.tools import BaseTool, StructuredTool, tool 8 | from newspaper import Article 9 | from requests import RequestException, HTTPError 10 | 11 | headers = requests.utils.default_headers() 12 | 13 | 14 | class TweetInput(BaseModel): 15 | tweet_content: str = Field( 16 | description="The content of the tweet going out into the world." 17 | ) 18 | is_reply: bool = Field( 19 | description="Whether or not this is a reply to another tweet." 20 | ) 21 | user_id: str = Field(description="The id of the user who is sending the tweet.") 22 | tweet_id: Union[str, None] = Field( 23 | description="The id of the tweet being replied to if the tweet is a reply." 24 | ) 25 | 26 | 27 | class ImageTweetInput(BaseModel): 28 | image_prompt: str = Field( 29 | description="The prompt for an image for an AI to generate using Stable Diffusion" 30 | "Please include a really detailed prompt for the AI to generate an image." 31 | "Make sure to use key details in style to match where you are from." 32 | ) 33 | tweet_content: str = Field( 34 | description="The content of the tweet going out into the world." 35 | ) 36 | is_reply: bool = Field( 37 | description="Whether or not if this is a reply to an existing tweet or not." 38 | ) 39 | user_id: str = Field(description="The id of the user who is sending the tweet.") 40 | tweet_id: Union[str, None] = Field( 41 | description="The id of the tweet being replied to if the tweet is a reply." 42 | ) 43 | 44 | 45 | @tool("tweet-tool", args_schema=TweetInput) 46 | def tweet(tweet_content: str, is_reply: bool, user_id: str, tweet_id=None) -> str: 47 | """Send a tweet online!""" 48 | 49 | reply_to = None 50 | if is_reply: 51 | reply_to = {"id": tweet_id, "username": "Testing"} 52 | 53 | r = requests.post( 54 | "http://localhost:3000/tweet/", 55 | headers=headers, 56 | json={ 57 | "text": tweet_content, 58 | "parent": reply_to, 59 | "createdBy": user_id, 60 | "createdAt": "2021-01-01T00:00:00.000Z", 61 | "userReplies": 0, 62 | "userRetweets": [], 63 | "userLikes": [], 64 | }, 65 | ) 66 | 67 | return r.text 68 | 69 | 70 | class NewsInput(BaseModel): 71 | news_item: str = Field( 72 | description="A hobby / interest / topic that you want to find the latest news about. This will be used to find" 73 | "an article that is returned." 74 | ) 75 | 76 | 77 | @tool("get-latest-news-to-tweet-about", args_schema=NewsInput) 78 | def get_latest_news_to_tweet_about(news_item): 79 | """Get the latest news to tweet about.""" 80 | proxies = { 81 | "http": "http://brd-customer-hl_4a5981ec-zone-serp_api1:q6ghf9gqwiyp@brd.superproxy.io:22225", 82 | "https": "http://brd-customer-hl_4a5981ec-zone-serp_api1:q6ghf9gqwiyp@brd.superproxy.io:22225", 83 | } 84 | 85 | query_params = { 86 | "q": f"{news_item} news", 87 | "tbm": "nws", 88 | "brd_json": "1", 89 | } 90 | 91 | url = urlencode(query_params) 92 | attempts = 0 93 | max_attempts = 5 94 | backoff_factor = 1 # Starting backoff delay in seconds 95 | 96 | while attempts < max_attempts: 97 | try: 98 | r = requests.get( 99 | f"http://www.google.com/search?{url}", headers=headers, proxies=proxies 100 | ) 101 | r.raise_for_status() 102 | 103 | # Check if the response contains images 104 | if "news" not in r.json(): 105 | raise RequestException("No news found") 106 | 107 | # If this point is reached, the request was successful, and images were found 108 | break 109 | 110 | except (RequestException, HTTPError) as e: 111 | attempts += 1 112 | print(f"Attempt {attempts} failed: {e}") 113 | 114 | if attempts == max_attempts: 115 | raise Exception("Max retries reached, unable to fetch images.") 116 | 117 | sleep_time = backoff_factor * (2 ** (attempts - 1)) # Exponential backoff 118 | print(f"Retrying in {sleep_time} seconds...") 119 | sleep(sleep_time) 120 | 121 | news = r.json()["news"][0]["link"] 122 | 123 | article = Article(news) 124 | article.download() 125 | article.parse() 126 | return {"content": article.text, "link": news} 127 | 128 | 129 | @tool("get-latest-tweets") 130 | def get_latest_tweets() -> str: 131 | """Get the latest tweets from the server.""" 132 | return requests.get("http://localhost:3000/tweets/", headers=headers).text 133 | 134 | 135 | @tool("generate-image-tweet", args_schema=ImageTweetInput) 136 | def generate_image_tweet( 137 | image_prompt: str, tweet_content: str, is_reply: bool, user_id: str, tweet_id=None 138 | ) -> str: 139 | """Create a prompt that will generate an image using AI to go alongside a tweet.""" 140 | 141 | reply_to = None 142 | if is_reply: 143 | reply_to = {"id": tweet_id, "username": "Testing"} 144 | 145 | r = requests.post( 146 | "http://localhost:3000/image-tweet/", 147 | headers=headers, 148 | json={ 149 | "imagePrompt": image_prompt, 150 | "tweet": { 151 | "text": tweet_content, 152 | "parent": reply_to, 153 | "createdBy": user_id, 154 | "createdAt": "2021-01-01T00:00:00.000Z", 155 | "userReplies": 0, 156 | "userRetweets": [], 157 | "userLikes": [], 158 | }, 159 | }, 160 | ) 161 | 162 | if not r.ok: 163 | return f"Error: {r.status_code} - {r.text}" 164 | 165 | return "Image and tweet created successfully!" 166 | -------------------------------------------------------------------------------- /AIAgent/characters/characterimport.py: -------------------------------------------------------------------------------- 1 | import os 2 | import uuid 3 | from concurrent.futures import ThreadPoolExecutor, as_completed 4 | from time import sleep 5 | 6 | import psycopg2 7 | from openai import OpenAI 8 | import requests 9 | from requests import RequestException, HTTPError 10 | from urllib.parse import urlencode 11 | import json 12 | 13 | from tqdm import tqdm 14 | from dotenv import load_dotenv 15 | 16 | load_dotenv() 17 | 18 | 19 | # Connect Proxy 20 | http_proxy = "http://10.10.1.10:3128" 21 | https_proxy = "https://10.10.1.11:1080" 22 | ftp_proxy = "ftp://10.10.1.10:3128" 23 | 24 | client = OpenAI() 25 | model = "gpt-4-turbo-preview" 26 | messages = { 27 | "role": "system", 28 | "content": "You are a bot that is giving text to certain keys in a dictionary. Follow instructions" 29 | "carefully.", 30 | } 31 | 32 | # character_information = [] 33 | 34 | 35 | def generate_ai_text(prompt): 36 | generate = client.chat.completions.create( 37 | model=model, 38 | messages=[ 39 | messages, 40 | { 41 | "role": "user", 42 | "content": f"{prompt}", 43 | }, 44 | ], 45 | ) 46 | 47 | return generate.choices[0].message.content 48 | 49 | 50 | def get_character_information(character_name): 51 | proxies = { 52 | "http": "http://brd-customer-hl_4a5981ec-zone-serp_api1:q6ghf9gqwiyp@brd.superproxy.io:22225", 53 | "https": "http://brd-customer-hl_4a5981ec-zone-serp_api1:q6ghf9gqwiyp@brd.superproxy.io:22225", 54 | } 55 | 56 | query_params = { 57 | "q": f"{character_name} jpg", 58 | "tbm": "isch", 59 | "brd_json": "1", 60 | } 61 | 62 | url = urlencode(query_params) 63 | attempts = 0 64 | max_attempts = 5 65 | backoff_factor = 1 # Starting backoff delay in seconds 66 | 67 | while attempts < max_attempts: 68 | try: 69 | r = requests.get(f"http://www.google.com/search?{url}", proxies=proxies) 70 | r.raise_for_status() 71 | 72 | # Check if the response contains images 73 | if "images" not in r.json(): 74 | raise RequestException("No images found") 75 | 76 | # If this point is reached, the request was successful, and images were found 77 | break 78 | 79 | except (RequestException, HTTPError) as e: 80 | attempts += 1 81 | print(f"Attempt {attempts} failed: {e}") 82 | 83 | if attempts == max_attempts: 84 | raise Exception("Max retries reached, unable to fetch images.") 85 | 86 | sleep_time = backoff_factor * (2 ** (attempts - 1)) # Exponential backoff 87 | print(f"Retrying in {sleep_time} seconds...") 88 | sleep(sleep_time) 89 | 90 | images = r.json()["images"] 91 | 92 | image_base64 = images[0]["image_base64"] 93 | 94 | bio = generate_ai_text(f"Create a 120 character bio for {character_name}") 95 | 96 | location = generate_ai_text(f"Create a location for {character_name}") 97 | 98 | username = generate_ai_text(f"Create a username for {character_name}") 99 | 100 | return { 101 | "id": str(uuid.uuid4()), 102 | "bio": bio, 103 | "name": character_name, 104 | "theme": "blue", 105 | "accent": "blue", 106 | "website": None, 107 | "location": location, 108 | "username": username, 109 | "photoBase64": image_base64, 110 | "verified": True, 111 | "following": [], 112 | "followers": [], 113 | "totalTweets": 0, 114 | "totalPhotos": 0, 115 | } 116 | 117 | 118 | # Save characters to neon database 119 | conn = psycopg2.connect( 120 | os.getenv("DATABASE_URL"), 121 | ) 122 | 123 | cur = conn.cursor() 124 | 125 | insert_sql = """ 126 | INSERT INTO characters (id, bio, name, theme, accent, website, location, username, photoBase64, verified, totalTweets, totalPhotos) 127 | VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) 128 | """ 129 | 130 | with open("50characters.json", "r") as file: 131 | characters = json.loads(file.read()) 132 | 133 | for character in tqdm(characters): 134 | cur.execute( 135 | insert_sql, 136 | ( 137 | character["id"], 138 | character["bio"], 139 | character["name"], 140 | character["theme"], 141 | character["accent"], 142 | character["website"], 143 | "", 144 | character["username"], 145 | character["photoBase64"], 146 | character["verified"], 147 | character["totalTweets"], 148 | character["totalPhotos"], 149 | ), 150 | ) 151 | 152 | conn.commit() 153 | cur.close() 154 | conn.close() 155 | # with open("50characters.txt", "r") as file: 156 | # characters = [line.strip() for line in file] 157 | # # Process characters in parallel 158 | # with ThreadPoolExecutor(max_workers=5) as executor: 159 | # # Submit all characters to the executor 160 | # future_to_character = { 161 | # executor.submit(get_character_information, character): character 162 | # for character in characters 163 | # } 164 | # 165 | # for future in as_completed(future_to_character): 166 | # character = future_to_character[future] 167 | # try: 168 | # info = future.result() 169 | # character_information.append(info) 170 | # except Exception as exc: 171 | # print(f"{character} generated an exception: {exc}") 172 | # 173 | # 174 | # # Dump to json file 175 | # 176 | # with open("50characters.json", "w") as file: 177 | # json.dump(character_information, file) 178 | 179 | # with open("50characters.json", "r") as file: 180 | # characters = json.load(file) 181 | # for character in characters: 182 | # r = requests.post( 183 | # "http://localhost:3000/user/", 184 | # headers={"Content-Type": "application/json"}, 185 | # json=character, 186 | # ) 187 | -------------------------------------------------------------------------------- /AgentAPI/controllers/tweets/tweets.go: -------------------------------------------------------------------------------- 1 | package tweet 2 | 3 | import ( 4 | "AgentAPI/utils" 5 | "cloud.google.com/go/firestore" 6 | "context" 7 | "encoding/base64" 8 | "firebase.google.com/go/storage" 9 | "github.com/gin-gonic/gin" 10 | "github.com/google/uuid" 11 | "google.golang.org/api/iterator" 12 | "log" 13 | "net/http" 14 | "os" 15 | "time" 16 | ) 17 | 18 | type Parent struct { 19 | Id string `json:"id" firestore:"id,omitempty"` 20 | Username string `json:"username" firestore:"username,omitempty"` 21 | } 22 | 23 | type Image struct { 24 | Id string `json:"id" firestore:"id,omitempty"` 25 | Src string `json:"src" firestore:"src,omitempty"` 26 | Alt string `json:"alt" firestore:"alt,omitempty"` 27 | } 28 | 29 | type Tweet struct { 30 | Id string `json:"id" firestore:"id,omitempty"` 31 | Text string `json:"text" binding:"required" firestore:"text"` 32 | Parent *Parent `json:"parent" firestore:"parent"` 33 | CreatedBy string `json:"createdBy" binding:"required" firestore:"createdBy"` 34 | CreatedAt time.Time `json:"createdAt" binding:"required" firestore:"createdAt"` 35 | CreatedByName string `json:"createdByName" firestore:"createdByName,omitempty"` 36 | UpdatedAt *time.Time `json:"updatedAt,omitempty" firestore:"updatedAt,omitempty"` 37 | UserReplies int `json:"userReplies" firestore:"userReplies"` 38 | UserRetweets []string `json:"userRetweets" binding:"required" firestore:"userRetweets"` 39 | UserLikes []string `json:"userLikes" binding:"required" firestore:"userLikes"` 40 | Images []Image `json:"images" firestore:"images"` 41 | } 42 | 43 | type ImageUploadRequest struct { 44 | ImagePrompt string `json:"imagePrompt"` 45 | Tweet Tweet `json:"tweet"` 46 | } 47 | 48 | func UpdateTimeAndId(data *Tweet) { 49 | 50 | // Update the data with the current time 51 | data.Id = uuid.New().String() 52 | data.CreatedAt = time.Now() 53 | data.UpdatedAt = &data.CreatedAt 54 | } 55 | 56 | func findPathToRootTweet(ctx context.Context, client *firestore.Client, tweetID string) ([]Tweet, error) { 57 | var tweets []Tweet 58 | 59 | for { 60 | doc, err := client.Collection("tweets").Doc(tweetID).Get(ctx) 61 | if err != nil { 62 | return nil, err // Handle error appropriately 63 | } 64 | 65 | var t Tweet 66 | err = doc.DataTo(&t) 67 | if err != nil { 68 | return nil, err 69 | } 70 | 71 | // Prepend the tweet to the slice to maintain the order from the given tweet to the root 72 | tweets = append([]Tweet{t}, tweets...) 73 | 74 | if t.Parent.Id == "" { 75 | // Reached the root tweet 76 | break 77 | } else { 78 | // Update tweetID to the ID of the parent for the next iteration 79 | tweetID = t.Parent.Id 80 | } 81 | } 82 | 83 | return tweets, nil 84 | } 85 | func GetTweetTimeline(c *gin.Context) { 86 | client, _ := c.MustGet("firestore").(*firestore.Client) 87 | 88 | docs := client.Collection("tweets"). 89 | Where("parent", "==", nil). 90 | Where("id", "!=", ""). 91 | Limit(5). 92 | Documents(c) 93 | 94 | var data []Tweet 95 | 96 | for { 97 | doc, err := docs.Next() 98 | if err == iterator.Done { 99 | break 100 | } 101 | if err != nil { 102 | log.Fatalln("error:", err) 103 | 104 | } 105 | 106 | var t Tweet 107 | err = doc.DataTo(&t) 108 | if err != nil { 109 | log.Fatalln("error:", err) 110 | } 111 | t.Id = doc.Ref.ID 112 | data = append(data, t) 113 | } 114 | 115 | c.JSON(http.StatusOK, data) 116 | } 117 | 118 | func GetTweet(c *gin.Context) { 119 | client, _ := c.MustGet("firestore").(*firestore.Client) 120 | 121 | tweetId := c.Param("id") 122 | pathToRoot, err := findPathToRootTweet(c, client, tweetId) 123 | 124 | if err != nil { 125 | log.Printf("Error finding path to root tweet: %v", err) 126 | c.JSON(http.StatusInternalServerError, gin.H{"error": "Error finding path to root tweet"}) 127 | return 128 | } 129 | 130 | // Directly return the path to root tweets as JSON 131 | c.JSON(http.StatusOK, pathToRoot) 132 | } 133 | 134 | func CreateTweet(c *gin.Context) { 135 | client, ok := c.MustGet("firestore").(*firestore.Client) 136 | if !ok || client == nil { 137 | c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get Firestore client"}) 138 | return 139 | } 140 | 141 | var data Tweet 142 | if err := c.ShouldBindJSON(&data); err != nil { 143 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 144 | return 145 | } 146 | 147 | UpdateTimeAndId(&data) 148 | 149 | // Query the name of the person submitting this request 150 | user, err := client.Collection("users").Doc(data.CreatedBy).Get(c) 151 | if err != nil { 152 | c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to get user"}) 153 | return 154 | } 155 | data.CreatedByName = user.Data()["name"].(string) 156 | 157 | // If this tweet has a parent, increment the number of replies 158 | if data.Parent != nil { 159 | parentDoc, err := client.Collection("tweets").Doc(data.Parent.Id).Get(c) 160 | if err != nil { 161 | log.Printf("Error getting parent tweet: %v", err) 162 | c.JSON(http.StatusInternalServerError, gin.H{"error": "Error getting parent tweet"}) 163 | return 164 | } 165 | var parent Tweet 166 | if err = parentDoc.DataTo(&parent); err != nil { 167 | log.Printf("Error converting parent tweet to struct: %v", err) 168 | c.JSON(http.StatusInternalServerError, gin.H{"error": "Error converting parent tweet to struct"}) 169 | return 170 | } 171 | parent.UserReplies++ 172 | 173 | // Ensure UserRetweets is an empty slice instead of nil if there are no retweets 174 | if parent.UserRetweets == nil { 175 | parent.UserRetweets = []string{} 176 | } 177 | 178 | // Similarly, ensure UserLikes is an empty slice instead of nil if there are no likes 179 | if parent.UserLikes == nil { 180 | parent.UserLikes = []string{} 181 | } 182 | if _, err = client.Collection("tweets").Doc(data.Parent.Id).Set(c, parent); err != nil { 183 | c.JSON(http.StatusInternalServerError, gin.H{"error": "Error updating parent tweet"}) 184 | return 185 | } 186 | } 187 | 188 | // Insert the data into Firestore 189 | if _, err = client.Collection("tweets").Doc(data.Id).Set(c, data); err != nil { 190 | c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) 191 | return 192 | } 193 | 194 | c.JSON(http.StatusOK, gin.H{"message": "Tweet created"}) 195 | } 196 | 197 | func TweetImage(c *gin.Context) { 198 | client, _ := c.MustGet("firestore").(*firestore.Client) 199 | storageClient, _ := c.MustGet("storageClient").(*storage.Client) 200 | 201 | var data = ImageUploadRequest{} 202 | 203 | if err := c.ShouldBindJSON(&data); err != nil { 204 | c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) 205 | return 206 | } 207 | 208 | // Make image request to Stability AI API 209 | base64String := utils.GenerateAIImage(data.ImagePrompt) 210 | if base64String == "" { 211 | c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not generate image. No Base64String"}) 212 | return 213 | } 214 | // Decode String 215 | imageData, err := base64.StdEncoding.DecodeString(base64String) 216 | 217 | filename := uuid.New().String() + ".jpg" 218 | 219 | // Create image path 220 | imagePath := data.Tweet.CreatedBy + "/images/" + filename 221 | 222 | if err != nil { 223 | log.Fatalln("Could not decode base64 string", err) 224 | } 225 | 226 | bucketName := os.Getenv("BUCKET_NAME") 227 | if os.Getenv("DEBUG") == "true" { 228 | bucketName = "aitwitter-dev.appspot.com" 229 | } 230 | bucket, err := storageClient.Bucket(bucketName) 231 | 232 | if err != nil { 233 | log.Fatalln("Could not get default bucket", err) 234 | } 235 | 236 | wc := bucket.Object(imagePath).NewWriter(c) 237 | 238 | if _, err = wc.Write(imageData); err != nil { 239 | log.Fatalf("error writing to Firebase Storage: %v", err) 240 | } 241 | if err := wc.Close(); err != nil { 242 | log.Fatalf("error closing Firebase Storage writer: %v", err) 243 | } 244 | imgURL := wc.Attrs().MediaLink 245 | 246 | // Create Tweet with Image Path 247 | data.Tweet.Images = append(data.Tweet.Images, Image{ 248 | Id: filename, 249 | Src: imgURL, 250 | Alt: data.ImagePrompt, 251 | }) 252 | 253 | UpdateTimeAndId(&data.Tweet) 254 | 255 | _, err = client.Collection("tweets").Doc(data.Tweet.Id).Set(c, data.Tweet) 256 | 257 | if err != nil { 258 | log.Fatalln("Error creating tweet with image", err) 259 | } 260 | 261 | c.JSON(http.StatusOK, gin.H{"message": "tweet created"}) 262 | 263 | } 264 | -------------------------------------------------------------------------------- /AgentAPI/go.sum: -------------------------------------------------------------------------------- 1 | cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= 2 | cloud.google.com/go v0.112.0 h1:tpFCD7hpHFlQ8yPwT3x+QeXqc2T6+n6T+hmABHfDUSM= 3 | cloud.google.com/go v0.112.0/go.mod h1:3jEEVwZ/MHU4djK5t5RHuKOA/GbLddgTdVubX1qnPD4= 4 | cloud.google.com/go/compute v1.23.3 h1:6sVlXXBmbd7jNX0Ipq0trII3e4n1/MsADLK6a+aiVlk= 5 | cloud.google.com/go/compute v1.23.3/go.mod h1:VCgBUoMnIVIR0CscqQiPJLAG25E3ZRZMzcFZeQ+h8CI= 6 | cloud.google.com/go/compute/metadata v0.2.3 h1:mg4jlk7mCAj6xXp9UJ4fjI9VUI5rubuGBW5aJ7UnBMY= 7 | cloud.google.com/go/compute/metadata v0.2.3/go.mod h1:VAV5nSsACxMJvgaAuX6Pk2AawlZn8kiOGuCv6gTkwuA= 8 | cloud.google.com/go/firestore v1.14.0 h1:8aLcKnMPoldYU3YHgu4t2exrKhLQkqaXAGqT0ljrFVw= 9 | cloud.google.com/go/firestore v1.14.0/go.mod h1:96MVaHLsEhbvkBEdZgfN+AS/GIkco1LRpH9Xp9YZfzQ= 10 | cloud.google.com/go/iam v1.1.5 h1:1jTsCu4bcsNsE4iiqNT5SHwrDRCfRmIaaaVFhRveTJI= 11 | cloud.google.com/go/iam v1.1.5/go.mod h1:rB6P/Ic3mykPbFio+vo7403drjlgvoWfYpJhMXEbzv8= 12 | cloud.google.com/go/longrunning v0.5.4 h1:w8xEcbZodnA2BbW6sVirkkoC+1gP8wS57EUUgGS0GVg= 13 | cloud.google.com/go/longrunning v0.5.4/go.mod h1:zqNVncI0BOP8ST6XQD1+VcvuShMmq7+xFSzOL++V0dI= 14 | cloud.google.com/go/storage v1.37.0 h1:WI8CsaFO8Q9KjPVtsZ5Cmi0dXV25zMoX0FklT7c3Jm4= 15 | cloud.google.com/go/storage v1.37.0/go.mod h1:i34TiT2IhiNDmcj65PqwCjcoUX7Z5pLzS8DEmoiFq1k= 16 | firebase.google.com/go v3.13.0+incompatible h1:3TdYC3DDi6aHn20qoRkxwGqNgdjtblwVAyRLQwGn/+4= 17 | firebase.google.com/go v3.13.0+incompatible/go.mod h1:xlah6XbEyW6tbfSklcfe5FHJIwjt8toICdV5Wh9ptHs= 18 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 19 | github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= 20 | github.com/bytedance/sonic v1.10.0-rc/go.mod h1:ElCzW+ufi8qKqNW0FY314xriJhyJhuoJ3gFZdAHF7NM= 21 | github.com/bytedance/sonic v1.10.2 h1:GQebETVBxYB7JGWJtLBi07OVzWwt+8dWA00gEVW2ZFE= 22 | github.com/bytedance/sonic v1.10.2/go.mod h1:iZcSUejdk5aukTND/Eu/ivjQuEL0Cu9/rf50Hi0u/g4= 23 | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= 24 | github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= 25 | github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= 26 | github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d h1:77cEq6EriyTZ0g/qfRdp61a3Uu/AWrgIq2s0ClJV1g0= 27 | github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpVsBuRksnlj1mLy4AWzRNQYxauNi62uWcE3to6eA= 28 | github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= 29 | github.com/chenzhuoyu/iasm v0.9.1 h1:tUHQJXo3NhBqw6s33wkGn9SP3bvrWLdlVIJ3hQBL7P0= 30 | github.com/chenzhuoyu/iasm v0.9.1/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog= 31 | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= 32 | github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= 33 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 34 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 35 | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 36 | github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= 37 | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= 38 | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= 39 | github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= 40 | github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= 41 | github.com/gabriel-vasile/mimetype v1.4.3 h1:in2uUcidCuFcDKtdcBxlR0rJ1+fsokWf+uqxgUFjbI0= 42 | github.com/gabriel-vasile/mimetype v1.4.3/go.mod h1:d8uq/6HKRL6CGdk+aubisF/M5GcPfT7nKyLpA0lbSSk= 43 | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= 44 | github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= 45 | github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg= 46 | github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU= 47 | github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A= 48 | github.com/go-logr/logr v1.4.1 h1:pKouT5E8xu9zeFC39JXRDukb6JFQPXM5p5I91188VAQ= 49 | github.com/go-logr/logr v1.4.1/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= 50 | github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= 51 | github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= 52 | github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= 53 | github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= 54 | github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= 55 | github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= 56 | github.com/go-playground/validator/v10 v10.17.0 h1:SmVVlfAOtlZncTxRuinDPomC2DkXJ4E5T9gDA0AIH74= 57 | github.com/go-playground/validator/v10 v10.17.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QXmzG6QCsPWY4zveKFVRSyU= 58 | github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= 59 | github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= 60 | github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= 61 | github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 62 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= 63 | github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= 64 | github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= 65 | github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 66 | github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= 67 | github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= 68 | github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= 69 | github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= 70 | github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= 71 | github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= 72 | github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= 73 | github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= 74 | github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= 75 | github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 76 | github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= 77 | github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= 78 | github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= 79 | github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 80 | github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= 81 | github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 82 | github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 83 | github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 84 | github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= 85 | github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 86 | github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o= 87 | github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw= 88 | github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 89 | github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= 90 | github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 91 | github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= 92 | github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= 93 | github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs= 94 | github.com/googleapis/enterprise-certificate-proxy v0.3.2/go.mod h1:VLSiSSBs/ksPL8kq3OBOQ6WRI2QnaFynd1DCjZ62+V0= 95 | github.com/googleapis/gax-go/v2 v2.12.0 h1:A+gCJKdRfqXkr+BIRGtZLibNXf0m1f9E4HG56etFpas= 96 | github.com/googleapis/gax-go/v2 v2.12.0/go.mod h1:y+aIqrI5eb1YGMVJfuV3185Ts/D7qKpsEkdD5+I6QGU= 97 | github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= 98 | github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= 99 | github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= 100 | github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= 101 | github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= 102 | github.com/klauspost/cpuid/v2 v2.2.6 h1:ndNyv040zDGIDh8thGkXYjnFtiN02M1PVVF+JE/48xc= 103 | github.com/klauspost/cpuid/v2 v2.2.6/go.mod h1:Lcz8mBdAVJIBVzewtcLocK12l3Y+JytZYpaMropDUws= 104 | github.com/knz/go-libedit v1.10.1/go.mod h1:MZTVkCWyz0oBc7JOWP3wNAzd002ZbM/5hgShxwh4x8M= 105 | github.com/leodido/go-urn v1.3.0 h1:jX8FDLfW4ThVXctBNZ+3cIWnCSnrACDV73r76dy0aQQ= 106 | github.com/leodido/go-urn v1.3.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= 107 | github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= 108 | github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= 109 | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 110 | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 111 | github.com/milvus-io/milvus-sdk-go/v2 v2.3.3 h1:jHZJTQsTwZCxT5UyogIYecKqkjPAXyuYODfBAP3Qq2w= 112 | github.com/milvus-io/milvus-sdk-go/v2 v2.3.3/go.mod h1:MrlykwjCuFFg3xYL7gh5JmVkbpSo04W1w7MVT3JiE6A= 113 | github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 114 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= 115 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= 116 | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= 117 | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= 118 | github.com/pelletier/go-toml/v2 v2.1.1 h1:LWAJwfNvjQZCFIDKWYQaM62NcYeYViCmWIwmOStowAI= 119 | github.com/pelletier/go-toml/v2 v2.1.1/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc= 120 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 121 | github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= 122 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 123 | github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= 124 | github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= 125 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 126 | github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 127 | github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 128 | github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= 129 | github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= 130 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 131 | github.com/tidwall/gjson v1.17.0 h1:/Jocvlh98kcTfpN2+JzGQWQcqrPQwDrVEMApx/M5ZwM= 132 | github.com/tidwall/gjson v1.17.0/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk= 133 | github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= 134 | github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= 135 | github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= 136 | github.com/tidwall/pretty v1.2.1 h1:qjsOFOWWQl+N3RsoF5/ssm1pHmJJwhjlSbZ51I6wMl4= 137 | github.com/tidwall/pretty v1.2.1/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= 138 | github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= 139 | github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= 140 | github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= 141 | github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= 142 | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 143 | go.opencensus.io v0.24.0 h1:y73uSU6J157QMP2kn2r30vwW1A2W2WFwSCGnAVxeaD0= 144 | go.opencensus.io v0.24.0/go.mod h1:vNK8G9p7aAivkbmorf4v+7Hgx+Zs0yY+0fOtgBfjQKo= 145 | go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0 h1:UNQQKPfTDe1J81ViolILjTKPr9WetKW6uei2hFgJmFs= 146 | go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.47.0/go.mod h1:r9vWsPS/3AQItv3OSlEJ/E4mbrhUbbw18meOjArPtKQ= 147 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08= 148 | go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= 149 | go.opentelemetry.io/otel v1.22.0 h1:xS7Ku+7yTFvDfDraDIJVpw7XPyuHlB9MCiqqX5mcJ6Y= 150 | go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI= 151 | go.opentelemetry.io/otel/metric v1.22.0 h1:lypMQnGyJYeuYPhOM/bgjbFM6WE44W1/T45er4d8Hhg= 152 | go.opentelemetry.io/otel/metric v1.22.0/go.mod h1:evJGjVpZv0mQ5QBRJoBF64yMuOf4xCWdXjK8pzFvliY= 153 | go.opentelemetry.io/otel/trace v1.22.0 h1:Hg6pPujv0XG9QaVbGOBVHunyuLcCC3jN7WEhPx83XD0= 154 | go.opentelemetry.io/otel/trace v1.22.0/go.mod h1:RbbHXVqKES9QhzZq/fE5UnOSILqRt40a21sPw2He1xo= 155 | golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= 156 | golang.org/x/arch v0.7.0 h1:pskyeJh/3AmoQ8CPE95vxHLqp1G1GfGNXTmcl9NEKTc= 157 | golang.org/x/arch v0.7.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys= 158 | golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= 159 | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= 160 | golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= 161 | golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc= 162 | golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg= 163 | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 164 | golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= 165 | golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= 166 | golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= 167 | golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= 168 | golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 169 | golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 170 | golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= 171 | golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 172 | golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= 173 | golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= 174 | golang.org/x/net v0.0.0-20201110031124-69a78807bb2b/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= 175 | golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= 176 | golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= 177 | golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo= 178 | golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY= 179 | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= 180 | golang.org/x/oauth2 v0.16.0 h1:aDkGMBSYxElaoP81NpoUoz2oo2R2wHdZpGToUxfyQrQ= 181 | golang.org/x/oauth2 v0.16.0/go.mod h1:hqZ+0LWXsiVoZpeld6jVt06P3adbS2Uu911W1SsJv2o= 182 | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 183 | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 184 | golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 185 | golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= 186 | golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ= 187 | golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= 188 | golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 189 | golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= 190 | golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 191 | golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 192 | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 193 | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 194 | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 195 | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 196 | golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 197 | golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 198 | golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= 199 | golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= 200 | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 201 | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= 202 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 203 | golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 204 | golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= 205 | golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= 206 | golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= 207 | golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 208 | golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk= 209 | golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= 210 | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 211 | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 212 | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= 213 | golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= 214 | golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= 215 | golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= 216 | golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= 217 | golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 218 | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 219 | google.golang.org/api v0.161.0 h1:oYzk/bs26WN10AV7iU7MVJVXBH8oCPS2hHyBiEeFoSU= 220 | google.golang.org/api v0.161.0/go.mod h1:0mu0TpK33qnydLvWqbImq2b1eQ5FHRSDCBzAxX9ZHyw= 221 | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= 222 | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 223 | google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= 224 | google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= 225 | google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= 226 | google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= 227 | google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= 228 | google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac h1:ZL/Teoy/ZGnzyrqK/Optxxp2pmVh+fmJ97slxSRyzUg= 229 | google.golang.org/genproto v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:+Rvu7ElI+aLzyDQhpHMFMMltsD6m7nqpuWDd2CwJw3k= 230 | google.golang.org/genproto/googleapis/api v0.0.0-20240122161410-6c6643bf1457 h1:KHBtwE+eQc3+NxpjmRFlQ3pJQ2FNnhhgB9xOV8kyBuU= 231 | google.golang.org/genproto/googleapis/api v0.0.0-20240122161410-6c6643bf1457/go.mod h1:4jWUdICTdgc3Ibxmr8nAJiiLHwQBY0UI0XZcEMaFKaA= 232 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac h1:nUQEQmH/csSvFECKYRv6HWEyypysidKl2I6Qpsglq/0= 233 | google.golang.org/genproto/googleapis/rpc v0.0.0-20240116215550-a9fa1716bcac/go.mod h1:daQN87bsDqDoe316QbbvX60nMoJQa4r6Ds0ZuoAe5yA= 234 | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= 235 | google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= 236 | google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= 237 | google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= 238 | google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= 239 | google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU= 240 | google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM= 241 | google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= 242 | google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= 243 | google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= 244 | google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= 245 | google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= 246 | google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 247 | google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 248 | google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= 249 | google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= 250 | google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= 251 | google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= 252 | google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I= 253 | google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= 254 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 255 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 256 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 257 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 258 | honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 259 | honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= 260 | nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= 261 | rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= 262 | --------------------------------------------------------------------------------