From b022034c772300b0215d4329128024c375da2bdc Mon Sep 17 00:00:00 2001 From: Tomasz Rewak Date: Wed, 17 May 2023 12:43:08 +0200 Subject: [PATCH] More cleanup and fixing react errors. --- ai.py | 4 +- assets/style.css | 8 ++-- components/header.js | 14 +++++++ components/magi.js | 13 ++++-- components/modal.js | 39 +++++++++--------- components/response.js | 16 +++---- components/status.js | 18 ++++++++ components/wise_man.js | 23 ++++++----- main.py | 94 +++++++++++++----------------------------- playground.py | 49 ---------------------- 10 files changed, 117 insertions(+), 161 deletions(-) create mode 100644 components/header.js create mode 100644 components/status.js delete mode 100644 playground.py diff --git a/ai.py b/ai.py index 6ba9604..b7a05fe 100644 --- a/ai.py +++ b/ai.py @@ -19,10 +19,10 @@ def is_yes_or_no_question(question: str, key: str): content = response['choices'][0]['message']['content'] - if re.match('^\W*yes\W*$', content, re.IGNORECASE): + if content == 'Yes': return True - if re.match('^\W*no\W*$', content, re.IGNORECASE): + if content == 'No': return False raise Exception(f'Invalid question annotation response: {content}') diff --git a/assets/style.css b/assets/style.css index 38db4b5..d76b7c9 100644 --- a/assets/style.css +++ b/assets/style.css @@ -30,19 +30,19 @@ body { /**/ 2fr /**/ - [balthasar-start casper-balthasar-connection] + [left-header-end balthasar-start casper-balthasar-connection] /**/ 0.5fr /**/ - [casper-end left-header-end title casper-melchior-connection] + [casper-end title casper-melchior-connection] /**/ 1fr /**/ - [balthasar-melchior-connection right-header-start melchior-start] + [balthasar-melchior-connection melchior-start] /**/ 0.5fr /**/ - [balthasar-end response] + [right-header-start balthasar-end response] /**/ 2fr /**/ diff --git a/components/header.js b/components/header.js new file mode 100644 index 0000000..a46fe14 --- /dev/null +++ b/components/header.js @@ -0,0 +1,14 @@ +import React from "react"; +const $ = React.createElement; + +export default function Header({ side, title }) { + const className = `header ${side}`; + + return $('div', { className }, + $('hr', {}), + $('hr', {}), + $('span', {}, title), + $('hr', {}), + $('hr', {}) + ); +} \ No newline at end of file diff --git a/components/magi.js b/components/magi.js index 484a49d..f4fda6c 100644 --- a/components/magi.js +++ b/components/magi.js @@ -1,7 +1,12 @@ import React from "react"; +const $ = React.createElement; -export default function Magi(props) { - const { setProps, children } = props; - - return React.createElement("div", { className: "magi" }, children); +export default function Magi({ children }) { + return $('div', { className: 'magi' }, + $('div', { className: 'connection casper-balthasar' }), + $('div', { className: 'connection casper-melchior' }), + $('div', { className: 'connection balthasar-melchior' }), + ...children, + $('div', { className: 'title' }, 'MAGI') + ); } \ No newline at end of file diff --git a/components/modal.js b/components/modal.js index 4cb2c9d..62fd402 100644 --- a/components/modal.js +++ b/components/modal.js @@ -1,4 +1,5 @@ import React from 'react'; +const $ = React.createElement; export default function Modal({ setProps, name, is_open, question, answer }) { if (!is_open) return null; @@ -7,28 +8,28 @@ export default function Modal({ setProps, name, is_open, question, answer }) { const answerId = answer.id; if (questionId !== answerId) - answer = { id: questionId, status: 'error', error: 'questionId !== answerId' }; + answer = { id: questionId, status: 'error', error: 'loading...' }; const close = () => { setProps({ is_open: false }); }; - return React.createElement('div', { className: 'modal' }, [ - React.createElement('div', { className: 'modal-header' }, [ - React.createElement('div', { className: 'modal-title' }, [name]), - React.createElement('div', { className: 'close', onClick: close }, ['X']), - ]), - React.createElement('div', { className: 'modal-body' }, [ - React.createElement('div', {}, 'question: '), - React.createElement('div', {}, question.query), - React.createElement('div', {}, 'status: '), - React.createElement('div', {}, answer.status), - React.createElement('div', {}, 'error: '), - React.createElement('div', {}, answer.error), - React.createElement('div', {}, 'conditions: '), - React.createElement('div', {}, answer.conditions), - React.createElement('div', {}, 'full response: '), - React.createElement('div', {}, answer.response) - ]), - ]); + return $('div', { className: 'modal' }, + $('div', { className: 'modal-header' }, + $('div', { className: 'modal-title' }, name), + $('div', { className: 'close', onClick: close }, 'X'), + ), + $('div', { className: 'modal-body' }, + $('div', {}, 'question: '), + $('div', {}, question.query), + $('div', {}, 'status: '), + $('div', {}, answer.status), + $('div', {}, 'error: '), + $('div', {}, answer.error), + $('div', {}, 'conditions: '), + $('div', {}, answer.conditions), + $('div', {}, 'full response: '), + $('div', {}, answer.response) + ), + ); } \ No newline at end of file diff --git a/components/response.js b/components/response.js index ba24cbd..858b42d 100644 --- a/components/response.js +++ b/components/response.js @@ -1,4 +1,5 @@ import React from 'react'; +const $ = React.createElement; function getStatusText(status) { if (status === 'info') @@ -38,16 +39,17 @@ function getStatusColor(status) { throw new Error('Invalid status: ' + status); } -export default function Response(props) { - const { status, question_id, answer_id } = props; - +export default function Response({ status, question_id, answer_id }) { const text = getStatusText(status); const color = getStatusColor(status); - return React.createElement('div', { className: `response ${question_id !== answer_id ? 'flicker' : ''}`, style: { color: color, borderColor: color } }, - [ - React.createElement('div', { className: 'inner' }, [text]) - ]); + let className = 'response'; + if (question_id !== answer_id) + className += ' flicker'; + + return $('div', { className, style: { color: color, borderColor: color } }, + $('div', { className: 'inner' }, text) + ); } Response.defaultProps = { diff --git a/components/status.js b/components/status.js new file mode 100644 index 0000000..ffc448f --- /dev/null +++ b/components/status.js @@ -0,0 +1,18 @@ +import React from 'react'; +const $ = React.createElement; + +export default function Status({ extention }) { + const extentionLabel = `EXTENTION:${extention}`; + + return $('div', { className: 'system-status' }, + $('div', {}, 'CODE:473'), + $('div', {}, 'FILE:MAGI_SYS'), + $('div', {}, extentionLabel), + $('div', {}, 'EX_MODE:OFF'), + $('div', {}, 'PRIORITY:AAA') + ); +} + +Status.defaultProps = { + extention: '????' +}; \ No newline at end of file diff --git a/components/wise_man.js b/components/wise_man.js index 41881ba..058525b 100644 --- a/components/wise_man.js +++ b/components/wise_man.js @@ -1,7 +1,7 @@ import React from 'react'; +const $ = React.createElement; - -function useColor(status) { +function getColor(status) { if (status === 'yes') return '#52e691'; @@ -20,22 +20,23 @@ function useColor(status) { throw new Error(`Invalid status: ${status}`); } -export default function WiseMan(props) { - const { setProps, name, order_number, question_id, answer, n_clicks } = props; +export default function WiseMan({ setProps, name, order_number, question_id, answer, n_clicks }) { const fullName = `${name.toUpperCase()} • ${order_number}`; - const color = useColor(answer['status']); + const color = getColor(answer['status']); const processing = question_id !== answer['id']; const onClick = () => { setProps({ n_clicks: n_clicks + 1 }); }; - return React.createElement('div', { className: `wise-man ${name}`, onClick: onClick, key: name }, - [ - React.createElement('div', { className: `inner ${processing ? 'flicker' : ''}`, style: { background: color } }, [ - fullName - ]) - ]) + let outerClassName = `wise-man ${name}`; + let innerClassName = 'inner'; + if (processing) + innerClassName += ' flicker'; + + return $('div', { className: outerClassName, onClick: onClick, key: name }, + $('div', { className: innerClassName, style: { background: color } }, fullName) + ) } WiseMan.defaultProps = { diff --git a/main.py b/main.py index 34cea94..39e5ca6 100644 --- a/main.py +++ b/main.py @@ -1,8 +1,7 @@ -from dataclasses import dataclass import os -from dash_extensions.enrich import Dash, Input, Output, State, Trigger, callback, ALL, MATCH, callback_context +from dash_extensions.enrich import Dash, Input, Output, State, Trigger, callback, ALL, MATCH import dash_core_components as dcc -import dash_html_components as html +from dash_html_components import Div, Label from dash_local_react_components import load_react_component import ai @@ -12,58 +11,37 @@ Magi = load_react_component(app, 'components', 'magi.js') WiseMan = load_react_component(app, 'components', 'wise_man.js') Response = load_react_component(app, 'components', 'response.js') Modal = load_react_component(app, 'components', 'modal.js') +Header = load_react_component(app, 'components', 'header.js') +Status = load_react_component(app, 'components', 'status.js') -app.layout = html.Div( +app.layout = Div( className='system', children=[ Magi(id='magi', children=[ - html.Div(className='connection casper-balthasar'), - html.Div(className='connection casper-melchior'), - html.Div(className='connection balthasar-melchior'), - html.Div(className='header left', children=[ - html.Hr(), - html.Hr(), - html.Span('質 問 '), - html.Hr(), - html.Hr() - ]), - html.Div(className='header right', children=[ - html.Hr(), - html.Hr(), - html.Span('解 決 '), - html.Hr(), - html.Hr() - ]), - html.Div( - className='system-status', - children=[ - html.Div(children='CODE:473'), - html.Div(children='FILE:MAGI_SYS'), - html.Div(id='extention', children='EXTENTION:????'), - html.Div(children='EX_MODE:OFF'), - html.Div(children='PRIORITY:AAA')]), + Header(side='left', title='質 問'), + Header(side='right', title='解 決'), + Status(id='status'), WiseMan( - id={'type': 'wise-man', 'name': 'melchior'}, - name='melchior', - order_number=1, - personality='You are a scientist. Your goal is to further our understanding of the universe and advance our technological progress.'), + id={'type': 'wise-man', 'name': 'melchior'}, + name='melchior', + order_number=1, + personality='You are a scientist. Your goal is to further our understanding of the universe and advance our technological progress.'), WiseMan( - id={'type': 'wise-man', 'name': 'balthasar'}, - name='balthasar', - order_number=2, - personality='You are a mother. Your goal is to protect your children and ensure their well-being.'), + id={'type': 'wise-man', 'name': 'balthasar'}, + name='balthasar', + order_number=2, + personality='You are a mother. Your goal is to protect your children and ensure their well-being.'), WiseMan( - id={'type': 'wise-man', 'name': 'casper'}, - name='casper', - order_number=3, - personality='You are a woman. Your goal is to pursue love, dreams and desires.'), - Response(id='response', status='info'), - html.Div(className='title', children='MAGI') + id={'type': 'wise-man', 'name': 'casper'}, + name='casper', + order_number=3, + personality='You are a woman. Your goal is to pursue love, dreams and desires.'), + Response(id='response', status='info') ]), - html.Div(className='input-container', children=[ - html.Label('access code: '), + Div(className='input-container', children=[ + Label('access code: '), dcc.Input(id='key', autoComplete='off', type='password', value=os.getenv('OPENAI_API_KEY', '')), - html.Label('question: '), + Label('question: '), dcc.Input(id='query', type='text', value='', debounce=True, autoComplete='off'), ]), Modal(id={'type': 'modal', 'name': 'melchior'}, name='melchior'), @@ -83,8 +61,6 @@ app.layout = html.Div( State('question', 'data'), prevent_initial_call=True) def question(query: str, question: dict): - print('question') - return {'id': question['id'] + 1, 'query': query} @@ -94,13 +70,9 @@ def question(query: str, question: dict): State('key', 'value'), prevent_initial_call=True) def annotated_question(question: dict, key: str): - print('annotated_question') - try: is_yes_or_no_question = ai.is_yes_or_no_question(question['query'], key) - print(is_yes_or_no_question) - return { 'id': question['id'], 'query': question['query'], @@ -108,7 +80,6 @@ def annotated_question(question: dict, key: str): 'error': None } except Exception as e: - print(e) return { 'id': question['id'], 'query': question['query'], @@ -118,15 +89,14 @@ def annotated_question(question: dict, key: str): @callback( - Output('extention', 'children'), + Output('status', 'extention'), Input('question', 'data'), Input('annotated-question', 'data')) def extention(question: dict, annotated_question: dict): if question['id'] != annotated_question['id']: - return 'EXTENTION:????' + return '????' - code = '7312' if annotated_question['is_yes_or_no_question'] else '3023' - return f'EXTENTION:{code}' + return '7312' if annotated_question['is_yes_or_no_question'] else '3023' @callback( @@ -136,26 +106,20 @@ def extention(question: dict, annotated_question: dict): State('key', 'value'), prevent_initial_call=True) def wise_man_answer(question: dict, personality: str, key: str): - print('wise_man_answer') - if question['error']: return {'id': question['id'], 'response': question['error'], 'status': 'error'} try: answer = ai.get_answer(question['query'], personality, key) - print(answer) if question['is_yes_or_no_question']: classification = ai.classify_answer(question['query'], personality, answer, key) else: classification = {'status': 'info', 'conditions': None} - print(classification) - return {'id': question['id'], 'response': answer, 'status': classification['status'], 'conditions': classification['conditions'], 'error': None} except Exception as e: - print(e) return {'id': question['id'], 'response': None, 'status': 'error', 'conditions': 'None', 'error': str(e)} @@ -198,7 +162,7 @@ def response_status(answers: list): Output({'type': 'modal', 'name': MATCH}, 'is_open'), Trigger({'type': 'wise-man', 'name': MATCH}, 'n_clicks'), prevent_initial_call=True) -def modal(): +def modal_visibility(): return True @@ -207,7 +171,7 @@ def modal(): Output({'type': 'modal', 'name': MATCH}, 'answer'), Input('question', 'data'), Input({'type': 'wise-man', 'name': MATCH}, 'answer')) -def modal(question: dict, answer: dict): +def modal_content(question: dict, answer: dict): return question, answer diff --git a/playground.py b/playground.py deleted file mode 100644 index d662420..0000000 --- a/playground.py +++ /dev/null @@ -1,49 +0,0 @@ -import openai - -questions = [ - 'Is love more important than science?', - 'Should one follow emotions instead of reason?', - 'Is 3 > 2?', - 'How are you?', - 'Is Robert in today?', - 'Can you describe Robert for me?', - 'What is most important in life?', -] - -for question in questions: - response = openai.ChatCompletion.create( - model='gpt-3.5-turbo', - logit_bias={ - 9642: 100, # Yes - 2822: 90 # No - }, - max_tokens=1, - messages=[ - {'role': 'system', 'content': 'You answer questions with a simple "yes" or "no".'}, - {'role': 'user', 'content': f'Is the following question a boolean question? \n {question}'}, - ] - ) - - print(response['choices'][0]['message']['content']) - -# { -# "choices": [ -# { -# "finish_reason": "stop", -# "index": 0, -# "message": { -# "content": "Yes.", -# "role": "assistant" -# } -# } -# ], -# "created": 1684003959, -# "id": "chatcmpl-7Foe7sKt2SqEWcjmI5VG9Jc5ndRrd", -# "model": "gpt-3.5-turbo-0301", -# "object": "chat.completion", -# "usage": { -# "completion_tokens": 2, -# "prompt_tokens": 50, -# "total_tokens": 52 -# } -# }