Route SSD Detect through typed server recognition

ober

71b239d6a8a3d8907bf5b8dcc84716835eb17b4f

diff --git a/templates/ssd-review-parts/main-server-detect.ss b/templates/ssd-review-parts/main-server-detect.ss
new file mode 100644
index 0000000..291fe10
--- /dev/null
+++ b/templates/ssd-review-parts/main-server-detect.ss
@@ -0,0 +1,299 @@
+(import (jerboa prelude))
+
+(def fragment
+  '((typed-kotlin-file "com/sfb/ssdreview/MainServerDetect.kt"
+      (kotlin-imports (android graphics Bitmap)
+                      (android net Uri)
+                      (org json JSONObject))
+      (typed-library (com sfb ssdreview)
+        (export mainServerDetectFirst)
+        (type Bitmap)
+        (type Exception)
+        (type Int32)
+        (type MainActivity)
+        (type JSONObject)
+        (type SfbServerClient)
+        (type SfbServerPdf)
+        (type SfbServerRecognition)
+        (type SsdGroup)
+        (type SsdReviewView)
+        (type SsdSession)
+        (type Uri)
+        (extern (mainServerDetectBitmap
+                  (activity : MainActivity)) : (Nullable Bitmap)
+          (kotlin-member-get currentBitmap))
+        (extern (mainServerDetectUri
+                  (activity : MainActivity)) : (Nullable Uri)
+          (kotlin-member-get pdfUri))
+        (extern (mainServerDetectGeneration
+                  (activity : MainActivity)) : Int32
+          (kotlin-member-get loadGeneration))
+        (extern (mainServerDetectPage
+                  (activity : MainActivity)) : Int32
+          (kotlin-member-get pageIndex))
+        (extern (mainServerDetectPageCount
+                  (activity : MainActivity)) : Int32
+          (kotlin-member-get pageCount))
+        (extern (mainServerDetectPdfName
+                  (activity : MainActivity)) : String
+          (kotlin-member-get pdfName))
+        (extern (mainServerDetectPdfSha1
+                  (activity : MainActivity)) : String
+          (kotlin-member-get pdfSha1))
+        (extern (mainServerDetectPdfId
+                  (activity : MainActivity)) : String
+          (kotlin-member-get serverPdfId))
+        (extern (mainServerDetectClient
+                  (activity : MainActivity)) : SfbServerClient
+          (kotlin-member-get serverClient))
+        (extern (mainServerDetectView
+                  (activity : MainActivity)) : SsdReviewView
+          (kotlin-member-get reviewView))
+        (extern (mainServerDetectRunBackground
+                  (name : String)
+                  (action : (-> Unit))) : Unit
+          (kotlin-call runBackgroundNamed))
+        (extern (mainServerDetectRunOnUi
+                  (activity : MainActivity)
+                  (action : (-> Unit))) : Unit
+          (kotlin-member-call runOnUiThread))
+        (extern (mainServerDetectSetStatus
+                  (activity : MainActivity)
+                  (status : String)) : Unit
+          (kotlin-call mainActivitySetStatusRaw))
+        (extern (mainServerDetectFindPdf
+                  (client : SfbServerClient)
+                  (name : String)) : (Nullable SfbServerPdf)
+          (kotlin-member-call findServerPdfByName))
+        (extern (mainServerDetectMatchedPdfId
+                  (pdf : SfbServerPdf)) : String
+          (kotlin-member-get pdfId))
+        (extern (mainServerDetectFetchRecognition
+                  (client : SfbServerClient)
+                  (pdfId : String)
+                  (page : Int32)
+                  (dpi : Int32)) : SfbServerRecognition
+          (kotlin-member-call fetchServerRecognition))
+        (extern (mainServerDetectRecognitionGroups
+                  (recognition : SfbServerRecognition)) : (List SsdGroup)
+          (kotlin-member-get groups))
+        (extern (mainServerDetectRecognitionSession
+                  (pdfId : String)
+                  (name : String)
+                  (uri : Uri)
+                  (pageIndex : Int32)
+                  (pageCount : Int32)
+                  (bitmap : Bitmap)
+                  (recognition : SfbServerRecognition)
+                  (manifestArea : (Nullable FloatArray))) : SsdSession
+          (kotlin-call mainServerRecognitionSession))
+        (type FloatArray)
+        (extern (mainServerDetectCurrentLoad
+                  (expectedGeneration : Int32)
+                  (actualGeneration : Int32)
+                  (actualUri : (Nullable Uri))
+                  (expectedUri : Uri)
+                  (actualPage : Int32)
+                  (expectedPage : Int32)) : Bool
+          (kotlin-call currentLoadMatches))
+        (extern (mainServerDetectShowSession
+                  (activity : MainActivity)
+                  (view : SsdReviewView)
+                  (session : SsdSession)) : Unit
+          (kotlin-call mainActivityShowSession))
+        (extern (mainServerDetectRefresh
+                  (view : SsdReviewView)) : Unit
+          (kotlin-call reviewViewRefresh))
+        (extern (mainServerDetectLogResult
+                  (activity : MainActivity)
+                  (stage : String)
+                  (session : SsdSession)
+                  (source : String)
+                  (learned : Int32)
+                  (ocr : Int32)) : Unit
+          (kotlin-call mainActivityLogDetectResultRaw))
+        (extern (mainServerDetectLogEvent
+                  (activity : MainActivity)
+                  (event : String)
+                  (fields : JSONObject)) : Unit
+          (kotlin-call mainActivityLogClientEvent))
+        (extern (mainServerDetectFallback
+                  (activity : MainActivity)
+                  (forceDetect : Bool)
+                  (generation : Int32)
+                  (page : Int32)
+                  (uri : (Nullable Uri))
+                  (pdfName : String)
+                  (pdfSha1 : String)
+                  (pageCount : Int32)
+                  (dpi : Int32)
+                  (truthThreshold : Int32)
+                  (targetCellCount : Int32)
+                  (readTimeout : Int32)) : Unit
+          (kotlin-call mainActivityDetectCurrent))
+        (extern (mainServerDetectExceptionMessage
+                  (error : Exception)) : (Nullable String)
+          (kotlin-member-get message))
+        (def (mainServerDetectCurrent
+               (activity : MainActivity)
+               (generation : Int32)
+               (uri : Uri)
+               (page : Int32)) : Bool
+          (mainServerDetectCurrentLoad
+            generation
+            (mainServerDetectGeneration activity)
+            (mainServerDetectUri activity)
+            uri
+            (mainServerDetectPage activity)
+            page))
+        (def (mainServerDetectErrorText
+               (error : Exception)) : String
+          (let ((message (mainServerDetectExceptionMessage error)))
+            (if (nullable-null? message) "unknown" (nullable-get message))))
+        (def (mainServerDetectFailureFields
+               (error : Exception)) : JSONObject
+          (let ((fields (json-object-empty)))
+            (begin
+              (json-object-put-string!
+                fields
+                "error"
+                (mainServerDetectErrorText error))
+              fields)))
+        (def (mainServerDetectResolvePdfId
+               (activity : MainActivity)
+               (client : SfbServerClient)
+               (name : String)) : String
+          (let ((current (string-trim (mainServerDetectPdfId activity))))
+            (if (not (string-blank? current))
+              current
+              (let ((matched (mainServerDetectFindPdf client name)))
+                (if (nullable-null? matched)
+                  ""
+                  (mainServerDetectMatchedPdfId
+                    (nullable-get matched)))))))
+        (def (mainServerDetectFallbackCaptured
+               (activity : MainActivity)
+               (generation : Int32)
+               (page : Int32)
+               (uri : Uri)
+               (name : String)
+               (sha1 : String)
+               (pageCount : Int32)
+               (dpi : Int32)
+               (truthThreshold : Int32)
+               (targetCellCount : Int32)
+               (readTimeout : Int32)) : Unit
+          (mainServerDetectFallback
+            activity
+            #t
+            generation
+            page
+            (nullable-some uri)
+            name
+            sha1
+            pageCount
+            dpi
+            truthThreshold
+            targetCellCount
+            readTimeout))
+        (def (mainServerDetectApply
+               (activity : MainActivity)
+               (generation : Int32)
+               (page : Int32)
+               (uri : Uri)
+               (session : SsdSession)) : Unit
+          (if (mainServerDetectCurrent activity generation uri page)
+            (begin
+              (mainServerDetectShowSession
+                activity
+                (mainServerDetectView activity)
+                session)
+              (mainServerDetectRefresh
+                (mainServerDetectView activity))
+              (mainServerDetectSetStatus
+                activity
+                (string-append
+                  "Detect: "
+                  (string-append
+                    (int32->string
+                      (list-size
+                        (mainServerDetectRecognitionGroupsForSession
+                          session)))
+                    " evidence-backed groups from sfb-server")))
+              (mainServerDetectLogResult
+                activity
+                "manual-server-detect"
+                session
+                "sfb-server"
+                (int32 0)
+                (int32 0)))
+            (begin)))
+        (extern (mainServerDetectRecognitionGroupsForSession
+                  (session : SsdSession)) : (List SsdGroup)
+          (kotlin-member-get groups))
+        (def (mainServerDetectFirst
+               (activity : MainActivity)
+               (dpi : Int32)
+               (truthThreshold : Int32)
+               (targetCellCount : Int32)
+               (readTimeout : Int32)) : Unit
+          (let ((bitmap (mainServerDetectBitmap activity))
+                (uri (mainServerDetectUri activity)))
+            (if (or (nullable-null? bitmap) (nullable-null? uri))
+              (begin)
+              (let ((loadedBitmap (nullable-get bitmap))
+                    (loadedUri (nullable-get uri))
+                    (generation (mainServerDetectGeneration activity))
+                    (page (mainServerDetectPage activity))
+                    (pageCount (mainServerDetectPageCount activity))
+                    (name (mainServerDetectPdfName activity))
+                    (sha1 (mainServerDetectPdfSha1 activity)))
+                (begin
+                  (mainServerDetectSetStatus
+                    activity
+                    "Requesting sfb-server recognition...")
+                  (mainServerDetectRunBackground
+                    "sfb-server-detect"
+                    (lambda ()
+                      (try
+                        (let ((client (mainServerDetectClient activity)))
+                          (let ((pdfId
+                                  (mainServerDetectResolvePdfId
+                                    activity client name)))
+                            (if (string-blank? pdfId)
+                              (mainServerDetectFallbackCaptured
+                                activity generation page loadedUri name sha1
+                                pageCount dpi truthThreshold targetCellCount
+                                readTimeout)
+                              (let ((recognition
+                                      (mainServerDetectFetchRecognition
+                                        client pdfId (+ page (int32 1)) dpi)))
+                                (if (= (list-size
+                                         (mainServerDetectRecognitionGroups
+                                           recognition))
+                                       (int32 0))
+                                  (mainServerDetectFallbackCaptured
+                                    activity generation page loadedUri name sha1
+                                    pageCount dpi truthThreshold targetCellCount
+                                    readTimeout)
+                                  (let ((session
+                                          (mainServerDetectRecognitionSession
+                                            pdfId name loadedUri page pageCount
+                                            loadedBitmap recognition
+                                            (nullable-none FloatArray))))
+                                    (mainServerDetectRunOnUi
+                                      activity
+                                      (lambda ()
+                                        (mainServerDetectApply
+                                          activity generation page loadedUri
+                                          session)))))))))
+                        (catch (error : Exception)
+                          (begin
+                            (mainServerDetectLogEvent
+                              activity
+                              "manual-server-detect-fallback"
+                              (mainServerDetectFailureFields error))
+                            (mainServerDetectFallbackCaptured
+                              activity generation page loadedUri name sha1
+                              pageCount dpi truthThreshold targetCellCount
+                              readTimeout)))))))))))))))
diff --git a/templates/ssd-review-parts/main-server-pages.ss b/templates/ssd-review-parts/main-server-pages.ss
index 70c7c6a..37190ab 100644
--- a/templates/ssd-review-parts/main-server-pages.ss
+++ b/templates/ssd-review-parts/main-server-pages.ss
@@ -17,7 +17,8 @@
       (typed-library (com sfb ssdreview)
         (export mainServerUri mainServerOpenPdfs
                 mainServerFindEndpointAsync mainServerShowEndpointDialog
-                mainServerRenderCurrentPage mainServerRestorePdf)
+                mainServerRenderCurrentPage mainServerRestorePdf
+                mainServerRecognitionSession)
         (type Bitmap)
         (type Builder)
         (type DialogInterface)
diff --git a/templates/ssd-review-parts/server-ai.ss b/templates/ssd-review-parts/server-ai.ss
index c0e840b..baa6561 100644
--- a/templates/ssd-review-parts/server-ai.ss
+++ b/templates/ssd-review-parts/server-ai.ss
@@ -7,4 +7,5 @@
     (include-fragment "server-client.ss")
     (include-fragment "ai-report.ss")
     (include-fragment "main-server-lifecycle.ss")
-    (include-fragment "main-server-pages.ss")))
+    (include-fragment "main-server-pages.ss")
+    (include-fragment "main-server-detect.ss")))