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 +}