diff --git a/cmd/config.go b/cmd/config.go index e4c03f0..fb8b593 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -18,7 +18,7 @@ var ( {}, {int(entity.EN), int(entity.JP)}, {int(entity.NormalFormat), int(entity.EmojiFormat), int(entity.PrefixFormat)}, - {int(entity.WrapServer), int(entity.OpenAiAPI)}, + {int(entity.Server), int(entity.Local)}, } configOptionLabel = [][]string{ {}, diff --git a/cmd/suggest.go b/cmd/suggest.go index 13d6e16..b5bdfd2 100644 --- a/cmd/suggest.go +++ b/cmd/suggest.go @@ -2,6 +2,11 @@ package cmd import ( "fmt" + "github.com/cocoide/commitify/internal/entity" + "github.com/cocoide/commitify/internal/gateway" + "github.com/cocoide/commitify/internal/service" + "github.com/cocoide/commitify/internal/usecase" + "golang.org/x/net/context" "log" "os" "strings" @@ -12,8 +17,6 @@ import ( "github.com/charmbracelet/lipgloss" "github.com/fatih/color" "github.com/spf13/cobra" - - "github.com/cocoide/commitify/internal/service" ) var ( @@ -29,7 +32,7 @@ type suggestModel struct { isEditing bool spinner spinner.Model textInput textinput.Model - scs *service.SuggestCmdService + scs *usecase.SuggestCmdUsecase } func (sm *suggestModel) Init() tea.Cmd { @@ -120,11 +123,20 @@ func NewSuggestModel() *suggestModel { ti.Focus() // suggestコマンドのサービスの取得 - scs, err := service.NewSuggestCmdService() + inputOutput := gateway.NewInputOutputGateway() + var commitMessageService service.CommitMessageService + config, err := entity.ReadConfig() if err != nil { - log.Fatal(err) - os.Exit(-1) + log.Fatalf("設定ファイルの読み込みができませんでした") + } + switch config.WithGptRequestLocation() { + case entity.Client: + nlp := gateway.NewOpenAIGateway(context.Background()) + commitMessageService = gateway.NewClientCommitMessageGateway(nlp) + case entity.Server: + commitMessageService = gateway.NewGrpcServerGateway() } + suggestCmdUsecase := usecase.NewSuggestCmdUsecase(commitMessageService, inputOutput) return &suggestModel{ choices: []string{""}, @@ -133,7 +145,7 @@ func NewSuggestModel() *suggestModel { isLoading: true, isEditing: false, textInput: ti, - scs: scs, + scs: suggestCmdUsecase, } } diff --git a/go.mod b/go.mod index 154614d..c700d69 100644 --- a/go.mod +++ b/go.mod @@ -6,11 +6,13 @@ require ( github.com/charmbracelet/bubbles v0.16.1 github.com/charmbracelet/bubbletea v0.24.2 github.com/charmbracelet/lipgloss v0.7.1 + github.com/cocoide/commitify-grpc-server v0.0.0-20230925123729-e460fb67f971 github.com/fatih/color v1.15.0 - github.com/golang/mock v1.4.4 - github.com/sashabaranov/go-openai v1.15.1 + github.com/golang/mock v1.6.0 + github.com/sashabaranov/go-openai v1.15.2 github.com/spf13/cobra v1.7.0 github.com/spf13/viper v1.16.0 + golang.org/x/net v0.15.0 google.golang.org/grpc v1.58.0 google.golang.org/protobuf v1.31.0 ) @@ -35,7 +37,6 @@ require ( require ( github.com/atotto/clipboard v0.1.4 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect - github.com/charmbracelet/lipgloss v0.7.1 // indirect github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 // indirect github.com/golang/protobuf v1.5.3 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect @@ -47,7 +48,6 @@ require ( github.com/muesli/reflow v0.3.0 // indirect github.com/muesli/termenv v0.15.1 // indirect github.com/rivo/uniseg v0.2.0 // indirect - golang.org/x/net v0.15.0 // indirect golang.org/x/sync v0.3.0 // indirect golang.org/x/sys v0.12.0 // indirect golang.org/x/term v0.12.0 // indirect diff --git a/go.sum b/go.sum index 900e963..62f959e 100644 --- a/go.sum +++ b/go.sum @@ -56,6 +56,8 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cocoide/commitify-grpc-server v0.0.0-20230925123729-e460fb67f971 h1:u0ooNLw6PuHWUDLoVx5NiNt9858HvXqvvPNOpL+tpZw= +github.com/cocoide/commitify-grpc-server v0.0.0-20230925123729-e460fb67f971/go.mod h1:iDkIWp+CfRdHHSm4Nix6uS9dVzEgDsYPeCn+yklpCJc= github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81 h1:q2hJAaP1k2wIvVRd/hEHD7lacgqrCPS+k8g1MndzfWY= github.com/containerd/console v1.0.4-0.20230313162750-1ae8d489ac81/go.mod h1:YynlIjWYF8myEu6sdkwKIvGQq+cOckRm6So2avqoYAk= github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -86,8 +88,9 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw= -github.com/golang/mock v1.4.4 h1:l75CXGRSwbaYNpl/Z2X1XIIAMSCquvXgpVZDhwEIJsc= github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4= +github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= +github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -190,8 +193,8 @@ github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJ github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -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/sashabaranov/go-openai v1.15.2 h1:0PW+ttxe+UNYKDkA1KTly7K6YhFBqnVBbblQ3t8AfY4= +github.com/sashabaranov/go-openai v1.15.2/go.mod h1:lj5b/K+zjTSFxVLijLSTDZuP7adOgerWeFyZLUhAKRg= github.com/spf13/afero v1.9.5 h1:stMpOSZFs//0Lv29HduCmli3GUfpFoF3Y1Q/aXj/wVM= github.com/spf13/afero v1.9.5/go.mod h1:UBogFpq8E9Hx+xc5CNTTEpTnuHVmXDwZcZcE1eb/UhQ= github.com/spf13/cast v1.5.1 h1:R+kOtfhWQE6TVQzY+4D7wJLBgkdVasCEFxSUBYBYIlA= @@ -213,14 +216,15 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY= github.com/stretchr/testify v1.8.3/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/subosito/gotenv v1.4.2 h1:X1TuBLAMDFbaTAChgCBLu3DU3UPyELpnF2jjJ2cz/S8= github.com/subosito/gotenv v1.4.2/go.mod h1:ayKnFf/c6rvx/2iiLrJUk1e6plDbT3edrFNGqEflhK0= github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= @@ -267,6 +271,7 @@ golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -298,6 +303,7 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.15.0 h1:ugBLEUaxABaB5AJqW9enI0ACdci2RUd4eP51NTBvuJ8= golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk= @@ -320,6 +326,7 @@ golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -354,8 +361,10 @@ golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -426,6 +435,7 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/internal/entity/config.go b/internal/entity/config.go index 519e183..a11a39b 100644 --- a/internal/entity/config.go +++ b/internal/entity/config.go @@ -3,10 +3,9 @@ package entity import ( "encoding/json" "fmt" - "os" - - pb "github.com/cocoide/commitify/pkg/grpc" + "github.com/cocoide/commitify-grpc-server/pkg/pb" "github.com/spf13/viper" + "os" ) // コミットメッセージの言語の列挙型 @@ -26,12 +25,12 @@ const ( PrefixFormat ) -// AIのソースの列挙型 -type AISource int +// ChatGPTのAPIを叩く場所 +type GptRequestLocation int const ( - WrapServer AISource = iota - OpenAiAPI + Server GptRequestLocation = iota + Client ) type Config struct { @@ -133,3 +132,14 @@ func SaveConfig(configIndex, updateConfigParamInt int, updateConfigParamStr stri return nil } + +func (c *Config) WithGptRequestLocation() GptRequestLocation { + switch c.AISource { + case 0: + return Server + case 1: + return Client + default: + return Server + } +} diff --git a/internal/gateway/ai_source_grpc.go b/internal/gateway/ai_source_grpc.go deleted file mode 100644 index 612c542..0000000 --- a/internal/gateway/ai_source_grpc.go +++ /dev/null @@ -1,65 +0,0 @@ -package gateway - -import ( - "context" - "crypto/tls" - "fmt" - "log" - "os" - - "github.com/cocoide/commitify/internal/entity" - pb "github.com/cocoide/commitify/pkg/grpc" - "google.golang.org/grpc" - "google.golang.org/grpc/credentials" -) - -const ( - // serveAddress = "localhost:54322" - serveAddress = "commitify.fly.dev:443" -) - -type grpcServeGateway struct { - client pb.CommitMessageServiceClient -} - -func NewGrpcServeGateway() *grpcServeGateway { - gsg := new(grpcServeGateway) - - conn, err := grpc.Dial( - serveAddress, - grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})), - ) - if err != nil { - log.Printf("Connection failed: %v", err) - os.Exit(-1) - return nil - } - - gsg.client = pb.NewCommitMessageServiceClient(conn) - - return gsg -} - -func (gsg grpcServeGateway) FetchCommitMessages(fileDiffStr string) ([]string, error) { - // 設定情報を取得 - conf, err := entity.ReadConfig() - if err != nil { - fmt.Printf("設定ファイルが開けません: %v", err) - } - cft, lt := conf.Config2PbVars() - - req := &pb.CommitMessageRequest{ - InputCode: fileDiffStr, - CodeFormat: cft, - Language: lt, - } - - res, err := gsg.client.GenerateCommitMessage(context.Background(), req) - if err != nil { - log.Fatal("gRPCの送信に失敗: ", err) - return nil, err - } - - return res.GetMessages(), nil - -} diff --git a/internal/gateway/ai_source_interface.go b/internal/gateway/ai_source_interface.go deleted file mode 100644 index 3dcd9a4..0000000 --- a/internal/gateway/ai_source_interface.go +++ /dev/null @@ -1,5 +0,0 @@ -package gateway - -type AISourceGatewayInterface interface { - FetchCommitMessages(fileDiffStr string) ([]string, error) -} diff --git a/internal/gateway/clinet.go b/internal/gateway/clinet.go new file mode 100644 index 0000000..329a818 --- /dev/null +++ b/internal/gateway/clinet.go @@ -0,0 +1,41 @@ +package gateway + +import ( + "fmt" + "github.com/cocoide/commitify/internal/entity" + "github.com/cocoide/commitify/internal/service" + "regexp" + "strings" +) + +const ( + NormalMessagePrompt = "Generate up to 5 commit messages for [%s]. Each message should be separated by only space" +) + +var CommitMessageRegex = regexp.MustCompile(`^(\d.\s+)|^(-\s+)|^(\s+)`) + +type clientCommitMessageGateway struct { + nlp service.NLPService +} + +func NewClientCommitMessageGateway(nlp service.NLPService) service.CommitMessageService { + return &clientCommitMessageGateway{nlp: nlp} +} + +func (l *clientCommitMessageGateway) GenerateCommitMessageList(code string, conf entity.Config) ([]string, error) { + prompt := fmt.Sprintf(NormalMessagePrompt, code) + result, err := l.nlp.GetAnswerFromPrompt(prompt) + if err != nil { + return nil, err + } + messages := strings.Split(result, "\n") + messages = l.removeFromArrayByRegex(messages, CommitMessageRegex) + return messages, nil +} + +func (l *clientCommitMessageGateway) removeFromArrayByRegex(array []string, pattern *regexp.Regexp) []string { + for i, msg := range array { + array[i] = pattern.ReplaceAllString(msg, "") + } + return array +} diff --git a/internal/gateway/grpc.go b/internal/gateway/grpc.go new file mode 100644 index 0000000..d0391b1 --- /dev/null +++ b/internal/gateway/grpc.go @@ -0,0 +1,46 @@ +package gateway + +import ( + "crypto/tls" + "github.com/cocoide/commitify-grpc-server/pkg/pb" + "github.com/cocoide/commitify/internal/entity" + "github.com/cocoide/commitify/internal/service" + "golang.org/x/net/context" + "google.golang.org/grpc" + "google.golang.org/grpc/credentials" + "log" +) + +const ( + serverAddress = "commitify.fly.dev:443" +) + +type grpcServerGateway struct { + client pb.CommitMessageServiceClient +} + +func NewGrpcServerGateway() service.CommitMessageService { + conn, err := grpc.Dial( + serverAddress, + grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})), + ) + if err != nil { + log.Fatalf("Failed to setup grpc connection: %v", err) + } + client := pb.NewCommitMessageServiceClient(conn) + return &grpcServerGateway{client: client} +} + +func (g *grpcServerGateway) GenerateCommitMessageList(code string, conf entity.Config) ([]string, error) { + formatType, languageType := conf.Config2PbVars() + req := &pb.CommitMessageRequest{ + CodeFormat: formatType, + Language: languageType, + InputCode: code, + } + res, err := g.client.GenerateCommitMessage(context.Background(), req) + if err != nil { + return nil, err + } + return res.Messages, nil +} diff --git a/internal/gateway/input_output.go b/internal/gateway/input_output.go new file mode 100644 index 0000000..25bfbb7 --- /dev/null +++ b/internal/gateway/input_output.go @@ -0,0 +1,20 @@ +package gateway + +import ( + "github.com/cocoide/commitify/internal/service" + "os/exec" +) + +type inputOutputGateway struct { +} + +func NewInputOutputGateway() service.GithubService { + return &inputOutputGateway{} +} + +func (g *inputOutputGateway) GetStaginCodeDiff() (string, error) { + // Gitが入ってるかどうかのチェックも入れる + // 入っていないなら専用のエラーメッセージを生成 + diff, err := exec.Command("git", "diff", "--staged").Output() + return string(diff), err +} diff --git a/internal/gateway/ai_source_openai.go b/internal/gateway/open_ai.go similarity index 54% rename from internal/gateway/ai_source_openai.go rename to internal/gateway/open_ai.go index c543f7f..0aa5c7c 100644 --- a/internal/gateway/ai_source_openai.go +++ b/internal/gateway/open_ai.go @@ -2,23 +2,19 @@ package gateway import ( "context" + "github.com/cocoide/commitify/internal/service" "log" "github.com/cocoide/commitify/internal/entity" "github.com/sashabaranov/go-openai" ) -type OpenAIGateway interface { - GetAnswerFromPrompt(prompt string, variability float32) (string, error) - AsyncGetAnswerFromPrompt(prompt string, variability float32) <-chan string -} - type openAIGateway struct { client *openai.Client ctx context.Context } -func NewOpenAIGateway(ctx context.Context) OpenAIGateway { +func NewOpenAIGateway(ctx context.Context) service.NLPService { config, err := entity.ReadConfig() if err != nil { log.Fatalf("Failed to read config: %v", err) @@ -27,7 +23,7 @@ func NewOpenAIGateway(ctx context.Context) OpenAIGateway { return &openAIGateway{client: client, ctx: ctx} } -func (og *openAIGateway) GetAnswerFromPrompt(prompt string, variability float32) (string, error) { +func (og *openAIGateway) GetAnswerFromPrompt(prompt string) (string, error) { req := openai.ChatCompletionRequest{ Model: openai.GPT3Dot5Turbo, Messages: []openai.ChatCompletionMessage{ @@ -36,7 +32,7 @@ func (og *openAIGateway) GetAnswerFromPrompt(prompt string, variability float32) Content: prompt, }, }, - Temperature: variability, + Temperature: 0.001, } res, err := og.client.CreateChatCompletion(og.ctx, req) if err != nil { @@ -45,14 +41,3 @@ func (og *openAIGateway) GetAnswerFromPrompt(prompt string, variability float32) answer := res.Choices[0].Message.Content return answer, nil } - -func (og *openAIGateway) AsyncGetAnswerFromPrompt(prompt string, variability float32) <-chan string { - responseCh := make(chan string, 1) - - go func() { - answer, _ := og.GetAnswerFromPrompt(prompt, variability) - responseCh <- answer - }() - - return responseCh -} diff --git a/internal/service/file_diff_service.go b/internal/service/file_diff_service.go deleted file mode 100644 index e9e2405..0000000 --- a/internal/service/file_diff_service.go +++ /dev/null @@ -1,17 +0,0 @@ -package service - -import "os/exec" - -type fileDiffService struct { -} - -func NewFileDiffService() fileDiffService { - fds := fileDiffService{} - return fds -} - -func (fds *fileDiffService) createFileDiffStr() (string, error) { - diff, err := exec.Command("git", "diff", "--staged").Output() - - return string(diff), err -} diff --git a/internal/service/message.go b/internal/service/message.go deleted file mode 100644 index c84bb83..0000000 --- a/internal/service/message.go +++ /dev/null @@ -1,41 +0,0 @@ -package service - -// import ( -// "fmt" -// "strings" - -// "github.com/cocoide/commitify/internal/gateway" -// ) - -// const ( -// CommitMessagePrompt = "Generate up to 5 commit messages for [%s]. Each message should be separated by only space" -// FormatNotice = ", format commit as:\n- feat: [feature description]\n- bugfix: [bugfix description]" -// ) - -// var PromptVariability float32 = 0.01 - -// // メッセージの生成、加工に関するクラス -// type MessageService interface { -// GenerateCommitMessage(stagingCode string) ([]string, error) -// } - -// type messageService struct { -// og gateway.OpenAIGateway -// } - -// func NewMessageService(og gateway.OpenAIGateway) MessageService { -// return &messageService{og: og} -// } - -// func (s *messageService) GenerateCommitMessage(stagingCode string) ([]string, error) { -// if len(stagingCode) < 1 { -// return nil, fmt.Errorf("There is no staging code") -// } -// prompt := fmt.Sprintf(CommitMessagePrompt, stagingCode) -// result, err := s.og.GetAnswerFromPrompt(prompt, PromptVariability) -// if err != nil { -// return nil, err -// } -// messages := strings.Split(result, "\n") -// return messages, nil -// } diff --git a/internal/service/message_test.go b/internal/service/message_test.go deleted file mode 100644 index bd6a82c..0000000 --- a/internal/service/message_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package service_test - -// import ( -// "fmt" -// "reflect" -// "testing" - -// "github.com/cocoide/commitify/internal/service" -// mock_gateway "github.com/cocoide/commitify/mock" -// "github.com/golang/mock/gomock" -// ) - -// func Test_GenerateCommitMessage(t *testing.T) { -// stagingCode := "test" -// type test struct { -// ErrorCaseName string -// ChatGptResult string -// ModifiedResult []string -// } -// tests := []test{ -// {"先頭にインデックスを含む", "1. test\n2. test", []string{"test", "test"}}, -// {"先頭にハイフンを含む", "- test\n- test", []string{"test", "test"}}, -// {"先頭にスペースを含む", " test\n test", []string{"test", "test"}}, -// {"改行ができていない", "Add A function. Update B", []string{"Add A function", "Update B"}}, -// // たまに, 改行せずピリオド『.』で文章を区切るパターンがある -// } -// ctrl := gomock.NewController(t) -// og := mock_gateway.NewMockOpenAIGateway(ctrl) -// ms := service.NewMessageService(og) - -// for _, test := range tests { -// prompt := fmt.Sprintf(service.CommitMessagePrompt, stagingCode) -// og.EXPECT(). -// GetAnswerFromPrompt(prompt, service.PromptVariability). -// Return(test.ChatGptResult, nil) - -// serviceResult, err := ms.GenerateCommitMessage(stagingCode) -// if err != nil { -// t.Error(err.Error()) -// } -// if !reflect.DeepEqual(test.ModifiedResult, serviceResult) { -// fmt.Printf("FAIL: %s\n", test.ErrorCaseName) -// t.Errorf("Exp: %v, Got: %v", test.ModifiedResult, serviceResult) -// } -// } -// } diff --git a/internal/service/service.go b/internal/service/service.go new file mode 100644 index 0000000..0fb0bc0 --- /dev/null +++ b/internal/service/service.go @@ -0,0 +1,17 @@ +package service + +import "github.com/cocoide/commitify/internal/entity" + +// 分割コミットの生成のクライアント側もここに入れていく +type CommitMessageService interface { + GenerateCommitMessageList(code string, config entity.Config) ([]string, error) +} + +// githubに関するデータのinput/output +type GithubService interface { + GetStaginCodeDiff() (string, error) +} + +type NLPService interface { + GetAnswerFromPrompt(prompt string) (string, error) +} diff --git a/internal/service/suggest_cmd.go b/internal/service/suggest_cmd.go deleted file mode 100644 index 389f4c3..0000000 --- a/internal/service/suggest_cmd.go +++ /dev/null @@ -1,53 +0,0 @@ -package service - -import ( - "log" - "os/exec" - - "github.com/cocoide/commitify/internal/entity" - "github.com/cocoide/commitify/internal/gateway" -) - -type SuggestCmdService struct { - ais gateway.AISourceGatewayInterface - fds fileDiffService -} - -func NewSuggestCmdService() (*SuggestCmdService, error) { - conf, err := entity.ReadConfig() - if err != nil { - return nil, err - } - - var aigi gateway.AISourceGatewayInterface - switch conf.AISource { - case int(entity.WrapServer): - aigi = gateway.NewGrpcServeGateway() - case int(entity.OpenAiAPI): - log.Fatal("現在、非対応の機能です。") - return nil, err - default: - aigi = gateway.NewGrpcServeGateway() - } - - fds := NewFileDiffService() - - return &SuggestCmdService{ais: aigi, fds: fds}, nil -} - -func (scs *SuggestCmdService) GenerateCommitMessages() ([]string, error) { - fileDiffStr, err := scs.fds.createFileDiffStr() - if err != nil { - return nil, err - } - - return scs.ais.FetchCommitMessages(fileDiffStr) -} - -func (scs *SuggestCmdService) SubmitCommit(commitMessage string) error { - cmd := exec.Command("git", "commit", "-m", commitMessage) - if err := cmd.Run(); err != nil { - return err - } - return nil -} diff --git a/internal/usecase/suggest_cmd.go b/internal/usecase/suggest_cmd.go new file mode 100644 index 0000000..2682011 --- /dev/null +++ b/internal/usecase/suggest_cmd.go @@ -0,0 +1,39 @@ +package usecase + +import ( + "fmt" + "github.com/cocoide/commitify/internal/service" + "os/exec" + + "github.com/cocoide/commitify/internal/entity" +) + +type SuggestCmdUsecase struct { + message service.CommitMessageService + github service.GithubService +} + +func NewSuggestCmdUsecase(message service.CommitMessageService, github service.GithubService) *SuggestCmdUsecase { + return &SuggestCmdUsecase{message: message, github: github} +} + +func (u *SuggestCmdUsecase) GenerateCommitMessages() ([]string, error) { + stagingCodeDiff, err := u.github.GetStaginCodeDiff() + // stagingCodeを取捨選択する処理をここに入れる + if err != nil { + return nil, err + } + conf, err := entity.ReadConfig() + if err != nil { + return nil, fmt.Errorf("Failed to open config file: %v", err) + } + return u.message.GenerateCommitMessageList(stagingCodeDiff, conf) +} + +func (u *SuggestCmdUsecase) SubmitCommit(commitMessage string) error { + cmd := exec.Command("git", "commit", "-m", commitMessage) + if err := cmd.Run(); err != nil { + return err + } + return nil +}