diff --git a/dev-requirements.txt b/dev-requirements.txt index 6f7c4be..8159328 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -2,31 +2,6 @@ ruff build twine -ipython -python-dotenv - -# internet -requests -html2text -duckduckgo-search - -# cli -typer[all] - -# data -duckdb>=0.9.2 -ibis-framework[duckdb,polars,deltalake] @ git+https://github.com/ibis-project/ibis -xlsx2csv -XlsxWriter - - -# ai -marvin==1.3.0 -openai<=1.0 - -# gui -#reflex -streamlit # docs quartodoc diff --git a/justfile b/justfile index e40ec17..ac12a49 100644 --- a/justfile +++ b/justfile @@ -5,6 +5,7 @@ set dotenv-load # aliases alias fmt := format +alias marvin-docs := docs-marvin # list justfile recipes default: @@ -14,19 +15,20 @@ default: ipy *args: birdbrain ipy {{ args }} +# install +install: + @pip install -e '.' + # setup setup: @pip install -r dev-requirements.txt + just install # build build: just clean @python -m build -# install -install: - @pip install -e '.' - # uninstall uninstall: @pip uninstall ibis-birdbrain -y @@ -63,3 +65,9 @@ clean: @rm -rf *.ddb* || True @rm -rf data/*.parquet || True +# open docs +docs: + @open https://ibis-project.github.io/ibis-birdbrain/ + +docs-marvin: + @open https://www.askmarvin.ai/welcome/what_is_marvin/ diff --git a/pyproject.toml b/pyproject.toml index a2dbd13..2eeaadc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,6 @@ +[tool.hatch.metadata] +allow-direct-references = true + [build-system] requires = ["hatchling"] build-backend = "hatchling.build" @@ -20,14 +23,14 @@ dependencies = [ 'ipython', 'python-dotenv', 'toml', + 'httpx', 'Pillow', 'typer[all]', 'requests', 'html2text', 'duckduckgo-search', - 'marvin==1.3.0', - 'openai', - 'ibis-framework[duckdb,polars,deltalake]', + 'marvin>2,<3', + 'ibis-framework[duckdb] @ git+https://github.com/ibis-project/ibis', 'plotly', 'streamlit', ] diff --git a/src/ibis_birdbrain/bot.py b/src/ibis_birdbrain/bot.py index 0f1a842..0f4fbc6 100644 --- a/src/ibis_birdbrain/bot.py +++ b/src/ibis_birdbrain/bot.py @@ -1,12 +1,9 @@ -"""Ibis Birdbrain bot. - -A bot can be called to perform tasks on behalf of a user, in turn calling -its available tools (including other bots) to perform those tasks. -""" - # imports import ibis +import marvin +import inspect +from enum import Enum from uuid import uuid4 from typing import Any from datetime import datetime @@ -14,48 +11,222 @@ from ibis.backends.base import BaseBackend from ibis_birdbrain.logging import log -from ibis_birdbrain.messages import Message +from ibis_birdbrain.attachments import ( + Attachment, + Attachments, + TableAttachment, + CodeAttachment, +) +from ibis_birdbrain.messages import Message, Messages, Email from ibis_birdbrain.utils.messages import to_message +# strings +description = """ +# Ibis Birdbrain + +Ibis "birdbrain" Birdbrain is the portable ML-powered data bot. + +## Overview + +birdbrain communicates with a user through messages and attachments, like email. +This is part of the "system intiialization" message that instructs the bot on +how to behave. The bot MUST follow the user's instructions. Messages are +organized from oldest to newest in descending order. + +Messages are separated by `---`. Attachments are at the bottom of the message. + +## Flows + +Based on the context from the bot's messages, a flow will be selected and +performed. This will result in a series of messagse with attachments to act on +behalf of the user. The bot will then respond with a message to the user. + +## Instructions + +You MUST follow these instructions: + +- be concise; ignore platitudes and do not use them +- be professional; speak in the tone of a staff-level data scientist +- use standard markdown format to communicate (for long messages only) +- DO NOT write any Message metadata; the surrounding system handles that +- if asked basic information (schema, description, etc) about the data, just respond +- if queried about the data, run SQL code to answer the query + +## Attachments + +You have access to the following attachments: +""" + +description = inspect.cleandoc(description) + +flow_instructions = """ +Choose the flow that makes sense for the bot given the context of the messages. + +Respond if you have all the information needed to respond to the user. +Otherwise, choose one of the flows to generate additional messages. +""" +flow_instructions = inspect.cleandoc(flow_instructions) + +eda_flow_instructions = """ +Choose the flow that makes sense for the bot given the context of the messages. + +Get the pre-existing code if it exists and is relevant. Fix code if an error was +encounter. Write code if no code exists. Execute code to get the results. +""" + # classes +class Flows(Enum): + """Ibis Birdbrain flows.""" + + RESPOND = "respond" + SQL_CODE = "sql_code" + VISUALIZE = "visualize" + + +class EDAFlows(Enum): + """Ibis Birdbrain EDA flows.""" + + GET_CODE = "get_code" + FIX_CODE = "fix_code" + WRITE_CODE = "write_code" + EXECUTE_CODE = "execute_code" + + +# functions +@marvin.fn +def respond(messages: Messages) -> str: + """Respond to the user. Write the BODY of the message only""" + + +@marvin.fn +def messages_to_text_query(messages: Messages) -> str: + """Convert the messages to a text query.""" + + +@marvin.fn +def _text_to_sql(text: str, attachments: Attachments) -> str: + """Convert the text to SQL code to execute on the attachments. + + Return only a SQL SELECT statement. + """ + + +def text_to_sql(text: str, attachments: Attachments) -> str: + """Text to SQL""" + return _text_to_sql(text, attachments).strip().strip(";") + + +def respond_flow(messages: Messages) -> Messages: + pass + + +def sql_flow(messages: Messages) -> Messages: + extract_guid_instructions = f""" + Extract relevant attachment GUIDs (ONLY the ATTACHMENT GUIDs) from the messages. + + Options include: {messages.attachments()} + """ + + rm = Messages() + + extract_guid_instructions = inspect.cleandoc(extract_guid_instructions) + + guids = marvin.extract( + messages, + str, + instructions=extract_guid_instructions, + ) + log.info(f"Extracted GUIDs: {guids}") + + # get the attachments + attachments = Attachments() + # TODO: fix this ugliness + for guid in guids: + for message in messages: + if guid in messages[message].attachments: + attachments.append(messages[message].attachments[guid]) + log.info(f"Attachments: {attachments}") + + # get the text query + text_query = messages_to_text_query(messages) + + # convert the text to SQL + sql = text_to_sql(text_query, attachments) + a = CodeAttachment(language="sql", content=sql) + + # construct the response message + m = Email( + body=f"SQL attachted for query: {text_query}", + subject="SQL code", + attachments=[a], + ) + + # append the message to the response messages + rm.append(m) + + return rm + + +def visualize_flow(messages: Messages) -> Messages: + pass + + +# bot class Bot: """Ibis Birdbrain bot.""" id: str created_at: datetime - data: dict[str, BaseBackend] + con: BaseBackend name: str user_name: str description: str version: str + messages: Messages current_subject: str def __init__( self, - data: dict[str, str] = { - "system": "duckdb://birdbrain.ddb", - "memory": "duckdb://", - }, + con=ibis.connect("duckdb://birdbrain.ddb"), name="birdbrain", user_name="user", - description="Ibis Birdbrain bot.", + description=description, version="infinity", + messages=Messages(), ) -> None: """Initialize the bot.""" self.id = uuid4() self.created_at = datetime.now() - self.data = {k: ibis.connect(v) for k, v in data.items()} + self.con = con self.name = name self.user_name = user_name self.description = description self.version = version + self.messages = messages self.current_subject = "" + # get table attachments from con + attachments = Attachments() + for table in con.list_tables(): + a = TableAttachment(con.table(table)) + attachments.append(a) + + # system initialization message + m = Email( + body=self.description, + subject="system initialization", + to_address=self.name, + from_address=self.name, + attachments=attachments, + ) + self.messages.append(m) + + def __call__( self, text: str = "Who are you and what can you do?", @@ -63,7 +234,39 @@ def __call__( ) -> Message: """Call upon the bot.""" + # convert user input to message log.info(f"Bot {self.name} called with text: {text}") im = to_message(text, stuff) - return im + # add message to messages + self.messages.append(im) + + # get the flow + flow = marvin.classify( + str(self.messages), + Flows, + instructions=flow_instructions, + ) + log.info(f"Bot {self.name} selected flow: {flow}") + + match flow: + case Flows.RESPOND: + response = respond(self.messages) + m = Email( + body=response, + subject="response", + to_address=self.user_name, + from_address=self.name, + ) + self.messages.append(m) + case Flows.SQL_CODE: + ms = sql_flow(self.messages) + # TODO: fix this ugliness + for m in ms: + self.messages.append(ms[m]) + case Flows.VISUALIZE: + pass + case _: + pass + + return self.messages[-1] diff --git a/src/ibis_birdbrain/commands/ipy.py b/src/ibis_birdbrain/commands/ipy.py index 94f0cca..9ad2f9e 100644 --- a/src/ibis_birdbrain/commands/ipy.py +++ b/src/ibis_birdbrain/commands/ipy.py @@ -8,10 +8,7 @@ def ipy_run(interactive=False): # config ibis.options.interactive = True ibis.options.repr.interactive.max_rows = 20 - ibis.options.repr.interactive.max_columns = 20 - - # setup bot - bot = Bot() + ibis.options.repr.interactive.max_columns = None\ # start IPython IPython.embed(colors="neutral") diff --git a/untitled.ipynb b/untitled.ipynb new file mode 100644 index 0000000..ca47b1c --- /dev/null +++ b/untitled.ipynb @@ -0,0 +1,618 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "import ibis\n", + "import inspect\n", + "\n", + "from ibis_birdbrain import Bot" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "ibis.options.interactive = True\n", + "ibis.options.repr.interactive.max_rows = 20\n", + "ibis.options.repr.interactive.max_columns = None" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "if False:\n", + " filename = \"mortgage.parquet\"\n", + " con = ibis.connect(\"duckdb://mortgage.ddb\")\n", + "\n", + " t = con.read_parquet(filename)\n", + " con.create_table(\"mortgage\", t)\n", + "\n", + "if False:\n", + " con = ibis.connect(\"duckdb://imdb.ddb\")\n", + " ex_str = \"imdb\"\n", + "\n", + " for name, obj in inspect.getmembers(ibis.examples):\n", + " if ex_str in name:\n", + " con.create_table(name, obj.fetch().to_pyarrow())\n" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "con = ibis.connect(\"duckdb://mortgage.ddb\")\n", + "bot = Bot(con=con)" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "1" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "len(bot.messages)" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "INFO:root:Bot birdbrain called with text: describe the data\n" + ] + }, + { + "data": { + "text/html": [ + "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n",
+      "INFO:root:Bot birdbrain selected flow: Flows.RESPOND\n"
+     ]
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "To: user\n",
+       "From: birdbrain\n",
+       "Subject: response\n",
+       "Sent at: 2024-02-12 20:59:18.917163\n",
+       "Message: f46a6a5b-7395-4d23-8c35-dd60e8c9203b\n",
+       "\n",
+       "The data is a table with mortgage loan information, including fields such as loan and servicer identifiers, loan terms, borrower's credit score, loan status, property details, and financial metrics. Schema provided in the request details the types and names of each column.\n",
+       "\n",
+       "Attachments:\n",
+       "\n"
+      ]
+     },
+     "execution_count": 6,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "bot(\"describe the data\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 7,
+   "metadata": {},
+   "outputs": [
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "INFO:root:Bot birdbrain called with text: what's the average interest rate?\n"
+     ]
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n",
+      "INFO:root:Bot birdbrain selected flow: Flows.SQL_CODE\n"
+     ]
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n",
+      "INFO:root:Extracted GUIDs: ['bb0114da-7c18-4fbb-a141-b734133ec4f5']\n"
+     ]
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "INFO:root:Attachments: TableAttachment\n",
+      "    **guid**: bb0114da-7c18-4fbb-a141-b734133ec4f5\n",
+      "    **time**: 2024-02-12 20:59:11.185707\n",
+      "    **name**: mortgage\n",
+      "    **desc**: \n",
+      "ibis.Schema {\n",
+      "  reference_pool_id                         string\n",
+      "  loan_id                                   string\n",
+      "  monthly_reporting_period                  string\n",
+      "  channel                                   string\n",
+      "  seller_name                               string\n",
+      "  servicer_name                             string\n",
+      "  master_servicer                           string\n",
+      "  original_interest_rate                    float64\n",
+      "  current_interest_rate                     float64\n",
+      "  original_upb                              float64\n",
+      "  upb_at_issuance                           float64\n",
+      "  current_upb                               float64\n",
+      "  original_loan_term                        int32\n",
+      "  origination_date                          string\n",
+      "  first_payment_date                        string\n",
+      "  loan_age                                  int64\n",
+      "  remaining_months_to_legal_maturity        int32\n",
+      "  remaining_months_to_maturity              int32\n",
+      "  maturity_date                             string\n",
+      "  original_ltv                              int64\n",
+      "  original_cltv                             int64\n",
+      "  number_of_borrowers                       int32\n",
+      "  dti                                       float64\n",
+      "  borrower_credit_score_at_origination      int32\n",
+      "  coborrower_credit_score_at_origination    int32\n",
+      "  first_time_buyer                          string\n",
+      "  loan_purpose                              string\n",
+      "  property_type                             string\n",
+      "  number_of_units                           int64\n",
+      "  occupancy_status                          string\n",
+      "  property_state                            string\n",
+      "  msa                                       string\n",
+      "  zip                                       string\n",
+      "  mortgage_issuance_percentage              float64\n",
+      "  amortization_type                         string\n",
+      "  payment_penalty_flag                      string\n",
+      "  interest_only_flag                        string\n",
+      "  interest_only_first_payment               string\n",
+      "  months_to_amortization                    int32\n",
+      "  current_loan_delinquency_status           string\n",
+      "  loan_payment_history                      string\n",
+      "  modification_flag                         string\n",
+      "  mortgage_insurance_cancellation_flag      string\n",
+      "  zero_balance_code                         string\n",
+      "  zero_balance_effective_date               string\n",
+      "  upb_at_removal                            float64\n",
+      "  repurchase_date                           string\n",
+      "  scheduled_principal_current               float64\n",
+      "  total_principal_current                   float64\n",
+      "  unscheduled_principal_current             float64\n",
+      "  last_paid_installment_date                string\n",
+      "  foreclosure_date                          string\n",
+      "  disposition_date                          string\n",
+      "  foreclosure_costs                         float64\n",
+      "  preservation_repair_costs                 float64\n",
+      "  asset_recovery_costs                      float64\n",
+      "  misc_holding_expenses                     float64\n",
+      "  taxes_holding_property                    float64\n",
+      "  net_sales_proceeds                        float64\n",
+      "  credit_enhancement_proceeds               float64\n",
+      "  repurchase_make_whole_proceeds            float64\n",
+      "  other_foreclosure_proceeds                float64\n",
+      "  modification_noninterest_bearing_upb      float64\n",
+      "  principal_foregiveness_amount             float64\n",
+      "  original_list_start_date                  string\n",
+      "  original_list_price                       int64\n",
+      "  current_list_start_date                   string\n",
+      "  current_list_price                        int64\n",
+      "  borrower_credit_score_at_issuance         int32\n",
+      "  coborrower_credit_score_at_issuance       int32\n",
+      "  borrower_credit_score_current             int32\n",
+      "  coborrower_credit_score_current           int32\n",
+      "  mortgage_insurance_type                   string\n",
+      "  servicing_activity_flag                   string\n",
+      "  current_period_modification_loss_amount   float64\n",
+      "  cumulative_modification_loss_amount       float64\n",
+      "  current_period_net_gain_loss              float64\n",
+      "  cumulative_period_net_gain_loss           float64\n",
+      "  special_eligibility_program               string\n",
+      "  foreclosure_principal_writeoff_amount     float64\n",
+      "  relocation_mortgage_indicator             string\n",
+      "  zero_balance_code_change_date             string\n",
+      "  loan_holdback_flag                        string\n",
+      "  loan_holdback_effective_date              string\n",
+      "  delinquent_accrued_interest               float64\n",
+      "  property_valuation_method                 string\n",
+      "  high_balance_loan_indicator               string\n",
+      "  arm_initial_rate_period_less_than_5y      string\n",
+      "  arm_product_type                          string\n",
+      "  initial_fixed_rate_period                 int32\n",
+      "  interest_rate_adjustment_frequency        int32\n",
+      "  next_interest_rate_adjustment_date        string\n",
+      "  next_payment_change_date                  string\n",
+      "  index                                     string\n",
+      "  arm_cap_structure                         string\n",
+      "  initial_interest_rate_cap_up_percent      float64\n",
+      "  periodic_interest_rate_cap_up_percent     float64\n",
+      "  lifetime_interest_rate_cap_up_percent     float64\n",
+      "  mortgage_margin                           float64\n",
+      "  arm_baloon_indicator                      string\n",
+      "  arm_plan_number                           int32\n",
+      "  borrower_assistance_plan                  string\n",
+      "  hltv_refi_option_flag                     string\n",
+      "  deal_name                                 string\n",
+      "  repurchase_make_whole_proceeds_flag       string\n",
+      "  alternative_delinquency_resolution        string\n",
+      "  alternative_delinquency_resolution_count  int32\n",
+      "  total_deferral_amount                     float64\n",
+      "}\n",
+      "    **table**:\n",
+      "┏━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━┳\n",
+      "┃\u001b[1m \u001b[0m\u001b[1mreference_pool_id\u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mloan_id\u001b[0m\u001b[1m     \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mmonthly_reporting_period\u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mchannel\u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mseller_name\u001b[0m\u001b[1m            \u001b[0m\u001b[1m \u001b[0m┃\u001b[1m \u001b[0m\u001b[1mservicer_name\u001b[0m\u001b[1m \u001b[0m┃\n",
+      "┡━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━╇\n",
+      "│ \u001b[2mstring\u001b[0m            │ \u001b[2mstring\u001b[0m       │ \u001b[2mstring\u001b[0m                   │ \u001b[2mstring\u001b[0m  │ \u001b[2mstring\u001b[0m                  │ \u001b[2mstring\u001b[0m        │\n",
+      "├───────────────────┼──────────────┼──────────────────────────┼─────────┼─────────────────────────┼───────────────┼\n",
+      "│ \u001b[2m~\u001b[0m                 │ \u001b[32m100007365142\u001b[0m │ \u001b[32m012000                  \u001b[0m │ \u001b[32mR      \u001b[0m │ \u001b[32mJpmorgan Chase Bank, Na\u001b[0m │ \u001b[2m~\u001b[0m             │\n",
+      "│ \u001b[2m~\u001b[0m                 │ \u001b[32m100007365142\u001b[0m │ \u001b[32m022000                  \u001b[0m │ \u001b[32mR      \u001b[0m │ \u001b[32mJpmorgan Chase Bank, Na\u001b[0m │ \u001b[2m~\u001b[0m             │\n",
+      "│ \u001b[2m~\u001b[0m                 │ \u001b[32m100007365142\u001b[0m │ \u001b[32m032000                  \u001b[0m │ \u001b[32mR      \u001b[0m │ \u001b[32mJpmorgan Chase Bank, Na\u001b[0m │ \u001b[2m~\u001b[0m             │\n",
+      "│ \u001b[2m~\u001b[0m                 │ \u001b[32m100007365142\u001b[0m │ \u001b[32m042000                  \u001b[0m │ \u001b[32mR      \u001b[0m │ \u001b[32mJpmorgan Chase Bank, Na\u001b[0m │ \u001b[2m~\u001b[0m             │\n",
+      "│ \u001b[2m~\u001b[0m                 │ \u001b[32m100007365142\u001b[0m │ \u001b[32m052000                  \u001b[0m │ \u001b[32mR      \u001b[0m │ \u001b[32mJpmorgan Chase Bank, Na\u001b[0m │ \u001b[2m~\u001b[0m             │\n",
+      "│ \u001b[2m~\u001b[0m                 │ \u001b[32m100007365142\u001b[0m │ \u001b[32m062000                  \u001b[0m │ \u001b[32mR      \u001b[0m │ \u001b[32mJpmorgan Chase Bank, Na\u001b[0m │ \u001b[2m~\u001b[0m             │\n",
+      "│ \u001b[2m~\u001b[0m                 │ \u001b[32m100007365142\u001b[0m │ \u001b[32m072000                  \u001b[0m │ \u001b[32mR      \u001b[0m │ \u001b[32mJpmorgan Chase Bank, Na\u001b[0m │ \u001b[2m~\u001b[0m             │\n",
+      "│ \u001b[2m~\u001b[0m                 │ \u001b[32m100007365142\u001b[0m │ \u001b[32m082000                  \u001b[0m │ \u001b[32mR      \u001b[0m │ \u001b[32mJpmorgan Chase Bank, Na\u001b[0m │ \u001b[2m~\u001b[0m             │\n",
+      "│ \u001b[2m~\u001b[0m                 │ \u001b[32m100007365142\u001b[0m │ \u001b[32m092000                  \u001b[0m │ \u001b[32mR      \u001b[0m │ \u001b[32mJpmorgan Chase Bank, Na\u001b[0m │ \u001b[2m~\u001b[0m             │\n",
+      "│ \u001b[2m~\u001b[0m                 │ \u001b[32m100007365142\u001b[0m │ \u001b[32m102000                  \u001b[0m │ \u001b[32mR      \u001b[0m │ \u001b[32mJpmorgan Chase Bank, Na\u001b[0m │ \u001b[2m~\u001b[0m             │\n",
+      "│ \u001b[2m~\u001b[0m                 │ \u001b[32m100007365142\u001b[0m │ \u001b[32m112000                  \u001b[0m │ \u001b[32mR      \u001b[0m │ \u001b[32mJpmorgan Chase Bank, Na\u001b[0m │ \u001b[2m~\u001b[0m             │\n",
+      "│ \u001b[2m~\u001b[0m                 │ \u001b[32m100007365142\u001b[0m │ \u001b[32m122000                  \u001b[0m │ \u001b[32mR      \u001b[0m │ \u001b[32mJpmorgan Chase Bank, Na\u001b[0m │ \u001b[2m~\u001b[0m             │\n",
+      "│ \u001b[2m~\u001b[0m                 │ \u001b[32m100007365142\u001b[0m │ \u001b[32m012001                  \u001b[0m │ \u001b[32mR      \u001b[0m │ \u001b[32mJpmorgan Chase Bank, Na\u001b[0m │ \u001b[2m~\u001b[0m             │\n",
+      "│ \u001b[2m~\u001b[0m                 │ \u001b[32m100007365142\u001b[0m │ \u001b[32m022001                  \u001b[0m │ \u001b[32mR      \u001b[0m │ \u001b[32mJpmorgan Chase Bank, Na\u001b[0m │ \u001b[2m~\u001b[0m             │\n",
+      "│ \u001b[2m~\u001b[0m                 │ \u001b[32m100007365142\u001b[0m │ \u001b[32m032001                  \u001b[0m │ \u001b[32mR      \u001b[0m │ \u001b[32mJpmorgan Chase Bank, Na\u001b[0m │ \u001b[2m~\u001b[0m             │\n",
+      "│ \u001b[2m~\u001b[0m                 │ \u001b[32m100007365142\u001b[0m │ \u001b[32m042001                  \u001b[0m │ \u001b[32mR      \u001b[0m │ \u001b[32mJpmorgan Chase Bank, Na\u001b[0m │ \u001b[2m~\u001b[0m             │\n",
+      "│ \u001b[2m~\u001b[0m                 │ \u001b[32m100007365142\u001b[0m │ \u001b[32m052001                  \u001b[0m │ \u001b[32mR      \u001b[0m │ \u001b[32mJpmorgan Chase Bank, Na\u001b[0m │ \u001b[2m~\u001b[0m             │\n",
+      "│ \u001b[2m~\u001b[0m                 │ \u001b[32m100007365142\u001b[0m │ \u001b[32m062001                  \u001b[0m │ \u001b[32mR      \u001b[0m │ \u001b[32mJpmorgan Chase Bank, Na\u001b[0m │ \u001b[2m~\u001b[0m             │\n",
+      "│ \u001b[2m~\u001b[0m                 │ \u001b[32m100007365142\u001b[0m │ \u001b[32m072001                  \u001b[0m │ \u001b[32mR      \u001b[0m │ \u001b[32mJpmorgan Chase Bank, Na\u001b[0m │ \u001b[2m~\u001b[0m             │\n",
+      "│ \u001b[2m~\u001b[0m                 │ \u001b[32m100007365142\u001b[0m │ \u001b[32m082001                  \u001b[0m │ \u001b[32mR      \u001b[0m │ \u001b[32mJpmorgan Chase Bank, Na\u001b[0m │ \u001b[2m~\u001b[0m             │\n",
+      "│ \u001b[2m…\u001b[0m                 │ \u001b[2m…\u001b[0m            │ \u001b[2m…\u001b[0m                        │ \u001b[2m…\u001b[0m       │ \u001b[2m…\u001b[0m                       │ \u001b[2m…\u001b[0m             │\n",
+      "└───────────────────┴──────────────┴──────────────────────────┴─────────┴─────────────────────────┴───────────────┴\n"
+     ]
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n"
+     ]
+    },
+    {
+     "data": {
+      "text/html": [
+       "
\n"
+      ],
+      "text/plain": []
+     },
+     "metadata": {},
+     "output_type": "display_data"
+    },
+    {
+     "name": "stderr",
+     "output_type": "stream",
+     "text": [
+      "INFO:httpx:HTTP Request: POST https://api.openai.com/v1/chat/completions \"HTTP/1.1 200 OK\"\n"
+     ]
+    },
+    {
+     "data": {
+      "text/plain": [
+       "To: \n",
+       "From: \n",
+       "Subject: SQL code\n",
+       "Sent at: 2024-02-12 20:59:35.895894\n",
+       "Message: 0a8b58b5-7399-4074-9245-d2515d9ba77b\n",
+       "\n",
+       "SQL attachted for query: SELECT AVG(original_interest_rate) as average_interest_rate FROM mortgage\n",
+       "\n",
+       "Attachments:\n",
+       "\n",
+       "CodeAttachment\n",
+       "    **guid**: 1064f4a2-6533-4058-874e-088e99911aa7\n",
+       "    **time**: 2024-02-12 20:59:35.895868\n",
+       "    **name**: None\n",
+       "    **desc**: None\n",
+       "    **text**:\n",
+       "SELECT AVG(original_interest_rate) as average_interest_rate FROM mortgage\n",
+       "    **language**: sql\n",
+       "    **code**:\n",
+       "SELECT AVG(original_interest_rate) as average_interest_rate FROM mortgage"
+      ]
+     },
+     "execution_count": 7,
+     "metadata": {},
+     "output_type": "execute_result"
+    }
+   ],
+   "source": [
+    "bot(\"what's the average interest rate?\")"
+   ]
+  },
+  {
+   "cell_type": "code",
+   "execution_count": 8,
+   "metadata": {},
+   "outputs": [
+    {
+     "data": {
+      "text/html": [
+       "
┏━━━━━━━━━━━━━━━━━━━━━━━┓\n",
+       "┃ average_interest_rate ┃\n",
+       "┡━━━━━━━━━━━━━━━━━━━━━━━┩\n",
+       "│ float64               │\n",
+       "├───────────────────────┤\n",
+       "│              7.960559 │\n",
+       "└───────────────────────┘\n",
+       "
\n" + ], + "text/plain": [ + "┏━━━━━━━━━━━━━━━━━━━━━━━┓\n", + "┃\u001b[1m \u001b[0m\u001b[1maverage_interest_rate\u001b[0m\u001b[1m \u001b[0m┃\n", + "┡━━━━━━━━━━━━━━━━━━━━━━━┩\n", + "│ \u001b[2mfloat64\u001b[0m │\n", + "├───────────────────────┤\n", + "│ \u001b[1;36m7.960559\u001b[0m │\n", + "└───────────────────────┘" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "bot.con.sql(\"SELECT AVG(original_interest_rate) as average_interest_rate FROM mortgage\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "bot(\"who are you?\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "bot(\"analyze that data for me\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "bot(\"visualize that data for me\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from ibis_birdbrain.bot import Flows" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# list options in the Flows Enum class\n", + "\n", + "for flow in Flows:\n", + " print(flow.name)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "bot.messages" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "len(bot.messages)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "bot.con" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "bot.name" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "bot.user_name" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "bot.description" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "bot.version" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from ibis_birdbrain.bot import description" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(description)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "venv", + "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.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +}