commit 67d8d41fa88f4c2a222410a30f5427ace716966b
Author: Yongbin Kim <iam@yongbin.kim>
Date: Sun, 19 Nov 2023 03:46:34 +0900
First commit
Diffstat:
5 files changed, 236 insertions(+), 0 deletions(-)
diff --git a/.gitignore b/.gitignore
@@ -0,0 +1,24 @@
+# Allowlisting gitignore template for GO projects prevents us
+# from adding various unwanted local files, such as generated
+# files, developer configurations or IDE-specific files etc.
+#
+# Recommended: Go.AllowList.gitignore
+
+# Ignore everything
+*
+
+# But not these files...
+!/.gitignore
+
+!*.go
+!go.sum
+!go.mod
+
+!README
+!LICENSE
+
+# !Makefile
+
+# ...even if they are in subdirectories
+!*/
+
diff --git a/README b/README
@@ -0,0 +1,44 @@
+# ADD; AI-Driven Development
+
+Because I am lazy.
+
+This program uses Huggingface Inference API. It's basically free-to-use, but I recommend pro plan, because it's much faster.
+
+
+# Getting started
+
+$ go install go.lair.cx/add/cmd/addgen@latest
+$ addgen --init # Generate sample configuration
+
+$ vi greetings.yaml
+
+
+ADD uses yaml to "define" the program.
+
+- name: Make Greetings
+ type: Function
+ input:
+ - name: String
+ - entered:
+ output:
+ - message: String
+ behavior: >
+ This method creates a greetings message.
+ If the entered variable is true, the message format is: "Hi, ${name}!"
+ If the entered variable is false, the message format is: "Bye, ${name}!"
+
+
+Use `addgen [yaml]` to generate code.
+
+$ addgen greetings.yaml
+```go
+// MakeGreeting generates a personalized greeting message based on the given name and whether the person has entered the room.
+func MakeGreeting(name string, entered bool) string {
+ if entered {
+ return fmt.Sprintf("Hi, %s!", name)
+ } else {
+ return fmt.Sprintf("Bye, %s!", name)
+ }
+}
+```
+
diff --git a/cmd/addgen/main.go b/cmd/addgen/main.go
@@ -0,0 +1,138 @@
+package main
+
+import (
+ "bytes"
+ "encoding/json"
+ "errors"
+ "flag"
+ "fmt"
+ "log"
+ "net/http"
+ "os"
+ "strings"
+)
+
+// Config represents the configuration for the program.
+type Config struct {
+ Lang string `json:"lang"`
+ Endpoint string `json:"endpoint"`
+ Token string `json:"token"`
+ Parameters map[string]any `json:"parameters"`
+ Options map[string]any `json:"options"`
+}
+
+func main() {
+ flag.Parse()
+
+ args := flag.Args()
+ if len(args) < 1 {
+ log.Fatalln("Usage: addgen [source.yaml]")
+ }
+
+ // Read the configuration file
+ data, err := os.ReadFile("add.json")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ var config Config
+ err = json.Unmarshal(data, &config)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Verify the configuration
+ if len(config.Lang) == 0 || len(config.Endpoint) == 0 || len(config.Token) == 0 {
+ log.Fatalf("Invalid configuration: lang=%q, endpoint=%q, token=%q\n", config.Lang, config.Endpoint, config.Token)
+ }
+
+ // Read the prompt file
+ prompt, err := os.ReadFile("prompt.txt")
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Read the yaml file
+ inputData, err := os.ReadFile(args[0])
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ input := appendToPrompt(
+ // Replace placeholders in the prompt
+ strings.ReplaceAll(string(prompt), "{{ content }}", string(inputData)),
+
+ // Append the language identifier to the prompt
+ fmt.Sprintf("```%s\n", config.Lang),
+ )
+
+ // Query the endpoint repeatedly until there is no more results
+ for {
+ result, err := query(config, input)
+ if err != nil {
+ log.Fatal(err)
+ }
+ if len(result) == 0 {
+ break
+ }
+
+ input = appendToPrompt(input, result)
+ }
+}
+
+func appendToPrompt(prompt string, s string) string {
+ fmt.Print(s)
+ return prompt + s
+}
+
+func query(config Config, prompt string) (string, error) {
+ // Create the HTTP client
+ client := http.Client{}
+
+ var queryParams = map[string]any{
+ "inputs": prompt,
+ "parameters": config.Parameters,
+ "options": config.Options,
+ }
+
+ body, err := json.Marshal(queryParams)
+ if err != nil {
+ return "", nil
+ }
+
+ // Set up the request
+ req, err := http.NewRequest("POST", config.Endpoint, bytes.NewBuffer(body))
+ if err != nil {
+ return "", err
+ }
+
+ // Add the authorization header
+ req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", config.Token))
+ req.Header.Set("Content-Type", "application/json")
+
+ // Make the request
+ resp, err := client.Do(req)
+ if err != nil {
+ return "", err
+ }
+
+ defer resp.Body.Close()
+
+ // Check the status code
+ if resp.StatusCode != http.StatusOK {
+ return "", errors.New(fmt.Sprintf("Unexpected status code: %d", resp.StatusCode))
+ }
+
+ // Decode the response
+ var response []struct {
+ GeneratedText string `json:"generated_text"`
+ }
+
+ err = json.NewDecoder(resp.Body).Decode(&response)
+ if err != nil {
+ return "", err
+ }
+
+ // Return the generated text
+ return response[0].GeneratedText, nil
+}
diff --git a/examples/helloworld_test.go b/examples/helloworld_test.go
@@ -0,0 +1,27 @@
+package main
+
+import (
+ "fmt"
+ "log"
+ "os"
+)
+
+func main() {
+ if len(os.Args) < 2 {
+ log.Fatalf("Usage: %s (name)", os.Args[0])
+ }
+
+ fmt.Println(MakeGreeting(os.Args[1], true))
+ fmt.Println(MakeGreeting(os.Args[1], false))
+}
+
+// Below is generated code
+
+// MakeGreeting generates a personalized greeting message based on the given name and whether the person has entered the room.
+func MakeGreeting(name string, entered bool) string {
+ if entered {
+ return fmt.Sprintf("Hi, %s!", name)
+ } else {
+ return fmt.Sprintf("Bye, %s!", name)
+ }
+}
diff --git a/go.mod b/go.mod
@@ -0,0 +1,3 @@
+module go.lair.cx/add
+
+go 1.21.3