From 60ceb25fe92bc65358d53cc0828575f206570f7c Mon Sep 17 00:00:00 2001 From: Konstantin Date: Sun, 6 Sep 2026 02:40:44 +0300 Subject: [PATCH] Add Hubris integration page --- integrations/hubris.md | 118 +++++++++++++++++++++++++++++++++++++++++ logos/hubris.png | Bin 0 -> 14609 bytes 2 files changed, 118 insertions(+) create mode 100644 integrations/hubris.md create mode 100644 logos/hubris.png diff --git a/integrations/hubris.md b/integrations/hubris.md new file mode 100644 index 00000000..9833b01e --- /dev/null +++ b/integrations/hubris.md @@ -0,0 +1,118 @@ +--- +layout: integration +name: Hubris +description: Use 500+ models from OpenAI, Anthropic, Google, DeepSeek, Qwen and others through Hubris, an OpenAI-compatible LLM gateway billed in Russian rubles +authors: + - name: Hubris + socials: + github: Aimagine-life +pypi: https://pypi.org/project/haystack-ai/ +repo: https://github.com/deepset-ai/haystack +type: Model Provider +report_issue: https://github.com/deepset-ai/haystack/issues +logo: /logos/hubris.png +version: Haystack 2.0 +toc: true +--- + +### **Table of Contents** + +- [Overview](#overview) +- [Usage](#usage) + +## Overview + +[Hubris](https://hubris.pw) is an OpenAI-compatible LLM gateway: one API key and one balance (billed in Russian rubles) for models from OpenAI, Anthropic, Google, DeepSeek, Qwen, Z.ai, Moonshot, xAI, MiniMax and others. The full catalog with prices is at [hubris.pw/models](https://hubris.pw/models); model ids always use the `vendor/model` form (for example `anthropic/claude-sonnet-5`). + +## Usage + +The Hubris API is OpenAI compatible, so it works with Haystack's OpenAI components out of the box. Create an API key at [hubris.pw/keys](https://hubris.pw/keys) and set it as the `HUBRIS_API_KEY` environment variable. + +### Using `ChatGenerator` + +```python +from haystack.components.generators.chat import OpenAIChatGenerator +from haystack.dataclasses import ChatMessage +from haystack.utils import Secret + +generator = OpenAIChatGenerator( + api_key=Secret.from_env_var("HUBRIS_API_KEY"), + api_base_url="https://api.hubris.pw/v1", + model="anthropic/claude-sonnet-5", +) + +messages = [ + ChatMessage.from_system("You are a helpful assistant."), + ChatMessage.from_user("What is the capital of France?"), +] +response = generator.run(messages=messages) +print(response["replies"][0].text) +``` + +### In a pipeline + +Here's a question-answering pipeline over a web page. Any model from the [catalog](https://hubris.pw/models) can be used; `google/gemini-3.7-flash` is a good fit for long pages. + +```python +from haystack import Pipeline +from haystack.components.builders import ChatPromptBuilder +from haystack.components.converters import HTMLToDocument +from haystack.components.fetchers import LinkContentFetcher +from haystack.components.generators.chat import OpenAIChatGenerator +from haystack.dataclasses import ChatMessage +from haystack.utils import Secret + +template = [ + ChatMessage.from_user( + """According to the contents of this website: +{% for document in documents %} + {{document.content}} +{% endfor %} +Answer the given question: {{query}} +Answer:""" + ) +] + +pipeline = Pipeline() +pipeline.add_component("fetcher", LinkContentFetcher()) +pipeline.add_component("converter", HTMLToDocument()) +pipeline.add_component("prompt", ChatPromptBuilder(template=template, required_variables=["documents", "query"])) +pipeline.add_component( + "llm", + OpenAIChatGenerator( + api_key=Secret.from_env_var("HUBRIS_API_KEY"), + api_base_url="https://api.hubris.pw/v1", + model="google/gemini-3.7-flash", + ), +) + +pipeline.connect("fetcher.streams", "converter.sources") +pipeline.connect("converter.documents", "prompt.documents") +pipeline.connect("prompt.prompt", "llm.messages") + +result = pipeline.run( + { + "fetcher": {"urls": ["https://hubris.pw/docs"]}, + "prompt": {"query": "How do I authenticate requests to Hubris?"}, + } +) +print(result["llm"]["replies"][0].text) +``` + +### Embeddings + +Embedding models from the catalog work through the OpenAI embedders the same way: + +```python +from haystack.components.embedders import OpenAITextEmbedder +from haystack.utils import Secret + +embedder = OpenAITextEmbedder( + api_key=Secret.from_env_var("HUBRIS_API_KEY"), + api_base_url="https://api.hubris.pw/v1", + model="openai/text-embedding-3-small", +) +print(embedder.run(text="Haystack pipelines with Hubris")["embedding"][:5]) +``` + +Streaming (`streaming_callback`), tool calling (`tools`) and structured output (`response_format`) work exactly as with the stock OpenAI components; the `supported_parameters` field of `GET https://api.hubris.pw/v1/models` lists what each model accepts. diff --git a/logos/hubris.png b/logos/hubris.png new file mode 100644 index 0000000000000000000000000000000000000000..476560fa812a29dfbc35dd5ca991083cd3105cbf GIT binary patch literal 14609 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 bq0+_6Gw7X