@@ -11,6 +11,7 @@ import (
1111 "runtime"
1212 "strconv"
1313 "strings"
14+ "sync"
1415
1516 ort "github.com/yalue/onnxruntime_go"
1617 "golang.org/x/sync/errgroup"
@@ -23,11 +24,14 @@ import (
2324type ORTModel struct {
2425 Session * ort.DynamicAdvancedSession
2526 GenerativeSession * ortgenai.Session
27+ GenerativeEngine * ortgenai.Engine
2628 SessionOptions * ort.SessionOptions
2729 Options * options.OrtOptions
2830 Destroy func () error
2931}
3032
33+ var generativeBackendMutex = sync.Mutex {}
34+
3135func mapORTOptions (options * options.Options ) ([]string , map [string ]map [string ]string , error ) {
3236 if options == nil || options .ORTOptions == nil {
3337 return []string {}, map [string ]map [string ]string {}, nil // let default EPs be used
@@ -87,11 +91,54 @@ func mapORTOptions(options *options.Options) ([]string, map[string]map[string]st
8791}
8892
8993func createORTGenerativeSession (model * Model , options * options.Options ) error {
90-
9194 if strings .HasPrefix (model .Path , "s3:" ) {
9295 return errors .New ("ORT Gen AI does not support S3 paths. Please download the model to a local directory and try again" )
9396 }
9497
98+ err := initialiseORTGenAI (options )
99+ if err != nil {
100+ return err
101+ }
102+
103+ providers , providerOptions , err := mapORTOptions (options )
104+ if err != nil {
105+ return fmt .Errorf ("error mapping ORT options for generative session: %w" , err )
106+ }
107+
108+ if options .ORTOptions .UseEngine {
109+ ortGenAiEngine , err := ortgenai .CreateEngineWithOptions (model .Path , providers , providerOptions )
110+ if err != nil {
111+ return fmt .Errorf ("error creating ortgenai engine: %w" , err )
112+ }
113+ model .ORTModel = & ORTModel {
114+ GenerativeEngine : ortGenAiEngine ,
115+ Options : options .ORTOptions ,
116+ Destroy : func () error {
117+ ortGenAiEngine .Destroy ()
118+ return nil
119+ },
120+ }
121+ } else {
122+ ortGenAiSession , err := ortgenai .CreateSessionWithOptions (model .Path , providers , providerOptions )
123+ if err != nil {
124+ return fmt .Errorf ("error creating ortgenai session: %w" , err )
125+ }
126+ model .ORTModel = & ORTModel {
127+ GenerativeSession : ortGenAiSession ,
128+ Options : options .ORTOptions ,
129+ Destroy : func () error {
130+ ortGenAiSession .Destroy ()
131+ return nil
132+ },
133+ }
134+ }
135+ return nil
136+ }
137+
138+ func initialiseORTGenAI (options * options.Options ) error {
139+ generativeBackendMutex .Lock ()
140+ defer generativeBackendMutex .Unlock ()
141+
95142 if ! ortgenai .IsInitialized () {
96143 if options == nil || options .ORTOptions == nil {
97144 return fmt .Errorf ("ORT options must be provided to initialize ortgenai" )
@@ -124,22 +171,6 @@ func createORTGenerativeSession(model *Model, options *options.Options) error {
124171 return fmt .Errorf ("error initializing the ort genai environment: %w" , err )
125172 }
126173 }
127- providers , providerOptions , err := mapORTOptions (options )
128- if err != nil {
129- return fmt .Errorf ("error mapping ORT options for generative session: %w" , err )
130- }
131- ortGenAiSession , err := ortgenai .CreateSessionWithOptions (model .Path , providers , providerOptions )
132- if err != nil {
133- return fmt .Errorf ("error creating ortgenai session: %w" , err )
134- }
135- model .ORTModel = & ORTModel {
136- GenerativeSession : ortGenAiSession ,
137- Options : options .ORTOptions ,
138- Destroy : func () error {
139- ortGenAiSession .Destroy ()
140- return nil
141- },
142- }
143174 return nil
144175}
145176
@@ -156,8 +187,9 @@ func runGenerativeORTSessionOnBatch(ctx context.Context, batch *PipelineBatch, p
156187 }
157188
158189 session := p .Model .ORTModel .GenerativeSession
159- if session == nil {
160- return nil , nil , errors .New ("ORT generative session is not initialized" )
190+ engine := p .Model .ORTModel .GenerativeEngine
191+ if session == nil && engine == nil {
192+ return nil , nil , errors .New ("ORT generative session/engine is not initialized" )
161193 }
162194
163195 inputs , ok := batch .InputValues .([][]ortgenai.Message )
@@ -183,6 +215,10 @@ func runGenerativeORTSessionOnBatch(ctx context.Context, batch *PipelineBatch, p
183215 generateCtx , cancel := context .WithCancel (ctx )
184216
185217 if batch .Images != nil {
218+ if session == nil {
219+ cancel ()
220+ return nil , nil , errors .New ("multimodal generation requires a session, but only engine is initialized" )
221+ }
186222 images , ok := batch .Images .(* ortgenai.Images )
187223 if ! ok {
188224 cancel ()
@@ -194,7 +230,11 @@ func runGenerativeORTSessionOnBatch(ctx context.Context, batch *PipelineBatch, p
194230 return nil , nil , fmt .Errorf ("error during multimodal generation start: %w" , err )
195231 }
196232 } else {
197- ortTokenStream , ortErrorStream , err = session .Generate (generateCtx , inputs , tools , & ortgenai.GenerationOptions {MaxLength : maxLength , Temperature : temperature , TopP : topP , Seed : seed , Guidance : ortGuidance })
233+ if engine != nil {
234+ ortTokenStream , ortErrorStream , err = engine .Generate (generateCtx , inputs , tools , & ortgenai.GenerationOptions {MaxLength : maxLength , Temperature : temperature , TopP : topP , Seed : seed , Guidance : ortGuidance })
235+ } else {
236+ ortTokenStream , ortErrorStream , err = session .Generate (generateCtx , inputs , tools , & ortgenai.GenerationOptions {MaxLength : maxLength , Temperature : temperature , TopP : topP , Seed : seed , Guidance : ortGuidance })
237+ }
198238 if err != nil {
199239 cancel ()
200240 return nil , nil , fmt .Errorf ("error during generation start: %w" , err )
@@ -237,14 +277,14 @@ func runGenerativeORTSessionOnBatch(ctx context.Context, batch *PipelineBatch, p
237277 if ! ok {
238278 return
239279 }
240- idx := tokenDelta .Sequence
241- if completeSequences [idx ] {
280+ sequence := tokenDelta .Sequence
281+ if completeSequences [sequence ] {
242282 // Already complete; ignore further tokens for this sequence.
243283 continue
244284 }
245285 if tokenDelta .EOSReached {
246286 // EOS terminates sequence; no token content to forward.
247- completeSequences [idx ] = true
287+ completeSequences [sequence ] = true
248288 completedCount ++
249289 if completedCount == totalSequences {
250290 cancel ()
@@ -254,26 +294,26 @@ func runGenerativeORTSessionOnBatch(ctx context.Context, batch *PipelineBatch, p
254294 }
255295
256296 // Forward token immediately.
257- tokenStream <- SequenceDelta {Token : tokenDelta .Token , Index : idx }
297+ tokenStream <- SequenceDelta {Token : tokenDelta .Token , Sequence : sequence }
258298
259299 // Detect stop sequences using a bounded rolling window.
260300 // Window size is maxStopLen + len(current token) to catch:
261301 // - stops spanning the boundary between previous tail and this token
262302 // - stops fully contained inside a single (possibly long) token
263303 if len (filteredStops ) > 0 && maxStopLen > 0 {
264- tail := tails [idx ] + tokenDelta .Token
304+ tail := tails [sequence ] + tokenDelta .Token
265305 keep := maxStopLen + len (tokenDelta .Token )
266306 if keep < maxStopLen {
267307 keep = maxStopLen
268308 }
269309 if len (tail ) > keep {
270310 tail = tail [len (tail )- keep :]
271311 }
272- tails [idx ] = tail
312+ tails [sequence ] = tail
273313
274314 for _ , s := range filteredStops {
275315 if strings .Contains (tail , s ) {
276- completeSequences [idx ] = true
316+ completeSequences [sequence ] = true
277317 completedCount ++
278318 if completedCount == totalSequences {
279319 cancel ()
0 commit comments