Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/access for rdb resource #374

Open
wants to merge 45 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
5e2eb15
preparare doundation
aran-nakayama Sep 29, 2024
e25cfe9
working with mock data
aran-nakayama Sep 29, 2024
35b5eae
use vannna to make sql and pass to the dana agent through dbresource
aran-nakayama Oct 1, 2024
001f6d5
make file for making example table and data
aran-nakayama Oct 1, 2024
3c047f4
train vanna for generating SQL from prompt
aran-nakayama Oct 2, 2024
0d63e06
resource data is taple and it seems that openssa has difficulty to un…
aran-nakayama Oct 3, 2024
ffae625
make myvanna file to clean code
aran-nakayama Oct 3, 2024
47ecfe8
TypeError: Can't instantiate abstract class DbResource without an imp…
Oct 11, 2024
86c0840
change how to import from openssa to try to make it work (but it didn't)
Oct 18, 2024
4e9f648
nailcare
aran-nakayama Oct 22, 2024
27d9c37
nailcare
aran-nakayama Oct 22, 2024
39b218b
save tmp (need to be fixed)
aran-nakayama Oct 22, 2024
7227879
style: reformat code
phanhongan Oct 26, 2024
f27c9ed
refactor: replace random.choice by secrets.choice to avoid security r…
phanhongan Oct 26, 2024
2ade37a
Merge from `main`
phanhongan Oct 26, 2024
82432fb
style: add empty lines and space
phanhongan Oct 26, 2024
2ec3e3a
style: add empty lines
phanhongan Oct 26, 2024
5a93152
style: rearrange imports
phanhongan Oct 26, 2024
7f9f044
refactor: replace Exception by ValueError & RuntimeError
phanhongan Oct 26, 2024
08a2170
style: import 3rd party before 1st party
phanhongan Oct 26, 2024
4c51982
fix: add default db port
phanhongan Oct 26, 2024
654b8f7
fix: add default db port as string
phanhongan Oct 26, 2024
c255aa9
build: add pymysql
phanhongan Oct 26, 2024
9bf2495
fix: set default values for DB connection
phanhongan Oct 26, 2024
2030be4
ci: add MySQL to Mac
phanhongan Oct 26, 2024
16220cd
ci: install Docker for pulling MySQL
phanhongan Oct 26, 2024
a5a1a8a
ci: setup Docker Buildx
phanhongan Oct 26, 2024
4921af5
ci: setup MySQL on Ubuntu
phanhongan Oct 26, 2024
9fbf2ce
ci: wait for MySQL to be ready
phanhongan Oct 26, 2024
e9ee662
ci: use random root password for MySQL
phanhongan Oct 26, 2024
965881c
ci: remove MYSQL_USER="root"
phanhongan Oct 26, 2024
78f0789
ci: remove MYSQL_USER="root" in test env
phanhongan Oct 26, 2024
e44b6ab
ci: use empty password for MySQL
phanhongan Oct 26, 2024
0a0e048
ci: remove MYSQL_USER="root" if using MYSQL_ALLOW_EMPTY_PASSWORD
phanhongan Oct 26, 2024
35063d0
ci: run db migrations before testing
phanhongan Oct 26, 2024
7cdbeae
build: add alembic
phanhongan Oct 26, 2024
54135fe
test: add alembic
phanhongan Oct 26, 2024
ff1df64
ci: install alembic
phanhongan Oct 26, 2024
d042cf5
ci: init alembic
phanhongan Oct 26, 2024
e6e6426
ci: install MySQL driver
phanhongan Oct 26, 2024
a2edf10
ci: use pymysql when running db migration
phanhongan Oct 26, 2024
cff10f6
ci: no password in db connection
phanhongan Oct 26, 2024
ef5aa89
ci: add alembic.ini
phanhongan Oct 27, 2024
aaba05d
fix: put alembic.ini in `openssa`
phanhongan Oct 27, 2024
3ea10b7
fix: put alembic.ini in root
phanhongan Oct 27, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 29 additions & 1 deletion .github/workflows/install-lint-test-on-mac.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,25 @@ jobs:

strategy:
matrix:
python-version: # github.com/actions/python-versions/releases
python-version: # github.com/actions/python-versions/releases
- 3.12
# - 3.13

services:
mysql:
image: mysql:9.1.0
env:
MYSQL_USER: root
MYSQL_PASSWORD: password
MYSQL_DATABASE: test
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping --silent"
--health-interval=10s
--health-timeout=5s
--health-retries=3

steps:
- name: Checkout Repo
uses: actions/checkout@v4 # github.com/actions/checkout
Expand All @@ -28,12 +43,22 @@ jobs:
with:
python-version: ${{ matrix.python-version }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2

- name: Install Poetry
run: make get-poetry

- name: Install Package & Dependencies
run: make install

- name: Wait for MySQL to be ready
run: |
until mysqladmin ping -h 127.0.0.1 --silent; do
echo "Waiting for MySQL..."
sleep 5
done

- name: Lint Code
run: make lint

Expand All @@ -42,3 +67,6 @@ jobs:
env:
LEPTON_API_KEY: ${{ secrets.LEPTON_API_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
MYSQL_USER: root
MYSQL_PASSWORD: password
MYSQL_DATABASE: test
31 changes: 31 additions & 0 deletions .github/workflows/install-lint-test-on-ubuntu.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,20 @@ jobs:
- 3.12
# - 3.13

services:
mysql:
image: mysql:latest
env:
MYSQL_ALLOW_EMPTY_PASSWORD: "yes"
MYSQL_DATABASE: test
ports:
- 3306:3306
options: >-
--health-cmd="mysqladmin ping --silent"
--health-interval=10s
--health-timeout=5s
--health-retries=3

steps:
- name: Checkout Repo
uses: actions/checkout@v4 # github.com/actions/checkout
Expand All @@ -34,6 +48,22 @@ jobs:
- name: Install Package & Dependencies
run: make install

- name: Wait for MySQL to be ready
run: |
until mysqladmin ping -h 127.0.0.1 --silent; do
echo "Waiting for MySQL..."
sleep 5
done

- name: Install Alembic
run: pip install alembic

- name: Run Migrations
run: |
python -m alembic upgrade head
env:
DATABASE_URL: mysql+pymysql://[email protected]/test

- name: Lint Code
run: make lint

Expand All @@ -42,3 +72,4 @@ jobs:
env:
LEPTON_API_KEY: ${{ secrets.LEPTON_API_KEY }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
DB_NAME: test
85 changes: 85 additions & 0 deletions alembic.ini
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# A generic, single database configuration.

[alembic]
# path to migration scripts
script_location = alembic

# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s

# timezone to use when rendering the date
# within the migration file as well as the filename.
# string value is passed to dateutil.tz.gettz()
# leave blank for localtime
# timezone =

# max length of characters to apply to the
# "slug" field
# truncate_slug_length = 40

# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false

# set to 'true' to allow .pyc and .pyo files without
# a source .py file to be detected as revisions in the
# versions/ directory
# sourceless = false

# version location specification; this defaults
# to alembic/versions. When using multiple version
# directories, initial revisions must be specified with --version-path
# version_locations = %(here)s/bar %(here)s/bat alembic/versions

# the output encoding used when revision files
# are written from script.py.mako
# output_encoding = utf-8

sqlalchemy.url = mysql+pymysql://user:pass@localhost/dbname


[post_write_hooks]
# post_write_hooks defines scripts or Python functions that are run
# on newly generated revision scripts. See the documentation for further
# detail and examples

# format using "black" - use the console_scripts runner, against the "black" entrypoint
# hooks=black
# black.type=console_scripts
# black.entrypoint=black
# black.options=-l 79

# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARN
handlers = console
qualname =

[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine

[logger_alembic]
level = INFO
handlers =
qualname = alembic

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S
Binary file added chroma.sqlite3
Binary file not shown.
1 change: 1 addition & 0 deletions examples/japanese-easy-demo/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ readme = "README.md"
[tool.poetry.dependencies]
python = ">=3.12,<3.13"
openssa = "^0.24.3.12"
python-dotenv = "^1.0.1"


[build-system]
Expand Down
7 changes: 7 additions & 0 deletions examples/use-rdb-resource/.env.template
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
OPENAI_API_KEY=your openai API key

DB_USERNAME=your_username
DB_PASSWORD=your_password
DB_HOST=your_host
DB_PORT=your_port
DB_NAME=your_database_name
4 changes: 4 additions & 0 deletions examples/use-rdb-resource/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
db_config.yaml
Chinook.sqlite
chroma.sqlite3
*.bin
26 changes: 26 additions & 0 deletions examples/use-rdb-resource/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Access Database resources and inference by DANA

## What is this example doing?

- Use DbResource file to get data from RDB(MySQL) Using SQL made by Vanna, and answer question by DANA.

## Setting-up

- What you need
- commands (if you are mac user, you can install those things by Homebrew)
- mysql
- Also, create or use existing database for this example.
- poetry
- API Key
- Use your own OpenAI API key

- Setting up Commands
- `cd examples/use-rdb-resource`
- `poetry install`
- `cp .env.template .env`
- update .env data with your environment data
- `poetry run python make_example_table_data.py`
- if this command doesn't work, then run `poetry env use 3.12`
- change python version to resolve dependensies version
- `poetry run python main.py`
- run main file to answer question by DANA using DbResource, and see the result in the terminal.
41 changes: 41 additions & 0 deletions examples/use-rdb-resource/main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
from dotenv import load_dotenv

from myvanna import generate_sql_from_prompt

# from openssa import DANA, DbResource
from openssa.core.agent.dana import DANA # , FileResource
from openssa.core.resource.db import DbResource

load_dotenv()


def get_or_create_agent(query) -> DANA:
return DANA(
resources=[DbResource(query=query)]
)


def solve(question, query) -> str:
agent = get_or_create_agent(query)
try:
return agent.solve(problem=question)
except ValueError as err:
return f'ERROR: {err}'
except RuntimeError as err:
return f'ERROR: {err}'


if __name__ == '__main__':
QUESTION = (
"Can you list the products in order of sales volume from highest to lowest?"
)

query = generate_sql_from_prompt(QUESTION)
print(query)
answer = solve(QUESTION, query)

print('--------------------------------')
print(answer)
print('--------------------------------')
print(query)
print('--------------------------------')
103 changes: 103 additions & 0 deletions examples/use-rdb-resource/make_example_table_data.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import os
import random
import secrets

from dotenv import load_dotenv
from faker import Faker
from sqlalchemy import Column, Integer, String, Date, inspect, create_engine
from sqlalchemy.orm import sessionmaker, declarative_base

from myvanna import train_vanna_for_sales_data

load_dotenv()

Base = declarative_base()


class SalesData(Base):
__tablename__ = 'sales_data'
sale_id = Column(Integer, primary_key=True, autoincrement=True)
product_id = Column(Integer)
product_name = Column(String(255))
sale_date = Column(Date)
region = Column(String(255))


class MySQLDatabase:
def __init__(self):
self.engine = self.create_engine()
self.Session = sessionmaker(bind=self.engine)

def create_engine(self):
username = os.getenv('DB_USERNAME')
password = os.getenv('DB_PASSWORD')
host = os.getenv('DB_HOST')
port = os.getenv('DB_PORT')
database = os.getenv('DB_NAME')
connection_string = f'mysql+pymysql://{username}:{password}@{host}:{port}/{database}'
return create_engine(connection_string)

def get_session(self):
return self.Session()

def create_tables(self):
Base.metadata.create_all(self.engine)

def drop_table(self, table_class):
inspector = inspect(self.engine)
if inspector.has_table(table_class.__tablename__):
table_class.__table__.drop(self.engine)


fake = Faker()
seed_value = 42
random.seed(seed_value)
Faker.seed(seed_value)

products = [
{"id": 101, "name": "Smartwatch", "price": 150.00},
{"id": 102, "name": "Laptop", "price": 1200.00},
{"id": 103, "name": "Smartphone", "price": 800.00},
{"id": 104, "name": "Tablet", "price": 400.00},
{"id": 105, "name": "Headphones", "price": 100.00}
]

regions = ["North America", "Europe", "Asia", "South America", "Africa"]


def generate_sales_data(session, num_records):
sales_data_list = []
for _ in range(num_records):
product = secrets.choice(products)
region = secrets.choice(regions)
sale_date = fake.date_between(start_date='-1y', end_date='today')
sales_data = SalesData(
product_id=product["id"],
product_name=product["name"],
sale_date=sale_date,
region=region
)
sales_data_list.append(sales_data)
session.bulk_save_objects(sales_data_list)
session.commit()


if __name__ == "__main__":
db = MySQLDatabase()

db.drop_table(SalesData)
db.create_tables()

session = db.get_session()

generate_sales_data(session, 20000)

train_vanna_for_sales_data("""
CREATE TABLE sales_data (
sale_id INT PRIMARY KEY AUTO_INCREMENT,
product_id INT,
product_name VARCHAR(255),
sale_date DATE,
region VARCHAR(255)
)
""")
Loading
Loading