feat: Add .env.example configuration file and integrate Redis service into Docker Compose for improved task management. Update desktop application to support document indexing and extraction workflows, enhancing user experience with a new extraction wizard and stepper components. Revise README and documentation for clarity on setup and usage.

This commit is contained in:
erik
2026-07-05 22:39:07 -05:00
parent 9aca926988
commit d95f8f6ad8
70 changed files with 9807 additions and 499 deletions
@@ -0,0 +1,110 @@
package model
import (
"encoding/json"
"fmt"
"math"
"os"
"sync"
ort "github.com/yalue/onnxruntime_go"
)
type InferenceMeta struct {
Threshold float64 `json:"threshold"`
FeatureColumns []string `json:"feature_columns"`
}
type Predictor struct {
session *ort.DynamicAdvancedSession
threshold float64
mu sync.Mutex
}
func NewPredictor(modelPath, metaPath string) (*Predictor, error) {
if lib := os.Getenv("ONNXRUNTIME_SHARED_LIBRARY"); lib != "" {
ort.SetSharedLibraryPath(lib)
}
if err := ort.InitializeEnvironment(); err != nil {
return nil, fmt.Errorf("onnx init: %w", err)
}
metaBytes, err := os.ReadFile(metaPath)
if err != nil {
return nil, fmt.Errorf("read inference meta: %w", err)
}
var meta InferenceMeta
if err := json.Unmarshal(metaBytes, &meta); err != nil {
return nil, fmt.Errorf("parse inference meta: %w", err)
}
if meta.Threshold == 0 {
meta.Threshold = 0.5
}
session, err := ort.NewDynamicAdvancedSession(
modelPath,
[]string{"float_input"},
[]string{"probabilities"},
nil,
)
if err != nil {
return nil, fmt.Errorf("onnx session: %w", err)
}
return &Predictor{session: session, threshold: meta.Threshold}, nil
}
func (p *Predictor) Threshold() float64 {
return p.threshold
}
func (p *Predictor) Close() error {
if p.session != nil {
p.session.Destroy()
}
return ort.DestroyEnvironment()
}
func (p *Predictor) PredictProba(features [][8]float32) ([]float64, error) {
if len(features) == 0 {
return nil, nil
}
n := len(features)
flat := make([]float32, 0, n*8)
for _, row := range features {
flat = append(flat, row[:]...)
}
inputShape := ort.NewShape(int64(n), 8)
inputTensor, err := ort.NewTensor(inputShape, flat)
if err != nil {
return nil, err
}
defer inputTensor.Destroy()
outputShape := ort.NewShape(int64(n), 2)
outputTensor, err := ort.NewEmptyTensor[float32](outputShape)
if err != nil {
return nil, err
}
defer outputTensor.Destroy()
p.mu.Lock()
err = p.session.Run([]ort.Value{inputTensor}, []ort.Value{outputTensor})
p.mu.Unlock()
if err != nil {
return nil, err
}
data := outputTensor.GetData()
probs := make([]float64, n)
for i := 0; i < n; i++ {
probs[i] = float64(data[i*2+1])
}
return probs, nil
}
func RoundProb(p float64) float64 {
return math.Round(p*10000) / 10000
}