From 13ab47ce8d2f6091750e74a7c13d97cec661b1f1 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 14 Dec 2025 05:42:29 +0000 Subject: [PATCH 1/3] Initial plan From ccb670adfdb2bded0ba2a0161eb5dfd6a2a4c908 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 14 Dec 2025 05:49:34 +0000 Subject: [PATCH 2/3] Add AI Badgr provider integration Co-authored-by: miguelmanlyx <220451577+miguelmanlyx@users.noreply.github.com> --- cookbook/providers/aibadgr.ipynb | 177 ++++++++++++++++++++++++++ src/globals.ts | 2 + src/providers/aibadgr/api.ts | 18 +++ src/providers/aibadgr/chatComplete.ts | 56 ++++++++ src/providers/aibadgr/index.ts | 18 +++ src/providers/index.ts | 2 + 6 files changed, 273 insertions(+) create mode 100644 cookbook/providers/aibadgr.ipynb create mode 100644 src/providers/aibadgr/api.ts create mode 100644 src/providers/aibadgr/chatComplete.ts create mode 100644 src/providers/aibadgr/index.ts diff --git a/cookbook/providers/aibadgr.ipynb b/cookbook/providers/aibadgr.ipynb new file mode 100644 index 000000000..62ab9d34f --- /dev/null +++ b/cookbook/providers/aibadgr.ipynb @@ -0,0 +1,177 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Portkey + AI Badgr\n", + "\n", + "[Portkey](https://app.portkey.ai/) is the Control Panel for AI apps. With its popular AI Gateway and Observability Suite, hundreds of teams ship reliable, cost-efficient, and fast apps." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Use Budget-Friendly AI Badgr API with OpenAI Compatibility using Portkey!\n", + "\n", + "AI Badgr is a budget/utility OpenAI-compatible provider that offers tier-based model access:\n", + "- **basic**: Budget-tier models (phi-3-mini)\n", + "- **normal**: Standard-tier models (mistral-7b)\n", + "- **premium**: High-quality models (llama3-8b-instruct)\n", + "\n", + "Since Portkey is fully compatible with the OpenAI signature, you can connect to the Portkey AI Gateway through the OpenAI Client.\n", + "\n", + "- Set the `base_url` as `PORTKEY_GATEWAY_URL`\n", + "- Add `default_headers` to consume the headers needed by Portkey using the `createHeaders` helper method." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "You will need Portkey and AI Badgr API keys to run this notebook.\n", + "\n", + "- Sign up for [Portkey here](https://app.portkey.ai/signup) and generate your API key.\n", + "- Get your AI Badgr API key from [AI Badgr](https://aibadgr.com)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "!pip install -qU portkey-ai openai" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## With OpenAI Client" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from openai import OpenAI\n", + "from portkey_ai import PORTKEY_GATEWAY_URL, createHeaders\n", + "\n", + "client = OpenAI(\n", + " base_url=PORTKEY_GATEWAY_URL,\n", + " default_headers=createHeaders(\n", + " provider=\"aibadgr\",\n", + " api_key=\"YOUR_AIBADGR_API_KEY\"\n", + " )\n", + ")\n", + "\n", + "chat_completion = client.chat.completions.create(\n", + " messages=[{\"role\": \"user\", \"content\": \"What is the meaning of life?\"}],\n", + " model=\"premium\" # Use tier names: basic, normal, or premium\n", + ")\n", + "\n", + "print(chat_completion.choices[0].message.content)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## With Portkey Client" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from portkey_ai import Portkey\n", + "\n", + "portkey = Portkey(\n", + " api_key=\"YOUR_PORTKEY_API_KEY\",\n", + " provider=\"aibadgr\",\n", + " Authorization=\"YOUR_AIBADGR_API_KEY\"\n", + ")\n", + "\n", + "completion = portkey.chat.completions.create(\n", + " messages=[{\"role\": \"user\", \"content\": \"Explain quantum computing in simple terms\"}],\n", + " model=\"premium\"\n", + ")\n", + "\n", + "print(completion.choices[0].message.content)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Streaming Responses" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "stream = portkey.chat.completions.create(\n", + " messages=[{\"role\": \"user\", \"content\": \"Write a short poem about AI\"}],\n", + " model=\"premium\",\n", + " stream=True\n", + ")\n", + "\n", + "for chunk in stream:\n", + " if chunk.choices[0].delta.content:\n", + " print(chunk.choices[0].delta.content, end=\"\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Model Tiers\n", + "\n", + "AI Badgr provides tier-based model access:\n", + "\n", + "- **basic**: Budget-tier models (maps to phi-3-mini)\n", + "- **normal**: Standard-tier models (maps to mistral-7b)\n", + "- **premium**: High-quality models (maps to llama3-8b-instruct)\n", + "\n", + "OpenAI model names are also accepted and automatically mapped to the appropriate tier." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Observability with Portkey\n", + "\n", + "By routing requests through Portkey you can track metrics like:\n", + "- Token usage and costs\n", + "- Request latency\n", + "- Success/error rates\n", + "\n", + "View all your analytics at [Portkey Dashboard](https://app.portkey.ai/)." + ] + } + ], + "metadata": { + "colab": { + "provenance": [] + }, + "kernelspec": { + "display_name": "Python 3", + "name": "python3" + }, + "language_info": { + "name": "python" + } + }, + "nbformat": 4, + "nbformat_minor": 0 +} \ No newline at end of file diff --git a/src/globals.ts b/src/globals.ts index 1af397d91..249419cfc 100644 --- a/src/globals.ts +++ b/src/globals.ts @@ -110,6 +110,7 @@ export const NEXTBIT: string = 'nextbit'; export const MODAL: string = 'modal'; export const Z_AI: string = 'z-ai'; export const IO_INTELLIGENCE: string = 'iointelligence'; +export const AIBADGR: string = 'aibadgr'; export const VALID_PROVIDERS = [ ANTHROPIC, @@ -183,6 +184,7 @@ export const VALID_PROVIDERS = [ MODAL, Z_AI, IO_INTELLIGENCE, + AIBADGR, ]; export const CONTENT_TYPES = { diff --git a/src/providers/aibadgr/api.ts b/src/providers/aibadgr/api.ts new file mode 100644 index 000000000..198bc1949 --- /dev/null +++ b/src/providers/aibadgr/api.ts @@ -0,0 +1,18 @@ +import { ProviderAPIConfig } from '../types'; + +const AIBadgrAPIConfig: ProviderAPIConfig = { + getBaseURL: () => 'https://aibadgr.com/api/v1', + headers: ({ providerOptions }) => { + return { Authorization: `Bearer ${providerOptions.apiKey}` }; + }, + getEndpoint: ({ fn }) => { + switch (fn) { + case 'chatComplete': + return '/chat/completions'; + default: + return ''; + } + }, +}; + +export default AIBadgrAPIConfig; diff --git a/src/providers/aibadgr/chatComplete.ts b/src/providers/aibadgr/chatComplete.ts new file mode 100644 index 000000000..7651aa4d7 --- /dev/null +++ b/src/providers/aibadgr/chatComplete.ts @@ -0,0 +1,56 @@ +import { AIBADGR } from '../../globals'; + +interface AIBadgrStreamChunk { + id: string; + object: string; + created: number; + model: string; + choices: { + index: number; + delta: { + role?: string; + content?: string; + tool_calls?: object[]; + }; + finish_reason: string | null; + }[]; + usage?: { + prompt_tokens: number; + completion_tokens: number; + total_tokens: number; + }; +} + +export const AIBadgrChatCompleteStreamChunkTransform = ( + responseChunk: string +) => { + let chunk = responseChunk.trim(); + chunk = chunk.replace(/^data: /, ''); + chunk = chunk.trim(); + + if (chunk === '[DONE]') { + return `data: ${chunk}\n\n`; + } + + try { + const parsedChunk: AIBadgrStreamChunk = JSON.parse(chunk); + return ( + `data: ${JSON.stringify({ + id: parsedChunk.id, + object: parsedChunk.object, + created: parsedChunk.created, + model: parsedChunk.model, + provider: AIBADGR, + choices: parsedChunk.choices.map((choice) => ({ + index: choice.index, + delta: choice.delta, + finish_reason: choice.finish_reason, + })), + usage: parsedChunk.usage, + })}` + '\n\n' + ); + } catch (error) { + console.error('Error parsing AI Badgr stream chunk:', error); + return `data: ${chunk}\n\n`; + } +}; diff --git a/src/providers/aibadgr/index.ts b/src/providers/aibadgr/index.ts new file mode 100644 index 000000000..c58a47133 --- /dev/null +++ b/src/providers/aibadgr/index.ts @@ -0,0 +1,18 @@ +import { ProviderConfigs } from '../types'; +import AIBadgrAPIConfig from './api'; +import { AIBadgrChatCompleteStreamChunkTransform } from './chatComplete'; +import { chatCompleteParams, responseTransformers } from '../open-ai-base'; +import { AIBADGR } from '../../globals'; + +const AIBadgrConfig: ProviderConfigs = { + api: AIBadgrAPIConfig, + chatComplete: chatCompleteParams([]), + responseTransforms: { + ...responseTransformers(AIBADGR, { + chatComplete: true, + }), + 'stream-chatComplete': AIBadgrChatCompleteStreamChunkTransform, + }, +}; + +export default AIBadgrConfig; diff --git a/src/providers/index.ts b/src/providers/index.ts index 6940531b6..66d961347 100644 --- a/src/providers/index.ts +++ b/src/providers/index.ts @@ -71,6 +71,7 @@ import ZAIConfig from './z-ai'; import MatterAIConfig from './matterai'; import ModalConfig from './modal'; import IOIntelligenceConfig from './iointelligence'; +import AIBadgrConfig from './aibadgr'; const Providers: { [key: string]: ProviderConfigs } = { openai: OpenAIConfig, @@ -142,6 +143,7 @@ const Providers: { [key: string]: ProviderConfigs } = { modal: ModalConfig, 'z-ai': ZAIConfig, iointelligence: IOIntelligenceConfig, + aibadgr: AIBadgrConfig, }; export default Providers; From 5d6f8365d058b34a1a88b1b449a443f09109e0de Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 14 Dec 2025 05:54:06 +0000 Subject: [PATCH 3/3] Address code review feedback - improve error logging and documentation Co-authored-by: miguelmanlyx <220451577+miguelmanlyx@users.noreply.github.com> --- cookbook/providers/aibadgr.ipynb | 14 +++++++------- src/providers/aibadgr/chatComplete.ts | 7 ++++++- 2 files changed, 13 insertions(+), 8 deletions(-) diff --git a/cookbook/providers/aibadgr.ipynb b/cookbook/providers/aibadgr.ipynb index 62ab9d34f..9789d0c34 100644 --- a/cookbook/providers/aibadgr.ipynb +++ b/cookbook/providers/aibadgr.ipynb @@ -16,9 +16,9 @@ "## Use Budget-Friendly AI Badgr API with OpenAI Compatibility using Portkey!\n", "\n", "AI Badgr is a budget/utility OpenAI-compatible provider that offers tier-based model access:\n", - "- **basic**: Budget-tier models (phi-3-mini)\n", - "- **normal**: Standard-tier models (mistral-7b)\n", - "- **premium**: High-quality models (llama3-8b-instruct)\n", + "- **basic**: Budget-tier models for simple tasks\n", + "- **normal**: Standard-tier models for general use\n", + "- **premium**: High-quality models for complex tasks\n", "\n", "Since Portkey is fully compatible with the OpenAI signature, you can connect to the Portkey AI Gateway through the OpenAI Client.\n", "\n", @@ -136,11 +136,11 @@ "source": [ "## Model Tiers\n", "\n", - "AI Badgr provides tier-based model access:\n", + "AI Badgr provides tier-based model access optimized for different use cases:\n", "\n", - "- **basic**: Budget-tier models (maps to phi-3-mini)\n", - "- **normal**: Standard-tier models (maps to mistral-7b)\n", - "- **premium**: High-quality models (maps to llama3-8b-instruct)\n", + "- **basic**: Budget-tier models optimized for cost and speed\n", + "- **normal**: Standard-tier models balancing performance and cost\n", + "- **premium**: High-quality models for complex reasoning and tasks\n", "\n", "OpenAI model names are also accepted and automatically mapped to the appropriate tier." ] diff --git a/src/providers/aibadgr/chatComplete.ts b/src/providers/aibadgr/chatComplete.ts index 7651aa4d7..17afc9c18 100644 --- a/src/providers/aibadgr/chatComplete.ts +++ b/src/providers/aibadgr/chatComplete.ts @@ -50,7 +50,12 @@ export const AIBadgrChatCompleteStreamChunkTransform = ( })}` + '\n\n' ); } catch (error) { - console.error('Error parsing AI Badgr stream chunk:', error); + console.error( + 'Error parsing AI Badgr stream chunk:', + error, + 'Chunk:', + chunk + ); return `data: ${chunk}\n\n`; } };