diff --git a/TODO b/TODO index c80772b..1582dda 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,9 @@ ### # +# fix all face, right-click options: +# partial fix for face to new and existing person - the person and refimg +# data are correct, but the face_file_link is not connected (do this in person) - and if we do run AI jobs, they will overwrite it anyway (watch out for race condition) +# #1 get override data into view # also all the add ref img/add override, etc are non-functional - FIX the override* stuff first to get table/naming consistency as that is half the problem # NMO data -> there is an NMO object (just NMO names/types - |json), then there is per face level data - this should be a reference from Face and Schema/marshmallow diff --git a/internal/js/view_support.js b/internal/js/view_support.js index 2df2168..c0d5198 100644 --- a/internal/js/view_support.js +++ b/internal/js/view_support.js @@ -298,6 +298,23 @@ function OverrideForceMatch( person_id, key ) } ) } +// function that handles the POSTed data that comes back when we add a +// reference image to a new or existing person (right-click on a face) +// used in success callbacks from CreatePersonAndRefimg() and AddRefimgTo() +function handleAddRefimgData(key, data) +{ + document.viewing.file_details.faces[item[key].which_face].refimg=data.refimg + document.viewing.file_details.faces[item[key].which_face].refimg_lnk={} + // if we used this img, for now set distance to 0 - it is an exact match! + document.viewing.file_details.faces[item[key].which_face].refimg_lnk.face_distance=0.0 + $('#dbox').modal('hide') + $('#faces').prop('checked',true) + DrawImg() + CheckForJobs() +} + +// when we right-click a face and make a new person, this code creates and +// associates the face function CreatePersonAndRefimg( key ) { d='&face_id='+item[key].id @@ -306,29 +323,17 @@ function CreatePersonAndRefimg( key ) +'&surname='+$('#surname').val() +'&refimg_data='+item[key].refimg_data $.ajax({ type: 'POST', data: d, url: '/match_with_create_person', - success: function(data) { - document.viewing.file_details.faces[item[key].which_face].refimg.person.tag=data.who - document.viewing.file_details.faces[item[key].which_face].facefile_lnk.face_distance=data.distance - $('#dbox').modal('hide') - $('#faces').prop('checked',true) - DrawImg() - CheckForJobs() - } + success: function(data) { handleAddRefimgData(key, data ) }, }) } +// when we right-click a face and connect to an existing person, this connects +// the refimg and associates the face function AddRefimgTo( person_id, key, search ) { d='&face_id='+item[key].id+'&person_id='+person_id+'&refimg_data='+item[key].refimg_data+'&search='+search $.ajax({ type: 'POST', data: d, url: '/add_refimg_to_person', - success: function(data) { - document.viewing.file_details.faces[item[key].which_face].refimg.person.tag=data.who - document.viewing.file_details.faces[item[key].which_face].facefile_lnk.face_distance=data.distance - $('#dbox').modal('hide') - $('#faces').prop('checked',true) - DrawImg() - CheckForJobs() - } + success: function(data) { handleAddRefimgData(key, data ) }, }) } diff --git a/person.py b/person.py index 95694aa..556caa4 100644 --- a/person.py +++ b/person.py @@ -3,8 +3,9 @@ from flask_wtf import FlaskForm from flask import request, render_template, redirect, url_for, make_response, jsonify from main import db, app, ma from settings import Settings, AIModel -from sqlalchemy import Sequence, func +from sqlalchemy import Sequence, func, select from sqlalchemy.exc import SQLAlchemyError +from sqlalchemy.orm import joinedload from flask_login import login_required, current_user from werkzeug.utils import secure_filename from shared import GenFace, GenThumb, PA @@ -114,7 +115,7 @@ def AddRefimgToPerson( filename, person ): SetFELog( f"Failed to add Refimg: {e.orig}", "danger" ) except Exception as e: SetFELog( f"Failed to modify Refimg: {e}", "danger" ) - return + return refimg ################################################################################ # TempRefimgFile: helper function that takes data POST'd (from dialog box to @@ -182,9 +183,12 @@ def match_with_create_person(): p = Person( tag=request.form["tag"], surname=request.form["surname"], firstname=request.form["firstname"] ) # add this fname (of temp refimg) to person fname=TempRefimgFile( request.form['refimg_data'], p.tag ) - AddRefimgToPerson( fname, p ) + r=AddRefimgToPerson( fname, p ) SetFELog( f"Created person: {p.tag}" ) - return make_response( jsonify( who=p.tag, distance='0.0' ) ) + refimg_schema=RefimgSchema(many=False) + r_data=refimg_schema.dump(r) + + return make_response( jsonify( refimg=r_data, who=p.tag, distance='0.0' ) ) ################################################################################ # /person/ -> GET/POST(save or delete) -> shows/edits/delets a single person @@ -267,7 +271,7 @@ def add_refimg(): except Exception as e: SetFELog( f"Failed to load reference image: {e}", "danger" ) - AddRefimgToPerson( fname, person ) + r=AddRefimgToPerson( fname, person ) return redirect( url_for( 'person', id=person.id) ) ################################################################################ @@ -289,6 +293,28 @@ def find_persons(who): return make_response( resp ) +class FaceRefimgLinkSchema(ma.SQLAlchemyAutoSchema): + class Meta: model = FaceRefimgLink + load_instance = True + +class PersonSchema(ma.SQLAlchemyAutoSchema): + class Meta: model=Person + load_instance = True + +class RefimgSchema(ma.SQLAlchemyAutoSchema): + class Meta: + model = Refimg + exclude = ('face',) + load_instance = True + person = ma.Nested(PersonSchema) + +class FaceSchema(ma.SQLAlchemyAutoSchema): + class Meta: + model=Face + exclude = ('face',) + load_instance = True + refimg = ma.Nested(RefimgSchema,allow_none=True) + refimg_lnk = ma.Nested(FaceRefimgLinkSchema,allow_none=True) ################################################################################ # /add_refimg_to_person/ -> POST @@ -296,12 +322,14 @@ def find_persons(who): @app.route("/add_refimg_to_person", methods=["POST"]) @login_required def add_refimg_to_person(): - f = Face.query.get( request.form['face_id'] ) - p = Person.query.get( request.form['person_id'] ) + stmt = select(Face).options( joinedload(Face.refimg_lnk) ).where(Face.id == request.form['face_id']) + f=db.session.execute(stmt).scalars().first() + stmt = select(Person).options( joinedload(Person.refimg) ).where(Person.id == request.form['person_id']) + p=db.session.execute(stmt).scalars().first() # add this fname (of temp refimg) to person fname=TempRefimgFile( request.form['refimg_data'], p.tag ) - AddRefimgToPerson( fname, p ) + r=AddRefimgToPerson( fname, p ) if request.form['search'] == "true": jex=[] @@ -316,7 +344,10 @@ def add_refimg_to_person(): jex.append( JobExtra( name=f"path_type", value=str(ptype.id) ) ) job=NewJob( name="run_ai_on_path", num_files=0, wait_for=None, jex=jex, desc="Look for face(s) in storage path(s)" ) - return make_response( jsonify( who=p.tag, distance='0.0' ) ) + refimg_schema=RefimgSchema(many=False) + r_data=refimg_schema.dump(r) + + return make_response( jsonify( refimg=r_data, who=p.tag, distance='0.0' ) ) ################################################################################ # /add_force_match_override -> POST