{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Working with OpenRouter in Pixeltable\n", "\n", "Pixeltable's OpenRouter integration enables you to access multiple LLM providers through a unified API via OpenRouter.\n", "\n", "### Prerequisites\n", "\n", "- An OpenRouter account with an API key (https://openrouter.ai)\n", "\n", "### Important notes\n", "\n", "- OpenRouter usage may incur costs based on the models you use and your usage volume.\n", "- Be mindful of sensitive data and consider security measures when integrating with external services." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "First you'll need to install required libraries and enter your OpenRouter API key." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%pip install -qU pixeltable openai" ] }, { "cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [], "source": [ "import getpass\n", "import os\n", "\n", "if 'OPENROUTER_API_KEY' not in os.environ:\n", " os.environ['OPENROUTER_API_KEY'] = getpass.getpass(\n", " 'Enter your OpenRouter API key:'\n", " )" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now let's create a Pixeltable directory to hold the tables for our demo." ] }, { "cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Connected to Pixeltable database at: postgresql+psycopg://postgres:@/pixeltable?host=/Users/pjlb/.pixeltable/pgdata\n", "Created directory 'openrouter_demo'.\n" ] }, { "name": "stderr", "output_type": "stream", "text": [ "/Users/pierre/pixeltable/pixeltable/env.py:494: UserWarning: Progress reporting is disabled because ipywidgets is not installed. To fix this, run: `pip install ipywidgets`\n", " warnings.warn(\n" ] }, { "data": { "text/plain": [ "" ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import pixeltable as pxt\n", "\n", "# Remove the 'openrouter_demo' directory and its contents, if it exists\n", "pxt.drop_dir('openrouter_demo', force=True)\n", "pxt.create_dir('openrouter_demo')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Chat completions\n", "\n", "Create a Table: In Pixeltable, create a table with columns to represent your input data and the columns where you want to store the results from OpenRouter." ] }, { "cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Created table 'chat'.\n", "Added 0 column values with 0 errors in 0.01 s\n" ] }, { "data": { "text/plain": [ "No rows affected." ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from pixeltable.functions import openrouter\n", "\n", "# Create a table in Pixeltable and add a computed column that calls OpenRouter\n", "t = pxt.create_table('openrouter_demo/chat', {'input': pxt.String})\n", "\n", "messages = [{'role': 'user', 'content': t.input}]\n", "\n", "t.add_computed_column(\n", " output=openrouter.chat_completions(\n", " messages=messages,\n", " model='anthropic/claude-sonnet-4',\n", " model_kwargs={\n", " # Optional dict with parameters compatible with the model\n", " 'max_tokens': 300,\n", " 'temperature': 0.7,\n", " },\n", " )\n", ")" ] }, { "cell_type": "code", "execution_count": 5, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Added 0 column values with 0 errors in 0.01 s\n" ] }, { "data": { "text/plain": [ "No rows affected." ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Parse the response into a new column\n", "t.add_computed_column(response=t.output.choices[0].message.content)" ] }, { "cell_type": "code", "execution_count": 6, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Inserted 2 rows with 0 errors in 7.59 s (0.26 rows/s)\n" ] }, { "data": { "text/html": [ "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
inputresponse
Can you make me a coffee?I can't physically make you a coffee since I'm an AI assistant without a physical form, but I'd be happy to help in other ways! I could:\n", "\n", "- Share a great coffee recipe or brewing tips\n", "- Help you find nearby coffee shops\n", "- Suggest coffee alternatives if you're out of beans\n", "- Walk you through different brewing methods\n", "\n", "What kind of coffee help would be most useful for you right now?
How many species of felids have been classified?There are **38-40 species** of felids (cats) currently recognized by most taxonomic authorities, though the exact number varies slightly depending on the classification system used.\n", "\n", "The family Felidae is divided into two subfamilies:\n", "\n", "**Pantherinae** (big cats) - about 7 species:\n", "- Lion, tiger, leopard, jaguar, snow leopard, clouded leopard, and Sunda clouded leopard\n", "\n", "**Felinae** (small cats) - about 31-33 species:\n", "- Including domestic cats, lynx species, pumas, cheetahs, ocelots, servals,  ...... iation in total count (38-40) comes from ongoing taxonomic research and debates about whether certain populations should be classified as separate species or subspecies. For example, some authorities recognize the Sunda clouded leopard as distinct from the clouded leopard, and there are ongoing discussions about the classification of various small cat populations.\n", "\n", "This number represents currently living species and doesn't include the many extinct felid species known from the fossil record.
" ], "text/plain": [ " input \\\n", "0 Can you make me a coffee? \n", "1 How many species of felids have been classified? \n", "\n", " response \n", "0 I can't physically make you a coffee since I'm... \n", "1 There are **38-40 species** of felids (cats) c... " ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Start a conversation\n", "t.insert(\n", " [\n", " {'input': 'How many species of felids have been classified?'},\n", " {'input': 'Can you make me a coffee?'},\n", " ]\n", ")\n", "t.select(t.input, t.response).head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Using different models\n", "\n", "One of OpenRouter's key benefits is easy access to models from multiple providers. Let's create a table that compares responses from Anthropic Claude, OpenAI GPT-4, and Meta Llama." ] }, { "cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Created table 'compare_models'.\n", "Added 0 column values with 0 errors in 0.01 s\n", "Added 0 column values with 0 errors in 0.01 s\n", "Added 0 column values with 0 errors in 0.01 s\n" ] }, { "data": { "text/plain": [ "No rows affected." ] }, "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create a table to compare different models\n", "compare_t = pxt.create_table(\n", " 'openrouter_demo/compare_models', {'prompt': pxt.String}\n", ")\n", "\n", "messages = [{'role': 'user', 'content': compare_t.prompt}]\n", "\n", "# Add responses from different models\n", "compare_t.add_computed_column(\n", " claude=openrouter.chat_completions(\n", " messages=messages,\n", " model='anthropic/claude-sonnet-4',\n", " model_kwargs={'max_tokens': 150},\n", " )\n", " .choices[0]\n", " .message.content\n", ")\n", "\n", "compare_t.add_computed_column(\n", " gpt4=openrouter.chat_completions(\n", " messages=messages,\n", " model='openai/gpt-4o-mini',\n", " model_kwargs={'max_tokens': 150},\n", " )\n", " .choices[0]\n", " .message.content\n", ")\n", "\n", "compare_t.add_computed_column(\n", " llama=openrouter.chat_completions(\n", " messages=messages,\n", " model='meta-llama/llama-3.3-70b-instruct',\n", " model_kwargs={'max_tokens': 150},\n", " )\n", " .choices[0]\n", " .message.content\n", ")" ] }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Inserted 1 row with 0 errors in 1.27 s (0.79 rows/s)\n" ] }, { "data": { "text/html": [ "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
promptclaudegpt4llama
Explain quantum entanglement in one sentence.Quantum entanglement is a phenomenon where two or more particles become mysteriously connected such that measuring one particle instantly affects the others, regardless of the distance separating them.Quantum entanglement is a phenomenon in quantum physics where two or more particles become linked in such a way that the state of one particle instantly influences the state of the other, regardless of the distance separating them.Quantum entanglement is a phenomenon in which two or more particles become connected in such a way that their properties, such as spin or energy, are correlated regardless of the distance between them, allowing for instantaneous and non-local interaction.
" ], "text/plain": [ " prompt \\\n", "0 Explain quantum entanglement in one sentence. \n", "\n", " claude \\\n", "0 Quantum entanglement is a phenomenon where two... \n", "\n", " gpt4 \\\n", "0 Quantum entanglement is a phenomenon in quantu... \n", "\n", " llama \n", "0 Quantum entanglement is a phenomenon in which ... " ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Insert a prompt and compare responses\n", "compare_t.insert(\n", " [{'prompt': 'Explain quantum entanglement in one sentence.'}]\n", ")\n", "compare_t.select(\n", " compare_t.prompt, compare_t.claude, compare_t.gpt4, compare_t.llama\n", ").head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Advanced features: provider routing\n", "\n", "OpenRouter allows you to specify provider preferences for fallback behavior and cost optimization." ] }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Created table 'routing'.\n", "Added 0 column values with 0 errors in 0.01 s\n", "Added 0 column values with 0 errors in 0.01 s\n" ] }, { "data": { "text/plain": [ "No rows affected." ] }, "execution_count": 9, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create a table with provider routing\n", "routing_t = pxt.create_table(\n", " 'openrouter_demo/routing', {'input': pxt.String}\n", ")\n", "\n", "messages = [{'role': 'user', 'content': routing_t.input}]\n", "routing_t.add_computed_column(\n", " output=openrouter.chat_completions(\n", " messages=messages,\n", " model='anthropic/claude-sonnet-4',\n", " model_kwargs={'max_tokens': 300},\n", " # Specify provider preferences\n", " provider={\n", " 'order': [\n", " 'Anthropic',\n", " 'OpenAI',\n", " ], # Try Anthropic first, then OpenAI\n", " 'allow_fallbacks': True,\n", " },\n", " )\n", ")\n", "\n", "routing_t.add_computed_column(\n", " response=routing_t.output.choices[0].message.content\n", ")" ] }, { "cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Inserted 1 row with 0 errors in 3.97 s (0.25 rows/s)\n" ] }, { "data": { "text/html": [ "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
inputresponse
What are the primary colors?The primary colors are **red, blue, and yellow**.\n", "\n", "These are considered primary because they cannot be created by mixing other colors together, and they serve as the foundation for creating all other colors through various combinations.\n", "\n", "It's worth noting that there are different color systems:\n", "- **Traditional/artistic primaries**: Red, blue, yellow\n", "- **Light primaries (RGB)**: Red, green, blue (used in digital displays)\n", "- **Print primaries (CMYK)**: Cyan, magenta, yellow (plus black for printing)\n", "\n", "The red-blue-yellow system is what's most commonly taught and referenced when people ask about primary colors.
" ], "text/plain": [ " input \\\n", "0 What are the primary colors? \n", "\n", " response \n", "0 The primary colors are **red, blue, and yellow... " ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "routing_t.insert([{'input': 'What are the primary colors?'}])\n", "routing_t.select(routing_t.input, routing_t.response).head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Advanced Features: Context Window Optimization\n", "\n", "OpenRouter supports transforms like 'middle-out' to optimize handling of long contexts." ] }, { "cell_type": "code", "execution_count": 11, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Created table 'transforms'.\n", "Added 0 column values with 0 errors in 0.01 s\n", "Added 0 column values with 0 errors in 0.01 s\n" ] }, { "data": { "text/plain": [ "No rows affected." ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Create a table with transforms for long context optimization\n", "transform_t = pxt.create_table(\n", " 'openrouter_demo/transforms', {'long_context': pxt.String}\n", ")\n", "\n", "messages = [{'role': 'user', 'content': transform_t.long_context}]\n", "transform_t.add_computed_column(\n", " output=openrouter.chat_completions(\n", " messages=messages,\n", " model='openai/gpt-4o-mini',\n", " model_kwargs={'max_tokens': 200},\n", " # Apply middle-out transform for better long context handling\n", " transforms=['middle-out'],\n", " )\n", ")\n", "\n", "transform_t.add_computed_column(\n", " response=transform_t.output.choices[0].message.content\n", ")" ] }, { "cell_type": "code", "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Inserted 1 row with 0 errors in 1.82 s (0.55 rows/s)\n" ] }, { "data": { "text/html": [ "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
response
The main AI developments mentioned are:\n", "\n", "1. **Machine Learning Algorithms** - These can detect patterns in data that humans might miss.\n", "2. **Deep Learning** - This has revolutionized computer vision and natural language processing.\n", "3. **Reinforcement Learning** - An area of development for the future of AI.\n", "4. **Generative Models** - Another area of promising future development in AI.
" ], "text/plain": [ " response\n", "0 The main AI developments mentioned are:\\n\\n1. ..." ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Example with longer context\n", "long_text = \"\"\"\n", "Artificial intelligence has transformed many industries. Machine learning algorithms\n", "can now detect patterns in data that humans might miss. Deep learning has revolutionized\n", "computer vision and natural language processing. The future of AI looks promising with\n", "developments in areas like reinforcement learning and generative models.\n", "\n", "Question: What are the main AI developments mentioned?\n", "\"\"\"\n", "\n", "transform_t.insert([{'long_context': long_text}])\n", "transform_t.select(transform_t.response).head()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Learn more\n", "\n", "To learn more about advanced techniques like RAG operations in Pixeltable, check out the [RAG Operations in Pixeltable](https://docs.pixeltable.com/howto/use-cases/rag-operations) tutorial.\n", "\n", "For more information about OpenRouter's features and available models, visit:\n", "\n", "- [OpenRouter Documentation](https://openrouter.ai/docs)\n", "- [Available Models](https://openrouter.ai/models)" ] } ], "metadata": { "kernelspec": { "display_name": "pixeltable", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.11" } }, "nbformat": 4, "nbformat_minor": 4 }