diff --git a/content/_plugins/studio.py b/content/_plugins/studio.py new file mode 100644 index 0000000..3434a8e --- /dev/null +++ b/content/_plugins/studio.py @@ -0,0 +1,117 @@ +""" +This file implements an avatar studio +""" +import py_avataaars as pa +from py_avataaars import PyAvataaar as Avatar +import pandas as pd +import numpy as np +import transport +from transport import providers +from enum import Enum +import io +import base64 +import copy + + +# _map = {'eye type':pa.EyesType,'frame style':pa.AvatarStyle,'race':pa.SkinColor,'hair color':pa.HairColor,'facial hair':pa.FacialHairType, 'facial hair color':pa.HairColor,'hair dress':pa.TopType,'mouth':pa.MouthType,'nose':pa.NoseType,'eyebrows':pa.EyebrowType } +# _vmap= {'eye type':'eye_type','frame style':'style','race':'skin_color','hair color':'hair_color','facial hair color':'facial_hair_color','facial hair':'facial_hair_type','hair dress':'top_type','eyebrows':'eye_brow','nose':'nose_type','mouth':'mouth_type'} +# _omap = {'eye_type':pa.EyesType,'style':pa.AvatarStyle} +_df = [['eye type','eye_type',pa.EyesType],['frame style','style',pa.AvatarStyle],['hair color','hair_color',pa.HairColor],['race','skin_color',pa.SkinColor],['facial hair','facial_hair_type',pa.FacialHairType], +['facial hair color','facial_hair_color',pa.Color],['mouth','mouth_type',pa.MouthType],['hat color','hat_color',pa.Color],['accessory','accessories_type',pa.AccessoriesType],['nose','nose_type',pa.NoseType],['eyebrows','eyebrow_type',pa.EyebrowType], +['hair dress','top_type',pa.TopType],['clothes', 'clothe_type', pa.ClotheType],['clothe color','clothe_color', pa.Color],['clothe graphics','clothe_graphic_type',pa.ClotheGraphicType] +] + +_df = pd.DataFrame(_df,columns=['label','variable','values']) +_df.to_csv('/home/steve/me.avatar.csv',index=False) +def _parameters(): + _out = {'basic':{},'face':{},'clothes':{}} + for _index in np.arange(_df.shape[0]) : + row = _df.iloc[_index] + key = row['label'] + if key in ['race','nose','mouth','eyebrows','eye type'] : + _id = 'basic' + elif 'clothe' in key or key=='accessory': + _id = 'clothes' + else: + _id = 'face' + if len( list(row['values'])) < 2 : + continue + _out[_id][key] = {'values': [{'name':_item.name.replace('_', ' '),'value':_item.value} for _item in row['values']],'variable':row['variable']} + + + return _out +def cast(_args) : + _params = {} + for key in _args : + value = int(_args[key]) + + _info = _df[_df.variable == key].copy() + if _info.shape[0] > 0 : + _params[key] = list(_info['values'].tolist()[0])[value] + # _params[key] = _info['values'].tolist()[value] + return _params +# def _xparameters() : +# """ +# This function returns parameters to be used within an HTML context +# """ +# _orgout = {'basic':{},'extended':{}} +# _out = {} +# for _key in _map : + +# # _out[_key] = {'class':_map[_key].__name__,'values':[],"variable":_vmap[_key]} +# # _out[_key]['values'] = [{'name':_item.name.replace('_', ' '),'value':_item.value} for _item in _map[_key]] +# if _key == 'nose' : +# continue +# if _key in ['race','nose','mouth','eyebrows','eye type'] : +# _out = _orgout['basic'] +# else: +# _out = _orgout['extended'] +# _out[_key] = {'class':_map[_key].__name__,'values':[],"variable":_vmap[_key]} +# _out[_key]['values'] = [{'name':_item.name.replace('_', ' '),'value':_item.value} for _item in _map[_key]] + +# # return _out +# return _orgout + +def _build (_args): + """ + This function builds the avatar with a set of arguments + """ + + _args = cast(_args) + if _args : + + _avatar = Avatar(**_args) + _stream = _avatar.render_png() + _stream =io.BytesIO(_stream) + + _stream = base64.encodebytes(_stream.getvalue()).decode('ascii') + else: + _stream = None + return _stream +def _save(_args): + """ + This function will save the data/candidate to the database + :_args {alias,email,stream} + """ + + writer = transport.factory.instance(provider=providers.MONGO,context='write',db='genomix',doc='participants') + reader = transport.factory.instance(provider=providers.MONGO,context='read',db='genomix',doc='participants') + + # + # Let us make sure the candidate doesn't exist + _df = reader.read(mongo={"find":"participants","filter":{"alias":_args['alias']},"projection":{"_id":0}}) + _info = None + try: + if _df.shape[0] == 0 : + writer.write(_args) + else: + writer.set(_args) + _info = "1" + except Exception as e: + pass + return _info + +def _participants (): + reader = transport.factory.instance(provider=providers.MONGO,context='read',db='genomix',doc='participants') + _df = reader.read(mongo={"find":"participants","limit":10,"projection":{"_id":0}}) + return _df.to_dict(orient='records') \ No newline at end of file diff --git a/content/dialog.html b/content/dialog.html new file mode 100644 index 0000000..64031bf --- /dev/null +++ b/content/dialog.html @@ -0,0 +1,40 @@ + + +
+
+
:title
+
+ +
+
+

+ +

+
+ :message + + +
+

+

+ +

+
+
+
Okay
+
+
+
\ No newline at end of file diff --git a/content/index.html b/content/index.html new file mode 100644 index 0000000..0826a1e --- /dev/null +++ b/content/index.html @@ -0,0 +1,166 @@ + + +
+ + +
+
+ +
+
+
+
+ + Save & Continue +
+
+
+
+
+ + {%set _params = routes['api/studio/_parameters']() %} + {%set sections = _params.keys() %} +
+ {%for _name in sections %} +
{{_name}}
+ {%endfor%} +
+
+ +

+

+

+ {%for _key in _params %} + + {%set _iparams = _params[_key] %} +
+ +
+ {%for _name in _iparams%} + +
+
{{_name|safe}}
+ {%set values = _iparams[_name]['values'] %} +
+ +
+ +
+ + {%endfor%} +
+ {% if loop.index == 3 %} + + {%endif%} +
+ {%endfor%} + + + +
+ +
+
+ + + + diff --git a/content/participants.html b/content/participants.html new file mode 100644 index 0000000..f6d55cc --- /dev/null +++ b/content/participants.html @@ -0,0 +1,60 @@ + + + + + + + + + + +
+ + {%set _participants = routes['api/studio/_participants']()%} + +
+ +
+ + {%for _user in _participants %} + +
+
+ +
+
+
{{_user.alias}}
+
{{_user.email}}
+
+
+ {%endfor%} +
+ +
+
diff --git a/static/img/logo.png b/static/img/logo.png index eb64b3a..7f3c48f 100644 Binary files a/static/img/logo.png and b/static/img/logo.png differ diff --git a/static/img/logo.svg b/static/img/logo.svg index 06b19c8..abaf927 100644 --- a/static/img/logo.svg +++ b/static/img/logo.svg @@ -1 +1 @@ - \ No newline at end of file + \ No newline at end of file diff --git a/static/js/studio.js b/static/js/studio.js new file mode 100644 index 0000000..8d6b471 --- /dev/null +++ b/static/js/studio.js @@ -0,0 +1,99 @@ +var _build = function(){ + var _nodes = $('.selected_item :selected') + var _body = {} + jx.utils.patterns.visitor(_nodes,function(_item){ + if (_item.selected == true){ + var _name = _item.parentNode.name ; + var _value = _item.value + _body[_name] = parseInt(_value) + } + }) + // + // Let us submit the payload and and render the image + var http = HttpClient.instance() + http.setHeader('Content-Type','application/json') + http.setData (JSON.stringify(_body)) + http.post('/api/studio/_build',function(x){ + stream = 'data:image/png;base64,' + x.responseText + jx.dom.set.attribute('image','src',stream) + // jx.dom.set.attribute('_avatar2','src',stream) + }) + +} + +var _open = function(_id){ + $('.studio .section').hide() + $('.studio .'+_id.trim()).slideDown() + jx.dom.set.value('section-label',_id) + if (_id == 'login'){ + $('.button').hide() + }else{ + $('.button').show() + } + + +} + +_save = function(){ + var _stream = jx.dom.get.attribute('image','src') + var _alias = jx.dom.get.value('alias').trim().toLowerCase() + var _email= jx.dom.get.value('email').trim().toLowerCase() + var _body = {email:_email,alias:_alias,png:_stream,'_args':{}} + var _nodes = $('.selected_item :selected') + if (_alias.match(/^[a-z]{3,}$/) == null || _email.match(/^[a-z,0-9,.,-]+\@[a-z,0-9,-]{2,}\.[a-z]{2,3}$/) == null){ + _message = (['The alias and/or email are invlaid, Please enter correct alias and/or email','']).join('') + _dialog('Error found','fa-solid fa-xmark',_message) + return + } + jx.utils.patterns.visitor(_nodes,function(_item){ + if (_item.selected == true){ + var _name = _item.parentNode.name ; + var _value = _item.value + _body._args[_name] = parseInt(_value) + } + }) + http = HttpClient.instance() + http.setHeader('content-type','application/json') + http.setData(JSON.stringify(_body)) + http.post('/api/studio/_save',function(x){ + if(x.status == 200){ + // + // + _message = (['An avatar for ',_alias,'has been saved/updated']).join(' ') + + _icon = 'fa-solid fa-floppy-disk' + _pointer = function(){_reset(); $('.jxmodal').slideUp()} + + }else{ + _message = (['An avatar for ',_alias,'has failed to be added']).join(' ') + _icon = 'fa-solid fa-xmark' + _pointer = null; + } + _dialog('New Avatar',_icon,_message) + }) +} + +var _dialog = function(title,icon,msg,_pointer){ + var http = HttpClient.instance() + http.setHeader('uri','dialog.html') + http.setHeader('dom','_dialog') + http.post('/page',function(x){ + var _html = x.responseText.replace(/:title/,title).replace(/:message/,msg).replace(/:icon/,icon) + jx.modal.show({html:_html,id:'_dialog'}) + if (_pointer == null){ + _pointer = function(){$('.jxmodal').slideUp()} + + } + + $('.dialog .button').on('click',function(){ + _pointer() + }) + }) +} + +var _reset = function(){ + $("option:selected").prop("selected", false) + // jx.dom.set.attribute('image','src','') + _open('basic') + _build() +} \ No newline at end of file diff --git a/templates/pane.html b/templates/pane.html index 19eb620..a0fb378 100644 --- a/templates/pane.html +++ b/templates/pane.html @@ -1,10 +1,26 @@ -
-
Latest News
+ +
+
New here ?
+ +

-
-
- -
- _anouncement -
\ No newline at end of file +
+
About Genomix Privacy
+ +
+

+ +
+
Existing Avatars
+ + +
+