-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from osangenis/hello_world_service
Hello world service
- Loading branch information
Showing
14 changed files
with
403 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
--- | ||
name: Generate services | ||
|
||
on: | ||
push: | ||
branches: [main] | ||
pull_request: | ||
branches: [main] | ||
|
||
env: | ||
GPT_API: https://api.github.com | ||
|
||
permissions: | ||
contents: write | ||
pull-requests: write | ||
|
||
jobs: | ||
hello-service: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: actions/setup-go@v2 | ||
with: | ||
go-version: '1.19.3' # Important to have the minor | ||
- name: generate_prompt | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
|
||
#In this project, gpt files are generated from templates | ||
*.gpt |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
// Command line tool to render a GPT-3 prompt result into files | ||
package main | ||
|
||
import ( | ||
"context" | ||
"flag" | ||
"fmt" | ||
"io" | ||
"os" | ||
"strings" | ||
|
||
"github.com/osangenis/pap/v2/cmd/openai-render/response" | ||
openai "github.com/sashabaranov/go-openai" | ||
) | ||
|
||
const openaiKeyEnv = "OPENAI_API_KEY" | ||
|
||
func main() { | ||
pOutputDir := flag.String("output_dir", "", "The directory in where files/code blocks from the response will be saved") | ||
flag.Parse() | ||
|
||
if pOutputDir == nil || *pOutputDir == "" { | ||
panic("The flag output_dir is required") | ||
} | ||
|
||
apiKey := os.Getenv(openaiKeyEnv) | ||
if apiKey == "" { | ||
panic(fmt.Sprintf("%v is not set", openaiKeyEnv)) | ||
} | ||
|
||
client := openai.NewClient(apiKey) | ||
resp, err := client.CreateChatCompletion( | ||
context.Background(), | ||
openai.ChatCompletionRequest{ | ||
Model: openai.GPT3Dot5Turbo, | ||
Messages: []openai.ChatCompletionMessage{ | ||
{ | ||
Role: openai.ChatMessageRoleUser, | ||
Content: stdin(), | ||
}, | ||
}, | ||
}, | ||
) | ||
|
||
if err != nil { | ||
panic(fmt.Sprintf("ChatCompletion error: %v\n", err)) | ||
} | ||
|
||
files := response.FilesFromChat(resp.Choices[0].Message.Content, "go") | ||
for _, file := range files { | ||
err = os.WriteFile(*pOutputDir+"/"+file.Path, []byte(file.Content), 0644) | ||
if err != nil { | ||
panic(fmt.Sprintf("Error writing file %v : %v\n", file.Path, err)) | ||
} | ||
} | ||
|
||
fmt.Println(resp.Choices[0].Message.Content) | ||
} | ||
|
||
func stdin() string { | ||
buf, err := io.ReadAll(os.Stdin) | ||
if err != nil { | ||
panic(err) | ||
} | ||
return strings.TrimSuffix(string(buf), "\n") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
package response | ||
|
||
import ( | ||
"regexp" | ||
) | ||
|
||
// OutputFiles is a list of code blocks extracted as files | ||
type OutputFiles []*OutputFile | ||
|
||
// OutputFile is a code block extracted as a file with a relative path and content | ||
type OutputFile struct { | ||
Path string | ||
Content string | ||
} | ||
|
||
// Filenames just returns the filenames of the output files as []string | ||
func (o OutputFiles) Filenames() []string { | ||
res := []string{} | ||
for _, file := range o { | ||
res = append(res, file.Path) | ||
} | ||
return res | ||
} | ||
|
||
// FilesFromChat extracts files from a ChatCompletionResponse code blocks. | ||
// If lang is specified, it will be used to determine which code blocks to extract as | ||
// files. If lang is empty, all code blocks will be extracted to files | ||
func FilesFromChat(resp string, lang string) OutputFiles { | ||
filesGroup := OutputFiles{} | ||
// you can check this regex at | ||
// https: //regex101.com/r/Rs5m3T/1 | ||
codeBlockRegex := regexp.MustCompile(`\x60([^\x60]+)\x60:\W\x60\x60\x60(\w+)([^\x60]+)\x60\x60\x60`) | ||
for _, match := range codeBlockRegex.FindAllStringSubmatch(resp, -1) { | ||
fPath := match[1] | ||
fLang := match[2] | ||
fContent := match[3] | ||
if lang == "" || fLang == lang { | ||
filesGroup = append(filesGroup, &OutputFile{ | ||
Path: fPath, | ||
Content: fContent, | ||
}) | ||
} | ||
} | ||
return filesGroup | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
package response | ||
|
||
import ( | ||
"os" | ||
"testing" | ||
|
||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func Test_FilesFromChat(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
filePath string | ||
lang string | ||
want []string | ||
}{ | ||
{ | ||
name: "extract go files from code blocks like In `hello/ping.go`: ```...", | ||
filePath: "fixtures/sample.output", | ||
lang: "go", | ||
want: []string{ | ||
"hello/ping.go", | ||
"cmd/main.go", | ||
}, | ||
}, | ||
} | ||
|
||
for _, test := range tests { | ||
t.Run(test.name, func(t *testing.T) { | ||
fixture := readFileAsString(t, test.filePath) | ||
got := FilesFromChat(fixture, test.lang) | ||
assert.ElementsMatch(t, test.want, got.Filenames()) | ||
}) | ||
} | ||
} | ||
|
||
func readFileAsString(t *testing.T, filePath string) string { | ||
bytes, err := os.ReadFile(filePath) | ||
require.NoError(t, err) | ||
return string(bytes) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
Sure! Here's an example implementation of the gRPC API service based on the given `hello.proto` file. | ||
|
||
In `hello.proto`: | ||
```protobuf | ||
/** | ||
* Hello World API service | ||
* | ||
* Just an experimenting API that will ping what you send | ||
*/ | ||
syntax = "proto3"; | ||
|
||
package hello; | ||
|
||
option go_package = "github.com/osangenis/hello"; | ||
|
||
message PingRequest { | ||
string in = 1; | ||
} | ||
|
||
message PingResponse { | ||
string out = 1; | ||
} | ||
|
||
// Hello Service | ||
service HelloService { | ||
// Returns the same string that was sent | ||
rpc Ping(PingRequest) returns (PingResponse); | ||
} | ||
``` | ||
|
||
In `cmd/main.go`: | ||
```go | ||
... | ||
package main | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"net" | ||
"os" | ||
|
||
"github.com/osangenis/hello/hello" | ||
"google.golang.org/grpc" | ||
) | ||
|
||
func main() { | ||
port := os.Getenv("PORT") | ||
if port == "" { | ||
port = "8080" | ||
} | ||
|
||
listenAddr := fmt.Sprintf(":%s", port) | ||
lis, err := net.Listen("tcp", listenAddr) | ||
if err != nil { | ||
log.Fatalf("failed to listen: %v", err) | ||
} | ||
|
||
grpcServer := grpc.NewServer() | ||
helloService := hello.NewHelloServiceServer() | ||
hello.RegisterHelloServiceServer(grpcServer, helloService) | ||
|
||
log.Printf("Server listening on port %s", port) | ||
if err := grpcServer.Serve(lis); err != nil { | ||
log.Fatalf("failed to serve: %v", err) | ||
} | ||
} | ||
``` | ||
|
||
In `hello/ping.go`: | ||
```go | ||
... | ||
package hello | ||
|
||
import ( | ||
"context" | ||
) | ||
|
||
type HelloServiceServer struct { | ||
} | ||
|
||
// NewHelloServiceServer creates a new instance of HelloServiceServer. | ||
func NewHelloServiceServer() *HelloServiceServer { | ||
return &HelloServiceServer{} | ||
} | ||
|
||
// Ping implements the Ping gRPC method. | ||
func (s *HelloServiceServer) Ping(ctx context.Context, req *PingRequest) (*PingResponse, error) { | ||
return &PingResponse{ | ||
Out: req.In, | ||
}, nil | ||
} | ||
``` | ||
|
||
To run the service, use the command `go run cmd/main.go` in the root directory of the project. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
- Add source code comments | ||
- File names must be in snake case | ||
- Don't include any explanations in your responses |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
module github.com/osangenis/pap/v2 | ||
|
||
go 1.20 | ||
|
||
require ( | ||
github.com/sashabaranov/go-openai v1.15.1 | ||
github.com/stretchr/testify v1.8.4 | ||
) | ||
|
||
require ( | ||
github.com/davecgh/go-spew v1.1.1 // indirect | ||
github.com/pmezard/go-difflib v1.0.0 // indirect | ||
gopkg.in/yaml.v3 v3.0.1 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= | ||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= | ||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= | ||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= | ||
github.com/sashabaranov/go-openai v1.15.1 h1:BAV5LCVEzvZ3rN/Lh5NRVs2z6AahPt/jn5s2/cEEG0M= | ||
github.com/sashabaranov/go-openai v1.15.1/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= | ||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= | ||
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= | ||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= | ||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= | ||
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
/** | ||
* Hello World API service | ||
* | ||
* Just an experimenting API that will ping what you send | ||
*/ | ||
syntax = "proto3"; | ||
|
||
package hello; | ||
|
||
option go_package = "github.com/osangenis/hello"; | ||
|
||
message PingRequest { | ||
string in = 1; | ||
} | ||
|
||
message PingResponse { | ||
string out = 1; | ||
} | ||
|
||
// Hello Service | ||
service HelloService { | ||
// Returns the same string that was sent | ||
rpc Ping(PingRequest) returns (PingResponse); | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
|
||
package main | ||
|
||
import ( | ||
"fmt" | ||
"log" | ||
"net" | ||
"os" | ||
|
||
"github.com/osangenis/hello/hello" | ||
"google.golang.org/grpc" | ||
) | ||
|
||
func main() { | ||
port := os.Getenv("PORT") | ||
if port == "" { | ||
port = "8080" | ||
} | ||
|
||
lis, err := net.Listen("tcp", fmt.Sprintf(":%s", port)) | ||
if err != nil { | ||
log.Fatalf("failed to listen: %v", err) | ||
} | ||
|
||
s := grpc.NewServer() | ||
hello.RegisterHelloServiceServer(s, &hello.Server{}) | ||
|
||
log.Printf("Server listening on port %s", port) | ||
if err := s.Serve(lis); err != nil { | ||
log.Fatalf("failed to serve: %v", err) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
|
||
package hello | ||
|
||
import ( | ||
"context" | ||
) | ||
|
||
type Server struct{} | ||
|
||
func (s *Server) Ping(ctx context.Context, req *PingRequest) (*PingResponse, error) { | ||
return &PingResponse{ | ||
Out: req.In, | ||
}, nil | ||
} |
Oops, something went wrong.