{"id":15648028,"url":"https://github.com/ksylvest/omniai","last_synced_at":"2026-04-02T14:13:15.633Z","repository":{"id":244514299,"uuid":"813253662","full_name":"ksylvest/omniai","owner":"ksylvest","description":"OmniAI standardizes the APIs for multiple AI providers like OpenAI's Chat GPT, Mistral's LeChat, Claude's Anthropic, Google's Gemini and DeepSeek's Chat..","archived":false,"fork":false,"pushed_at":"2026-03-26T22:33:02.000Z","size":661,"stargazers_count":251,"open_issues_count":3,"forks_count":13,"subscribers_count":6,"default_branch":"main","last_synced_at":"2026-03-27T10:38:51.362Z","etag":null,"topics":["anthropic","chatgpt","claude","deepseek","gemini","google","lechat","mistral","omniai","openai","ruby"],"latest_commit_sha":null,"homepage":"https://omniai.ksylvest.com/","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ksylvest.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","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":"2024-06-10T19:12:07.000Z","updated_at":"2026-03-26T22:32:15.000Z","dependencies_parsed_at":"2024-06-15T09:33:26.874Z","dependency_job_id":"f6a83ac7-5f1f-485b-ba28-fbf5dd48c497","html_url":"https://github.com/ksylvest/omniai","commit_stats":{"total_commits":142,"total_committers":3,"mean_commits":"47.333333333333336","dds":"0.23239436619718312","last_synced_commit":"4533adc9fed397445825e194d6238754d2d94e59"},"previous_names":["ksylvest/omniai"],"tags_count":97,"template":false,"template_full_name":null,"purl":"pkg:github/ksylvest/omniai","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ksylvest%2Fomniai","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ksylvest%2Fomniai/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ksylvest%2Fomniai/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ksylvest%2Fomniai/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ksylvest","download_url":"https://codeload.github.com/ksylvest/omniai/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ksylvest%2Fomniai/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31307627,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-02T12:59:32.332Z","status":"ssl_error","status_checked_at":"2026-04-02T12:54:48.875Z","response_time":89,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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":["anthropic","chatgpt","claude","deepseek","gemini","google","lechat","mistral","omniai","openai","ruby"],"created_at":"2024-10-03T12:22:49.558Z","updated_at":"2026-04-02T14:13:15.623Z","avatar_url":"https://github.com/ksylvest.png","language":"Ruby","funding_links":[],"categories":["The latest additions 🎉","Ruby","Open Source"],"sub_categories":["API Libraries"],"readme":"# OmniAI\n\n[![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](https://github.com/ksylvest/omniai/blob/main/LICENSE)\n[![RubyGems](https://img.shields.io/gem/v/omniai)](https://rubygems.org/gems/omniai)\n[![GitHub](https://img.shields.io/badge/github-repo-blue.svg)](https://github.com/ksylvest/omniai)\n[![Yard](https://img.shields.io/badge/docs-site-blue.svg)](https://omniai.ksylvest.com)\n[![CircleCI](https://img.shields.io/circleci/build/github/ksylvest/omniai)](https://circleci.com/gh/ksylvest/omniai)\n\nOmniAI provides a unified Ruby API for integrating with multiple AI providers, including Anthropic, DeepSeek, Google, Mistral, and OpenAI. It streamlines AI development by offering a consistent interface for features such as chat, text-to-speech, speech-to-text, and embeddings—ensuring seamless interoperability across platforms. Switching between providers is effortless, making any integration more flexible and reliable.\n\n- [OmniAI::Anthropic](https://github.com/ksylvest/omniai-anthropic)\n- [OmniAI::DeepSeek](https://github.com/ksylvest/omniai-deepseek)\n- [OmniAI::Llama](https://github.com/ksylvest/omniai-llama)\n- [OmniAI::Google](https://github.com/ksylvest/omniai-google)\n- [OmniAI::Mistral](https://github.com/ksylvest/omniai-mistral)\n- [OmniAI::OpenAI](https://github.com/ksylvest/omniai-openai)\n\n## 📄 Examples\n\n### Example #1: [💬 Chat w/ Text](https://github.com/ksylvest/omniai/blob/main/examples/chat_with_text)\n\nThis example demonstrates using `OmniAI` with **Anthropic** to ask for a joke. The response is parsed and printed.\n\n```ruby\nrequire 'omniai/anthropic'\n\nclient = OmniAI::Anthropic::Client.new\n\nputs client.chat(\"Tell me a joke\").text\n```\n\n```\nWhy don't scientists trust atoms? Because they make up everything!\n```\n\n### Example #2: [💬 Chat w/ Prompt](https://github.com/ksylvest/omniai/blob/main/examples/chat_with_prompt)\n\nThis example demonstrates using `OmniAI` with **Mistral** to ask for the fastest animal. It includes a system and user message in the prompt. The response is streamed in real time.\n\n```ruby\nrequire \"omniai/mistral\"\n\nclient = OmniAI::Mistral::Client.new\n\nclient.chat(stream: $stdout) do |prompt|\n  prompt.system \"Respond in both English and French.\"\n  prompt.user \"What is the fastest animal?\"\nend\n```\n\n```\n**English**: The peregrine falcon is generally considered the fastest animal, reaching speeds of over 390 km/h.\n**French**: Le faucon pèlerin est généralement considéré comme l'animal le plus rapide, atteignant des vitesses de plus de 390 km/h.\n```\n\n### Example #3: [💬 Chat w/ Vision](https://github.com/ksylvest/omniai/blob/main/examples/chat_with_vision)\n\nThis example demonstrates using `OmniAI` with **OpenAI** to prompt a “biologist” for an analysis of photos, identifying the animals within each one. A system and user message are provided, and the response is streamed in real time.\n\n```ruby\nrequire \"omniai/openai\"\n\nclient = OmniAI::OpenAI::Client.new\n\nCAT_URL = \"https://images.unsplash.com/photo-1472491235688-bdc81a63246e?q=80\u0026w=1024\u0026h=1024\u0026fit=crop\u0026fm=jpg\"\nDOG_URL = \"https://images.unsplash.com/photo-1517849845537-4d257902454a?q=80\u0026w=1024\u0026h=1024\u0026fit=crop\u0026fm=jpg\"\n\nclient.chat(stream: $stdout) do |prompt|\n  prompt.system(\"You are a helpful biologist with expertise in animals who responds with the Latin names.\")\n  prompt.user do |message|\n    message.text(\"What animals are in the attached photos?\")\n    message.url(CAT_URL, \"image/jpeg\")\n    message.url(DOG_URL, \"image/jpeg\")\n  end\nend\n```\n\n```\nThe first photo is of a cat, *Felis Catus*.\nThe second photo is of a dog, *Canis Familiaris*.\n```\n\n### Example #4: [💬 Chat w/ Tools](https://github.com/ksylvest/omniai/blob/main/examples/chat_with_tools)\n\nThis example demonstrates using `OmniAI` with **Google** to ask for the weather. A tool “Weather” is provided. The tool accepts a location and unit (Celsius or Fahrenheit) then calculates the weather. The LLM makes multiple tool-call requests and is automatically provided with a tool-call response prior to streaming in real-time the result.\n\n```ruby\nrequire 'omniai/google'\n\nclient = OmniAI::Google::Client.new\n\nclass WeatherTool \u003c OmniAI::Tool\n  description \"Lookup the weather for a lat / lng.\"\n\n  parameter :lat, :number, description: \"The latitude of the location.\"\n  parameter :lng, :number, description: \"The longitude of the location.\"\n  parameter :unit, :string, enum: %w[Celsius Fahrenheit], description: \"The unit of measurement.\"\n  required %i[lat lng]\n\n  # @param lat [Float]\n  # @param lng [Float]\n  # @param unit [String] \"Celsius\" or \"Fahrenheit\"\n  #\n  # @return [String] e.g. \"20° Celsius at lat=43.7 lng=-79.4\"\n  def execute(lat:, lng:, unit: \"Celsius\")\n    puts \"[weather] lat=#{lat} lng=#{lng} unit=#{unit}\"\n    \"#{rand(20..50)}° #{unit} at lat=#{lat} lng=#{lng}\"\n  end\nend\n\nclass GeocodeTool \u003c OmniAI::Tool\n  description \"Lookup the latitude and longitude of a location.\"\n\n  parameter :location, :string, description: \"The location to geocode.\"\n  required %i[location]\n\n  # @param location [String] \"Toronto, Canada\"\n  #\n  # @return [Hash] { lat: Float, lng: Float, location: String }\n  def execute(location:)\n    puts \"[geocode] location=#{location}\"\n\n    {\n      lat: rand(-90.0..+90.0),\n      lng: rand(-180.0..+180.0),\n      location:,\n    }\n  end\nend\n\ntools = [\n  WeatherTool.new,\n  GeocodeTool.new,\n]\n\nclient.chat(stream: $stdout, tools:) do |prompt|\n  prompt.system \"You are an expert in weather.\"\n  prompt.user 'What is the weather in \"London\" in Celsius and \"Madrid\" in Fahrenheit?'\nend\n```\n\n```\n[geocode] location=London\n[weather] lat=... lng=... unit=Celsius\n[geocode] location=Madrid\n[weather] lat=... lng=... unit=Fahrenheit\n\nThe weather is 24° Celsius in London and 42° Fahrenheit in Madrid.\n```\n\n_For a set of pre-built tools for interacting with browsers, databases, docker, and more try the [OmniAI::Tools](https://omniai-tools.ksylvest.com/) project._\n\n### Example #5: [💬 Chat w/ History](https://github.com/ksylvest/omniai/blob/main/examples/chat_with_history)\n\nTracking a prompt history over multiple user and assistant messages is especially helpful when building an agent like conversation experience. A prompt can be used to track this back-and-forth conversation:\n\n```ruby\nrequire \"omniai/openai\"\n\nputs(\"Type 'exit' or 'quit' to leave.\")\n\nclient = OmniAI::OpenAI::Client.new\n\nconversation = OmniAI::Chat::Prompt.build do |prompt|\n  prompt.system \"You are a helpful assistant. Respond in both English and French.\"\nend\n\nloop do\n  print \"\u003e \"\n  text = gets.chomp.strip\n  next if text.empty?\n  break if text.eql?(\"exit\") || text.eql?(\"quit\")\n\n  conversation.user(text)\n  response = client.chat(conversation, stream: $stdout)\n  conversation.assistant(response.text)\nend\n```\n\n### Example #6 [💬 Chat w/ Schema](https://github.com/ksylvest/omniai/blob/main/examples/chat_with_schema)\n\nRequesting structured data back from an LLM is possible by defining a schema, then passing the schema into the chat. The following example defines a structured schema using `OmniAI::Schema` to model a `Contact`. The results of the LLM call are then parsed using the schema to ensure all types are correct.\n\n```ruby\nformat = OmniAI::Schema.format(name: \"Contact\", schema: OmniAI::Schema.object(\n  description: \"A contact with a name, relationship, and addresses.\",\n  properties: {\n    name: OmniAI::Schema.string,\n    relationship: OmniAI::Schema.string(enum: %w[friend family]),\n    addresses: OmniAI::Schema.array(\n      items: OmniAI::Schema.object(\n        title: \"Address\",\n        description: \"An address with street, city, state, and zip code.\",\n        properties: {\n          street: OmniAI::Schema.string,\n          city: OmniAI::Schema.string,\n          state: OmniAI::Schema.string,\n          zip: OmniAI::Schema.string,\n        },\n        required: %i[street city state zip]\n      )\n    ),\n  },\n  required: %i[name]\n))\n\nresponse = client.chat(format:) do |prompt|\n  prompt.user \u003c\u003c~TEXT\n    Parse the following contact:\n\n    NAME: George Harrison\n    RELATIONSHIP: friend\n    HOME: 123 Main St, Springfield, IL, 12345\n    WORK: 456 Elm St, Springfield, IL, 12345\n  TEXT\nend\n\nputs format.parse(response.text)\n```\n\n```\n{\n  name: \"George Harrison\",\n  relationship: \"friend\",\n  addresses: [\n    { street: \"123 Main St\", city: \"Springfield\", state: \"IL\", zip: \"12345\" },\n    { street: \"456 Elm St\", city: \"Springfield\", state: \"IL\", zip: \"12345\" },\n  ]\n}\n```\n\n### Example #7: [🐚 CLI](https://github.com/ksylvest/omniai/blob/main/examples/cli)\n\nThe `OmniAI` gem also ships with a CLI to simplify quick tests.\n\n```bash\n# Chat\n\nomniai chat \"Who designed the Ruby programming language?\"\nomniai chat --provider=\"google\" --model=\"gemini-2.0-flash\" \"Who are you?\"\n\n## Speech to Text\n\nomniai speak \"Salley sells sea shells by the sea shore.\" \u003e ./files/audio.wav\n\n# Text to Speech\n\nomniai transcribe \"./files/audio.wav\"\n\n# Embed\n\nomniai embed \"What is the capital of France?\"\n```\n\n### Example #8: [🔈 Text-to-Speech](https://github.com/ksylvest/omniai/blob/main/examples/text_to_speech)\n\nThis example demonstrates using `OmniAI` with **OpenAI** to convert text to speech and save it to a file.\n\n```ruby\nrequire 'omniai/openai'\n\nclient = OmniAI::OpenAI::Client.new\n\nFile.open(File.join(__dir__, 'audio.wav'), 'wb') do |file|\n  client.speak('Sally sells seashells by the seashore.', format: OmniAI::Speak::Format::WAV) do |chunk|\n    file \u003c\u003c chunk\n  end\nend\n```\n\n### Example #9: [🎤 Speech-to-Text](https://github.com/ksylvest/omniai/blob/main/examples/speech_to_text)\n\nThis example demonstrates using `OmniAI` with **OpenAI** to convert speech to text.\n\n```ruby\nrequire 'omniai/openai'\n\nclient = OmniAI::OpenAI::Client.new\n\nFile.open(File.join(__dir__, 'audio.wav'), 'rb') do |file|\n  transcription = client.transcribe(file)\n  puts(transcription.text)\nend\n```\n\n### Example #10: [💻 Embeddings](https://github.com/ksylvest/omniai/blob/main/examples/embeddings)\n\nThis example demonstrates using `OmniAI` with **Mistral** to generate embeddings for a dataset. It defines a set of entries (e.g. \"George is a teacher.\" or \"Ringo is a doctor.\") and then compares the embeddings generated from a query (e.g. \"What does George do?\" or \"Who is a doctor?\") to rank the entries by relevance.\n\n```ruby\nrequire 'omniai/mistral'\n\nCLIENT = OmniAI::Mistral::Client.new\n\nEntry = Data.define(:text, :embedding) do\n  def initialize(text:)\n    super(text:, embedding: CLIENT.embed(text).embedding)\n  end\nend\n\nENTRIES = [\n  Entry.new(text: 'John is a musician.'),\n  Entry.new(text: 'Paul is a plumber.'),\n  Entry.new(text: 'George is a teacher.'),\n  Entry.new(text: 'Ringo is a doctor.'),\n].freeze\n\ndef search(query)\n  embedding = CLIENT.embed(query).embedding\n\n  results = ENTRIES.sort_by do |data|\n    Math.sqrt(data.embedding.zip(embedding).map { |a, b| (a - b)**2 }.reduce(:+))\n  end\n\n  puts \"'#{query}': '#{results.first.text}'\"\nend\n\nsearch('What does George do?')\nsearch('Who is a doctor?')\nsearch('Who do you call to fix a toilet?')\n```\n\n```\n'What does George do?': 'George is a teacher.'\n'Who is a doctor?': 'Ringo is a doctor.'\n'Who do you call to fix a toilet?': 'Paul is a plumber.'\n```\n\n## 📦 Installation\n\nThe main `omniai` gem is installed with:\n\n```sh\ngem install omniai\n```\n\nSpecific provider gems are installed with:\n\n```sh\ngem install omniai-anthropic\ngem install omniai-deepseek\ngem install omniai-mistral\ngem install omniai-google\ngem install omniai-openai\n```\n\n## 📖 Usage\n\nOmniAI implements APIs for a number of popular clients by default. A client can be initialized using the specific gem (e.g. `omniai-openai` for `OmniAI::OpenAI`). Vendor specific docs can be found within each repo.\n\n### Client\n\n#### [OmniAI::Anthropic](https://github.com/ksylvest/omniai-anthropic)\n\n```ruby\nrequire 'omniai/anthropic'\n\nclient = OmniAI::Anthropic::Client.new\n```\n\n#### [OmniAI::DeepSeek](https://github.com/ksylvest/omniai-deepseek)\n\n```ruby\nrequire 'omniai/deepseek'\n\nclient = OmniAI::DeepSeek::Client.new\n```\n\n#### [OmniAI::Llama](https://github.com/ksylvest/omniai-llama)\n\n```ruby\nrequire 'omniai/llama'\n\nclient = OmniAI::Llama::Client.new\n```\n\n#### [OmniAI::Google](https://github.com/ksylvest/omniai-google)\n\n```ruby\nrequire 'omniai/google'\n\nclient = OmniAI::Google::Client.new\n```\n\n#### [OmniAI::Mistral](https://github.com/ksylvest/omniai-mistral)\n\n```ruby\nrequire 'omniai/mistral'\n\nclient = OmniAI::Mistral::Client.new\n```\n\n#### [OmniAI::OpenAI](https://github.com/ksylvest/omniai-openai)\n\n```ruby\nrequire 'omniai/openai'\n\nclient = OmniAI::OpenAI::Client.new\n```\n\n#### Usage with LocalAI\n\nLocalAI support is offered through [OmniAI::OpenAI](https://github.com/ksylvest/omniai-openai):\n\n[Usage with LocalAI](https://github.com/ksylvest/omniai-openai#usage-with-localai)\n\n#### Usage with Ollama\n\nOllama support is offered through [OmniAI::OpenAI](https://github.com/ksylvest/omniai-openai):\n\n[Usage with Ollama](https://github.com/ksylvest/omniai-openai#usage-with-ollama)\n\n#### Logging\n\nLogging the **request** / **response** is configurable by passing a logger into any client:\n\n```ruby\nrequire 'omniai/openai'\nrequire 'logger'\n\nlogger = Logger.new(STDOUT)\nclient = OmniAI::OpenAI::Client.new(logger:)\n```\n\n```\n[INFO]: POST https://...\n[INFO]: 200 OK\n...\n```\n\n#### Timeouts\n\nTimeouts are configurable by passing a `timeout` an integer duration for the request / response of any APIs using:\n\n```ruby\nrequire 'omniai/openai'\nrequire 'logger'\n\nlogger = Logger.new(STDOUT)\nclient = OmniAI::OpenAI::Client.new(timeout: 8) # 8 seconds\n```\n\nTimeouts are also configurable by passing a `timeout` hash with `timeout` / `read` / `write` keys using:\n\n```ruby\nrequire 'omniai/openai'\nrequire 'logger'\n\nlogger = Logger.new(STDOUT)\nclient = OmniAI::OpenAI::Client.new(timeout: {\n  read: 2, # i.e. 2 seconds\n  write: 3, # i.e. 3 seconds\n  connect: 4, # i.e. 4 seconds\n})\n```\n\n### 💬 Chat\n\nClients that support chat (e.g. Anthropic w/ \"Claude\", Google w/ \"Gemini\", Mistral w/ \"LeChat\", OpenAI w/ \"ChatGPT\", etc) generate text using the following calls:\n\n#### Using a Basic Prompt\n\nA chat response can be generated using a string for a prompt:\n\n```ruby\nresponse = client.chat('Tell me a joke.')\nresponse.text # 'Why don't scientists trust atoms? They make up everything!'\n```\n\n#### Using a Complex Prompt\n\nA chat response can be generated using a combination of messages and parts for a prompt:\n\n```ruby\nresponse = client.chat do |prompt|\n  prompt.system 'You are a helpful assistant with an expertise in animals.'\n  prompt.user do |message|\n    message.text 'What animals are in the attached photos?'\n    message.url('https://.../cat.jpeg', \"image/jpeg\")\n    message.url('https://.../dog.jpeg', \"image/jpeg\")\n    message.file('./hamster.jpeg', \"image/jpeg\")\n  end\nend\nresponse.text  # 'They are photos of a cat, a cat, and a hamster.'\n```\n\n#### Streaming via Proc\n\nA chat real-time stream of chunks can be generated with a proc:\n\n```ruby\nstream = proc do |chunk|\n  print(chunk.text) # '...'\nend\nclient.chat('Tell me a joke.', stream:)\n```\n\n#### Streaming via IO\n\nA chat real-time stream of chunks can also work with any IO object (e.g., `File`, `$stdout`, `$stdin`, etc.):\n\n```ruby\nclient.chat('Tell me a story', stream: $stdout)\n```\n\n#### Using Tools\n\nThe chat API can be provided with a set of tools to be invoked:\n\n```ruby\nclass WeatherTool\n  description \"Lookup the weather at a location in either Celsius or Fahrenheit.\"\n\n  parameter :location, :string, description: \"The location to find the weather.\", nullable: false\n  parameter :unit, :string, enum: %w[Celsius Fahrenheit], description: \"The unit of measurement.\", nullable: true\n  required %i[location unit]\n\n  # @param location [String]\n  # @param unit [String] \"Celsius\" or \"Fahrenheit\"\n  #\n  # @return [Hash]\n  def execute(location:, unit: \"Celsius\")\n    puts \"[weather] location=#{location} unit=#{unit}\"\n\n    {\n      temperature: \"#{rand(20..50)}°\",\n      humidity: rand(0..100),\n    }\n  end\nend\n\nclient.chat('What is the weather in \"London\" in Celsius and \"Paris\" in Fahrenheit?', tools: [WeatherTool.new])\n```\n\n#### Extended Thinking / Reasoning\n\nSome models support extended thinking or reasoning capabilities. OmniAI provides a unified `thinking:` option that works across all supported providers:\n\n```ruby\n# Enable thinking (provider uses sensible defaults)\nresponse = client.chat(\"What is 25 * 25?\", thinking: true)\n\n# Access thinking content\nresponse.choices.first.message.contents.each do |content|\n  case content\n  when OmniAI::Chat::Thinking\n    puts \"Thinking: #{content.thinking}\"\n  when OmniAI::Chat::Text\n    puts \"Response: #{content.text}\"\n  end\nend\n```\n\nWith streaming:\n\n```ruby\nclient.chat(\"Solve this step by step: What is 123 * 456?\", thinking: true, stream: $stdout)\n```\n\n**Provider Support:**\n\n| Provider | Option | Notes |\n|----------|--------|-------|\n| Anthropic | `thinking: true` or `thinking: { budget_tokens: N }` | Requires Claude 3.5+ models |\n| Google | `thinking: true` | Requires Gemini 2.0+ with thinking enabled |\n| OpenAI | `thinking: true` or `thinking: { effort: \"high\" }` | Requires o1/o3 models |\n\n### 🎤 Speech to Text\n\nClients that support transcribe (e.g. OpenAI w/ \"Whisper\") convert recordings to text via the following calls:\n\n#### Transcriptions with Path\n\n```ruby\ntranscription = client.transcribe(\"example.ogg\")\ntranscription.text # '...'\n```\n\n#### Transcriptions with Files\n\n```ruby\nFile.open(\"example.ogg\", \"rb\") do |file|\n  transcription = client.transcribe(file)\n  transcription.text # '...'\nend\n```\n\n### 🔈 Text to Speech\n\nClients that support speak (e.g. OpenAI w/ \"Whisper\") convert text to speech via the following calls:\n\n#### Speech with Stream\n\n```ruby\nFile.open('example.ogg', 'wb') do |file|\n  client.speak('The quick brown fox jumps over a lazy dog.', voice: 'HAL') do |chunk|\n    file \u003c\u003c chunk\n  end\nend\n```\n\n#### Speech with File\n\n```ruby\ntempfile = client.speak('The quick brown fox jumps over a lazy dog.', voice: 'HAL')\ntempfile.close\ntempfile.unlink\n```\n\n### 💻 Embeddings\n\nClients that support generating embeddings (e.g. OpenAI, Mistral, etc.) convert text to embeddings via the following:\n\n```ruby\nresponse = client.embed('The quick brown fox jumps over a lazy dog')\nresponse.usage # \u003cOmniAI::Embed::Usage prompt_tokens=5 total_tokens=5\u003e\nresponse.embedding # [0.1, 0.2, ...] \u003e\n```\n\nTheese APIs support generating embeddings in batches using the following code:\n\n```ruby\nresponse = client.embed([\n  'The quick brown fox jumps over a lazy dog',\n  'Pack my box with five dozen liquor jugs',\n])\nresponse.usage # \u003cOmniAI::Embed::Usage prompt_tokens=5 total_tokens=5\u003e\nresponse.embeddings.each do |embedding|\n  embedding # [0.1, 0.2, ...]\nend\n```\n\n## 🐚 CLI\n\nOmniAI packages a basic command line interface (CLI) to allow for exploration of various APIs. CLI documentation is available with the `--help` flag:\n\n```bash\nomniai --help\n```\n\n### Chat\n\n#### w/ a Prompt\n\n```bash\nomniai chat \"What is the coldest place on earth?\"\n```\n\n```\nThe coldest place on earth is Antarctica.\n```\n\n#### w/o a Prompt\n\n```bash\nomniai chat --provider=\"openai\" --model=\"gpt-4\" --temperature=\"0.5\"\n```\n\n```\nType 'exit' or 'quit' to abort.\n# What is the warmest place on earth?\n```\n\n```\nThe warmest place on earth is Africa.\n```\n\n### Embed\n\n#### w/ input\n\n```bash\nomniai embed \"The quick brown fox jumps over a lazy dog.\"\n```\n\n```\n0.0\n...\n```\n\n#### w/o input\n\n```bash\nomniai embed --provider=\"openai\" --model=\"text-embedding-ada-002\"\n```\n\n```\nType 'exit' or 'quit' to abort.\n# What is the capital of Spain?\nThe capital of Spain is **Madrid**.\n```\n\n```\n0.0\n...\n```\n\n#### Text-to-Speech\n\n```bash\nomniai speak \"Sally sells sea shells on the sea shore.\" \u003e audio.aac\n```\n\n#### Speech-to-Text\n\n```bash\nomniai transcribe ./audio.aac\n```\n\n## MCP\n\n[MCP](https://modelcontextprotocol.io/introduction) is an open protocol designed to standardize giving context to LLMs. The OmniAI implementation supports building an MCP server that operates via the [stdio](https://modelcontextprotocol.io/docs/concepts/transports) transport.\n\n**main.rb**\n\n```ruby\nclass Weather \u003c OmniAI::Tool\n  description \"Lookup the weather for a location\"\n\n  parameter :location, :string, description: \"A location (e.g. 'London' or 'Madrid').\"\n  required %i[location]\n\n  # @param location [String] required\n  # @return [String]\n  def execute(location:)\n    case location\n    when 'London' then 'Rainy'\n    when 'Madrid' then 'Sunny'\n    end\n  end\nend\n\ntransport = OmniAI::MCP::Transport::Stdio.new\nmcp = OmniAI::MCP::Server.new(tools: [Weather.new])\nmcp.run(transport:)\n```\n\n```bash\nruby main.rb\n```\n\n```bash\n{\n  \"jsonrpc\": \"2.0\",\n  \"id\": 1,\n  \"method\": \"tools/call\",\n  \"params\": { \"name\": \"echo\", \"arguments\": { \"message\": \"Hello, world!\" } }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fksylvest%2Fomniai","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fksylvest%2Fomniai","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fksylvest%2Fomniai/lists"}