Lucas ARRIESSE commited on
Commit
4633840
·
1 Parent(s): 595613d

Add support for a smaller model for fast tasks

Browse files
static/index.html CHANGED
@@ -426,67 +426,93 @@
426
  <button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>
427
  </form>
428
  </div>
429
- <h2 class="text-lg font-bold">Private generation settings</h2>
430
- <p class="py-4">Detail your private LLM credentials under to draft and generate solution using
431
- private
432
- LLM</p>
433
  <div class="space-y-4">
434
- <div>
435
- <label for="provider-url" class="block mb-2 text-sm font-medium">LLM provider URL</label>
436
- <input id="settings-provider-url" name="provider-url" class="input input-bordered w-full">
437
- </div>
 
 
 
 
 
 
 
 
438
 
439
- <div>
440
- <label for="provider-token" class="block mb-2 text-sm font-medium">LLM provider
441
- token</label>
442
- <input id="settings-provider-token" name="provider-token"
443
- class="input input-bordered w-full" type="password">
 
 
444
  </div>
445
-
446
- <div>
447
- <label for="provider-model" class="block mb-2 text-sm font-medium">Model</label>
 
 
448
  <button id="settings-fetch-models" class="btn btn-outline">Fetch models</button>
449
- <select id="settings-provider-model" name="provider-model" class="select">
450
- </select>
 
 
 
 
 
 
 
 
 
 
451
  </div>
452
 
453
- <div>
454
- <label for="assessment-rules" class="block mb-2 text-sm font-medium">Assessment
455
- rules</label>
456
- <textarea id="settings-assessment-rules" name="assessment-rules"
457
- class="textarea textarea-bordered w-full h-48"
458
- placeholder="Enter your rules here..."></textarea>
459
- </div>
 
 
 
460
 
461
- <div>
462
- <label for="portfolio-info" class="block mb-2 text-sm font-medium">Portfolio
463
- information</label>
464
- <textarea id="settings-portfolio" name="portfolio-info"
465
- class="textarea textarea-bordered w-full h-48"
466
- placeholder="Enter your portfolio info here..."></textarea>
467
- </div>
468
- <h2 class="text-lg font-bold">FTO analysis</h2>
469
- <p class="py-4">Configure the max numbers of topics explored in the FTO analysis.</p>
470
- <div class="w-full max-w-xs">
471
- <label for="settings-fto-topic-count">Number of topics to explore for FTO</label>
472
- <input id="settings-fto-topic-count" name="settings-fto-topic-count" type="range" min="1"
473
- max="10" value="4" class="range" step="1" />
474
- <!--c moche mais ca marche-->
475
- <div class="flex justify-between px-2.5 mt-2 text-xs">
476
- <span>|</span>
477
- <span></span>
478
- <span>|</span>
479
- <span></span>
480
- <span></span>
481
- <span>|</span>
482
  </div>
483
- <div class="flex justify-between px-2.5 mt-2 text-xs">
484
- <span>1</span>
485
- <span></span>
486
- <span>5</span>
487
- <span></span>
488
- <span></span>
489
- <span>10</span>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
490
  </div>
491
  </div>
492
  <p class="py-4">⚠ 'Save configuration' to keep the current configuration across sessions.</p>
 
426
  <button class="btn btn-sm btn-circle btn-ghost absolute right-2 top-2">✕</button>
427
  </form>
428
  </div>
429
+ <!--LLM api settings-->
 
 
 
430
  <div class="space-y-4">
431
+ <div class="space-y-2">
432
+ <h2 class="text-lg font-bold">LLM API access settings</h2>
433
+ <p class="font-s">Detail your LLM credentials under to draft and generate solutions using
434
+ the
435
+ provided private LLM served over a OpenAI-like API</p>
436
+ <div class="space-y-4">
437
+ <div>
438
+ <label for="provider-url" class="block mb-2 text-sm font-medium">LLM provider URL
439
+ (without last leading /)</label>
440
+ <input id="settings-provider-url" name="provider-url"
441
+ class="input input-bordered w-full">
442
+ </div>
443
 
444
+ <div>
445
+ <label for="provider-token" class="block mb-2 text-sm font-medium">LLM provider
446
+ token</label>
447
+ <input id="settings-provider-token" name="provider-token"
448
+ class="input input-bordered w-full" type="password">
449
+ </div>
450
+ </div>
451
  </div>
452
+ <!--LLM model selection for each task-->
453
+ <div class="space-y-2">
454
+ <h3 class="text-m font-bold">Model selection</h3>
455
+ <p class="font-s">Select the models to use for solution evaluation, refinement and
456
+ summarization.</p>
457
  <button id="settings-fetch-models" class="btn btn-outline">Fetch models</button>
458
+ <div>
459
+ <label for="reasoning-model-selection" class="block mb-2 text-sm font-medium">Model for
460
+ reasoning tasks (evaluation, assessment)</label>
461
+ <select id="settings-reasoning-model" name="reasoning-model-selection" class="select">
462
+ </select>
463
+ </div>
464
+ <div>
465
+ <label for="fast-model-selection" class="block mb-2 text-sm font-medium">Model for fast,
466
+ simple tasks (summarizing, structured output)</label>
467
+ <select id="settings-fast-model" name="fast-model-selection" class="select">
468
+ </select>
469
+ </div>
470
  </div>
471
 
472
+ <!--Solution assessment settings-->
473
+ <div class="space-y-2">
474
+ <h3 class="text-m font-bold">Solution assessment settings</h3>
475
+ <div>
476
+ <label for="assessment-rules" class="block mb-2 text-sm font-medium">Assessment
477
+ rules</label>
478
+ <textarea id="settings-assessment-rules" name="assessment-rules"
479
+ class="textarea textarea-bordered w-full h-48"
480
+ placeholder="Enter your rules here..."></textarea>
481
+ </div>
482
 
483
+ <div>
484
+ <label for="portfolio-info" class="block mb-2 text-sm font-medium">Portfolio
485
+ information</label>
486
+ <textarea id="settings-portfolio" name="portfolio-info"
487
+ class="textarea textarea-bordered w-full h-48"
488
+ placeholder="Enter your portfolio info here..."></textarea>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
489
  </div>
490
+ </div>
491
+
492
+ <div class="space-y-2">
493
+ <h2 class="text-m font-bold">FTO analysis</h2>
494
+ <p class="text-s">Configure the max numbers of topics explored in the FTO analysis.</p>
495
+ <div class="w-full max-w-xs">
496
+ <label for="settings-fto-topic-count">Number of topics to explore for FTO</label>
497
+ <input id="settings-fto-topic-count" name="settings-fto-topic-count" type="range"
498
+ min="1" max="10" value="4" class="range" step="1" />
499
+ <!--c moche mais ca marche-->
500
+ <div class="flex justify-between px-2.5 mt-2 text-xs">
501
+ <span>|</span>
502
+ <span></span>
503
+ <span>|</span>
504
+ <span></span>
505
+ <span></span>
506
+ <span>|</span>
507
+ </div>
508
+ <div class="flex justify-between px-2.5 mt-2 text-xs">
509
+ <span>1</span>
510
+ <span></span>
511
+ <span>5</span>
512
+ <span></span>
513
+ <span></span>
514
+ <span>10</span>
515
+ </div>
516
  </div>
517
  </div>
518
  <p class="py-4">⚠ 'Save configuration' to keep the current configuration across sessions.</p>
static/js/app.js CHANGED
@@ -1086,7 +1086,8 @@ document.getElementById('settings-fetch-models').addEventListener('click', _ =>
1086
  const url = document.getElementById('settings-provider-url').value;
1087
  const token = document.getElementById('settings-provider-token').value;
1088
 
1089
- populateLLMModelSelect('settings-provider-model', url, token).catch(e => alert("Error while fetching models: " + e))
 
1090
  });
1091
 
1092
  // ================== solution drafting events =============
 
1086
  const url = document.getElementById('settings-provider-url').value;
1087
  const token = document.getElementById('settings-provider-token').value;
1088
 
1089
+ populateLLMModelSelect('settings-reasoning-model', url, token).catch(e => alert("Error while fetching models: " + e))
1090
+ populateLLMModelSelect('settings-fast-model', url, token).catch(e => alert("Error while fetching models: " + e))
1091
  });
1092
 
1093
  // ================== solution drafting events =============
static/js/gen.js CHANGED
@@ -201,7 +201,7 @@ const StructuredAssessmentOutput = zod.object({
201
  insights: zod.array(zod.string()),
202
  });
203
 
204
- export async function assessSolution(providerUrl, modelName, apiKey, solution, assessment_rules, portfolio_info) {
205
  const template = await retrieveTemplate("assess");
206
 
207
  const assessment_template = formatTemplate(template, {
@@ -211,7 +211,7 @@ export async function assessSolution(providerUrl, modelName, apiKey, solution, a
211
  solution_description: solution.solution_description,
212
  });
213
 
214
- const assessment_full = await generateCompletion(providerUrl, modelName, apiKey, [
215
  { role: "user", content: assessment_template }
216
  ]);
217
 
@@ -221,7 +221,7 @@ export async function assessSolution(providerUrl, modelName, apiKey, solution, a
221
  "response_schema": zod.toJSONSchema(StructuredAssessmentOutput)
222
  })
223
 
224
- const extracted_info = await generateStructuredCompletion(providerUrl, modelName, apiKey, [{ role: "user", content: structured_filled_template }], StructuredAssessmentOutput);
225
 
226
  return { assessment_full, extracted_info };
227
  }
@@ -258,7 +258,7 @@ const FTOAnalysisTopicsSchema = zod.object({
258
  /**
259
  * Extract the topics to search for FTO
260
  */
261
- async function getFtoAnalysisTopics(providerUrl, modelName, apiKey, idea, count) {
262
  const template = await retrieveTemplate("fto_topics");
263
 
264
  const structured_template = formatTemplate(template, {
@@ -268,7 +268,7 @@ async function getFtoAnalysisTopics(providerUrl, modelName, apiKey, idea, count)
268
  "max_topic_count": count
269
  });
270
 
271
- const topics = await generateStructuredCompletion(providerUrl, modelName, apiKey, [{ role: "user", content: structured_template }], FTOAnalysisTopicsSchema);
272
 
273
  return topics;
274
  }
@@ -276,7 +276,7 @@ async function getFtoAnalysisTopics(providerUrl, modelName, apiKey, idea, count)
276
  /*
277
  * Assess the infringement of the idea wrt
278
  */
279
- async function assessFTOReport(providerUrl, modelName, apiKey, solution, fto_report, portfolio_info) {
280
  const template = await retrieveTemplate("fto_assess");
281
 
282
  const assessment_template = formatTemplate(template, {
@@ -288,7 +288,7 @@ async function assessFTOReport(providerUrl, modelName, apiKey, solution, fto_rep
288
 
289
  console.log("FTO Length: " + assessment_template.length);
290
 
291
- const assessment_full = await generateCompletion(providerUrl, modelName, apiKey, [
292
  { role: "user", content: assessment_template }
293
  ]);
294
 
@@ -298,18 +298,18 @@ async function assessFTOReport(providerUrl, modelName, apiKey, solution, fto_rep
298
  "response_schema": zod.toJSONSchema(StructuredAssessmentOutput)
299
  })
300
 
301
- const extracted_info = await generateStructuredCompletion(providerUrl, modelName, apiKey, [{ role: "user", content: structured_filled_template }], StructuredAssessmentOutput);
302
 
303
  return { assessment_full, extracted_info };
304
  }
305
 
306
- export async function runFTOAnalysis(providerUrl, providerModel, apiKey, solution, portfolio_info, ftoTopicCount) {
307
- const fto_topics = await getFtoAnalysisTopics(providerUrl, providerModel, apiKey, solution, ftoTopicCount);
308
  console.log(fto_topics);
309
 
310
  const fto_report = await performDeepSearch(fto_topics.topics);
311
 
312
- const assess_results = await assessFTOReport(providerUrl, providerModel, apiKey, solution, fto_report, portfolio_info);
313
  console.log(assess_results.extracted_info);
314
 
315
  return {
 
201
  insights: zod.array(zod.string()),
202
  });
203
 
204
+ export async function assessSolution(providerUrl, reasoningModel, fastModel, apiKey, solution, assessment_rules, portfolio_info) {
205
  const template = await retrieveTemplate("assess");
206
 
207
  const assessment_template = formatTemplate(template, {
 
211
  solution_description: solution.solution_description,
212
  });
213
 
214
+ const assessment_full = await generateCompletion(providerUrl, reasoningModel, apiKey, [
215
  { role: "user", content: assessment_template }
216
  ]);
217
 
 
221
  "response_schema": zod.toJSONSchema(StructuredAssessmentOutput)
222
  })
223
 
224
+ const extracted_info = await generateStructuredCompletion(providerUrl, fastModel, apiKey, [{ role: "user", content: structured_filled_template }], StructuredAssessmentOutput);
225
 
226
  return { assessment_full, extracted_info };
227
  }
 
258
  /**
259
  * Extract the topics to search for FTO
260
  */
261
+ async function getFtoAnalysisTopics(providerUrl, reasoningModel, apiKey, idea, count) {
262
  const template = await retrieveTemplate("fto_topics");
263
 
264
  const structured_template = formatTemplate(template, {
 
268
  "max_topic_count": count
269
  });
270
 
271
+ const topics = await generateStructuredCompletion(providerUrl, reasoningModel, apiKey, [{ role: "user", content: structured_template }], FTOAnalysisTopicsSchema);
272
 
273
  return topics;
274
  }
 
276
  /*
277
  * Assess the infringement of the idea wrt
278
  */
279
+ async function assessFTOReport(providerUrl, reasoningModel, fastModel, apiKey, solution, fto_report, portfolio_info) {
280
  const template = await retrieveTemplate("fto_assess");
281
 
282
  const assessment_template = formatTemplate(template, {
 
288
 
289
  console.log("FTO Length: " + assessment_template.length);
290
 
291
+ const assessment_full = await generateCompletion(providerUrl, reasoningModel, apiKey, [
292
  { role: "user", content: assessment_template }
293
  ]);
294
 
 
298
  "response_schema": zod.toJSONSchema(StructuredAssessmentOutput)
299
  })
300
 
301
+ const extracted_info = await generateStructuredCompletion(providerUrl, fastModel, apiKey, [{ role: "user", content: structured_filled_template }], StructuredAssessmentOutput);
302
 
303
  return { assessment_full, extracted_info };
304
  }
305
 
306
+ export async function runFTOAnalysis(providerUrl, reasoningModel, fastModel, apiKey, solution, portfolio_info, ftoTopicCount) {
307
+ const fto_topics = await getFtoAnalysisTopics(providerUrl, reasoningModel, apiKey, solution, ftoTopicCount);
308
  console.log(fto_topics);
309
 
310
  const fto_report = await performDeepSearch(fto_topics.topics);
311
 
312
+ const assess_results = await assessFTOReport(providerUrl, reasoningModel, fastModel, apiKey, solution, fto_report, portfolio_info);
313
  console.log(assess_results.extracted_info);
314
 
315
  return {
static/js/persistence.js CHANGED
@@ -1,5 +1,5 @@
1
  // clées utilisées pour la generation avec private compute
2
- const CONFIG_KEYS = ["providerUrl", "providerToken", "providerModel", "assessmentRules", "businessPortfolio", "ftoTopicCount"];
3
  // clée pour marquer si la config est remplie.
4
  const POPULATED_CONFIG_KEY = "_config_populated";
5
 
 
1
  // clées utilisées pour la generation avec private compute
2
+ const CONFIG_KEYS = ["providerUrl", "providerToken", "reasoningModel", "fastModel", "assessmentRules", "businessPortfolio", "ftoTopicCount"];
3
  // clée pour marquer si la config est remplie.
4
  const POPULATED_CONFIG_KEY = "_config_populated";
5
 
static/js/ui.js CHANGED
@@ -356,21 +356,22 @@ export function debounceAutoCategoryCount(state) {
356
  export function getConfigFields() {
357
  const providerUrl = document.getElementById('settings-provider-url').value;
358
  const providerToken = document.getElementById('settings-provider-token').value;
359
- const providerModel = document.getElementById('settings-provider-model').value;
 
360
  const assessmentRules = document.getElementById('settings-assessment-rules').value;
361
  const businessPortfolio = document.getElementById('settings-portfolio').value;
362
  const ftoTopicCount = document.getElementById('settings-fto-topic-count').value;
363
 
364
- return { providerUrl, providerToken, providerModel, assessmentRules, businessPortfolio, ftoTopicCount };
365
  }
366
 
367
  /**
368
  * Vérifie si les paramètres sont bien renseignés pour utiliser la génération privée.
369
  */
370
  export function checkPrivateLLMInfoAvailable() {
371
- const { providerUrl, providerToken, providerModel, assessmentRules, businessPortfolio } = getConfigFields();
372
  const isEmpty = (str) => (!str?.length);
373
- return !isEmpty(providerUrl) && !isEmpty(providerToken) && !isEmpty(assessmentRules) && !isEmpty(businessPortfolio) && !isEmpty(providerModel);
374
  // return true;
375
  }
376
 
@@ -433,7 +434,8 @@ export function handleLoadConfigFields() {
433
 
434
  const providerUrl = document.getElementById('settings-provider-url');
435
  const providerToken = document.getElementById('settings-provider-token');
436
- const providerModel = document.getElementById('settings-provider-model');
 
437
  const assessmentRules = document.getElementById('settings-assessment-rules');
438
  const businessPortfolio = document.getElementById('settings-portfolio');
439
  const ftoTopicCount = document.getElementById('settings-fto-topic-count');
@@ -443,12 +445,19 @@ export function handleLoadConfigFields() {
443
  assessmentRules.value = configuration.assessmentRules;
444
  businessPortfolio.value = configuration.businessPortfolio;
445
  ftoTopicCount.value = configuration.ftoTopicCount;
 
446
 
447
  // on doit d'abord recup les modeles avant de set la valeur
448
- populateLLMModelSelect('settings-provider-model', configuration.providerUrl, configuration.providerToken).then(() => {
449
- providerModel.value = configuration.providerModel;
450
  }).catch(e => {
451
- alert("Failed to set LLM model in model selector. Model may not be available anymore, check model in LLM settings.");
 
 
 
 
 
 
452
  })
453
  }
454
 
@@ -499,10 +508,10 @@ export function moveSolutionToDrafts(solution) {
499
 
500
  switchTab('draft-tab');
501
 
502
- const { providerUrl, providerToken, providerModel, assessmentRules, businessPortfolio } = getConfigFields();
503
 
504
  showLoadingOverlay("Assessing solution ....");
505
- assessSolution(providerUrl, providerModel, providerToken, solution, assessmentRules, businessPortfolio).then(response => {
506
  // reset the state of the draft history
507
  draftHistory = [];
508
  draftCurrentIndex = -1;
@@ -645,14 +654,14 @@ export function handleDraftRefine() {
645
  }
646
  // ---
647
 
648
- const { providerUrl, providerToken, providerModel, assessmentRules, businessPortfolio } = getConfigFields();
649
 
650
  showLoadingOverlay('Refining and assessing ....')
651
 
652
- refineSolution(providerUrl, providerModel, providerToken, currentState.solution, selectedInsights, userInsightsText, assessmentRules, businessPortfolio)
653
  .then(newSolution => {
654
  const refinedSolution = newSolution;
655
- return assessSolution(providerUrl, providerModel, providerToken, newSolution, assessmentRules, businessPortfolio)
656
  .then(assessedResult => {
657
  return { refinedSolution, assessedResult };
658
  });
@@ -692,14 +701,14 @@ function jumpToDraft(index) {
692
  }
693
 
694
  export function handleFTOAnalysis() {
695
- const { providerUrl, providerToken, providerModel, businessPortfolio, ftoTopicCount } = getConfigFields();
696
  const currentState = draftHistory[draftCurrentIndex];
697
 
698
  console.log("Launching FTO analysis");
699
 
700
  showLoadingOverlay("Running FTO analysis... This may take a while");
701
 
702
- runFTOAnalysis(providerUrl, providerModel, providerToken, currentState.solution, businessPortfolio, ftoTopicCount)
703
  .then(result => {
704
  // map from a list of insights to a selectable list of insights
705
  const newInsights = result.extracted_info.insights.map((e, idx, __) => ({ id: idx, text: e, checked: false }));
 
356
  export function getConfigFields() {
357
  const providerUrl = document.getElementById('settings-provider-url').value;
358
  const providerToken = document.getElementById('settings-provider-token').value;
359
+ const reasoningModel = document.getElementById('settings-reasoning-model').value;
360
+ const fastModel = document.getElementById('settings-fast-model').value;
361
  const assessmentRules = document.getElementById('settings-assessment-rules').value;
362
  const businessPortfolio = document.getElementById('settings-portfolio').value;
363
  const ftoTopicCount = document.getElementById('settings-fto-topic-count').value;
364
 
365
+ return { providerUrl, providerToken, reasoningModel, fastModel, assessmentRules, businessPortfolio, ftoTopicCount };
366
  }
367
 
368
  /**
369
  * Vérifie si les paramètres sont bien renseignés pour utiliser la génération privée.
370
  */
371
  export function checkPrivateLLMInfoAvailable() {
372
+ const { providerUrl, providerToken, reasoningModel, fastModel, assessmentRules, businessPortfolio } = getConfigFields();
373
  const isEmpty = (str) => (!str?.length);
374
+ return !isEmpty(providerUrl) && !isEmpty(providerToken) && !isEmpty(assessmentRules) && !isEmpty(businessPortfolio) && !isEmpty(reasoningModel) && !isEmpty(fastModel);
375
  // return true;
376
  }
377
 
 
434
 
435
  const providerUrl = document.getElementById('settings-provider-url');
436
  const providerToken = document.getElementById('settings-provider-token');
437
+ const reasoningModel = document.getElementById('settings-reasoning-model');
438
+ const fastModel = document.getElementById('settings-fast-model');
439
  const assessmentRules = document.getElementById('settings-assessment-rules');
440
  const businessPortfolio = document.getElementById('settings-portfolio');
441
  const ftoTopicCount = document.getElementById('settings-fto-topic-count');
 
445
  assessmentRules.value = configuration.assessmentRules;
446
  businessPortfolio.value = configuration.businessPortfolio;
447
  ftoTopicCount.value = configuration.ftoTopicCount;
448
+ fastModel.value = configuration.fastModel;
449
 
450
  // on doit d'abord recup les modeles avant de set la valeur
451
+ populateLLMModelSelect('settings-reasoning-model', configuration.providerUrl, configuration.providerToken).then(() => {
452
+ reasoningModel.value = configuration.reasoningModel;
453
  }).catch(e => {
454
+ alert("Failed to set LLM model for reasoning in the model selector. Model may not be available anymore, check LLM settings.");
455
+ })
456
+
457
+ populateLLMModelSelect('settings-fast-model', configuration.providerUrl, configuration.providerToken).then(() => {
458
+ fastModel.value = configuration.fastModel;
459
+ }).catch(e => {
460
+ alert("Failed to set fast LLM model in the model selector. Model may not be available anymore, check LLM settings.");
461
  })
462
  }
463
 
 
508
 
509
  switchTab('draft-tab');
510
 
511
+ const { providerUrl, providerToken, reasoningModel, fastModel, assessmentRules, businessPortfolio } = getConfigFields();
512
 
513
  showLoadingOverlay("Assessing solution ....");
514
+ assessSolution(providerUrl, reasoningModel, fastModel, providerToken, solution, assessmentRules, businessPortfolio).then(response => {
515
  // reset the state of the draft history
516
  draftHistory = [];
517
  draftCurrentIndex = -1;
 
654
  }
655
  // ---
656
 
657
+ const { providerUrl, providerToken, reasoningModel, fastModel, assessmentRules, businessPortfolio } = getConfigFields();
658
 
659
  showLoadingOverlay('Refining and assessing ....')
660
 
661
+ refineSolution(providerUrl, reasoningModel, providerToken, currentState.solution, selectedInsights, userInsightsText, assessmentRules, businessPortfolio)
662
  .then(newSolution => {
663
  const refinedSolution = newSolution;
664
+ return assessSolution(providerUrl, reasoningModel, fastModel, providerToken, newSolution, assessmentRules, businessPortfolio)
665
  .then(assessedResult => {
666
  return { refinedSolution, assessedResult };
667
  });
 
701
  }
702
 
703
  export function handleFTOAnalysis() {
704
+ const { providerUrl, providerToken, reasoningModel, fastModel, businessPortfolio, ftoTopicCount } = getConfigFields();
705
  const currentState = draftHistory[draftCurrentIndex];
706
 
707
  console.log("Launching FTO analysis");
708
 
709
  showLoadingOverlay("Running FTO analysis... This may take a while");
710
 
711
+ runFTOAnalysis(providerUrl, reasoningModel, fastModel, providerToken, currentState.solution, businessPortfolio, ftoTopicCount)
712
  .then(result => {
713
  // map from a list of insights to a selectable list of insights
714
  const newInsights = result.extracted_info.insights.map((e, idx, __) => ({ id: idx, text: e, checked: false }));