私は最近、GenCLI という名前の Golang を使用した AI を活用した CLI を構築しました。この CLI からテキスト形式で質問したり、画像を指定してターミナルから詳細を尋ねたりすることができます。もしそれがあなたにとって興味深いと思われるなら、このブログはあなたのためのものです。ここでは、CLI を完全にゼロから構築し、Google の Gemini API を使用してそれに AI 機能を与えます。私の GenCLI をチェックアウトしたい場合は、ここにリンクがあります。はい、オープンソースです。
ステップバイステップで各プロセスを理解しましょう。
フォルダーを作成し、お気に入りの IDE/エディターで開きます。私は VS Code を使用しており、フォルダーに go-ai という名前を付けました。次に、コマンド go mod init
go mod init github.com/Pradumnasaraf/go-ai
それが完了すると、go.mod が作成されます。
CLI を構築するためにすべてを手動で作成して実行することもできます。しかし、Cobra Package の優れている点は、構造を生成し、ファイルを生成し、CLI 用のパッケージをインストールする CLI があることです。これにより、プロセスが高速化され、エラーが少なくなります。 Cobra CLI ツールをインストールするには、以下のコマンドを使用します:
go install github.com/spf13/cobra-cli@latest
それが完了したら、ターミナルで cobra-cli を結び付けることでツールがインストールされているかどうかを確認でき、利用可能なツールのリストが表示されます。次に、cobra-cli init を実行してプロジェクトをセットアップします。実行後、cmd フォルダー、go.sum、main.go ファイルが自動的に作成されます。動作しているかどうかをテストするには、main.go を実行します。 CLI に関する出力がターミナルに表示されます (以下のスクリーンショットのように)
Google の Gemini API と通信して使用するには、まず Gemini Golang SKD パッケージをインストールする必要があります。そのためには、以下のコマンドを実行します。
go get github.com/google/generative-ai-go
他の API と同様に、API キーが必要です。それを取得するには、ここ https://aistudio.google.com/app/apikey にアクセスして取得してください。それは無料で、30 秒で完了します。 API キーを取得したら、次のコマンドを実行して環境変数を設定します:
export GEMINI_API_KEY=<YOUR_API_KEY>
この方法の問題は、ターミナルを閉じると環境変数が消えてしまうため、現在のセッションに対してのみ環境変数が存在することです。この問題を回避するには、export コマンドを .bashrc、.bash_profile、または .zshrc などのシェル構成ファイル (シェルに応じて異なります) に追加します。このようにして、システム内のどこからでも CLI にアクセスできます。
ここで、root.go にロジックを直接記述する代わりに、CLI のサブコマンドを作成します。そうする理由は、将来、より多くの機能とより多くのサブコマンドを含めたい場合、root コマンドをブロックせずに、より多くのサブコマンドを追加することで簡単に追加できるからです。これを理解できなくても、心配しないでください。理解できるようになります。
サブコマンドを作成するには、Cobra CLI にサブコマンドを作成するための add コマンドが用意されています。これを行うには、以下のコマンドを実行します。ここでは検索がサブコマンドになります。好きなものを選択できます。
cobra-cli add search
これを実行すると、これらの事前設定されたコードがすべて含まれた新しいファイルが cmd ディレクトリの下に作成されます。コードでは、変数 searchCmd を cobra.Command 構造体へのポインタに初期化し、サブコマンド名、用途などのフィールドに値を提供しています。 Run: の関数は、サブコマンドを実行するたびにトリガーされます。指示。また、init 関数に root コマンド用のコマンド (サブコマンド) が追加されていることがわかります。完全なコードは次のようになります。
package cmd import ( "fmt" "github.com/spf13/cobra" ) // searchCmd represents the search command var searchCmd = &cobra.Command{ Use: "search", Short: "A brief description of your command", Long: `A longer description that spans multiple lines and likely contains examples`, Run: func(cmd *cobra.Command, args []string) { fmt.Println("search called") }, } func init() { rootCmd.AddCommand(searchCmd) }
サブコマンド「search」が期待どおりに機能しているかどうかを確認するには、「search」コマンドを使用して CLI を実行します。端末に「search called」と表示されるでしょう。
go run main.go search
それでは、API 側の作業に移りましょう。 Google Gemini API のパッケージと、ロギングや OS レベルのタスクに必要なその他のパッケージをインポートしましょう。ここに完全なリストがあります。
import ( "context" "log" "os" "github.com/google/generative-ai-go/genai" "github.com/spf13/cobra" "google.golang.org/api/option" )
次に、getResponse という関数を追加しましょう。この関数は、Gemini API と通信し、応答を取得して出力するのに役立ちます。また、プロンプト テキスト (「AI と魔法についてのストーリーを書いてください」) がハードコードされているのが見えても、心配しないでください。変更はしますが、まず機能させましょう :)。これは完全な関数コードであり、init 関数の下に追加します。同じ開始コードが Gemini Web サイトにあります。
func getResponse() { ctx := context.Background() client, err := genai.NewClient(ctx, option.WithAPIKey(os.Getenv("GEMINI_API_KEY"))) if err != nil { log.Fatal(err) } defer client.Close() model := client.GenerativeModel("gemini-1.5-flash") resp, err := model.GenerateContent(ctx, genai.Text("Write a story about a AI and magic")) if err != nil { log.Fatal(err) } fmt.Println(resp.Candidates[0].Content.Parts[0]) }
Now let's add getResponse function to the in the field Run: function. So that when we run the sun command it will call getResponse function. Now the code will look like this.
package cmd import ( "context" "fmt" "log" "os" "github.com/google/generative-ai-go/genai" "github.com/spf13/cobra" "google.golang.org/api/option" ) // searchCmd represents the search command var searchCmd = &cobra.Command{ Use: "search", Short: "A brief description of your command", // Added the getResponse() function Run: func(cmd *cobra.Command, args []string) { getResponse() }, } func init() { rootCmd.AddCommand(searchCmd) } func getResponse() { ctx := context.Background() client, err := genai.NewClient(ctx, option.WithAPIKey(os.Getenv("GEMINI_API_KEY"))) if err != nil { log.Fatal(err) } defer client.Close() model := client.GenerativeModel("gemini-1.5-flash") resp, err := model.GenerateContent(ctx, genai.Text("Write a story about a AI and magic")) if err != nil { log.Fatal(err) } fmt.Println(resp.Candidates[0].Content.Parts[0]) }
If you getting a red squiggly line under the imported package names run go mod tidy. It will install the missing package and do a cleanup. Now, again execute the go run main.go search. This time you will get a response from the API for the Prompt we hardcoded, i.e, "Write a story about a AI and magic"
In case you are encountering the below error check if your environment variable is set properly with the right name. You can check by executing the printenv command in your terminal and see if it's present there or not.
Once everything is working, let’s make the prompt dynamic so that we don’t have to hardcode the prompt directly into the code and we provide it via the terminal.
To do that, add an ARG: field to the searchCmd struct so that the user at least needs to enter an argument after the sub-command. Also, we will modify the getResponse function to accept a slice of data because args will be in the slice format, and we will use the strings package to convert it into a sentence.
Lastly, replace the hardcoded text in genai.Text() with the userArgs variable we created to convert the slice into a sentence. This is how the complete code will look like; I have commented above on the changes we have to make for better understanding.
package cmd import ( "context" "fmt" "log" "os" "strings" // import strings package "github.com/google/generative-ai-go/genai" "github.com/spf13/cobra" "google.golang.org/api/option" ) var searchCmd = &cobra.Command{ Use: "search", Short: "A brief description of your command", Args: cobra.MinimumNArgs(1), // Minimum 1 arg required Run: func(cmd *cobra.Command, args []string) { getResponse(args) }, } func init() { rootCmd.AddCommand(searchCmd) } // Function can now accept slice parameter func getResponse(args []string) { // Creating a sentence out of a slice userArgs := strings.Join(args[0:], " ") ctx := context.Background() client, err := genai.NewClient(ctx, option.WithAPIKey(os.Getenv("GEMINI_API_KEY"))) if err != nil { log.Fatal(err) } defer client.Close() model := client.GenerativeModel("gemini-1.5-flash") // change the hardcoded text to userArgs variable resp, err := model.GenerateContent(ctx, genai.Text(userArgs)) if err != nil { log.Fatal(err) } fmt.Println(resp.Candidates[0].Content.Parts[0]) }
If you execute the go run main search now, it will give you an error message in the terminal saying at least one arg is required. This means our code is working perfectly.
Now let's execute the command the right way giving it an argument - a prompt/question.
As you can see, it provided us with the answer. We pass the prompt in quotes so that we can add special characters like "?", ".", etc. So here it is, a fully functional AI-powered CLI.
Now, if you want to publish the package so that your CLI can directly execute commands and be used from anywhere in the system, it’s very simple to do that. First, push your changes to GitHub and then head over to the URL https://pkg.go.dev/github.com/
Once it’s live, you can simply download the CLI by using the go install command:
go install <repo-url> go install github.com/Pradumnasaraf/go-ai@latest
And directly use the CLI with commands like go-ai, go-ai search, etc. If you encounter the error saying command not found: go-ai after running it, you need to add $GOPATH/bin to your $PATH environment variable. Refer to this guide for that.
That's it for this blog. This was a little longer than the blogs I usually write. I'm glad you're still reading and made it to the end—thank you so much for your support. I sometimes share tips on Twitter. You can connect with me there.
以上がGolang と Google Gemini を使用して AI を活用した CLI を構築するの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。