{"id":51243682,"url":"https://github.com/sneiko/goleo","last_synced_at":"2026-06-29T02:30:51.886Z","repository":{"id":365554563,"uuid":"1272414650","full_name":"sneiko/goleo","owner":"sneiko","description":"Go-first framework for building embedded AI demo apps from Go functions, streaming handlers, and adapter-backed backends.","archived":false,"fork":false,"pushed_at":"2026-06-17T21:45:23.000Z","size":855,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-17T22:20:28.009Z","etag":null,"topics":["ai","embedded-ui","genai","go","golang","llm","ollama","openai","streaming","web-ui"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sneiko.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"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,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-17T15:31:18.000Z","updated_at":"2026-06-17T21:45:28.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/sneiko/goleo","commit_stats":null,"previous_names":["sneiko/goleo"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/sneiko/goleo","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sneiko%2Fgoleo","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sneiko%2Fgoleo/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sneiko%2Fgoleo/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sneiko%2Fgoleo/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sneiko","download_url":"https://codeload.github.com/sneiko/goleo/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sneiko%2Fgoleo/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34911134,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-29T02:00:05.398Z","response_time":58,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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","embedded-ui","genai","go","golang","llm","ollama","openai","streaming","web-ui"],"created_at":"2026-06-29T02:30:50.366Z","updated_at":"2026-06-29T02:30:51.880Z","avatar_url":"https://github.com/sneiko.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Goleo: Build AI Demo Apps in Go\n\n[![Go version](https://img.shields.io/badge/go-1.24+-00ADD8?logo=go)](go.mod)\n[![Frontend](https://img.shields.io/badge/frontend-React%20%2B%20Vite-646CFF?logo=vite)](frontend)\n[![Status](https://img.shields.io/badge/status-MVP-orange)](#status)\n\n[Usage](docs/usage.md) | [Components](docs/components.md) | [Architecture](docs/architecture.md) | [Examples](examples) | [Frontend](frontend)\n\nGoleo turns Go functions, streaming handlers, HTTP endpoints, OpenAI-compatible\nAPIs, Ollama models, local processes, and full-duplex voice handlers into\nembedded web apps.\n\nDefine inputs and outputs in Go, launch one binary, and get a usable local UI\nwith prediction, streaming, upload, asset playback, and voice session\nendpoints. The built frontend is embedded into the Go binary, so there is no\nseparate frontend deployment step.\n\n![Goleo showcase hero](docs/assets/readme-hero.png)\n\n## What You Can Build\n\n### Function-backed tools\n\nBuild richer local tools than a single textbox demo. The showcase form combines\ntyped inputs, file uploads, and multiple outputs in one surface.\n\n![Showcase form components](docs/assets/readme-components.png)\n\n### Streaming chat flows\n\nUse `Chat` with a streaming handler to ship copilot-style demos and assistant\nworkflows without building the chat shell yourself.\n\n![Showcase chat transcript](docs/assets/readme-chat.png)\n\n### Adapter-backed interfaces\n\nWrap external backends behind the same UI contract. The same surface can front a\nnative Go handler, an HTTP API, an OpenAI-compatible endpoint, Ollama, or a\nlocal process.\n\n![Showcase adapters](docs/assets/readme-adapters.png)\n\n## Built-In Components\n\nThe embedded UI supports typed form controls and structured outputs out of the\nbox.\n\nBuilt-in constructors include `Textbox`, `Number`, `Slider`, `Checkbox`,\n`Dropdown`, `Button`, `Markdown`, `JSON`, `Image`, `Audio`, `File`, `State`,\n`Row`, `Column`, `Group`, and `Chatbot`.\n\nYou can also use `CustomComponent` when you need to introduce a schema type\nbefore a first-class constructor exists.\n\n\u003cp\u003e\n  \u003cimg src=\"docs/assets/readme-components.png\" alt=\"Goleo components showcase\" width=\"49%\"\u003e\n  \u003cimg src=\"docs/assets/readme-outputs.png\" alt=\"Goleo outputs showcase\" width=\"49%\"\u003e\n\u003c/p\u003e\n\n## Audio and Voice\n\nUse `Interface` with `Audio(...)` when you want a normal request/response flow\nwith upload or microphone capture. The handler receives a `goleo.AudioInput`\nwith metadata plus a temporary `Path`. If the handler returns a\n`goleo.AudioOutput`, Goleo stores it and serves it back through\n`/api/assets/{id}` for browser playback.\n\n```go\napp.Interface(\n goleo.Handler(func(clip goleo.AudioInput) (string, goleo.AudioOutput, error) {\n  return \"received \" + clip.Name, goleo.AudioOutput{\n   Name:        \"reply.wav\",\n   ContentType: clip.ContentType,\n   Path:        clip.Path,\n  }, nil\n }),\n goleo.Inputs(goleo.Audio(\"Prompt audio\")),\n goleo.Outputs(goleo.Textbox(\"Summary\"), goleo.Audio(\"Reply audio\")),\n)\n```\n\nTo keep richer demo behavior visible:\n\n- tune throughput with `app.ConfigureQueue(maxConcurrency, maxQueue)`;\n- cancel stream runs with `POST /api/cancel` and returned `request_id`;\n- carry session values in `goleo.State(...)`.\n\nUse `Voice` when you need a live session over WebSocket with microphone chunks,\ninterrupts, and mixed text/audio output events. The browser connects to\n`/api/voice/{id}/ws`; your handler works with `session.Receive()`,\n`session.Send(...)`, and `session.SendAudio(...)`.\n\n```go\napp.Voice(goleo.VoiceHandler(func(session *goleo.VoiceSession) error {\n for {\n  event, err := session.Receive()\n  if err != nil {\n   return err\n  }\n\n  switch event.Type {\n  case \"session.start\":\n   if err := session.Send(goleo.VoiceEvent{Type: \"session.ready\"}); err != nil {\n    return err\n   }\n  case \"input.stop\":\n   if err := session.Send(goleo.VoiceEvent{Type: \"output.text\", Text: \"turn complete\"}); err != nil {\n    return err\n   }\n  case \"session.close\":\n   return session.Send(goleo.VoiceEvent{Type: \"session.closed\"})\n  }\n }\n}))\n```\n\nChoose the surface based on the interaction model:\n\n- `Interface + Audio`: turn-based upload or one-shot microphone capture.\n- `Voice`: long-lived duplex session with chunked mic input and interrupt.\n\n## Installation\n\nPrerequisite: Goleo requires Go 1.24 or higher.\n\n```sh\ngo get github.com/sneiko/goleo\n```\n\nFor local development of this repository:\n\n```sh\nmake check\n```\n\n\u003e [!TIP]\n\u003e `make run-*` targets bind to `:7871` by default. Override the port when it is\n\u003e already in use, for example `GOLEO_ADDR=:7872 make run-chat`.\n\n## Building Your First Demo\n\nCreate a Goleo app around any Go function:\n\n```go\npackage main\n\nimport (\n \"context\"\n \"log/slog\"\n \"os\"\n \"os/signal\"\n \"syscall\"\n\n \"github.com/sneiko/goleo\"\n)\n\nfunc main() {\n logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))\n app := goleo.New(goleo.WithLogger(logger))\n\n app.Interface(\n  goleo.Handler(func(input string) (string, error) {\n   return \"Hello \" + input, nil\n  }),\n  goleo.Inputs(goleo.Textbox(\"Prompt\")),\n  goleo.Outputs(goleo.Textbox(\"Result\")),\n )\n\n ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)\n defer stop()\n\n if err := app.LaunchContext(ctx, goleo.LaunchOptions{Addr: \":7860\"}); err != nil {\n  logger.Error(\"goleo server stopped\", \"error\", err)\n  os.Exit(1)\n }\n}\n```\n\nRun the bundled minimal example:\n\n```sh\nmake run-simple\n```\n\nOpen `http://localhost:7871` after the server starts.\n\nIf you run examples directly with `go run`, they use `:7860` unless\n`GOLEO_ADDR` is set.\n\n## Showcase Examples\n\nUse the richer examples when you want a more realistic surface than the minimal\nhello-world demo.\n\n| Command | Example | What it shows |\n| --- | --- | --- |\n| `make run-audio` | [`examples/audio`](examples/audio) | Turn-based audio upload or mic capture with text, JSON, and playback outputs |\n| `make run-showcase-form` | [`examples/showcase-form`](examples/showcase-form) | Typed form inputs, file upload, text output, and structured JSON |\n| `make run-showcase-chat` | [`examples/showcase-chat`](examples/showcase-chat) | Streaming chat transcript with a copilot-style response |\n| `make run-showcase-adapters` | [`examples/showcase-adapters`](examples/showcase-adapters) | Adapter-oriented prompt flow with backend metadata |\n| `make run-voice` | [`examples/voice`](examples/voice) | Full-duplex voice session with mic chunks, interrupt, and reply audio |\n| `make run-blocks` | [`examples/blocks`](examples/blocks) | Blocks interface with click/change/load events, state, and runtime updates |\n\n## More Examples\n\nThe repository keeps the focused integration demos as separate entry points.\n\n| Command | Example | Notes |\n| --- | --- | --- |\n| `make run-simple` | [`examples/simple`](examples/simple) | Minimal function-backed form |\n| `make run-chat` | [`examples/chat`](examples/chat) | Basic streaming chat surface |\n| `make run-audio` | [`examples/audio`](examples/audio) | First-class `Audio` component with app-served playback assets |\n| `make run-blocks` | [`examples/blocks`](examples/blocks) | Event-driven Blocks interface with state, load events, and update envelopes |\n| `make run-voice` | [`examples/voice`](examples/voice) | WebSocket voice runtime with `VoiceHandler` |\n| `make run-http` | [`examples/http-wrapper`](examples/http-wrapper) | Wrap an HTTP endpoint |\n| `OLLAMA_MODEL=llama3.2 make run-ollama` | [`examples/ollama`](examples/ollama) | Stream from Ollama |\n| `OPENAI_BASE_URL=http://localhost:11434/v1 OPENAI_MODEL=llama3.2 make run-openai-stream` | [`examples/openai-stream`](examples/openai-stream) | Stream from any OpenAI-compatible API |\n\n## Chat and Streaming\n\nUse `Chat` with a streaming handler for chat-style demos:\n\n```go\napp.Chat(goleo.StreamHandler(func(input string, emit goleo.EmitFunc) error {\n emit(\"You said: \" + input)\n return nil\n}))\n```\n\nRun the bundled chat demo:\n\n```sh\nmake run-chat\n```\n\n## Voice Sessions\n\nUse `Voice` for true duplex audio sessions where the browser streams microphone\nchunks to your handler and the handler emits back text, state, and audio\nevents.\n\nBrowser -\u003e server events in v1:\n\n- `session.start`\n- `input.audio`\n- `input.stop`\n- `output.interrupt`\n- `session.close`\n\nServer -\u003e browser events in v1:\n\n- `session.ready`\n- `output.text`\n- `output.audio`\n- `output.state`\n- `error`\n- `session.closed`\n\nRun the bundled duplex demo:\n\n```sh\nmake run-voice\n```\n\n## Wrapping APIs and Processes\n\nGoleo adapters return regular handler bindings, so you can swap native Go\nfunctions for external systems without changing the UI definition.\n\nWrap an HTTP endpoint:\n\n```go\napp.Interface(\n goleo.HTTPAdapter(goleo.HTTPAdapterOptions{URL: \"http://localhost:9000/predict\"}),\n goleo.Inputs(goleo.Textbox(\"Prompt\")),\n goleo.Outputs(goleo.Textbox(\"Result\")),\n)\n```\n\nWrap an OpenAI-compatible streaming API:\n\n```go\napp.Chat(goleo.OpenAICompatibleStreamAdapter(goleo.OpenAICompatibleOptions{\n BaseURL: \"http://localhost:11434/v1\",\n APIKey:  os.Getenv(\"OPENAI_API_KEY\"),\n Model:   \"llama3.2\",\n}))\n```\n\n## Server Lifecycle\n\nConfigure HTTP server timeouts when needed:\n\n```go\napp.Launch(goleo.LaunchOptions{\n Addr:              \":7860\",\n ReadHeaderTimeout: 5 * time.Second,\n ReadTimeout:       30 * time.Second,\n WriteTimeout:      0, // keep unset for long-lived streaming responses\n IdleTimeout:       60 * time.Second,\n ShutdownTimeout:   5 * time.Second,\n})\n```\n\nFor graceful shutdown, cancel the context passed to `LaunchContext`:\n\n```go\nctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM)\ndefer stop()\n\nerr := app.LaunchContext(ctx, goleo.LaunchOptions{Addr: \":7860\"})\n```\n\nFor advanced lifecycle control, build the server yourself:\n\n```go\nsrv := app.Server(goleo.LaunchOptions{Addr: \":7860\"})\nerr := srv.ListenAndServe()\n```\n\n## Logging and API Errors\n\nGoleo uses `log/slog` for structured logs. Logging is opt-in: if you do not\npass a logger, Goleo stays quiet.\n\n```go\nlogger := slog.New(slog.NewJSONHandler(os.Stdout, nil))\napp := goleo.New(goleo.WithLogger(logger))\n```\n\nThe built-in server logs request completion events with method, path, status,\nduration, and `request_id`. If a request includes `X-Request-ID`, Goleo keeps\nit; otherwise it generates one and returns it in the response header.\n\nAPI errors use a structured JSON shape:\n\n```json\n{\n  \"error\": {\n    \"code\": \"bad_request\",\n    \"message\": \"interface_id is required\"\n  }\n}\n```\n\n## Frontend Development\n\nGoleo stays Go-first: built frontend assets are committed under `server/assets`,\nso users can run examples without installing Node.js.\n\nThe embedded UI itself lives in `frontend` as a React/Vite/shadcn app:\n\n```sh\nmake frontend-install\nmake frontend-dev\nmake frontend-test\nmake frontend-build\n```\n\n`make frontend-build` writes the static assets consumed by Go's `go:embed`.\n\nMaintainers can regenerate the README screenshots with:\n\n```sh\nmake readme-assets\n```\n\n## Status\n\nThis is an MVP implementation focused on Gradio-style local AI demos:\n\n- `Interface` for function-backed forms\n- `Chat` for streaming chat demos\n- `Voice` for WebSocket duplex sessions\n- `Audio` for upload and microphone-driven media inputs/outputs\n- Embedded frontend assets served by the Go binary\n- JSON prediction endpoint, SSE streaming endpoint, upload endpoint, asset\n  endpoint, and voice WebSocket endpoint\n- Native Go, HTTP, OpenAI-compatible, Ollama, streaming, and process adapters\n- Optional structured logging with request IDs\n\nProduction platform features such as auth, persistent storage, hosting, queues,\nand multi-user state are intentionally out of scope for v1.\n\n## Architecture\n\nThe root `goleo` package is a facade over focused packages:\n\n- `component`: component schema and constructors\n- `core`: app model and schema generation\n- `media`: handler-facing audio types and browser-safe asset descriptors\n- `runtime`: handler binding and streaming abstraction\n- `server`: HTTP routes, uploads, assets, SSE, voice sessions, embedded frontend\n- `adapter`: HTTP, OpenAI-compatible, Ollama, and process adapters\n\nSee [docs/architecture.md](docs/architecture.md) for extension points.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsneiko%2Fgoleo","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsneiko%2Fgoleo","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsneiko%2Fgoleo/lists"}