mirror of
https://github.com/Pull-Pal/pull-pal.git
synced 2025-01-02 15:36:51 -05:00
Initial commit (part 2)
I added some code and comments too it's almost set up for me and you
This commit is contained in:
parent
f0893ed8b8
commit
a570437b9c
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*.swp
|
||||||
|
pal
|
7
Makefile
Normal file
7
Makefile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
SHELL := /bin/bash
|
||||||
|
|
||||||
|
build:
|
||||||
|
go build -v -o pal ./cmd
|
||||||
|
|
||||||
|
run:
|
||||||
|
go run ./cmd/
|
7
cmd/main.go
Normal file
7
cmd/main.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println("hello")
|
||||||
|
}
|
115
pullpal/common.go
Normal file
115
pullpal/common.go
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
package pullpal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"strings"
|
||||||
|
"text/template"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PullPal is the service responsible for:
|
||||||
|
// * Interacting with git server (e.g. reading issues and making PRs on Github)
|
||||||
|
// * Generating LLM prompts
|
||||||
|
// * Parsing LLM responses
|
||||||
|
// * Interacting with LLM (e.g. with GPT via OpenAI API)
|
||||||
|
type PullPal struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
// File represents a file in a git repository.
|
||||||
|
type File struct {
|
||||||
|
Path string
|
||||||
|
Contents string
|
||||||
|
}
|
||||||
|
|
||||||
|
// CodeChangeRequest contains all necessary information for generating a prompt for a LLM.
|
||||||
|
type CodeChangeRequest struct {
|
||||||
|
Files []File
|
||||||
|
Subject string
|
||||||
|
Body string
|
||||||
|
}
|
||||||
|
|
||||||
|
// String is the string representation of a CodeChangeRequest. Functionally, it contains the LLM prompt.
|
||||||
|
func (req CodeChangeRequest) String() string {
|
||||||
|
prompt := req.MustGetPrompt()
|
||||||
|
return "START OF PROMPT\n" + prompt + "\nEND OF PROMPT"
|
||||||
|
}
|
||||||
|
|
||||||
|
// MustGetPrompt only returns the prompt, but panics if the data in the request cannot populate the template.
|
||||||
|
func (req CodeChangeRequest) MustGetPrompt() string {
|
||||||
|
prompt, err := req.GetPrompt()
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
return prompt
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPrompt converts the information in the request to a prompt for an LLM.
|
||||||
|
func (req CodeChangeRequest) GetPrompt() (string, error) {
|
||||||
|
tmpl, err := template.ParseFiles("../template/code-change-request.tmpl")
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
var result bytes.Buffer
|
||||||
|
err = tmpl.Execute(&result, req)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.String(), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CodeChangeResponse contains data derived from an LLM response to a prompt generated via a CodeChangeRequest.
|
||||||
|
type CodeChangeResponse struct {
|
||||||
|
Files []File
|
||||||
|
Notes string
|
||||||
|
}
|
||||||
|
|
||||||
|
// String is a string representation of CodeChangeResponse.
|
||||||
|
func (res CodeChangeResponse) String() string {
|
||||||
|
out := "Notes:\n"
|
||||||
|
out += res.Notes + "\n\n"
|
||||||
|
out += "Files:\n"
|
||||||
|
for _, f := range res.Files {
|
||||||
|
out += f.Path + ":\n```\n"
|
||||||
|
out += f.Contents + "\n```\n"
|
||||||
|
}
|
||||||
|
|
||||||
|
return out
|
||||||
|
}
|
||||||
|
|
||||||
|
// ParseCodeChangeResponse parses the LLM's response to CodeChangeRequest (string) into a CodeChangeResponse.
|
||||||
|
func ParseCodeChangeResponse(llmResponse string) CodeChangeResponse {
|
||||||
|
sections := strings.Split(llmResponse, "Notes:")
|
||||||
|
|
||||||
|
filesSection := sections[0]
|
||||||
|
notes := strings.TrimSpace(sections[1])
|
||||||
|
|
||||||
|
files := parseFiles(filesSection)
|
||||||
|
|
||||||
|
return CodeChangeResponse{
|
||||||
|
Files: files,
|
||||||
|
Notes: notes,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseFiles process the "files" subsection of the LLM's response. It is a helper for GetCodeChangeResponse.
|
||||||
|
func parseFiles(filesSection string) []File {
|
||||||
|
fileStringList := strings.Split(filesSection, "name:")
|
||||||
|
// first item in the list is just gonna be "Files:"
|
||||||
|
fileStringList = fileStringList[1:]
|
||||||
|
|
||||||
|
fileList := make([]File, len(fileStringList))
|
||||||
|
for i, f := range fileStringList {
|
||||||
|
fileParts := strings.Split(f, "contents:")
|
||||||
|
path := strings.TrimSpace(fileParts[0])
|
||||||
|
contents := strings.TrimSpace(fileParts[1])
|
||||||
|
contents = strings.Trim(contents, "```")
|
||||||
|
|
||||||
|
fileList[i] = File{
|
||||||
|
Path: path,
|
||||||
|
Contents: contents,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fileList
|
||||||
|
}
|
26
template/code-change-request.tmpl
Normal file
26
template/code-change-request.tmpl
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
Files:
|
||||||
|
{{ range $index, $file := .Files }}
|
||||||
|
- name: {{ $file.Path }}:
|
||||||
|
contents:
|
||||||
|
```
|
||||||
|
{{ $file.Contents }}
|
||||||
|
```
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
Modify the files above to accomplish the following task:
|
||||||
|
Subject: {{ .Subject }}
|
||||||
|
Body:
|
||||||
|
{{ .Body }}
|
||||||
|
|
||||||
|
Respond in the exact format:
|
||||||
|
Files:
|
||||||
|
{{ range $index, $file := .Files }}
|
||||||
|
- name: {{ $file.Path }}
|
||||||
|
contents:
|
||||||
|
```
|
||||||
|
[new {{ $file.Path }} contents]
|
||||||
|
```
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
[additional context about your changes]
|
Loading…
Reference in New Issue
Block a user