Skip to content
This repository has been archived by the owner on Oct 24, 2023. It is now read-only.

OpenAI nodes #196

Open
wants to merge 50 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
c42c686
dalle node
vinicvaz Jul 3, 2023
45f757f
node docstring
vinicvaz Jul 3, 2023
689e13b
dalle unit test
vinicvaz Jul 3, 2023
8405720
whisper node
vinicvaz Jul 4, 2023
f7c96f5
json extractor node with test
vinicvaz Jul 4, 2023
e6bd680
update json extractor node
vinicvaz Jul 5, 2023
540b78e
update docstrings
vinicvaz Jul 5, 2023
81d1f2b
update docstrings
vinicvaz Jul 5, 2023
d560621
black
vinicvaz Jul 5, 2023
9dd24b1
nodes using previous node bytes value
vinicvaz Jul 6, 2023
c124755
mp3 option to load local file node
vinicvaz Jul 6, 2023
17e3fcc
wav file format
vinicvaz Jul 7, 2023
ee99c28
add example.md and app.txt to nodes
vinicvaz Jul 7, 2023
7297469
docstring
vinicvaz Jul 7, 2023
080bb06
openai node using new nodes api
vinicvaz Jul 13, 2023
4bfa969
removed args from decorator
vinicvaz Jul 13, 2023
2404144
update localfile loader case condition
vinicvaz Jul 13, 2023
f636dc9
update whisper logic
vinicvaz Jul 13, 2023
3b6e81a
add width and height to dalle
vinicvaz Jul 13, 2023
388e579
add run in venv
vinicvaz Jul 20, 2023
410a2f5
Merge branch 'new-node-api' of https://github.com/flojoy-io/nodes int…
vinicvaz Jul 20, 2023
1b38d0f
add openai key exception
vinicvaz Jul 20, 2023
ad1a4a2
update test
vinicvaz Jul 20, 2023
3c42aa3
dalle with retry
vinicvaz Jul 20, 2023
4f04095
usin b64 format from api
vinicvaz Jul 20, 2023
e114c57
add retry to json and whisper
vinicvaz Jul 20, 2023
aaad2fb
remove continue from retry
vinicvaz Jul 21, 2023
d6f30e7
remove openai from requirements
vinicvaz Jul 21, 2023
bdd149d
Merge branch 'main' into feat/openai-nodes
luiztauffer Jul 25, 2023
ccf80c6
fixes, formatting and imports
luiztauffer Jul 25, 2023
40df23d
Merge pull request #146 from Tauffer-Consulting/feat/openai-nodes
luiztauffer Jul 25, 2023
92e8d03
update speech to text to use textblob type
vinicvaz Aug 1, 2023
6e7249c
update app
vinicvaz Aug 1, 2023
5cad6b9
update properties to list of strings typing
vinicvaz Aug 1, 2023
660fc11
remove default argument from schema
vinicvaz Aug 1, 2023
dc260e6
bytes with b arg
vinicvaz Aug 1, 2023
9fb1510
deleting manifest
vinicvaz Aug 1, 2023
9c62528
whisper bytes b argument
vinicvaz Aug 1, 2023
aca13c6
WHISPER docstring
vinicvaz Aug 1, 2023
40186f6
update json extractor app
vinicvaz Aug 1, 2023
1142bd1
update dalle app
vinicvaz Aug 1, 2023
de4415a
Merge branch 'main' of https://github.com/flojoy-io/nodes into feat/o…
vinicvaz Aug 1, 2023
f568f59
Merge branch 'main' of https://github.com/flojoy-io/nodes into feat/o…
vinicvaz Aug 3, 2023
ca98294
comment tests
vinicvaz Aug 3, 2023
009685f
Merge branch 'main' of https://github.com/flojoy-io/nodes into feat/o…
vinicvaz Aug 4, 2023
3c9749d
black fix
vinicvaz Aug 4, 2023
aac2e8f
Merge branch 'main' into feat/openai-nodes
luiztauffer Aug 5, 2023
51528f1
Merge branch 'main' of https://github.com/flojoy-io/nodes into feat/o…
vinicvaz Aug 9, 2023
f9f5883
fix test type
vinicvaz Aug 9, 2023
43b878b
Merge branch 'main' of https://github.com/flojoy-io/nodes into feat/o…
Sep 15, 2023
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
80 changes: 80 additions & 0 deletions AI_ML/OPENAI/DALLE_IMAGE_GENERATOR/DALLE_IMAGE_GENERATOR.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import numpy as np
from flojoy import flojoy, Image, run_in_venv
import base64
from io import BytesIO
import os
import time

API_RETRY_ATTEMPTS = 5
API_RETRY_INTERVAL_IN_SECONDS = 1


@flojoy
@run_in_venv(pip_dependencies=["openai==0.27.8", "Pillow==10.0.0", "requests==2.28.1"])
def DALLE_IMAGE_GENERATOR(
prompt: str,
width: int = 1024,
height: int = 1024,
) -> Image:
"""
The DALLE_IMAGE_GENERATOR node takes a prompt and generates an image
using OpenAI's DALL-E model.
The prompt should be a sentence describing the image you want to generate.
The image will be returned as a DataContainer with the type 'image'.

Parameters
----------
prompt: string
A sentence describing the image you want to generate.
width: int
The width of the generated image.
height: int
The height of the generated image.
"""
import openai
from PIL import Image as PilImage

api_key = os.environ.get("OPENAI_API_KEY")
if not api_key:
raise Exception("OPENAI_API_KEY environment variable not set")

openai.api_key = api_key

for i in range(API_RETRY_ATTEMPTS):
try:
result = openai.Image.create(
prompt=prompt, n=1, size=f"{width}x{height}", response_format="b64_json"
)
print(f"No error in attempt {i} of generating image")
break
except openai.error.RateLimitError:
if i > API_RETRY_ATTEMPTS:
raise Exception("Rate limit error. Max retries exceeded.")

print(
f"Rate limit error, retrying in {API_RETRY_INTERVAL_IN_SECONDS} seconds"
)
time.sleep(API_RETRY_INTERVAL_IN_SECONDS)

if not result.data:
raise Exception("No image data in result")

base64_content = result.get("data")[0].get("b64_json")
image_data = base64.b64decode(base64_content)
img = PilImage.open(BytesIO(image_data))

img_array = np.asarray(img)
red_channel = img_array[:, :, 0]
green_channel = img_array[:, :, 1]
blue_channel = img_array[:, :, 2]

alpha_channel = None
if img_array.shape[2] == 4:
alpha_channel = img_array[:, :, 3]

return Image(
r=red_channel,
g=green_channel,
b=blue_channel,
a=alpha_channel,
)
28 changes: 28 additions & 0 deletions AI_ML/OPENAI/DALLE_IMAGE_GENERATOR/DALLE_IMAGE_GENERATOR_test_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import numpy
import pytest
import os


def test_DALLE_IMAGE_GENERATOR_no_api_key(mock_flojoy_decorator):
import DALLE_IMAGE_GENERATOR

with pytest.raises(Exception, match="OPENAI_API_KEY environment variable not set"):
prompt = "A painting of a cat"
res = DALLE_IMAGE_GENERATOR.DALLE_IMAGE_GENERATOR(
prompt=prompt,
)


def test_DALLE_IMAGE_GENERATOR(mock_flojoy_decorator):
api_key = os.getenv("OPENAI_API_KEY", None)
if api_key:
import DALLE_IMAGE_GENERATOR

prompt = "A painting of a cat"
res = DALLE_IMAGE_GENERATOR.DALLE_IMAGE_GENERATOR(
prompt=prompt,
)
assert res.type == "image"
assert isinstance(res.r, numpy.ndarray)
assert isinstance(res.g, numpy.ndarray)
assert isinstance(res.b, numpy.ndarray)
139 changes: 139 additions & 0 deletions AI_ML/OPENAI/DALLE_IMAGE_GENERATOR/app.txt
vinicvaz marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
{
"rfInstance": {
"nodes": [
{
"width": 208,
"height": 96,
"id": "DALLE_IMAGE_GENERATOR-73998810-4081-4630-adf6-8097b610118b",
"type": "AI_ML",
"data": {
"id": "DALLE_IMAGE_GENERATOR-73998810-4081-4630-adf6-8097b610118b",
"label": "DALLE IMAGE GENERATOR",
"func": "DALLE_IMAGE_GENERATOR",
"type": "AI_ML",
"ctrls": {
"prompt": {
"type": "str",
"default": null,
"desc": "A sentence describing the image you want to generate.",
"functionName": "DALLE_IMAGE_GENERATOR",
"param": "prompt",
"value": "A painting of a cat"
},
"width": {
"type": "int",
"default": 1024,
"desc": "The width of the generated image.",
"functionName": "DALLE_IMAGE_GENERATOR",
"param": "width",
"value": 1024
},
"height": {
"type": "int",
"default": 1024,
"desc": "The height of the generated image.",
"functionName": "DALLE_IMAGE_GENERATOR",
"param": "height",
"value": 1024
}
},
"outputs": [
{
"name": "default",
"id": "default",
"type": "Image",
"desc": null
}
],
"path": "PYTHON/nodes/AI_ML/OPENAI/DALLE_IMAGE_GENERATOR/DALLE_IMAGE_GENERATOR.py",
"selected": false
},
"position": {
"x": -155.761959015441,
"y": 338.9736881910637
},
"selected": false,
"positionAbsolute": {
"x": -155.761959015441,
"y": 338.9736881910637
},
"dragging": true
},
{
"width": 225,
"height": 226,
"id": "IMAGE-6886e358-8587-4e15-9486-910e911e79b5",
"type": "VISUALIZERS",
"data": {
"id": "IMAGE-6886e358-8587-4e15-9486-910e911e79b5",
"label": "IMAGE",
"func": "IMAGE",
"type": "VISUALIZERS",
"ctrls": {},
"inputs": [
{
"name": "default",
"id": "default",
"type": "Image",
"multiple": false,
"desc": null
}
],
"outputs": [
{
"name": "default",
"id": "default",
"type": "Plotly",
"desc": null
}
],
"path": "PYTHON/nodes/VISUALIZERS/PLOTLY/IMAGE/IMAGE.py",
"selected": false
},
"position": {
"x": 455.6504364167843,
"y": 307.93171338391926
},
"selected": false,
"positionAbsolute": {
"x": 455.6504364167843,
"y": 307.93171338391926
},
"dragging": true
}
],
"edges": [
{
"source": "DALLE_IMAGE_GENERATOR-73998810-4081-4630-adf6-8097b610118b",
"sourceHandle": "default",
"target": "IMAGE-6886e358-8587-4e15-9486-910e911e79b5",
"targetHandle": "default",
"id": "reactflow__edge-DALLE_IMAGE_GENERATOR-73998810-4081-4630-adf6-8097b610118bdefault-IMAGE-6886e358-8587-4e15-9486-910e911e79b5default"
}
],
"viewport": {
"x": 716.6989575195756,
"y": 316.2258438592044,
"zoom": 1.2380988852096646
}
},
"ctrlsManifest": [
{
"type": "input",
"name": "Slider",
"id": "INPUT_PLACEHOLDER",
"hidden": false,
"minHeight": 1,
"minWidth": 2,
"layout": {
"x": 0,
"y": 0,
"h": 2,
"w": 2,
"minH": 1,
"minW": 2,
"i": "INPUT_PLACEHOLDER"
}
}
]
}
6 changes: 6 additions & 0 deletions AI_ML/OPENAI/DALLE_IMAGE_GENERATOR/example.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
This app uses the DALL-E node to generate images from text.
Based on the users input, the node will generate an image and pass it to the next node.
The input text is defined in the node's form, for this app we are using the following text:
```
A cute baby sea otter
```
82 changes: 82 additions & 0 deletions AI_ML/OPENAI/JSON_EXTRACTOR/JSON_EXTRACTOR.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
from flojoy import flojoy, DataFrame as FlojoyDataFrame, run_in_venv
import os
import json
from copy import deepcopy
import time


ACCEPTED_SCHEMA_FORMATS = [".json"]

BASE_SCHEMA = {
"name": "information_extraction",
"description": "Extracts the information as JSON.",
"parameters": {"type": "object", "properties": {}, "required": []},
}

API_RETRY_ATTEMPTS = 5
API_RETRY_INTERVAL_IN_SECONDS = 1


@flojoy
@run_in_venv(pip_dependencies=["openai==0.27.8", "pandas==2.0.2"])
def JSON_EXTRACTOR(
properties: list[str],
prompt: str,
) -> FlojoyDataFrame:
"""
The JSON_EXTRACTOR node extract specific properties information from a text using JSON schema.

Parameters
----------
properties: string
Comma separated list of properties to extract. Example: "name,age,location"
prompt: string
Text to extract information from. Example: "I'm John, I am 30 years old and I live in New York."
"""
import openai
import pandas as pd

api_key = os.environ.get("OPENAI_API_KEY")
if not api_key:
raise Exception("OPENAI_API_KEY environment variable not set")
openai.api_key = api_key

if not properties:
raise Exception("No properties found to extract.")

schema = deepcopy(BASE_SCHEMA)
for property in properties:
schema["parameters"]["properties"][property] = {
"title": property,
"type": "string",
}
schema["parameters"]["required"].append(property)

for i in range(API_RETRY_ATTEMPTS):
try:
response = openai.ChatCompletion.create(
model="gpt-3.5-turbo-0613",
messages=[
{"role": "user", "content": prompt},
],
temperature=0,
functions=[schema],
function_call={"name": schema['name']},
)
print(f"No error in attempt {i} of extraction.")
break
except openai.error.RateLimitError:
if i > API_RETRY_ATTEMPTS:
raise Exception("Rate limit error. Max retries exceeded.")

print(
f"Rate limit error, retrying in {API_RETRY_INTERVAL_IN_SECONDS} seconds"
)
time.sleep(API_RETRY_INTERVAL_IN_SECONDS)

if not response.choices:
raise Exception("No extraction choices found in response.")

data = json.loads(response.choices[0].message.function_call.arguments)
df = pd.DataFrame(data=[data])
return FlojoyDataFrame(df=df)
32 changes: 32 additions & 0 deletions AI_ML/OPENAI/JSON_EXTRACTOR/JSON_EXTRACTOR_test_.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import pytest
import os


def test_DALLE_IMAGE_GENERATOR_no_api_key(mock_flojoy_decorator):
import JSON_EXTRACTOR

with pytest.raises(Exception, match="OPENAI_API_KEY environment variable not set"):
properties = "price,name,model"
prompt = """Headset Gamer Bluetooth MJ23 - $100
Extract the price, name and model from the above text."""
res = JSON_EXTRACTOR.JSON_EXTRACTOR(
properties=properties,
prompt=prompt,
)


def test_JSON_EXTRACTOR(mock_flojoy_decorator):
api_key = os.getenv("OPENAI_API_KEY", None)
if api_key:
import JSON_EXTRACTOR

properties = "price,name,model"
prompt = """Headset Gamer Bluetooth MJ23 - $100
Extract the price, name and model from the above text."""
mock_properties_list = ["price", "name", "model"]
res = JSON_EXTRACTOR.JSON_EXTRACTOR(
properties=properties,
prompt=prompt,
)
for property in mock_properties_list:
assert property in res.m.columns
Loading