Skip to content
Draft
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
2 changes: 1 addition & 1 deletion docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ services:
- VITE_REACT_APP_AAD_APP_CLIENT_ID=${AAD_APP_CLIENT_ID}
- VITE_REACT_APP_AAD_APP_TENANT_ID=${AAD_APP_TENANT_ID}
- VITE_REACT_APP_AAD_APP_REDIRECT_URI=${AAD_APP_REDIRECT_URI}
- VITE_REACT_APP_AAD_APP_SCOPE_URI=${AAD_APP_SCOPE_URI}
- VITE_REACT_APP_ADD_APP_SCOPE_URI=${ADD_APP_SCOPE_URI}
- VITE_REACT_APP_SERVER_HOST=${SERVER_HOST}
- VITE_REACT_APP_INSIGHTS_KEY=${APPINSIGHTS_INSTRUMENTATIONKEY}
- VITE_REACT_EDITOR=code
Expand Down
16 changes: 14 additions & 2 deletions docs/tutorials/quickstart.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ ADD_APP_SCOPE_URI="api://<uuid>/Users.Create"
ISSUER="https://sts.windows.net/<uuid>/"
```

4. Install libgraphviz-dev
```bash
sudo apt install libgraphviz-dev
```

## Instructions

1. **Start Docker:**
Expand All @@ -44,7 +49,7 @@ ISSUER="https://sts.windows.net/<uuid>/"
2. **Open Bash Terminal:**
- For Windows, use WSL2. **Note:** PowerShell will not work.

You need to setup 3 repositories to start the PwR Studio. Follow the instructions below to clone the repositories. Keep the repositories in the same directory as siblings. **Note:** Do not clone in your Windows directory as that will change the line endings.
You need to setup 4 repositories to start the PwR Studio. Follow the instructions below to clone the repositories. Keep the repositories in the same directory as siblings. **Note:** Do not clone in your Windows directory as that will change the line endings.

3. **Clone PwR-Studio Repository:**
```bash
Expand All @@ -71,16 +76,23 @@ You need to setup 3 repositories to start the PwR Studio. Follow the instruction
git clone git@github.com:microsoft/PwR-NL2DSL.git
```


6. **Clone [Jugalbandi-Manager](https://github.com/OpenNyAI/Jugalbandi-Manager) Repository:**
```bash
git clone git@github.com:OpenNyAI/Jugalbandi-Manager.git
```

Great job! You have successfully cloned the repositories. 🎉

Your directory structure should look like this:
```bash
├── Jugalbandi-Manager
├── Jugalbandi-Studio-Engine
├── PwR-NL2DSL
└── PwR-Studio
```

6. **Setup Local Environment Variables:**
7. **Setup Local Environment Variables:**
1. Go into `PwR-Studio` repository

```bash
Expand Down
7 changes: 4 additions & 3 deletions lib/pwr_studio/engines/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,7 @@ def __init__(
assert isinstance(kwargs["correlation_id"], str)
self._correlation_id = kwargs["correlation_id"]

if len(self._project.representations.keys()) == 0:
self.initalize()
self.initalize()

@abstractmethod
def _get_representations(self) -> List[PwRStudioRepresentation]:
Expand All @@ -58,7 +57,9 @@ def initalize(self):
for pwrRep in pwrRepresentations:
name = pwrRep.get_name()
data = pwrRep.get_data()
self._project.representations[name] = data

if name not in self._project.representations:
self._project.representations[name] = data

async def process_utterance(self, text: str, **kwargs):
allowed_args = {"chat_history", "files"}
Expand Down
20 changes: 20 additions & 0 deletions server/app/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -965,6 +965,26 @@ async def get_output_response(
print(
f"#3S - main.py Starting Output Webhook with {output_response.type}:{output_response.message}; PwR-RID={output_response.correlation_id}"
)

if output_response.project:
project = output_response.project
# if project.current_iteration:
# iterations_row['description'] = project.current_iteration.description

for name in project.representations:
representation = project.representations[name]
rep_dict = {
"name": name,
"type": representation.type,
"text": representation.text,
"project_id": pid,
"is_pwr_viewable": representation.is_pwr_viewable,
"is_user_viewable": True,
"is_editable": representation.is_editable,
"sort_order": representation.sort_order,
}
crud.create_representation(db, rep_dict)

if output_response.type == "output" or output_response.type == "debug":
crud.create_output_message(
db,
Expand Down
78 changes: 67 additions & 11 deletions studio/src/components/Chat/TestBot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,16 @@ import TypingLoader from "./TypingLoader";
import { sendRequest } from '../../api';
import TestBotFooter from "./TestBotFooter";
import { useId } from '@fluentui/react-hooks';

import FormInput from '../FormInput';
import DropdownInput from '../DropdownInput';

interface props {
id: string | undefined,
token: any,
userId: any,
setOnlineState: Function
setOnlineState: Function,
resetChat: bool,
resetChatToggle: Function
}

const testBotStyles = makeStyles(theme => ({
Expand All @@ -34,6 +37,10 @@ const testBotStyles = makeStyles(theme => ({
background: '#AFD8FF',
color: '#000'
},
plugin: {
background: '#C9CCCF',
color: '#000'
},
input: {
alignSelf: 'flex-end',
backgroundColor: '#f0949e',
Expand Down Expand Up @@ -75,6 +82,7 @@ const TestBot = (props: props) => {
const classUser = mergeStyles(classes.message, classes.user);
const classInput = mergeStyles(classes.message, classes.input);
const classAgent = mergeStyles(classes.message, classes.agent);
const classPlugin = mergeStyles(classes.message, classes.plugin);
const userTypes = ["instruction", "feedback"]
const noBackground = mergeStyles(classes.message, classes.noBackground)
const debugClass = mergeStyles(classes.message, classes.debug);
Expand All @@ -83,6 +91,7 @@ const TestBot = (props: props) => {
const [disableSend, setDisableSend] = React.useState(false);
const [callBackMode, setCallBackMode] = React.useState(false);

const botRestartmessage = "_reset_chat_"

const {
getWebSocket,
Expand Down Expand Up @@ -119,7 +128,7 @@ const TestBot = (props: props) => {
scrollChatToBottom();
}
}, [lastJsonMessage, addMessages]);

React.useEffect(() => {
if (readyState === ReadyState.OPEN) {
props.setOnlineState(true)
Expand All @@ -135,11 +144,13 @@ const TestBot = (props: props) => {
if (messageType === 'debug') {
return debugClass
}
if (message.indexOf('\xa1') > -1) {
return classInput
}
//if (message.indexOf('\xa1') > -1) {
// return classInput
//}
if (userTypes.includes(messageType)) {
return classUser
} else if (message.startsWith('##plugin')) {
return classPlugin
} else {
return classAgent
}
Expand Down Expand Up @@ -228,6 +239,44 @@ const TestBot = (props: props) => {
return msg;
}

const isCustomInputNeeded = (messages:any, type_check:string) => {
if (messages != null && messages.length > 1) {
if (messages[0].type === 'end'
&& messages[1].type === 'output'
&& messages[1].message.indexOf("\xa1") > -1) {
const msgBody = messages[1].message.split('\xa1')[0];
const jobj = JSON.parse(msgBody);
return jobj["type"] === type_check;
}
}
return false;
}

const isFromInputNeeded = (messages:any) => {
return isCustomInputNeeded(messages, "form");
}

const getFormFields = (messages:any) => {
const msgBody = messages[1].message.split('\xa1')[0];
return JSON.parse(msgBody)["vars"]
}

const isDropdownInputNeeded = (messages:any) => {
return isCustomInputNeeded(messages, "dropdown");
}

const getDropdownFields = (messages:any) => {
const msgBody = messages[1].message.split('\xa1')[0];
return JSON.parse(msgBody)["options"]
}

React.useEffect(() => {
if (props.resetChat) {
sendMessageToWss(botRestartmessage);
props.resetChatToggle(false);
}
}, [props.resetChat]);

return (
<Stack id={chatId}>
<Stack.Item>
Expand All @@ -239,7 +288,7 @@ const TestBot = (props: props) => {
{messages ? messages.map((message: any, index: string) => (
// <div key={crypto.randomUUID()}>
<>
{message.message.trim() !== '' && !['representation_edit', 'files'].includes(message.type) && !(message.type === 'thought' && ['input', 'event'].includes(message.message.trim())) &&
{message.message.trim() !== '' && !['representation_edit', 'files'].includes(message.type) && !(message.type === 'thought' && ['input', 'event'].includes(message.message.trim())) && message.message.trim() !== botRestartmessage &&
<div
key={crypto.randomUUID()}
className={getClassNames(message.type, message.message)}
Expand All @@ -251,16 +300,16 @@ const TestBot = (props: props) => {
{message.type === 'thought' && <Icon iconName="Accept" className={classes.thoughtIcon} />}
{message.type === 'error' && <Icon iconName="StatusErrorFull" style={{ color: 'red' }} className={classes.thoughtIcon} />}
</Stack.Item>
<Stack.Item>
<Stack.Item>
<div style={{ whiteSpace: 'pre-line' }}>
{message.type === 'output' ?
{message.type === 'output' ?
<div dangerouslySetInnerHTML={{ __html: getMessage(message.message) }} />
: getMessage(message.message)}
</div>
</Stack.Item>
</Stack>
</Stack.Item>

</Stack>
</div>}
</>
Expand All @@ -271,7 +320,14 @@ const TestBot = (props: props) => {
</div>
</Stack.Item>
<Stack.Item id={footerId} className={classes.footerStack}>
<TestBotFooter disableSend={disableSend} sendMessageToWss={sendMessageToWss} />
{ isFromInputNeeded(messages) ?
<FormInput variableNames={getFormFields(messages)} sendVariableValues={sendMessageToWss}/> :
(
isDropdownInputNeeded(messages) ?
<DropdownInput choices={getDropdownFields(messages)} sendChoice={sendMessageToWss}/> :
<TestBotFooter disableSend={disableSend} sendMessageToWss={sendMessageToWss} />
)
}
</Stack.Item>
</Stack>
)
Expand Down
50 changes: 50 additions & 0 deletions studio/src/components/DropdownInput/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import '@/styles/components/publishModal.scss';
import { DefaultButton, Dropdown, Label, Stack } from '@fluentui/react';
import React from 'react';

interface props {
choices: any,
sendChoice: Function
}

export const DropdownInput = (props: props) => {
const optionsList = props.choices ?? [];
const options = optionsList.map((x, i) => ({'key': '_' + i, 'text': x}));

if (options.length > 0) {
options[0].selected = true;
}

const [selectedOption, setSelectedOption] = React.useState(0);

const setChoice = (e, o, i) => {
setSelectedOption(i);
}

const updateChoice = () => {
if (options.length > 0)
props.sendChoice(optionsList[selectedOption]);
}

return (
<Stack className='content publish-modal-container'>
<Stack.Item>
<Stack>
<Stack.Item>
<Dropdown
label="Please select one of the options"
options={options}
onChange={setChoice} />
</Stack.Item>
</Stack>
<Stack>
<Stack.Item>
<DefaultButton onClick={updateChoice}>Submit</DefaultButton>
</Stack.Item>
</Stack>
</Stack.Item>
</Stack>
);
}

export default DropdownInput;
59 changes: 59 additions & 0 deletions studio/src/components/FormInput/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import '@/styles/components/publishModal.scss';
import { DefaultButton, Label, Stack, TextField } from '@fluentui/react';
import React from 'react';

interface props {
variableNames: any,
sendVariableValues: Function
}

export const FormInput = (props: props) => {
let valueDict = {}
for (var idx = 0; idx < props.variableNames.length; idx++) {
valueDict[idx] = React.useState('');
}

const sendFromData = () => {
let formData = {}
formData["type"] = "form"
formData["vars"] = {}

let simpleVersion = ""
for (var k in valueDict) {
formData["vars"][props.variableNames[k]] = valueDict[k][0];
simpleVersion += props.variableNames[k]
simpleVersion += " : "
simpleVersion += valueDict[k][0]
simpleVersion += "\n"
}
const stringVersion = JSON.stringify(formData) + "\xa1" + simpleVersion;
props.sendVariableValues(stringVersion);
}

return (
<Stack className='content publish-modal-container'>
<Stack.Item>
{props.variableNames.map((vname: string, index: number) => (
<Stack vertical>
<Stack.Item>
<Label>{vname}</Label>
</Stack.Item>
<Stack.Item>
<TextField
onChange={(e, value) => { valueDict[index][1](value || '') }}
value={valueDict[index][0]}/>
</Stack.Item>
</Stack>
))
}
<Stack>
<Stack.Item>
<DefaultButton onClick={() => sendFromData()}>Submit</DefaultButton>
</Stack.Item>
</Stack>
</Stack.Item>
</Stack>
);
}

export default FormInput;
Loading