Skip to content

Commit

Permalink
updating Wizard route
Browse files Browse the repository at this point in the history
  • Loading branch information
tcollins2011 committed Oct 23, 2024
1 parent 051c5ab commit fc3928e
Show file tree
Hide file tree
Showing 12 changed files with 208 additions and 1 deletion.
7 changes: 7 additions & 0 deletions client/src/api/schema/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ export interface paths {
patch?: never;
trace?: never;
};
"/api/chat": {
/**
* Query
* @description We're off to ask the wizard
*/
post: operations["query_api_chat_post"];
};
"/api/configuration": {
parameters: {
query?: never;
Expand Down
7 changes: 6 additions & 1 deletion client/src/components/DatasetInformation/DatasetError.vue
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { errorMessageAsString } from "@/utils/simple-error";
import DatasetErrorDetails from "@/components/DatasetInformation/DatasetErrorDetails.vue";
import FormElement from "@/components/Form/FormElement.vue";
import GalaxyWizard from "@/components/GalaxyWizard.vue";
library.add(faBug);
Expand Down Expand Up @@ -187,7 +188,11 @@ onMounted(async () => {
</a>
</b>
</p>

<!-- Galaxy Wizard Component Integration -->
<h4 class="mb-3 h-md">What might have happened?</h4>
<b-card>
<GalaxyWizard view="error" :query="jobDetails.tool_stderr" context="tool_error" />
</b-card>
<h4 class="mb-3 h-md">Issue Report</h4>

<BAlert v-for="(resultMessage, index) in resultMessages" :key="index" :variant="resultMessage[1]" show>
Expand Down
83 changes: 83 additions & 0 deletions client/src/components/GalaxyWizard.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
<script setup lang="ts">
import axios from "axios";

Check failure on line 2 in client/src/components/GalaxyWizard.vue

View workflow job for this annotation

GitHub Actions / client-unit-test (18)

Run autofix to sort these imports!
import { ref } from "vue";
import Heading from "./Common/Heading.vue";
import LoadingSpan from "./LoadingSpan.vue";

Check failure on line 5 in client/src/components/GalaxyWizard.vue

View workflow job for this annotation

GitHub Actions / client-unit-test (18)

Expected 1 empty line after import statement not followed by another import
const props = defineProps({
view: {
type: String,
default: "wizard",
},
query: {
type: String,
default: "",
},
context: {
type: String,
default: "",
},
});
const query = ref(props.query);
const queryResponse = ref("");
const busy = ref(false);
// on submit, query the server and put response in display box
function submitQuery() {
busy.value = true;
queryResponse.value = "";
const context = props.context || "username";
axios
.post("/api/chat", {
query: query.value,
context: context,
})
.then(function (response) {
console.log(response);
queryResponse.value = response.data;
})
.catch(function (error) {
console.error(error);
})
.finally(() => {
busy.value = false;
});
}
</script>
<template>
<div>
<!-- input text, full width top of page -->
<Heading v-if="props.view == 'wizard'" inline h2>Ask the wizard</Heading>
<div :class="props.view == 'wizard' && 'mt-2'">
<b-input
v-if="props.query == ''"
id="wizardinput"
v-model="query"
style="width: 100%"
placeholder="What's the difference in fasta and fastq files?"
@keyup.enter="submitQuery" />
<b-button
v-else-if="!queryResponse"
variant="info"
:disabled="busy"
@click="submitQuery">
<span v-if="!busy">
Let our Help Wizard Figure it out!
</span>
<LoadingSpan v-else message="Thinking..." />
</b-button>
</div>
<!-- spinner when busy -->
<div :class="props.view == 'wizard' && 'mt-4'">
<div v-if="busy">
<b-skeleton animation="wave" width="85%"></b-skeleton>
<b-skeleton animation="wave" width="55%"></b-skeleton>
<b-skeleton animation="wave" width="70%"></b-skeleton>
</div>
<div v-else class="chatResponse">{{ queryResponse }}</div>
</div>
</div>
</template>
<style lang="scss" scoped>
.chatResponse {
white-space: pre-wrap;
}
</style>
5 changes: 5 additions & 0 deletions client/src/entry/analysis/router.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import DatasetAttributes from "components/DatasetInformation/DatasetAttributes";
import DatasetDetails from "components/DatasetInformation/DatasetDetails";
import DatasetError from "components/DatasetInformation/DatasetError";
import FormGeneric from "components/Form/FormGeneric";
import GalaxyWizard from "components/GalaxyWizard.vue";
import HelpTerm from "components/Help/HelpTerm";
import HistoryExportTasks from "components/History/Export/HistoryExport";
import HistoryPublished from "components/History/HistoryPublished";
Expand Down Expand Up @@ -614,6 +615,10 @@ export function getRouter(Galaxy) {
activeList: "published",
},
},
{
path: "wizard",
component: GalaxyWizard,
},
{
path: "workflows/create",
component: WorkflowCreate,
Expand Down
9 changes: 9 additions & 0 deletions doc/source/admin/galaxy_options.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5364,6 +5364,15 @@
:Default: ``-1``
:Type: int

~~~~~~~~~~~~~~~~~~
``openai_api_key``
~~~~~~~~~~~~~~~~~~

:Description:
API key for OpenAI (https://openai.com/) to enable the wizard (or
more?)
:Default: ``None``
:Type: str

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
``enable_tool_recommendations``
Expand Down
3 changes: 3 additions & 0 deletions lib/galaxy/config/sample/galaxy.yml.sample
Original file line number Diff line number Diff line change
Expand Up @@ -2881,6 +2881,9 @@ galaxy:
# as threshold (above threshold: regular select fields will be used)
#select_type_workflow_threshold: -1

# API key for OpenAI (https://openai.com/) to enable the wizard
#openai_api_key: null

# Allow the display of tool recommendations in workflow editor and
# after tool execution. If it is enabled and set to true, please
# enable 'tool_recommendation_model_path' as well
Expand Down
6 changes: 6 additions & 0 deletions lib/galaxy/config/schemas/config_schema.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3923,6 +3923,12 @@ mapping:
use -1 (default) in order to always use the regular select fields,
use any other positive number as threshold (above threshold: regular select fields will be used)
openai_api_key:
type: str
required: false
desc: |
OpenAI API key to enable the wizard.
enable_tool_recommendations:
type: bool
default: false
Expand Down
3 changes: 3 additions & 0 deletions lib/galaxy/dependencies/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,9 @@ def check_influxdb(self):

def check_tensorflow(self):
return asbool(self.config["enable_tool_recommendations"])

def check_openai(self):
return self.config.get("openai_api_key", None) is not None

def check_weasyprint(self):
# See notes in ./conditional-requirements.txt for more information.
Expand Down
1 change: 1 addition & 0 deletions lib/galaxy/dependencies/conditional-requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ python-pam
galaxycloudrunner
pkce
total-perspective-vortex>=2.3.2,<3
openai

# For file sources plugins
fs.webdavfs>=0.4.2 # type: webdav
Expand Down
11 changes: 11 additions & 0 deletions lib/galaxy/schema/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -3708,6 +3708,17 @@ class MaterializeDatasetInstanceAPIRequest(MaterializeDatasetOptions):
class MaterializeDatasetInstanceRequest(MaterializeDatasetInstanceAPIRequest):
history_id: DecodedDatabaseIdField

class ChatPayload(Model):
query: str = Field(
...,
title="Query",
description="The query to be sent to the chatbot.",
)
context: Optional[str] = Field(
default=""
title="Context",
description="The context for the chatbot.",
)

class CreatePagePayload(PageSummaryBase):
content_format: PageContentFormat = ContentFormatField
Expand Down
73 changes: 73 additions & 0 deletions lib/galaxy/webapps/galaxy/api/chat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
"""
API Controller providing Chat functionality
"""
import logging

try:
import openai
except ImportError:
openai = None

from galaxy.config import GalaxyAppConfiguration
from galaxy.managers.context import ProvidesUserContext
from galaxy.webapps.galaxy.api import (
depends,
DependsOnTrans,
)
from galaxy.exceptions import ConfigurationError
from galaxy.schema.schema import ChatPayload
from . import (
depends,
Router,
)

log = logging.getLogger(__name__)

router = Router(tags=["chat"])

PROMPT = """
You are a highly intelligent question answering agent, expert on the Galaxy analysis platform and in the fields of computer science, bioinformatics, and genomics.
You will try to answer questions about Galaxy, and if you don't know the answer, you will ask the user to rephrase the question.
"""


@router.cbv
class ChatAPI:
config: GalaxyAppConfiguration = depends(GalaxyAppConfiguration)

@router.post("/api/chat")
def query(self, query: ChatPayload, trans: ProvidesUserContext = DependsOnTrans) -> str:
"""We're off to ask the wizard"""

if openai is None or self.config.openai_api_key is None:
raise ConfigurationError("OpenAI is not configured for this instance.")
else:
openai.api_key = self.config.openai_api_key

messages=[
{"role": "system", "content": PROMPT},
{"role": "user", "content": query.query},
]

if query.context == "username":
user = trans.user
if user is not None:
log.debug(f"CHATGPTuser: {user.username}")
msg = f"You will address the user as {user.username}"
else:
msg = f"You will address the user as Anonymous User"
messages.append({"role": "system", "content": msg})
elif query.context == "tool_error":
msg = "The user will provide you a Galaxy tool error, and you will try to debug and explain what happened"
messages.append({"role": "system", "content": msg})

log.debug(f"CHATGPTmessages: {messages}")

response = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=messages,
temperature=0,
)

answer = response["choices"][0]["message"]["content"]
return answer
1 change: 1 addition & 0 deletions lib/galaxy/webapps/galaxy/buildapp.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,7 @@ def app_pair(global_conf, load_app_kwds=None, wsgi_preflight=True, **kwargs):
webapp.add_client_route("/collection/{collection_id}/edit")
webapp.add_client_route("/jobs/submission/success")
webapp.add_client_route("/jobs/{job_id}/view")
webapp.add_client_route("/wizard")
webapp.add_client_route("/workflows/list")
webapp.add_client_route("/workflows/list_published")
webapp.add_client_route("/workflows/list_shared_with_me")
Expand Down

0 comments on commit fc3928e

Please sign in to comment.