@@ -12,6 +12,7 @@ import (
1212
1313 "github.com/photoprism/photoprism/internal/ai/face"
1414 "github.com/photoprism/photoprism/internal/config/customize"
15+ "github.com/photoprism/photoprism/internal/thumb/crop"
1516 "github.com/photoprism/photoprism/pkg/clean"
1617 "github.com/photoprism/photoprism/pkg/fs"
1718 "github.com/photoprism/photoprism/pkg/http/header"
@@ -689,6 +690,47 @@ func TestFile_AddFaces(t *testing.T) {
689690 })
690691}
691692
693+ // TestFile_AddFaceUpgradesProvenance pins that upgrading an embedding-less marker carries the
694+ // detector's own numbers with the vector. Left behind, the size bar falls back to an XMP box extent
695+ // and the score bar is looked up by the newly written detect_model.
696+ func TestFile_AddFaceUpgradesProvenance (t * testing.T ) {
697+ file := & File {
698+ FileUID : "fs6sg6bw45bnlqdw" ,
699+ FileHash : "0e3d3e2e5b2f4b1a9a3d7c1e5f6a8b9c0d1e2f30" ,
700+ FileWidth : 3000 ,
701+ FileHeight : 2000 ,
702+ }
703+
704+ // A sidecar region: a generous box, no embedding, and a score from no detector.
705+ area := crop.Area {Name : "face" , X : 0.4 , Y : 0.4 , W : 0.2 , H : 0.2 }
706+ existing := NewMarker (* file , area , "" , SrcXmp , MarkerFace , MarkerSize (area , * file ), 10 )
707+ require .NotNil (t , existing )
708+ require .NoError (t , existing .Create ())
709+ t .Cleanup (func () { UnscopedDb ().Delete (existing ) })
710+
711+ markers := Markers {* existing }
712+ file .markers = & markers
713+
714+ f := face.Face {
715+ Rows : 2000 ,
716+ Cols : 3000 ,
717+ Score : 88 ,
718+ Area : face .NewArea ("face" , 1000 , 1500 , 300 ),
719+ Embeddings : face.Embeddings {face .RandomEmbedding ()},
720+ EmbedModel : face .EmbeddingModelName (),
721+ ThumbSize : 97 ,
722+ }
723+
724+ file .AddFace (f , "" )
725+
726+ stored := & Marker {}
727+ require .NoError (t , UnscopedDb ().First (stored , "marker_uid = ?" , existing .MarkerUID ).Error )
728+
729+ assert .Equal (t , 97 , stored .ThumbSize , "the extent the vector was sampled at must be recorded" )
730+ assert .Equal (t , 88 , stored .Score , "the score must come from the detector that produced the vector" )
731+ assert .Equal (t , 97 , (* file .Markers ())[0 ].ThumbSize , "and the in-memory marker must match the row" )
732+ }
733+
692734func TestFile_ValidFaceCount (t * testing.T ) {
693735 t .Run ("FileFixturesExampleBridge" , func (t * testing.T ) {
694736 file := FileFixturesExampleBridge
0 commit comments