Welcome to the forum @calinjovrea! 
Prodigy on its own won't be able to know how to process custom UI fields which is why you still need to provide javascript functions that handle the user input and store it in the DB.
For example, you could add an update
callback to your html dropdown that gets triggered on change
function update() {
// Update the default values of `selected_complimentele` & `selected_indurarile` keys with the selected options
const complimenteleElement = document.getElementById("complimentele");
const indurarileElement = document.getElementById("indurarile");
if (complimenteleElement && indurarileElement) {
const complimentele = complimenteleElement.value;
const indurarile = indurarileElement.value;
prodigy.update({
selected_complimentele: complimentele,
selected_indurarile: indurarile
});
} else {
if (!complimenteleElement) {
console.error('Element with id "complimentele" not found.');
}
if (!indurarileElement) {
console.error('Element with id "indurarile" not found.');
}
}
}
This function callsprodigy.update
function that is responsible for updating the current state of the task. Other similar functions that you can interact with via javascript are documented here.
You probably want to restore the options to the default value once the user has answered the question. For that you could specify the reset
function and listen to prodigyanswer
event:
function reset(elementId, firstOption) {
const element = document.getElementById(elementId);
if (element) {
element.value = firstOption;
} else {
console.error(`Element with id "${elementId}" not found.`);
}
}
document.addEventListener('prodigyanswer', (event) => {
reset("complimentele", "frumoasă");
reset("indurarile", "milă");
});
Other events that you can listen to are documented in the same section linked above. You can even specify custom events but it won't be necessary for this particular case.
For simplicity, I'm hardcoding the default values to restore but you could as well access the array of options and choose the first one.
One case that I have not covered so far is when the user accepts the options without modifying anything. Our update
will only be triggered when the user changes the field, so I prepopulated the target fields (selected_complimentele
and selected_indurarile
) with the default value at the recipe level (see full code below).
In summary, the modified recipe would look like this:
import prodigy
from prodigy.components.loaders import Images
from pathlib import Path
def add_default_options(stream, field: str, default_selection: str):
for eg in stream:
eg[field] = default_selection
yield eg
@prodigy.recipe('image-caption')
def image_caption(dataset, image_path):
stream = Images(image_path)
îndurările = ['milă', 'îndurare', 'milostenie', 'compasiune', 'iertare', 'caritate', 'compătimire', 'graţie', 'eleganţă', 'bunăvoinţă', 'farmec','iertare','compătimire','toleranţă', 'răbdare','abţinere', 'clemenţă', 'blândeţe', 'indulgenţă', 'îngăduinţă']
complimentele = ['frumoasă', 'luminoasă', 'sclipitoare', 'orbitoare', 'elegantă', 'sclipitoare', 'superbă', 'mare', 'eleganţă', 'impozantă', 'impresionantă','generoasă','lucioasă','magnifică', 'minunată','împodobită', 'bogată', 'plină-de-noroi', 'somptuosă', 'radiantă', 'costisitoare', 'fabuloasă', 'strălucitoare', 'grandioasă', 'nebună', 'magnifică', 'aur-solid', 'splendidă', 'elegantă']
îndurările_ = ''.join([f"<option value='{w}'>{w}</option>" for w in îndurările])
complimentele_ = ''.join([f"<option value='{w}>{w}</option>" for w in complimentele])
stream = add_default_options(stream, 'selected_complimentele', complimentele[0])
stream = add_default_options(stream, 'selected_indurarile', îndurările[0])
custom_js = Path("custom.js").read_text()
blocks = [
{'view_id': 'image'},
{'view_id': 'html', 'html_template': f"<div style='opacity: 0.5'><select name='complimentele' id='complimentele' onchange='update()'> <option value='frumoasă'>frumoasă</option><option value='luminoasă'>luminoasă</option><option value='sclipitoare'>sclipitoare</option><option value='orbitoare'>orbitoare</option><option value='elegantă'>elegantă</option><option value='sclipitoare'>sclipitoare</option><option value='superbă'>superbă</option><option value='mare'>mare</option><option value='eleganţă'>eleganţă</option><option value='impozantă'>impozantă</option><option value='impresionantă'>impresionantă</option><option value='generoasă'>generoasă</option><option value='lucioasă'>lucioasă</option><option value='magnifică'>magnifică</option><option value='minunată'>minunată</option><option value='împodobită'>împodobită</option><option value='bogată'>bogată</option><option value='plină-de-noroi'>plină-de-noroi</option><option value='somptuosă'>somptuosă</option><option value='radiantă'>radiantă</option><option value='costisitoare'>costisitoare</option><option value='fabuloasă'>fabuloasă</option><option value='strălucitoare'>strălucitoare</option><option value='grandioasă'>grandioasă</option><option value='nebună'>nebună</option><option value='magnifică'>magnifică</option><option value='aur-solid'>aur-solid</option><option value='splendidă'>splendidă</option><option value='elegantă'>elegantă</option></select></div>", 'field_id': 'text', 'field_autofocus': True},
{'view_id': 'html', 'html_template': "<div style='opacity: 0.5'><strong> Cerere de </strong></div>", 'field_id': 'text', 'field_autofocus': True},
{'view_id': 'html', 'html_template': f"<div style='opacity: 0.5'><select name='îndurările' id='indurarile' onchange='update()'><option value='milă'>milă</option><option value='îndurare'>îndurare</option><option value='milostenie'>milostenie</option><option value='compasiune'>compasiune</option><option value='iertare'>iertare</option><option value='caritate'>caritate</option><option value='compătimire'>compătimire</option><option value='graţie'>graţie</option><option value='eleganţă'>eleganţă</option><option value='bunăvoinţă'>bunăvoinţă</option><option value='farmec'>farmec</option><option value='iertare'>iertare</option><option value='compătimire'>compătimire</option><option value='toleranţă'>toleranţă</option><option value='răbdare'>răbdare</option><option value='abţinere'>abţinere</option><option value='clemenţă'>clemenţă</option><option value='blândeţe'>blândeţe</option><option value='indulgenţă'>indulgenţă</option><option value='îngăduinţă'>îngăduinţă</option> </select></div>", 'field_id': 'text', 'field_autofocus': True}
]
return {
'dataset': dataset,
'stream': stream,
'view_id': 'blocks',
'config': {
'blocks': blocks,
'javascript': custom_js,
}
}
Note the update
callback in the HTML definition, the add_default_options
python function for prepopulating the target fields with defaults and the loading of the custom.js
file to custom_js
string, which is then passed as value to the javascript
key of config
in the return statement.
The entire custom.js
would look like this
function update() {
// Update the default values of `selected_complimentele` & `selected_indurarile` keys with the selected options
const complimenteleElement = document.getElementById("complimentele");
const indurarileElement = document.getElementById("indurarile");
if (complimenteleElement && indurarileElement) {
const complimentele = complimenteleElement.value;
const indurarile = indurarileElement.value;
prodigy.update({
selected_complimentele: complimentele,
selected_indurarile: indurarile
});
} else {
if (!complimenteleElement) {
console.error('Element with id "complimentele" not found.');
}
if (!indurarileElement) {
console.error('Element with id "indurarile" not found.');
}
}
}
function reset(elementId, firstOption) {
const element = document.getElementById(elementId);
if (element) {
element.value = firstOption;
} else {
console.error(`Element with id "${elementId}" not found.`);
}
}
document.addEventListener('prodigyanswer', (event) => {
reset("complimentele", "frumoasă");
reset("indurarile", "milă");
});
This should result in the options stored like this in the DB:
{
"image": ...
"text": "373",
"meta": {
"file": "373.jpeg"
},
"path": "../images/373.jpeg",
"selected_complimentele": "frumoasă",
"selected_indurarile": "milă",
"_input_hash": 1363510692,
"_task_hash": 1656897643,
"_view_id": "blocks",
"answer": "accept",
"_timestamp": 1717074014,
"_annotator_id": "2024-05-30_14-59-49",
"_session_id": "2024-05-30_14-59-49"
}