Skip to content
Snippets Groups Projects
Commit 9ca7f078 authored by Aleksander Einarsen's avatar Aleksander Einarsen
Browse files

Merge remote-tracking branch 'origin/dev' into dev/feature/compiler-module

parents 1f17a207 6192d3ea
Branches
No related tags found
No related merge requests found
Showing
with 1135 additions and 17 deletions
package compiler
// CompileStringToGo tries to compile a string of go code to a go executable, and returns the compiler output and an error.
// The function does not produce any executables, since they are deleted after the function ends.
func CompileStringToGo(code string) (string, error) {
var output string = ""
// SetupEnvironment
return output, nil
}
package displayindicator
import (
"fmt"
"time"
)
// Function to display a waiting/loading indicator
func DisplayLoadingIndicator(done chan bool) {
indicator := []string{"|", "/", "-", "\\"}
i := 0
for {
select {
case <-done:
fmt.Print("\r") // Clear the waiting indicator when done
return
default:
fmt.Printf("\r%s Generating...", indicator[i%len(indicator)])
i++
time.Sleep(200 * time.Millisecond)
}
}
}
package extraction
import (
"fmt"
"strings"
)
var GoPrompt = "The code should be in the Go programming language. There should also be 3 robust test cases within the same code. There should also be a main function inside of which all the execution takes place. Please only provide the source code and no further explanation, The format should be ```go <yourcode + testcases> ```"
var RustPrompt = "The code should be in the Rust programming language. There should also be 3 robust test cases within the same code. There should also be a main function inside of which all the execution takes place. Please only provide the source code and no further explanation, The format should be ```rust <yourcode + testcases> ```"
// func Extract(output string) string {
// parts := strings.Split(output, "```")
// var extracted = ""
// if strings.Contains(parts[1], "rust") {
// extracted = strings.TrimLeft(parts[1], "rust")
// } else {
// extracted = strings.TrimLeft(parts[1], "go")
// }
// return extracted
// }
// Extract extracts the code snippet between ``` and removes the language identifier.
func Extract(output string) (string, error) {
parts := strings.Split(output, "```")
if len(parts) < 2 {
return "", fmt.Errorf("the string wasn't in a proper format") // Handle the case if format is incorrect: Return empty string
}
// Trim the language identifier like `go` or `rust` from the code
code := parts[1]
lines := strings.SplitN(code, "\n", 2)
if len(lines) > 1 {
return "\n" + lines[1], nil // Return the code without the first line (language identifier)
}
return "", fmt.Errorf("the string doesn't contain any lines")
}
package extraction
import (
"testing"
)
// var GoInputs []string = []string{"```go\nfunc main() {}\n```", "```go\nfmt.Println('Hello World')\n```"}
// var expectedGoOuputs []string = []string{"\nfunc main() {}\n", "\nfmt.Println('Hello World')\n"}
// var RustInputs []string = []string{"```go\nfn main() {}\n```", "```go\nprintln!('Hello World')\n```"}
// var expectedRustOuputs []string = []string{"\nfn main() {}\n", "\nprintln!('Hello World')\n"}
// func TestExtraction(t *testing.T) {
// t.Run("Golang Extraction 1", func(t *testing.T) {
// var output = Extract(GoInputs[0])
// if output != expectedGoOuputs[0] {
// t.Error(output)
// }
// })
// t.Run("Golang Extraction 2", func(t *testing.T) {
// var output = Extract(GoInputs[1])
// if output != expectedGoOuputs[1] {
// t.Error(output)
// }
// })
// t.Run("Rust Extraction 1", func(t *testing.T) {
// var output = Extract(RustInputs[0])
// if output != expectedRustOuputs[0] {
// t.Error(output)
// }
// })
// t.Run("Rust Extraction 2", func(t *testing.T) {
// var output = Extract(RustInputs[1])
// if output != expectedRustOuputs[1] {
// t.Error(output)
// }
// })
// }
// Inputs and Expected Outputs for the Test Cases
// This can be considered a table-driven test or equivalence partitioning
var testCases = []struct {
name string
input string
expected string
}{
// Go Test Cases
{"Go Extraction 1 - Main", "```go\nfunc main() {}\n```", "\nfunc main() {}\n"},
{"Go Extraction 2 - Print", "```go\nfmt.Println('Hello World')\n```", "\nfmt.Println('Hello World')\n"},
{"Go Extraction 3 - Loop", "```go\nfor i := 0; i < 10; i++ {\nfmt.Println(i)\n}\n```", "\nfor i := 0; i < 10; i++ {\nfmt.Println(i)\n}\n"},
{"Go Extraction 4 - If Else", "```go\nif x > 10 {\nfmt.Println('Greater than 10')\n} else {\nfmt.Println('Less than or equal to 10')\n}\n```", "\nif x > 10 {\nfmt.Println('Greater than 10')\n} else {\nfmt.Println('Less than or equal to 10')\n}\n"},
{"Go Extraction 5 - Function with Parameters", "```go\nfunc add(a int, b int) int {\nreturn a + b\n}\n```", "\nfunc add(a int, b int) int {\nreturn a + b\n}\n"},
{"Go Extraction 6 - Nested Loops", "```go\nfor i := 0; i < 3; i++ {\nfor j := 0; j < 3; j++ {\nfmt.Printf('(%d, %d)', i, j)\n}\n}\n```", "\nfor i := 0; i < 3; i++ {\nfor j := 0; j < 3; j++ {\nfmt.Printf('(%d, %d)', i, j)\n}\n}\n"},
{"Go Extraction 7 - Invalid", "```go```", ""},
// Rust Test Cases
{"Rust Extraction 1 - Main", "```rust\nfn main() {}\n```", "\nfn main() {}\n"},
{"Rust Extraction 2 - Print", "```rust\nprintln!('Hello World')\n```", "\nprintln!('Hello World')\n"},
{"Rust Extraction 3 - Loop", "```rust\nfor i in 0..10 {\nprintf!(\"{}\", i);\n}\n```", "\nfor i in 0..10 {\nprintf!(\"{}\", i);\n}\n"},
{"Rust Extraction 4 - If Else", "```rust\nif x > 10 {\nprintln!(\"Greater than 10\");\n} else {\nprintln!(\"Less than or equal to 10\");\n}\n```", "\nif x > 10 {\nprintln!(\"Greater than 10\");\n} else {\nprintln!(\"Less than or equal to 10\");\n}\n"},
{"Rust Extraction 5 - Function with Parameters", "```rust\nfn add(a: i32, b: i32) -> i32 {\nreturn a + b;\n}\n```", "\nfn add(a: i32, b: i32) -> i32 {\nreturn a + b;\n}\n"},
{"Rust Extraction 6 - Nested Loops", "```rust\nfor i in 0..3 {\nfor j in 0..3 {\nprintf!(\"({},{})\", i, j);\n}\n}\n```", "\nfor i in 0..3 {\nfor j in 0..3 {\nprintf!(\"({},{})\", i, j);\n}\n}\n"},
}
// Refined Test Function using Table-Driven Approach
func TestExtraction(t *testing.T) {
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
output, err := Extract(tc.input)
if output != tc.expected {
t.Errorf("Test %s failed: Expected %q, got %q", tc.name, tc.expected, output)
t.Log(err.Error())
}
})
}
}
File moved
package main
import (
"bufio"
"fmt"
"llama/compiler"
displayindicator "llama/display-indicator"
"llama/extraction"
ollamaimplementation "llama/ollama-implementation"
"os"
"strings"
)
func main() {
reader := bufio.NewReader(os.Stdin)
var conversationContext []int // Variable to store conversation context
fmt.Print("Enter your prompt (or type 'exit' to quit): ")
userPrompt, _ := reader.ReadString('\n')
userPrompt = strings.TrimSpace(userPrompt)
for {
if userPrompt == "exit" {
fmt.Println("Exiting the program.")
break
}
var modifiedPrompt = userPrompt + extraction.GoPrompt
fmt.Println("Prompt received. Generating response...")
// Start a go routine to display a waiting indicator while the response is being generated
done := make(chan bool)
go displayindicator.DisplayLoadingIndicator(done)
// Generate response using Ollama API, passing the context
response, updatedContext, err := ollamaimplementation.GetOllamaResponse(modifiedPrompt, conversationContext)
// Signal the waiting indicator to stop
done <- true
if err != nil {
fmt.Println("Error generating response:", err)
continue
}
// Update the conversation context with the response
conversationContext = updatedContext
generatedCode, err_extract := extraction.Extract(response) // Handle error with string
if err_extract != nil {
fmt.Printf("The LLM gave a improper string in response: %v", response)
userPrompt = "exit"
continue
}
fmt.Println("Ollama's response:", generatedCode)
output, err := compiler.CompileStringToGo(generatedCode)
if err != nil {
userPrompt = output + "\nFollowing are the errors, please fix the code. Write it again, and write only source code along with same test cases with no further explanation. The format should be ```rust <yourcode + testcases> ```"
} else {
fmt.Printf("Compiled successfully. Here is the output: %v", output)
userPrompt = "exit"
}
}
}
package ollamaimplementation
import (
"bytes"
"encoding/json"
"net/http"
)
var OllamaEndpoint = "http://localhost:11434/api/generate" // The local endpoint for the Ollama API
// Struct for request to Ollama API
type OllamaRequest struct {
Prompt string `json:"prompt"`
Model string `json:"model"`
Context []int `json:"context,omitempty"` // Context to maintain conversation
}
// Struct for response from Ollama API
type OllamaResponse struct {
Model string `json:"model"`
CreatedAt string `json:"created_at"`
Response string `json:"response"`
Done bool `json:"done"`
DoneReason string `json:"done_reason,omitempty"`
Context []int `json:"context,omitempty"` // Updated context
TotalDuration int64 `json:"total_duration,omitempty"`
LoadDuration int64 `json:"load_duration,omitempty"`
PromptEvalCount int `json:"prompt_eval_count,omitempty"`
PromptEvalDuration int64 `json:"prompt_eval_duration,omitempty"`
EvalCount int `json:"eval_count,omitempty"`
EvalDuration int64 `json:"eval_duration,omitempty"`
}
func GetOllamaResponse(prompt string, context []int) (string, []int, error) {
// Create request payload with the model specified and context
requestBody, err := json.Marshal(OllamaRequest{
Prompt: prompt,
Model: "llama3.1",
Context: context, // Pass the conversation context
})
if err != nil {
return "", nil, err
}
// Send HTTP POST request to Ollama API
resp, err := http.Post(OllamaEndpoint, "application/json", bytes.NewBuffer(requestBody))
if err != nil {
return "", nil, err
}
defer resp.Body.Close()
// Read and accumulate response body in chunks
var completeResponse string
var updatedContext []int
decoder := json.NewDecoder(resp.Body)
for decoder.More() {
var chunk OllamaResponse
if err := decoder.Decode(&chunk); err != nil {
return "", nil, err
}
completeResponse += chunk.Response
// Capture the updated context from the response
updatedContext = chunk.Context
if chunk.Done {
break
}
}
return completeResponse, updatedContext, nil
}
package ollamaimplementation
import (
"encoding/json"
"io/ioutil"
"llama/extraction"
"net/http"
"net/http/httptest"
"strings"
"testing"
)
// Mock OllamaResponse for testing
var mockResponse = OllamaResponse{
Model: "llama3.1",
Response: "This is a mock response.",
Done: true,
Context: []int{1, 2, 3},
}
// Mock function to replace the actual HTTP request
func TestGetOllamaResponse(t *testing.T) {
// Create a mock HTTP server
mockServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// Check if the request method is POST
if r.Method != http.MethodPost {
t.Errorf("Expected POST request, got %s", r.Method)
}
// Read and verify the request body
body, err := ioutil.ReadAll(r.Body)
if err != nil {
t.Fatalf("Failed to read request body: %v", err)
}
// Verify the request payload contains the expected prompt and model
if !strings.Contains(string(body), `"prompt":"Test prompt"`) || !strings.Contains(string(body), `"model":"llama3.1"`) {
t.Errorf("Request body is not as expected: %s", string(body))
}
// Send a mock response
responseData, _ := json.Marshal(mockResponse)
w.Header().Set("Content-Type", "application/json")
w.Write(responseData)
}))
defer mockServer.Close()
// Temporarily replace the ollamaEndpoint with the mock server's URL
originalEndpoint := OllamaEndpoint
OllamaEndpoint = mockServer.URL
defer func() { OllamaEndpoint = originalEndpoint }() // Restore the original endpoint after the test
// Call the function to be tested
prompt := "Test prompt"
context := []int{}
response, updatedContext, err := GetOllamaResponse(prompt, context)
if err != nil {
t.Fatalf("Expected no error, got %v", err)
}
// Verify the response content
expectedResponse := "This is a mock response."
if response != expectedResponse {
t.Errorf("Expected response %q, got %q", expectedResponse, response)
}
// Verify the updated context
expectedContext := []int{1, 2, 3}
for i, val := range updatedContext {
if val != expectedContext[i] {
t.Errorf("Expected context %v, got %v", expectedContext, updatedContext)
}
}
}
// Test for prompts.
var promptTestCases = []struct {
name string
prompt string
suffixStr string
shouldContain []string
}{
{"5 Even Integers GO", "Write a program that generates 5 random integers.", extraction.GoPrompt, []string{"```go", "```"}},
{"Sort the array using mergesort GO", "Write a program that sorts the array [23, 2, 0, -1, 89, 500] using mergesort.", extraction.GoPrompt, []string{"```go", "```"}},
{"Reverse the string GO.", "Reverse the string 'ammar'", extraction.GoPrompt, []string{"```go", "```"}},
{"5 Even Integers rust", "Write a program that generates 5 random integers.", extraction.RustPrompt, []string{"```rust", "```"}},
{"Sort the array using mergesort rust", "Write a program that sorts the array [23, 2, 0, -1, 89, 500] using mergesort.", extraction.RustPrompt, []string{"```rust", "```"}},
{"Reverse the string rust.", "Reverse the string 'ammar'", extraction.RustPrompt, []string{"```rust", "```"}},
}
// Test function to verify the prefix and suffix of responses from GetOllamaResponse
func TestGetOllamaResponsePrompts(t *testing.T) {
for _, tc := range promptTestCases {
t.Run(tc.name, func(t *testing.T) {
// Call the function to get the response
response, _, _ := GetOllamaResponse(tc.prompt+tc.suffixStr, []int{})
// Check if the response starts with the expected prefix
if strings.HasPrefix(response, tc.shouldContain[0]) {
// Check if the response ends with "```"
if !strings.HasSuffix(response, "```") {
t.Errorf("Test %s failed: expected response to end with ```; got %q", tc.name, response)
}
} else {
t.Errorf("Test %s failed: expected response to start with %q; got %q", tc.name, tc.shouldContain[0], response)
}
})
}
}
package main
import (
"fmt"
)
const ollamaEndpoint = "http://localhost:11434/api/generate" // The local endpoint for the Ollama API
// Struct for request to Ollama API
type OllamaRequest struct {
Prompt string `json:"prompt"`
Model string `json:"model"`
}
func main() {
fmt.Println(ollamaEndpoint)
}
package compiler
import (
"log"
"os"
"os/exec"
"runtime"
"strings"
)
const TempOutputDir = "tempOutput/"
const TempModuleName = "tempOutput"
type Language string
// Supported languages
const (
Go Language = "go"
Rust Language = "rust"
)
type OS string
// Supported OS
const (
Windows OS = "windows"
Linux OS = "linux"
MacOS OS = "darwin" // Darwin is the kernel of macOS
)
// TODO: I want to make an interface for a compilable language, so that we can add more languages in the future
// TODO: The cmd might also be an interface or a struct, so that it can build itself based on the OS and language
// TODO: A cleanup and panic might be needed in setup because if it panics the temp folders should be removed
// TODO: I am not sure that the setup should panic, maybe it should return an error instead so its easier to clean up
type Compiler struct {
OS OS
Language Language
languageEnv ILanguageEnvironment
SourceCode string
Filename string
cmdPrefix string // For example "cmd /c" on Windows
Dependencies []string
tempOutputDir string
}
type ICompiler interface {
Compile() (string, error)
}
type GoEnvironment struct {
}
// Setup initializes the go environment by creating a go module and running go mod tidy. Panics if it fails.
func (ge *GoEnvironment) SetupEnvironment(cmdPrefix string) {
// One string
cmdString := cmdPrefix + " go mod init " + TempModuleName + " && go mod tidy"
// Split the string into a slice
cmdSlice := strings.Fields(cmdString) // Fields splits the strings around each instance of one or more consecutive white space characters
// Make the command
cmd := exec.Command(cmdSlice[0], cmdSlice[1:]...)
// Set its target directory
cmd.Dir = TempOutputDir
// Execute the command
err := cmd.Run()
if err != nil {
removeTempFolders(TempOutputDir)
log.Fatalf("Error initializing go module: %v", err)
}
}
func (ge *GoEnvironment) CheckCompileErrors(filename string, language Language, cmdPrefix string) (string, error) {
srcCodeFilename := appendSuffix(filename, language)
compiledFilename := filename
cmdString := cmdPrefix + " go build -o " + compiledFilename + " " + srcCodeFilename
cmdSlice := strings.Fields(cmdString) // Fields splits the string on white space of variable length
cmd := exec.Command(cmdSlice[0], cmdSlice[1:]...)
cmd.Dir = TempOutputDir
output, err := cmd.CombinedOutput()
return string(output), err
}
func InitCompiler(OS OS, language Language, sourceCode string, filename string, dependencies []string) ICompiler {
compiler := &Compiler{}
compiler.OS = OS
compiler.Language = language
compiler.SourceCode = sourceCode
compiler.Filename = filename
compiler.Dependencies = dependencies
compiler.cmdPrefix = getOsPrefix(OS)
compiler.languageEnv = getLanguageEnv(language)
return compiler
}
func getOsPrefix(OS OS) string {
// Set the cmd prefix based on the OS
switch OS {
case Windows:
return "cmd /c "
case Linux, MacOS:
return ""
default:
panic("Unsupported OS")
}
}
func getLanguageEnv(language Language) ILanguageEnvironment {
switch language {
case Go:
return &GoEnvironment{}
case Rust:
return &RustEnvironment{}
default:
panic("Unsupported language")
}
}
type ILanguageEnvironment interface {
SetupEnvironment(cmdPrefix string)
CheckCompileErrors(filename string, language Language, cmdPrefix string) (string, error)
}
type RustEnvironment struct {
Compiler
}
// SetupEnvironment initializes the rust environment by creating a cargo project and adding dependencies. Panics if it fails.
func (re *RustEnvironment) SetupEnvironment(cmdPrefix string) {
// Initialize the rust cargo project--------------------------------------------------------------------------------
// Command to initialize a cargo project
cmdString := cmdPrefix + " cargo init --bin " + TempModuleName
// Split the string into a slice
cmdSlice := strings.Fields(cmdString)
// Make the command
cmd := exec.Command(cmdSlice[0], cmdSlice[1:]...)
// Set its target directory
cmd.Dir = TempOutputDir
// Execute the command
err := cmd.Run()
if err != nil {
log.Fatalf("Error initializing rust project: %v", err)
}
// Write the source code to a file----------------------------------------------------------------------------------
// Create a new file with the source code in the src folder
// 0644 is the file permission where the user can read and write the file, and the group and others can only read the file.
err = os.WriteFile(TempOutputDir+TempModuleName+"/src/"+re.Filename, []byte(re.SourceCode), 0644)
// Update rust dependencies in cargo.toml file using cargo add (cargo-edit)-----------------------------------------
addCommand := re.cmdPrefix + " cargo add"
addSlice := strings.Split(addCommand, " ")
addSlice = append(addSlice, re.Dependencies...)
err = exec.Command(addSlice[0], addSlice[1:]...).Run()
if err != nil {
log.Fatalf("Error adding dependencies: %v", err)
}
}
func (re *RustEnvironment) CheckCompileErrors(filename string, language Language, cmdPrefix string) (string, error) {
srcCodeFilename := TempOutputDir + appendSuffix(filename, language)
output, err := exec.Command(cmdPrefix + " cargo check " + srcCodeFilename).CombinedOutput()
return string(output), err
}
/*
The compiler pipeline
1. Set up OS and Language
2. Set up the temp folders
3. Write the source code to a file
4. SetupEnvironment the code
5. Return the output and error
*/
func (c *Compiler) Compile() (string, error) {
// Set up temp folders
setupTempFolders(TempOutputDir)
defer removeTempFolders(TempOutputDir)
srcCodeFilename := TempOutputDir + appendSuffix(c.Filename, c.Language)
//compiledFilename := TempOutputDir + c.Filename
// SetupEnvironment either Go or Rust environment, should be an interface method
c.languageEnv.SetupEnvironment(c.cmdPrefix)
// Write the source code to a file
err := os.WriteFile(srcCodeFilename, []byte(c.SourceCode), 0644)
if err != nil {
log.Fatalf("Error writing source code to file: %v", err)
}
// CheckCompileErrors the code
return c.languageEnv.CheckCompileErrors(c.Filename, c.Language, c.cmdPrefix)
}
// appendSuffix appends the suffix to the filename if it is not already there depending on the language, panics if the language is not supported
func appendSuffix(filename string, language Language) string {
suffix := ""
switch language {
case Go:
suffix = ".go"
case Rust:
suffix = ".rs"
default:
panic("Unsupported language")
}
// We check if the filename already has the suffix, if not we append it
if !strings.HasSuffix(filename, suffix) {
filename += suffix
}
return filename
}
// setupTempFolders creates the temp output directory for compiled files, panics if it fails
func setupTempFolders(tempOutputDir string) {
// 0777 are the permissions for the directory, everyone can read, write and execute
err := os.MkdirAll(tempOutputDir, os.ModePerm)
if err != nil {
panic("Error creating temp output directory:\n\n" + err.Error())
}
}
// removeTempFolders removes the temp output directory for compiled files, panics if it fails
func removeTempFolders(tempOutputDir string) {
err := os.RemoveAll(tempOutputDir)
if err != nil {
panic("Error removing temp output directory:\n\n" + err.Error())
}
}
func CompileStringToGo(code string, filename string, dependencies []string) (string, error) {
// Get the OS
os := runtime.GOOS
// SetupEnvironment
return InitCompiler(OS(os), Go, code, filename, dependencies).Compile()
}
func CompileStringToRust(code string, filename string, dependencies []string) (string, error) {
// Get the OS
os := runtime.GOOS
// SetupEnvironment
return InitCompiler(OS(os), Rust, code, filename, dependencies).Compile()
}
package main
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
"strings"
)
const ollamaEndpoint = "http://localhost:11434/api/generate" // The local endpoint for the Ollama API
// Struct for request to Ollama API
type OllamaRequest struct {
Prompt string `json:"prompt"`
Model string `json:"model"`
Context []int `json:"context,omitempty"` // Context to maintain conversation
}
// Struct for response from Ollama API
type OllamaResponse struct {
Model string `json:"model"`
CreatedAt string `json:"created_at"`
Response string `json:"response"`
Done bool `json:"done"`
DoneReason string `json:"done_reason,omitempty"`
Context []int `json:"context,omitempty"` // Updated context
TotalDuration int64 `json:"total_duration,omitempty"`
LoadDuration int64 `json:"load_duration,omitempty"`
PromptEvalCount int `json:"prompt_eval_count,omitempty"`
PromptEvalDuration int64 `json:"prompt_eval_duration,omitempty"`
EvalCount int `json:"eval_count,omitempty"`
EvalDuration int64 `json:"eval_duration,omitempty"`
}
func main() {
reader := bufio.NewReader(os.Stdin)
var conversationContext []int // Variable to store conversation context
for {
fmt.Print("Enter your prompt (or type 'exit' to quit): ")
userPrompt, _ := reader.ReadString('\n')
userPrompt = strings.TrimSpace(userPrompt)
if userPrompt == "exit" {
fmt.Println("Exiting the program.")
break
}
// Generate response using Ollama API, passing the context
response, updatedContext, err := getOllamaResponse(userPrompt, conversationContext)
if err != nil {
fmt.Println("Error generating response:", err)
continue
}
// Update the conversation context with the response
conversationContext = updatedContext
fmt.Println("Ollama's response:", response)
}
}
// Function to make a POST request to Ollama API
func getOllamaResponse(prompt string, context []int) (string, []int, error) {
// Create request payload with the model specified and context
requestBody, err := json.Marshal(OllamaRequest{
Prompt: prompt,
Model: "llama3.1",
Context: context, // Pass the conversation context
})
if err != nil {
return "", nil, err
}
// Send HTTP POST request to Ollama API
resp, err := http.Post(ollamaEndpoint, "application/json", bytes.NewBuffer(requestBody))
if err != nil {
return "", nil, err
}
defer resp.Body.Close()
// Read and accumulate response body in chunks
var completeResponse string
var updatedContext []int
decoder := json.NewDecoder(resp.Body)
for decoder.More() {
var chunk OllamaResponse
if err := decoder.Decode(&chunk); err != nil {
return "", nil, err
}
completeResponse += chunk.Response
// Capture the updated context from the response
updatedContext = chunk.Context
if chunk.Done {
break
}
}
return completeResponse, updatedContext, nil
}
package main
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
"strings"
"time"
)
const ollamaEndpoint = "http://localhost:11434/api/generate" // The local endpoint for the Ollama API
// Struct for request to Ollama API
type OllamaRequest struct {
Prompt string `json:"prompt"`
Model string `json:"model"`
Context []int `json:"context,omitempty"` // Context to maintain conversation
}
// Struct for response from Ollama API
type OllamaResponse struct {
Model string `json:"model"`
CreatedAt string `json:"created_at"`
Response string `json:"response"`
Done bool `json:"done"`
DoneReason string `json:"done_reason,omitempty"`
Context []int `json:"context,omitempty"` // Updated context
TotalDuration int64 `json:"total_duration,omitempty"`
LoadDuration int64 `json:"load_duration,omitempty"`
PromptEvalCount int `json:"prompt_eval_count,omitempty"`
PromptEvalDuration int64 `json:"prompt_eval_duration,omitempty"`
EvalCount int `json:"eval_count,omitempty"`
EvalDuration int64 `json:"eval_duration,omitempty"`
}
func main() {
reader := bufio.NewReader(os.Stdin)
var conversationContext []int // Variable to store conversation context
for {
fmt.Print("Enter your prompt (or type 'exit' to quit): ")
userPrompt, _ := reader.ReadString('\n')
userPrompt = strings.TrimSpace(userPrompt)
if userPrompt == "exit" {
fmt.Println("Exiting the program.")
break
}
fmt.Println("Prompt received. Generating response...")
// Start a go routine to display a waiting indicator while the response is being generated
done := make(chan bool)
go displayLoadingIndicator(done)
// Generate response using Ollama API, passing the context
response, updatedContext, err := getOllamaResponse(userPrompt, conversationContext)
// Signal the waiting indicator to stop
done <- true
if err != nil {
fmt.Println("Error generating response:", err)
continue
}
// Update the conversation context with the response
conversationContext = updatedContext
fmt.Println("Ollama's response:", response)
}
}
// Function to display a waiting/loading indicator
func displayLoadingIndicator(done chan bool) {
indicator := []string{"|", "/", "-", "\\"}
i := 0
for {
select {
case <-done:
fmt.Print("\r") // Clear the waiting indicator when done
return
default:
fmt.Printf("\r%s Generating...", indicator[i%len(indicator)])
i++
time.Sleep(200 * time.Millisecond)
}
}
}
// Function to make a POST request to Ollama API
func getOllamaResponse(prompt string, context []int) (string, []int, error) {
// Create request payload with the model specified and context
requestBody, err := json.Marshal(OllamaRequest{
Prompt: prompt,
Model: "llama3.1",
Context: context, // Pass the conversation context
})
if err != nil {
return "", nil, err
}
// Send HTTP POST request to Ollama API
resp, err := http.Post(ollamaEndpoint, "application/json", bytes.NewBuffer(requestBody))
if err != nil {
return "", nil, err
}
defer resp.Body.Close()
// Read and accumulate response body in chunks
var completeResponse string
var updatedContext []int
decoder := json.NewDecoder(resp.Body)
for decoder.More() {
var chunk OllamaResponse
if err := decoder.Decode(&chunk); err != nil {
return "", nil, err
}
completeResponse += chunk.Response
// Capture the updated context from the response
updatedContext = chunk.Context
if chunk.Done {
break
}
}
return completeResponse, updatedContext, nil
}
package main
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
"strings"
)
const ollamaEndpoint = "http://localhost:11434/api/generate" // The local endpoint for the Ollama API
// Struct for request to Ollama API
type OllamaRequest struct {
Prompt string `json:"prompt"`
Model string `json:"model"`
}
// Struct for response from Ollama API
type OllamaResponse struct {
Response string `json:"response"`
Done bool `json:"done"`
}
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter your prompt: ")
userPrompt, _ := reader.ReadString('\n')
//Modifying the user prompt to make the code in rust or gloang, will always be rust so far
var userPromptModified string = userPrompt + "The code should be in the Go programming language. There should also be 3 robust test cases within the same code. There should also be a main function inside of which all the execution takes place. Please only provide the source code and no further explanation, The format should be ```go <yourcode + testcases> ```"
// if true {
// userPromptModified = userPrompt + "The code should be in the Go programming language. There should also be 3 robust test cases within the same code. There should also be a main function inside of which all the execution takes place. Please only provide the source code and no further explanation, The format should be ```go <yourcode + testcases> ```"
// } else {
// userPromptModified = userPrompt + "The code should be in the Rust programming language. There should also be 3 robust test cases within the same code. There should also be a main function inside of which all the execution takes place. Please only provide the source code and no further explanation, The format should be ```rust <yourcode + testcases> ```"
// }
fmt.Println(userPromptModified)
// Generate response using Ollama API
requestBody, err := json.Marshal(OllamaRequest{
Prompt: userPromptModified,
Model: "llama3.1",
})
if err != nil {
fmt.Println("Error generating response:", err)
return
}
// Send HTTP POST request to Ollama API
resp, err := http.Post(ollamaEndpoint, "application/json", bytes.NewBuffer(requestBody))
if err != nil {
fmt.Println("Error generating response:", err)
return
}
defer resp.Body.Close()
// Read and accumulate response body in chunks
var completeResponse string
decoder := json.NewDecoder(resp.Body)
for decoder.More() {
var chunk OllamaResponse
if err := decoder.Decode(&chunk); err != nil {
return
}
completeResponse += chunk.Response
if chunk.Done {
break
}
}
//fmt.Println("Ollama's response:", completeResponse)
var out = extract(completeResponse)
fmt.Println(out)
}
// Divides a string where you have ``` and then returns 1 index
func extract(output string) string {
parts := strings.Split(output, "```")
var extracted = ""
if strings.Contains(parts[1], "rust") {
extracted = strings.TrimLeft(parts[1], "rust")
} else {
extracted = strings.TrimLeft(parts[1], "go")
}
return extracted
}
module src
go 1.23.1
package main
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
const ollamaEndpoint = "http://localhost:11434/api/generate" // The local endpoint for the Ollama API
// Struct for request to Ollama API
type OllamaRequest struct {
Prompt string `json:"prompt"`
Model string `json:"model"`
}
// Struct for response from Ollama API
type OllamaResponse struct {
Response string `json:"response"`
Done bool `json:"done"`
}
func main() {
for {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter your prompt: ")
userPrompt, _ := reader.ReadString('\n')
// Generate response using Ollama API
if userPrompt == "exit" {
fmt.Println("Exiting the program.")
break
}
requestBody, err := json.Marshal(OllamaRequest{
Prompt: userPrompt,
Model: "llama3.1",
})
if err != nil {
fmt.Println("Error generating response:", err)
return
}
// Send HTTP POST request to Ollama API
resp, err := http.Post(ollamaEndpoint, "application/json", bytes.NewBuffer(requestBody))
if err != nil {
fmt.Println("Error generating response:", err)
return
}
defer resp.Body.Close()
// Read and accumulate response body in chunks
var completeResponse string
decoder := json.NewDecoder(resp.Body)
for decoder.More() {
var chunk OllamaResponse
if err := decoder.Decode(&chunk); err != nil {
return
}
completeResponse += chunk.Response
if chunk.Done {
break
}
}
fmt.Println("Ollama's response:", completeResponse)
}
}
package main
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"net/http"
"os"
)
const ollamaEndpoint = "http://localhost:11434/api/generate" // The local endpoint for the Ollama API
// Struct for request to Ollama API
type OllamaRequest struct {
Prompt string `json:"prompt"`
Model string `json:"model"`
}
// Struct for response from Ollama API
type OllamaResponse struct {
Response string `json:"response"`
Done bool `json:"done"`
}
func main() {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Enter your prompt: ")
userPrompt, _ := reader.ReadString('\n')
// Generate response using Ollama API
requestBody, err := json.Marshal(OllamaRequest{
Prompt: userPrompt,
Model: "llama3.1",
})
if err != nil {
fmt.Println("Error generating response:", err)
return
}
// Send HTTP POST request to Ollama APIÍ
resp, err := http.Post(ollamaEndpoint, "application/json", bytes.NewBuffer(requestBody))
if err != nil {
fmt.Println("Error generating response:", err)
return
}
defer resp.Body.Close()
// Read and accumulate response body in chunks
var completeResponse string
decoder := json.NewDecoder(resp.Body)
for decoder.More() {
var chunk OllamaResponse
if err := decoder.Decode(&chunk); err != nil {
return
}
completeResponse += chunk.Response
if chunk.Done {
break
}
}
fmt.Println("Ollama's response:", completeResponse)
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment