{"id":15394224,"url":"https://github.com/xyproto/geminiclient","last_synced_at":"2025-04-15T23:53:07.076Z","repository":{"id":253957684,"uuid":"844976681","full_name":"xyproto/geminiclient","owner":"xyproto","description":"Simple way to use Gemini from Go, including function calls / tools","archived":false,"fork":false,"pushed_at":"2024-08-26T11:30:39.000Z","size":5673,"stargazers_count":4,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-29T03:03:01.386Z","etag":null,"topics":["ai","gemini","gemini-functions-call","go","google","vertex-ai"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/xyproto.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-08-20T10:41:00.000Z","updated_at":"2024-08-26T11:30:34.000Z","dependencies_parsed_at":"2024-08-26T13:50:37.407Z","dependency_job_id":null,"html_url":"https://github.com/xyproto/geminiclient","commit_stats":null,"previous_names":["xyproto/simplegemini","xyproto/geminiclient"],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xyproto%2Fgeminiclient","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xyproto%2Fgeminiclient/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xyproto%2Fgeminiclient/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/xyproto%2Fgeminiclient/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/xyproto","download_url":"https://codeload.github.com/xyproto/geminiclient/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249173061,"owners_count":21224481,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai","gemini","gemini-functions-call","go","google","vertex-ai"],"created_at":"2024-10-01T15:22:29.984Z","updated_at":"2025-04-15T23:53:07.060Z","avatar_url":"https://github.com/xyproto.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"[![Build](https://github.com/xyproto/geminiclient/actions/workflows/build.yml/badge.svg)](https://github.com/xyproto/geminiclient/actions/workflows/build.yml)\n[![Go Report Card](https://goreportcard.com/badge/github.com/xyproto/geminiclient)](https://goreportcard.com/report/github.com/xyproto/geminiclient)\n[![License](https://img.shields.io/badge/license-Apache2-green.svg?style=flat)](https://raw.githubusercontent.com/xyproto/geminiclient/main/LICENSE)\n\n\n# Gemini Client\n\nA simple way to use the Gemini API.\n\n## Features and limitations\n\n* It is possible to submit a prompt and receive a response.\n* The package can run both locally (calling the Gemini API) and in Google Cloud (for example as a Google Cloud Run instance).\n* Supports multi-modal prompts (prompts where you can add text, images or data to the prompt).\n* Supports tool / function calling where you can supply custom Go functions to the Gemini client, and Gemini can call the functions as needed (but only for 1 tool/function, for now).\n* This package is a work in progress!\n* The only currently known issue is that when adding more than 1 tool/function, it appears to not work, ref. the `multicall` branch.\n* The functions starting with `Must` are alternatives to the ones that return a value and an error. These functions will just return the value, but panic if it fails. This is handy for testing and quick examples, but larger applications should probably not use them.\n\n## Example use\n\n1. Run `gcloud auth login` and/or `gcloud auth application-default login`, if needed.\n2. Get the Google Project ID at https://console.cloud.google.com/.\n3. `export GCP_PROJECT=123`, where \"123\" is your own Google Project ID.\n4. (optionally) `export GCP_LOCATION=us-west1`, if \"us-west1\" is the location you prefer.\n5. Create a directory for this experiment, for instance: `mkdir -p ~/geminitest \u0026\u0026 cd ~/geminitest`.\n6. Create a `main.go` file that looks like this (0.4 is the temperature, 0.0 is less creative, 1.0 is more creative):\n\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n\n    \"github.com/xyproto/geminiclient\"\n)\n\nfunc main() {\n    fmt.Println(geminiclient.MustAsk(\"Write a haiku about cows.\", 0.4))\n}\n```\n\n7. Prepare a simple `go.mod` project file with ie. `go mod init cows`\n8. Fetch the dependencies (this geminiclient package) with `go mod tidy`\n9. Build and run the executable: `go build \u0026\u0026 ./cows`\n10. Observe the output, that should look a bit like this:\n\n```go\nBlack and white patches,\nChewing grass in sunlit fields,\nMooing gentle song.\n```\n\n## A note about Google Cloud\n\nIf an application that uses `geminiclient` is deployed to ie. Google Cloud Run, then creating a new service account with \"Vertex AI User\" permissions is probably needed. This can be created in the \"IAM \u0026 Admin\" section. The service account can then be selected when deploying to Cloud Run.\n\n## Function calling / tool use\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"log\"\n    \"strings\"\n\n    \"github.com/xyproto/geminiclient\"\n)\n\nfunc main() {\n    gc := geminiclient.MustNew()\n\n    // Define a custom function for getting the weather, that Gemini can choose to call\n    getWeatherRightNow := func(location string) string {\n        fmt.Println(\"getWeatherRightNow was called\")\n        switch location {\n        case \"NY\":\n            return \"It's sunny in New York.\"\n        case \"London\":\n            return \"It's rainy in London.\"\n        default:\n            return \"Weather data not available.\"\n        }\n    }\n\n    // Add the weather function as a tool\n    err := gc.AddFunctionTool(\"get_weather_right_now\", \"Get the current weather for a specific location\", getWeatherRightNow)\n    if err != nil {\n        log.Fatalf(\"Failed to add function tool: %v\", err)\n    }\n\n    // Query Gemini with a prompt that requires using the custom weather tool\n    result, err := gc.Query(\"What is the weather in NY?\")\n    if err != nil {\n        log.Fatalf(\"Failed to query Gemini: %v\", err)\n    }\n\n    // Check and print the weather response\n    if !strings.Contains(result, \"sunny\") {\n        log.Fatalf(\"Expected 'sunny' to be in the response, but got: %v\", result)\n    }\n    fmt.Println(\"Weather AI Response:\", result)\n\n    gc.Clear() // Clear the current prompt parts, tools and functions\n\n    // Define a custom function for reversing a string\n    reverseString := func(input string) string {\n        fmt.Println(\"reverseString was called\")\n        runes := []rune(input)\n        for i, j := 0, len(runes)-1; i \u003c j; i, j = i+1, j-1 {\n            runes[i], runes[j] = runes[j], runes[i]\n        }\n        return string(runes)\n    }\n\n    // Add the string reversal function as a tool\n    err = gc.AddFunctionTool(\"reverse_string\", \"Reverse the given string\", reverseString)\n    if err != nil {\n        log.Fatalf(\"Failed to add function tool: %v\", err)\n    }\n\n    // Query Gemini with a prompt that requires using the string reversal tool\n    result, err = gc.Query(\"Reverse the string 'hello'. Reply with a single word.\")\n    if err != nil {\n        log.Fatalf(\"Failed to query Gemini: %v\", err)\n    }\n\n    // Check and print the string reversal response\n    expected := \"olleh\"\n    if !strings.Contains(result, expected) {\n        log.Fatalf(\"Expected '%s' to be in the response, but got: %v\", expected, result)\n    }\n    fmt.Println(\"Response:\", result)\n}\n```\n\n\n## Multimodal prompts / analyzing images\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"log\"\n\n    \"github.com/xyproto/geminiclient\"\n    \"github.com/xyproto/wordwrap\"\n)\n\nfunc main() {\n    const (\n        multiModalModelName = \"gemini-1.0-pro-vision\" // \"gemini-1.5-pro\" also works, if only text is sent\n        temperature         = 0.4\n        descriptionPrompt   = \"Describe what is common for these two images.\"\n    )\n\n    gc, err := geminiclient.NewMultiModal(multiModalModelName, temperature)\n    if err != nil {\n        log.Fatalf(\"Could not initialize the Gemini client with the %s model: %v\\n\", multiModalModelName, err)\n    }\n\n    // Build a prompt\n    if err := gc.AddImage(\"frog.png\"); err != nil {\n        log.Fatalf(\"Could not add frog.png: %v\\n\", err)\n    }\n    gc.AddURI(\"gs://generativeai-downloads/images/scones.jpg\")\n    gc.AddText(descriptionPrompt)\n\n    // Count the tokens that are about to be sent\n    tokenCount, err := gc.CountTokens()\n    if err != nil {\n        log.Fatalln(err)\n    }\n    fmt.Printf(\"Sending %d tokens.\\n\\n\", tokenCount)\n\n    // Submit the images and the text prompt\n    response, err := gc.Submit()\n    if err != nil {\n        log.Fatalln(err)\n    }\n\n    // Format and print out the response\n    if lines, err := wordwrap.WordWrap(response, 79); err == nil { // success\n        for _, line := range lines {\n            fmt.Println(line)\n        }\n        return\n    }\n\n    fmt.Println(response)\n}\n```\n\n## Producing JSON\n\n```go\npackage main\n\nimport (\n    \"fmt\"\n    \"log\"\n    \"time\"\n\n    \"github.com/xyproto/geminiclient\"\n)\n\nfunc main() {\n    const (\n        prompt      = `What color is the sky? Answer with a JSON struct where the only key is \"color\" and the value is a lowercase string.`\n        modelName   = \"gemini-1.5-pro\"\n        temperature = 0.0\n        timeout     = 10 * time.Second\n    )\n\n    gc, err := geminiclient.NewWithTimeout(modelName, temperature, timeout)\n    if err != nil {\n        log.Fatalln(err)\n    }\n\n    fmt.Println(prompt)\n\n    result, err := gc.Query(prompt)\n    if err != nil {\n        log.Fatalln(err)\n    }\n\n    fmt.Println(result)\n}\n```\n\n* `gemini-1.5-flash` is the default model.\n* `gemini-1.5-pro` is smarter, but slower and more expensive.\n\n## Environment variables\n\nThese environment variables are supported:\n\n* `GCP_PROJECT_ID` or `PROJECT_ID` for the Google Cloud Project ID\n* `GCP_LOCATION` or `PROJECT_LOCATION` for the Google Cloud Project location (like `us-west1`)\n* `MODEL_NAME` for the Gemini model name (like `gemini-1.5-flash` or `gemini-1.5-pro`)\n* `MULTI_MODAL_MODEL_NAME` for the Gemini multi-modal name (like `gemini-1.0-pro-vision`)\n\n## General info\n\n* Version: 1.7.0\n* License: Apache 2\n* Author: Alexander F. Rødseth\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxyproto%2Fgeminiclient","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fxyproto%2Fgeminiclient","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fxyproto%2Fgeminiclient/lists"}