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

Dev to Main #6

Merged
merged 19 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 11 additions & 5 deletions .github/workflows/python-app.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,8 @@
name: Python application

on:
push:
branches: [ "main" ]
pull_request:
branches: [ "main" ]
branches: [ "main","dev" ]

permissions:
contents: read
Expand All @@ -19,15 +17,21 @@ jobs:

steps:
- uses: actions/checkout@v4
- name: Set up Python 3.10
- name: Set up Python 3.12.3
uses: actions/setup-python@v3
with:
python-version: "3.10"
python-version: "3.12.3"
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install flake8 pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Install this package
run: |
pip install -e .
- name: Install Jupyter
run: |
pip install jupyter
- name: Lint with flake8
run: |
# stop the build if there are Python syntax errors or undefined names
Expand All @@ -37,3 +41,5 @@ jobs:
- name: Test with pytest
run: |
pytest
env:
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
11 changes: 11 additions & 0 deletions data/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# __init__.py

# This is the initialization file for the data module.

# Import any necessary modules or packages here

# Define any global variables or constants here

# Define any functions or classes here

# Add any necessary code to initialize the module here
9 changes: 9 additions & 0 deletions data/components.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
[
{
"Name": "Number Slider",
"Description": "A slider for selecting a numeric value.",
"IsCoreComponent": true,
"Inputs": [],
"Outputs": [
{ "Name": "Value", "DataType": "Number", "IsOptional": false }
]
},
{
"Name": "Cull Pattern",
"Description": "Cull (remove) elements in a list using a repeating bit mask.",
Expand Down
11 changes: 11 additions & 0 deletions data/components.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import json
import os


# Load the components.json file to a dictionary variable
def load_components():
# file path needed to work with pytest
dir_path = os.path.dirname(os.path.realpath(__file__))
with open(os.path.join(dir_path, 'components.json'), 'r') as f:
components_dict = json.load(f)
return components_dict
11 changes: 11 additions & 0 deletions models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# __init__.py

# This is the initialization file for the models module.

# Import any necessary modules or packages here

# Define any global variables or constants here

# Define any functions or classes here

# Add any necessary code to initialize the module here
79 changes: 79 additions & 0 deletions models/grasshopper_script_model_test.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
{
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"metadata": {},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"{'ChainOfThought': 'Use the sphere component with a number slider as input to set the radius', 'Advice': 'Adjust the radius of the sphere using a number slider for desired size', 'Additions': [{'Name': 'Sphere', 'Id': 1, 'Value': None}, {'Name': 'Number Slider', 'Id': 2, 'Value': '5..50..100'}], 'Connections': [{'From': {'Id': 2, 'ParameterName': 'Number'}, 'To': {'Id': 1, 'ParameterName': 'Radius'}}]}\n"
]
}
],
"source": [
"from pydantic import ValidationError\n",
"\n",
"from models import GrasshopperScriptModel\n",
"\n",
"# Example usage:\n",
"example_json = {\n",
" \"ChainOfThought\": \"Use the sphere component with a number slider as input to set the radius\",\n",
" \"Advice\": \"Adjust the radius of the sphere using a number slider for desired size\",\n",
" \"Additions\": [\n",
" {\n",
" \"Name\": \"Sphere\",\n",
" \"Id\": 1\n",
" },\n",
" {\n",
" \"Name\": \"Number Slider\",\n",
" \"Id\": 2,\n",
" \"Value\": \"5..50..100\"\n",
" }\n",
" ],\n",
" \"Connections\": [\n",
" {\n",
" \"To\": {\n",
" \"Id\": 1,\n",
" \"ParameterName\": \"Radius\"\n",
" },\n",
" \"From\": {\n",
" \"Id\": 2,\n",
" \"ParameterName\": \"Number\"\n",
" }\n",
" }\n",
" ]\n",
"}\n",
"\n",
"try:\n",
" config = GrasshopperScriptModel(**example_json)\n",
" print(config.model_dump())\n",
"except ValidationError as e:\n",
" print(e)"
]
}
],
"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.12.3"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
101 changes: 101 additions & 0 deletions models/models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
from pydantic import BaseModel, Field, field_validator
from typing import List, Optional
from data.components import load_components

components_dict = load_components()


class Component(BaseModel):
Name: str = Field(
...,
description="The name of the component to be added. Only standard"
"grasshopper components are allowed"
)
Id: int = Field(
...,
description="A unique identifier for the component, starting from 1"
"and counting upwards"
)
Value: Optional[str] = Field(
None,
alias='Value',
description="The range of values for the component, if applicable."
"Only to be used for Panel, Number Slider,"
"or Point components"
)

@field_validator("Name")
@classmethod
def validate_name_exists(cls, v):
name_iterator = (component["Name"] for component in components_dict)
if v not in name_iterator:
raise ValueError(f"The component {v} could not be found, either"
"there is a typo or it does not exist. Please"
"choose a valid component.")
return v


class InputConnectionDetail(BaseModel):
Id: int = Field(
...,
description="The unique identifier of the component the connection is"
"related to"
)
ParameterName: str = Field(
...,
description="The specific input parameter of the component that the"
"connection affects"
)


class OutputConnectionDetail(BaseModel):
Id: int = Field(
...,
description="The unique identifier of the component the connection is"
"related to"
)
ParameterName: str = Field(
...,
description="The specific output parameter of the component that the"
"connection affects"
)


class Connection(BaseModel):
From: OutputConnectionDetail = Field(
...,
description="The source component and parameter from which the"
"connection originates"
)
To: InputConnectionDetail = Field(
...,
description="The target component and parameter that the connection is"
"directing to"
)


class GrasshopperScriptModel(BaseModel):
"""
A representation of a grasshopper script with all grasshopper components
and the connections between them.
Use Number Slider for variable inputs to the script
"""
ChainOfThought: str = Field(
...,
description="step by step rational explaining how the script acheives "
"the aim, including the main components used"
)
Advice: str = Field(
...,
description="A piece of advice or instruction related to using the "
"grasshopper script"
)
Additions: List[Component] = Field(
...,
description="A list of components to be added to the configuration"
)
Connections: List[Connection] = Field(
...,
description="A list of connections defining relationships between "
"components' parameters"
)
50 changes: 17 additions & 33 deletions notebooks/ghpt_baseline.ipynb

Large diffs are not rendered by default.

173 changes: 32 additions & 141 deletions notebooks/ghpt_instructor.ipynb

Large diffs are not rendered by default.

35 changes: 35 additions & 0 deletions notebooks/test_notebooks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import os
import nbformat
from nbconvert.preprocessors import ExecutePreprocessor
import pytest

# file path needed to work with pytest
dir_path = os.path.dirname(os.path.realpath(__file__))
notebooks = [
os.path.join(dir_path, 'ghpt_baseline.ipynb'),
os.path.join(dir_path, 'ghpt_instructor.ipynb')
]


@pytest.mark.parametrize("notebook", notebooks)
def test_notebooks(notebook):
"""
Test function to execute and validate a Jupyter notebook.

Args:
notebook (str): The path to the Jupyter notebook file.

Raises:
AssertionError: If the notebook is empty or execution fails.
"""
with open(notebook) as f:
nb = nbformat.read(f, as_version=4)
ep = ExecutePreprocessor(timeout=600, kernel_name='python3')
try:
executed_nb, _ = ep.preprocess(
nb,
{'metadata': {'path': dir_path}}
)
assert executed_nb, f"Got empty notebook for {notebook}"
except Exception as e:
assert False, f"Failed executing {notebook}: {str(e)}"
5 changes: 4 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@ openai
requests
python-dotenv
instructor
anthropic
anthropic
nbformat
nbconvert
pytest
Loading