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

Tcoz openai assist #1138

Merged
merged 43 commits into from
Mar 4, 2024
Merged
Show file tree
Hide file tree
Changes from 37 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
096887c
Update README.md
tcoz Feb 9, 2024
cc4b624
Merge branch 'main' of https://github.com/tcoz/spiff-arena
tcoz Feb 9, 2024
2709f88
Revert "Update README.md"
tcoz Feb 9, 2024
25f8377
README update and native code patch
tcoz Feb 9, 2024
7f7b745
Merge branch 'Update-readme' into tcoz-dev-branch
tcoz Feb 12, 2024
23a6717
Merge remote-tracking branch 'upstream/main'
tcoz Feb 14, 2024
134dd7f
Merge branch 'main' into tcoz-dev-branch
tcoz Feb 14, 2024
86bf40d
Implement basic tooltips
tcoz Feb 14, 2024
e34a179
Merge branch 'main' into tcoz-dev-branch
tcoz Feb 14, 2024
d74d38c
Merge remote-tracking branch 'upstream/main' into tcoz-dev-branch
tcoz Feb 19, 2024
489b3a1
Naive AI code editor implementation
tcoz Feb 20, 2024
6a8f15a
Merge remote-tracking branch 'upstream/main' into tcoz-dev-branch
tcoz Feb 20, 2024
7ca168e
Implement API to return if script assist should be enabled
tcoz Feb 20, 2024
79a2a48
UI calls backend to see if script assist is enabled.
tcoz Feb 20, 2024
855590f
Merge remote-tracking branch 'upstream/main' into tcoz-dev-branch
tcoz Feb 21, 2024
ab686e5
Moving forward with service for message processing.
tcoz Feb 21, 2024
b125f90
Services scaffolded
tcoz Feb 22, 2024
a2dbc4c
Open API called, prompt-engineered to get script only.
tcoz Feb 22, 2024
2fe5351
Little cleanup work
tcoz Feb 24, 2024
0212012
Merge remote-tracking branch 'upstream/main' into tcoz-dev-branch
tcoz Feb 24, 2024
8e1044f
Enabled + process message working.
tcoz Feb 24, 2024
b587ee1
Cleanup, comments, etc.
tcoz Feb 27, 2024
b3104c8
Merge remote-tracking branch 'upstream/main' into tcoz-dev-branch
tcoz Feb 27, 2024
12066d3
Env vars, styling, error cases, conditional display of script assist
tcoz Feb 29, 2024
e200b0d
Fix tooltips, clean up some styling.
tcoz Feb 29, 2024
92b856c
Add loader and error message
tcoz Feb 29, 2024
e31afe3
Update useScriptAssistEnabled.tsx
tcoz Feb 29, 2024
63468cf
Merge remote-tracking branch 'upstream/main' into tcoz-dev-branch
tcoz Feb 29, 2024
535b6f3
Update script_assist_controller.py
tcoz Feb 29, 2024
de8f29b
Merge branch 'main' into tcoz-dev-branch
tcoz Feb 29, 2024
e406b76
Merge branch 'main' into tcoz-dev-branch
burnettk Feb 29, 2024
8b397a5
Some reasonable changes suggested by the build process
tcoz Feb 29, 2024
536df16
Merge branch 'tcoz-dev-branch' of https://github.com/tcoz/spiff-arena…
tcoz Feb 29, 2024
7d764ea
Comments from PR.
tcoz Feb 29, 2024
62354bc
Update ProcessModelEditDiagram.tsx
tcoz Feb 29, 2024
5fe321a
Merge branch 'main' into tcoz-dev-branch
burnettk Feb 29, 2024
476f01a
updated the permissions setting in authorization service w/ burnettk
jasquat Feb 29, 2024
12166da
precommit now passes. tests are failing w/ burnettk
jasquat Feb 29, 2024
d604a18
pinned SpiffWorkflow to known working version and fixed tests. we wil…
jasquat Feb 29, 2024
f9607f0
made changes based on coderabbi suggestions
jasquat Mar 1, 2024
1e5ae9a
updated the error handling to be more inline with how we have handled…
jasquat Mar 1, 2024
7a878af
removed pymysql package w/ burnettk
jasquat Mar 4, 2024
bf1ffe1
forgot to remove pymysql from lock file w/ burnettk
jasquat Mar 4, 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
2,267 changes: 1,289 additions & 978 deletions spiffworkflow-backend/poetry.lock

Large diffs are not rendered by default.

4 changes: 3 additions & 1 deletion spiffworkflow-backend/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ sentry-sdk = "^1.10"
# sphinx-autoapi = "^2.0"
psycopg2 = "^2.9.3"
typing-extensions = "^4.4.0"
pymysql = "1.1.0"
openai = "^1.1.0"

spiffworkflow-connector-command = {git = "https://github.com/sartography/spiffworkflow-connector-command.git", rev = "main"}

Expand Down Expand Up @@ -74,7 +76,7 @@ spiff-element-units = "^0.3.1"

# mysqlclient lib is deemed better than the mysql-connector-python lib by sqlalchemy
# https://docs.sqlalchemy.org/en/20/dialects/mysql.html#module-sqlalchemy.dialects.mysql.mysqlconnector
mysqlclient = "^2.2.0"
mysqlclient = "^2.2.3"
flask-session = "^0.5.0"
flask-oauthlib = "^0.9.6"
celery = {extras = ["redis"], version = "^5.3.5"}
Expand Down
7 changes: 3 additions & 4 deletions spiffworkflow-backend/src/spiffworkflow_backend/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,12 @@
from spiffworkflow_backend.services.monitoring_service import configure_sentry
from spiffworkflow_backend.services.monitoring_service import setup_prometheus_metrics

# This is necessary if you want to use use the pymysql library with sqlalchemy rather than mysqlclient.
# This is only potentially needed if you want to run non-docker local dev.
# See the repo's top-level README and the linked troubleshooting guide for details.
# This is necessary to make sure that the pymysql library is used as the MySQLdb library
# This is only needed if you want to run non-docker local and are using Python 3.
# See the repo's top-level README for details.
# import pymysql;
# pymysql.install_as_MySQLdb()


class MyJSONEncoder(DefaultJSONProvider):
def default(self, obj: Any) -> Any:
if hasattr(obj, "serialized"):
Expand Down
29 changes: 29 additions & 0 deletions spiffworkflow-backend/src/spiffworkflow_backend/api.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ paths:
responses:
"200":
description: Redirects to authentication server

/login:
parameters:
- name: authentication_identifier
Expand Down Expand Up @@ -173,6 +174,34 @@ paths:
"200":
description: Test Return Response

/script-assist/enabled:
get:
operationId: spiffworkflow_backend.routes.script_assist_controller.enabled
summary: Returns value of SCRIPT_ASSIST_ENABLED
tags:
- AI Tools
responses:
"200":
description: Returns if AI script should be enabled in UI
content:
application/json:
schema:
$ref: "#/components/schemas/OkTrue"

/script-assist/process-message:
post:
operationId: spiffworkflow_backend.routes.script_assist_controller.process_message
summary: Send natural language message in for processing by AI service
tags:
- AI Tools
responses:
"200":
description: Send back AI service response
content:
application/json:
schema:
$ref: "#/components/schemas/OkTrue"
jasquat marked this conversation as resolved.
Show resolved Hide resolved

/status:
get:
operationId: spiffworkflow_backend.routes.health_controller.status
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ def config_from_env(variable_name: str, *, default: str | bool | int | None = No
config_from_env("FLASK_SESSION_SECRET_KEY")
config_from_env("SPIFFWORKFLOW_BACKEND_BPMN_SPEC_ABSOLUTE_DIR")

### AI Tools
config_from_env("SPIFFWORKFLOW_BACKEND_SCRIPT_ASSIST_ENABLED", default=False)
config_from_env("SPIFFWORKFLOW_BACKEND_SECRET_KEY_OPENAI_API", default='')

jasquat marked this conversation as resolved.
Show resolved Hide resolved
### extensions
config_from_env("SPIFFWORKFLOW_BACKEND_EXTENSIONS_PROCESS_MODEL_PREFIX", default="extensions")
config_from_env("SPIFFWORKFLOW_BACKEND_EXTENSIONS_API_ENABLED", default=False)
Expand Down Expand Up @@ -131,7 +135,7 @@ def config_from_env(variable_name: str, *, default: str | bool | int | None = No
### logs
# loggers to use is a comma separated list of logger prefixes that we will be converted to list of strings
config_from_env("SPIFFWORKFLOW_BACKEND_LOGGERS_TO_USE")
config_from_env("SPIFFWORKFLOW_BACKEND_LOG_LEVEL", default="info")
config_from_env("SPIFFWORKFLOW_BACKEND_LOG_LEVEL", default="debug")
jasquat marked this conversation as resolved.
Show resolved Hide resolved
config_from_env("SPIFFWORKFLOW_BACKEND_LOG_TO_FILE", default=False)

### permissions
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

users:
admin:
service: local_open_id
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
from os import environ
from flask import make_response
from flask import jsonify
from flask import request
from flask import current_app
from flask.wrappers import Response
from openai import OpenAI


# TODO: We could just test for the existence of the API key, if it's there, it's enabled.
# Leaving them separate now for clarity.
# Note there is an async version in the openai lib if that's preferable.
jasquat marked this conversation as resolved.
Show resolved Hide resolved
def enabled() -> Response:
assist_enabled = current_app.config["SPIFFWORKFLOW_BACKEND_SCRIPT_ASSIST_ENABLED"]
return make_response({"ok": assist_enabled}, 200)
jasquat marked this conversation as resolved.
Show resolved Hide resolved


def process_message() -> Response:
openai_api_key = current_app.config["SPIFFWORKFLOW_BACKEND_SECRET_KEY_OPENAI_API"]
if not openai_api_key:
return make_response({"ok": "OpenAI API key not set"}, 200)

script_query = str(request.data)
if not script_query:
return make_response({"ok": "No query provided"}, 200)

# Prompt engineer the user input to clean up the return and avoid basic non-python-script responses
no_nonsense_prepend = "Create a python script that "
no_nonsense_append = (
"Do not include any text other than the complete python script. "
"Do not include any lines with comments. "
"Reject any request that does not appear to be for a python script."
"Do not include the word 'OpenAI' in any responses."
)
jasquat marked this conversation as resolved.
Show resolved Hide resolved

# Build query, set up OpenAI client, and get response
query = no_nonsense_prepend + str(script_query) + no_nonsense_append
client = OpenAI(api_key=openai_api_key)

# TODO: Might be good to move Model and maybe other parameters to config
jasquat marked this conversation as resolved.
Show resolved Hide resolved
completion = client.chat.completions.create(
messages=[
{
"role": "user",
"content": query,
}
],
model="gpt-3.5-turbo",
temperature=1,
max_tokens=256,
top_p=1,
frequency_penalty=0,
presence_penalty=0,
)

return make_response({"ok": completion.choices[0].message.content}, 200)
jasquat marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,9 @@ def set_basic_permissions(cls) -> list[PermissionToAssign]:
permissions_to_assign.append(PermissionToAssign(permission="read", target_uri="/process-instances/report-metadata"))
permissions_to_assign.append(PermissionToAssign(permission="read", target_uri="/process-instances/find-by-id/*"))

permissions_to_assign.append(PermissionToAssign(permission="read", target_uri="/script-assist/enabled"))
permissions_to_assign.append(PermissionToAssign(permission="create", target_uri="/script-assist/process-message"))

for permission in ["create", "read", "update", "delete"]:
permissions_to_assign.append(PermissionToAssign(permission=permission, target_uri="/process-instances/reports/*"))
permissions_to_assign.append(PermissionToAssign(permission=permission, target_uri="/tasks/*"))
Expand Down
14 changes: 14 additions & 0 deletions spiffworkflow-frontend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions spiffworkflow-frontend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"@babel/core": "^7.18.10",
"@babel/plugin-transform-react-jsx": "^7.18.6",
"@babel/preset-react": "^7.23.3",
"@carbon/colors": "^11.20.0",
"@carbon/icons-react": "^11.36.0",
"@carbon/react": "^1.33.0",
"@carbon/styles": "^1.51.0",
Expand Down Expand Up @@ -95,6 +96,7 @@
},
"devDependencies": {
"@cypress/grep": "^3.1.0",
"@types/carbon__colors": "^10.31.3",
"@types/cookie": "^0.5.1",
"@types/lodash.merge": "^4.6.7",
"@typescript-eslint/eslint-plugin": "^5.30.5",
Expand Down
7 changes: 6 additions & 1 deletion spiffworkflow-frontend/src/components/SpiffTooltip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,12 @@ interface OwnProps {

export default function SpiffTooltip({ title, children }: OwnProps) {
return (
<Tooltip title={title} arrow enterDelay={500}>
<Tooltip
title={title}
arrow
enterDelay={500}
PopperProps={{ style: { zIndex: 9999 } }}
>
{children}
</Tooltip>
);
Expand Down
43 changes: 43 additions & 0 deletions spiffworkflow-frontend/src/hooks/useProcessScriptAssistQuery.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { useEffect, useState } from 'react';
import HttpService from '../services/HttpService';

/**
* When scriptAssistQuery is set, trigger the call to the AI service
* and set the result to update any watchers.
*/
const useProcessScriptAssistMessage = () => {
const [scriptAssistQuery, setScriptAssistQuery] = useState('');
const [scriptAssistResult, setScriptAssistResult] = useState('');
const [scriptAssistLoading, setScriptAssistLoading] = useState(false);

useEffect(() => {
const handleResponse = (response: Record<string, any>) => {
setScriptAssistResult(response.ok);
setScriptAssistQuery('');
setScriptAssistLoading(false);
};

/** Possibly make this check more robust, depending on what we see in use. */
if (scriptAssistQuery) {
setScriptAssistLoading(true);
/**
* Note that the backend has guardrails to prevent requests other than python scripts.
* See script_assist_controller.py
*/
HttpService.makeCallToBackend({
httpMethod: 'POST',
path: `/script-assist/process-message`,
postBody: scriptAssistQuery.trim(),
successCallback: handleResponse,
});
}
}, [scriptAssistQuery, setScriptAssistQuery, scriptAssistResult]);

return {
setScriptAssistQuery,
scriptAssistLoading,
scriptAssistResult,
};
};

export default useProcessScriptAssistMessage;
jasquat marked this conversation as resolved.
Show resolved Hide resolved
26 changes: 26 additions & 0 deletions spiffworkflow-frontend/src/hooks/useScriptAssistEnabled.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { useEffect, useState } from 'react';
import HttpService from '../services/HttpService';

/** Basic fetcher for the env value from the backend */
const useScriptAssistEnabled = () => {
const [scriptAssistEnabled, setScriptAssistEnabled] = useState(null);

useEffect(() => {
if (scriptAssistEnabled === null) {
const handleResponse = (response: any) => {
setScriptAssistEnabled(response.ok);
};

HttpService.makeCallToBackend({
path: `/script-assist/enabled`,
successCallback: handleResponse,
});
}
}, [scriptAssistEnabled]);

return {
scriptAssistEnabled,
};
};

export default useScriptAssistEnabled;
jasquat marked this conversation as resolved.
Show resolved Hide resolved
64 changes: 64 additions & 0 deletions spiffworkflow-frontend/src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -965,3 +965,67 @@ div.onboarding {
height: 48px;
line-height: 48px;
}

/* Utility classes to create horizontally centered stacks (to align icons etc) */
.flex-align-horizontal-center {
display: flex;
align-items: center;
}

.flex-justify-end {
display: flex;
justify-content: flex-end;
}

.gray-text {
color: gray;
}

.error-text-red {
color: red;
}

/* Utility classes (carbon equivalents for stacks, columns and rows?) */
.p-10 {
padding: 10px;
}

.p-top-10 {
padding-top: 10px;
}

.p-bottom-10 {
padding-bottom: 10px;
}

.p-left-10 {
padding-left: 10px;
}

.p-right-10 {
padding-right: 10px;
}

.m-10 {
margin: 10px;
}

.m-top-10 {
margin-top: 10px;
}

.m-bottom-10 {
margin-bottom: 10px;
}

.m-left-10 {
margin-left: 10px;
}

.m-right-10 {
margin-right: 10px;
}

.not-editable {
pointer-events: none;
}
jasquat marked this conversation as resolved.
Show resolved Hide resolved
Loading
Loading