AI and personalities

This commit is contained in:
Tomasz Rewak
2023-05-15 18:11:18 +02:00
parent e44b15c91a
commit 9f3b8a616d
5 changed files with 266 additions and 24 deletions
+61
View File
@@ -0,0 +1,61 @@
import openai
import re
def is_yes_or_no_question(question: str, key: str):
openai.api_key = key
response = openai.ChatCompletion.create(
model='gpt-3.5-turbo',
messages=[
{'role': 'system', 'content': 'You answer questions with a simple "yes" or "no".'},
{'role': 'user', 'content': f'Can the following question be generally answered with a "yes" or "no"? \n {question}'},
]
)
content = response['choices'][0]['message']['content']
if re.match('^\W*yes\W*$', content, re.IGNORECASE):
return True
if re.match('^\W*no\W*$', content, re.IGNORECASE):
return False
raise Exception(f'Invalid question annotation response: {content}')
def get_answer(question: str, personality: str, key: str):
openai.api_key = key
response = openai.ChatCompletion.create(
model='gpt-3.5-turbo',
messages=[
{'role': 'system', 'content': personality},
{'role': 'system', 'content': 'Your answers are rather concise.'},
{'role': 'user', 'content': question},
]
)
return response['choices'][0]['text']
def classify_answer(question: str, personality: str, answer: str, key: str):
openai.api_key = key
response = openai.ChatCompletion.create(
model='gpt-3.5-turbo',
messages=[
{'role': 'system', 'content': personality},
{'role': 'system', 'content': 'Your answers are rather concise.'},
{'role': 'user', 'content': question},
{'role': 'system', 'content': answer},
{'role': 'user', 'content': 'Summarize you answer with a simple "yes" or "no" (answering with a single word). If (and only if) that\'s not possible, instead of answering with "yes" or "no", list conditions under which the answer would be "yes".'},
]
)
content = response['choices'][0]['message']['content']
if re.match('^\W*yes\W*$', content, re.IGNORECASE):
return {'classification': True, 'conditions': None}
if re.match('^\W*no\W*$', content, re.IGNORECASE):
return {'classification': False, 'conditions': None}
return {'classification': True, 'conditions': content}
+86 -1
View File
@@ -50,11 +50,48 @@ input {
.magi>.system-status {
grid-area: 3 / 2 / 4 / 3;
font-family: Helvetica;
font-family: 'Helvetica';
font-family: 'Lucida Console';
color: #ff8d00;
}
.magi>.system-status>div {
font-size: 3cqh;
margin-left: 4cqw;
transform: scaleX(1.2);
transform-origin: left;
}
.magi>.system-status>div:first-child {
font-size: 6cqh;
margin-left: 0;
}
.magi>.response {
grid-area: 3 / 6 / 4 / 7;
justify-self: flex-end;
align-self: center;
border: solid 2px;
padding: 2px;
}
.magi>.response>.inner {
white-space: nowrap;
border: solid 2px;
padding: 2px 10px;
font-size: 8cqh;
font-weight: bold;
}
.magi>.wise-man {
display: flex;
background: #ff8d00;
padding: 2px;
}
.magi>.wise-man>.inner {
width: 100%;
height: 100%;
font-family: Helvetica;
font-size: 8cqh;
font-weight: bold;
@@ -65,15 +102,63 @@ input {
.magi>.wise-man.melchior {
grid-area: 4 / 5 / 6 / 7;
}
.magi>.wise-man.melchior,
.magi>.wise-man.melchior>.inner {
clip-path: polygon(35% 0, 100% 0, 100% 100%, 0 100%, 0 44%)
}
.magi>.wise-man.balthasar {
grid-area: 2 / 3 / 5 / 6;
}
.magi>.wise-man.balthasar,
.magi>.wise-man.balthasar>.inner {
clip-path: polygon(0 0, 100% 0, 100% 80%, 75% 100%, 25% 100%, 0 80%);
}
.magi>.wise-man.casper {
grid-area: 4 / 2 / 6 / 4;
}
.magi>.wise-man.casper,
.magi>.wise-man.casper>.inner {
clip-path: polygon(0 0, 65% 0, 100% 44%, 100% 100%, 0 100%);
}
@keyframes flicker-animation {
0% {}
50% {
background: black;
color: black;
border-color: black;
}
}
.flicker {
animation: flicker-animation 0.25s infinite step-end;
}
.connection {
height: 10px;
background: #ff8d00;
align-self: center;
margin: -10%;
}
.connection.casper-balthasar {
grid-area: 4 / 3 / 5 / 4;
transform: rotate(-54deg);
}
.connection.casper-melchior {
grid-area: 5 / 4 / 6 / 5;
}
.connection.balthasar-melchior {
grid-area: 4 / 5 / 5 / 6;
transform: rotate(54deg);
}
+45
View File
@@ -0,0 +1,45 @@
import React from 'react';
function getStatusText(status) {
if (status === 'info')
return '情 報';
if (status === 'yes')
return '合 意';
if (status === 'no')
return '拒 絶';
if (status === 'conditional')
return '状 態';
throw new Error('Invalid status: ' + status);
}
function getStatusColor(status) {
if (status === 'info')
return '#3caee0';
if (status === 'yes')
return '#52e691';
if (status === 'no')
return '#a41413';
if (status === 'conditional')
return '#ff8d00';
throw new Error('Invalid status: ' + status);
}
export default function Response(props) {
const { status } = props;
const text = getStatusText(status);
const color = getStatusColor(status);
return React.createElement('div', { className: 'response', style: { color: color, borderColor: color } },
[
React.createElement('div', { className: 'inner' }, [text])
]);
}
+12 -9
View File
@@ -1,10 +1,7 @@
import React from 'react';
function useColor(status, processing) {
if (processing)
return '#f1f1f1';
function useColor(status) {
if (status === 'yes')
return '#52e691';
@@ -14,16 +11,22 @@ function useColor(status, processing) {
if (status === 'info')
return '#3caee0';
if (status == 'conditional')
return 'repeating-linear-gradient(56deg, rgb(82, 230, 145) 0px, rgb(82, 230, 145) 30px, #82cd68 30px, #82cd68 60px)';
throw new Error(`Invalid status: ${status}`);
}
export default function WiseMan(props) {
const { setProps, name, order_number, question_id, answer } = props;
const fullName = `${name.toUpperCase()}${order_number}`;
const color = useColor(answer['status'], question_id !== answer['id']);
const color = useColor(answer['status']);
const processing = question_id !== answer['id'];
return React.createElement('div', { className: `wise-man ${name}`, style: { background: color } },
[
fullName
])
return React.createElement('div', { className: `wise-man ${name}` },
[
React.createElement('div', { className: `inner ${processing ? 'flicker' : ''}`, style: { background: color } }, [
fullName
])
])
}
+62 -14
View File
@@ -1,28 +1,53 @@
from dataclasses import dataclass
import os
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_local_react_components import load_react_component
import random
import ai
app = Dash(__name__)
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')
app.layout = html.Div(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='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')]),
WiseMan(id={'type': 'wise-man', 'name': 'melchior'}, name='melchior', order_number=1, question_id=0, answer={'id': 0, 'response': 'yes', 'status': 'yes'}),
WiseMan(id={'type': 'wise-man', 'name': 'balthasar'}, name='balthasar', order_number=2, question_id=0, answer={'id': 0, 'response': 'yes', 'status': 'yes'}),
WiseMan(id={'type': 'wise-man', 'name': 'casper'}, name='casper', order_number=3, question_id=0, answer={'id': 0, 'response': 'yes', 'status': 'yes'}),
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')]),
WiseMan(
id={'type': 'wise-man', 'name': 'melchior'},
name='melchior',
order_number=1,
personality='You are a scientist. Your goal is to further our our understanding of the universe and advance our technological progress.',
question_id=0,
answer={'id': 0, 'response': 'yes', 'status': 'yes'}),
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.',
question_id=0,
answer={'id': 0, 'response': 'yes', 'status': 'yes'}),
WiseMan(
id={'type': 'wise-man', 'name': 'casper'},
name='casper',
order_number=3,
personality='You are a woman. Your goal is to pursue your dreams and desires.',
question_id=0,
answer={'id': 0, 'response': 'yes', 'status': 'yes'}),
Response(id='response', status='info'),
html.Div(className='title', children='MAGI'),
html.Div(className='header left', children=[
html.Hr(),
@@ -39,6 +64,8 @@ app.layout = html.Div(children=[
html.Hr()
])
]),
html.Label('MAGI access codes: '),
dcc.Input(id='key', autoComplete='off', type='password', value=os.getenv('OPENAI_API_KEY', '')),
dcc.Input(id='query', type='text', value='', debounce=True, autoComplete='off'),
dcc.Store(id='question', data={'id': 0, 'query': ''}),
@@ -51,16 +78,25 @@ app.layout = html.Div(children=[
@callback(
Output('question', 'data'),
Input('query', 'value'),
State('question', 'data'))
State('question', 'data'),
prevent_initial_call=True)
def question(query: str, question: dict):
print('question')
return {'id': question['id'] + 1, 'query': query}
@callback(
Output('annotated-question', 'data'),
Input('question', 'data'))
def annotated_question(question: dict):
return {'id': question['id'], 'query': question['query'], 'is_yes_no_question': question['query'].endswith('?')}
Input('question', 'data'),
State('key', 'value'),
prevent_initial_call=True)
def annotated_question(question: dict, key: str):
print('annotated_question')
is_yes_no_question = ai.is_yes_or_no_question(question['query'], key)
return {'id': question['id'], 'query': question['query'], 'is_yes_no_question': is_yes_no_question}
@callback(
@@ -69,10 +105,10 @@ def annotated_question(question: dict):
Input('annotated-question', 'data'))
def extention(question: dict, annotated_question: dict):
if question['id'] != annotated_question['id']:
return 'EXTENTION : ????'
return 'EXTENTION:????'
code = '2137' if annotated_question['is_yes_no_question'] else '3023'
return f'EXTENTION : {code}'
return f'EXTENTION:{code}'
@callback(
@@ -90,5 +126,17 @@ def question_id(question: dict):
return question['id']
@callback(
Output('response', 'status'),
Input({'type': 'wise-man', 'name': ALL}, 'answer'))
def response_status(answers: list):
if all([answer['status'] == 'yes' for answer in answers]):
return 'yes'
elif any([answer['status'] == 'no' for answer in answers]):
return 'no'
else:
return 'info'
if __name__ == '__main__':
app.run_server(debug=True)