lterriel commited on
Commit
0aaf5f7
·
1 Parent(s): 53aefb2

fix_bug_adopt_suggest (#3)

Browse files

- bugfix adopt suggestion bug (2bc2c4da823502330dea5f3a41924435ed503821)

Files changed (2) hide show
  1. provider.py +1 -1
  2. static/app.js +108 -76
provider.py CHANGED
@@ -151,7 +151,7 @@ class LLMClient:
151
  ann, err = self._parse_and_validate(raw_text, schema)
152
  if err:
153
  print(
154
- f"[LLM] error provider={self.provider} model={model} latency={time.time() - start:.2f}s error={e}")
155
  return ModelResult(model=model, ok=False, annotation=None, latency_s=time.time() - start, error=err,
156
  raw=raw_text)
157
  print(f"[LLM] done provider={self.provider} model={model} latency={time.time() - start:.2f}s")
 
151
  ann, err = self._parse_and_validate(raw_text, schema)
152
  if err:
153
  print(
154
+ f"[LLM] error provider={self.provider} model={model} latency={time.time() - start:.2f}s error={err}")
155
  return ModelResult(model=model, ok=False, annotation=None, latency_s=time.time() - start, error=err,
156
  raw=raw_text)
157
  print(f"[LLM] done provider={self.provider} model={model} latency={time.time() - start:.2f}s")
static/app.js CHANGED
@@ -326,6 +326,27 @@ function annotator() {
326
  }
327
  this.rev++;
328
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
329
  replaceSentence(sidx, sent) {
330
  const arr = [...this.state.sentences];
331
  arr[sidx] = {
@@ -877,11 +898,24 @@ function annotator() {
877
 
878
  adoptFromModel(model) {
879
  const sent = this.state.sentences[this.editor.sidx];
880
- const t = (sent.per_model[model]?.tokens || [])[this.editor.tidx];
881
- if (!t) return;
882
- // copy all fields except surface
 
883
  const surface = this.editor.tok.surface;
884
- this.editor.tok = {...t, surface};
 
 
 
 
 
 
 
 
 
 
 
 
885
  this.toast(`Adopted from ${this.modelShort(model)}.`, 'ok');
886
  },
887
 
@@ -912,76 +946,87 @@ function annotator() {
912
  },
913
 
914
  async saveToken() {
915
- const sidx = this.editor.sidx;
916
- const tidx = this.editor.tidx;
917
- const surface = this.editor.tok.surface;
918
- const changes = this.fieldChanges();
919
- const wantPropagate =
920
- this.editor.propagateToSimilar &&
921
- Object.keys(changes).length > 0 &&
922
- this.matchingTokenCount() > 0;
923
-
924
- this.editor.tok._corrected = true;
925
-
926
- const r = await fetch(`/api/sentence/${sidx}/token/${tidx}`, {
927
- method: 'POST',
928
- headers: {'Content-Type': 'application/json'},
929
- body: JSON.stringify({token: this.editor.tok})
930
- });
931
-
932
- if (!r.ok) {
933
- this.toast('Save failed.', 'error');
934
- return;
935
- }
936
-
937
- // returns full state to ensure consistency
938
- const data = await r.json();
939
- this.applyState(data);
940
-
941
- let propagatedCount = 0;
942
-
943
- if (wantPropagate) {
944
- try {
945
- const r2 = await fetch('/api/bulk_similar', {
946
  method: 'POST',
947
  headers: {'Content-Type': 'application/json'},
948
- body: JSON.stringify({
949
- surface,
950
- updates: changes,
951
- exclude: [{s: sidx, t: tidx}],
952
- }),
953
  });
954
 
955
- if (r2.ok) {
956
- const j = await r2.json();
 
 
 
 
 
 
957
 
958
- for (const item of (j.sentences || [])) {
959
- this.replaceSentence(item.idx, item.sentence);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
960
  }
 
 
 
961
 
962
- propagatedCount = (j.affected || []).length;
 
 
 
 
 
963
  }
964
- } catch (e) {
965
- this.toast('Propagation failed: ' + e.message, 'error');
966
- }
967
- }
968
 
969
- let iclMsg = '';
 
 
970
 
971
- if (data.icl_add_result === 'updated') {
972
- iclMsg = ` + updated ICL v${this.state.icl_pool.version}`;
973
- } else if (data.icl_add_result === 'inserted') {
974
- iclMsg = ` + added to ICL v${this.state.icl_pool.version}`;
975
- } else if (data.icl_add_result === 'unchanged') {
976
- iclMsg = ` + ICL unchanged`;
977
- }
978
 
979
- // auto-advance
980
- if (this.editor.autoAdvance) {
981
- const next = this.findNextDisagreement(sidx, tidx);
 
 
 
982
 
983
- if (next) {
984
- this.openTokenEditor(next.s, next.t);
 
 
 
985
 
986
  this.toast(
987
  propagatedCount > 0
@@ -989,20 +1034,7 @@ function annotator() {
989
  : `✓ Saved${iclMsg}.`,
990
  'ok'
991
  );
992
-
993
- return;
994
- }
995
- }
996
-
997
- this.closeModal();
998
-
999
- this.toast(
1000
- propagatedCount > 0
1001
- ? `✓ Saved + propagated to ${propagatedCount} other "${surface}"${iclMsg}.`
1002
- : `✓ Saved${iclMsg}.`,
1003
- 'ok'
1004
- );
1005
- },
1006
 
1007
  findNextDisagreement(sidx, tidx) {
1008
  const sents = this.state.sentences;
 
326
  }
327
  this.rev++;
328
  },
329
+ isFullStatePayload(data) {
330
+ return data && Array.isArray(data.sentences) && data.icl_pool !== undefined;
331
+ },
332
+
333
+ applyTokenSavePayload(sidx, data) {
334
+ if (!data) return;
335
+
336
+ // Nouveau backend : payload = _public_state()
337
+ if (this.isFullStatePayload(data)) {
338
+ this.applyState(data);
339
+ return;
340
+ }
341
+
342
+ // Ancien backend : payload = sentence uniquement
343
+ if (data.tokens && Array.isArray(data.tokens)) {
344
+ this.replaceSentence(sidx, data);
345
+ return;
346
+ }
347
+
348
+ console.warn('Unexpected token-save payload:', data);
349
+ },
350
  replaceSentence(sidx, sent) {
351
  const arr = [...this.state.sentences];
352
  arr[sidx] = {
 
898
 
899
  adoptFromModel(model) {
900
  const sent = this.state.sentences[this.editor.sidx];
901
+ const modelTok = (sent.per_model?.[model]?.tokens || [])[this.editor.tidx];
902
+
903
+ if (!modelTok || !this.editor.tok) return;
904
+
905
  const surface = this.editor.tok.surface;
906
+ const adopted = JSON.parse(JSON.stringify(modelTok));
907
+
908
+ for (const [k, v] of Object.entries(adopted)) {
909
+ if (k === 'surface') continue;
910
+ this.editor.tok[k] = v;
911
+ }
912
+
913
+ this.editor.tok.surface = surface;
914
+ this.editor.tok._corrected = true;
915
+
916
+ // Force Alpine reactivity
917
+ this.editor.tok = {...this.editor.tok};
918
+
919
  this.toast(`Adopted from ${this.modelShort(model)}.`, 'ok');
920
  },
921
 
 
946
  },
947
 
948
  async saveToken() {
949
+ const sidx = this.editor.sidx;
950
+ const tidx = this.editor.tidx;
951
+ const surface = this.editor.tok.surface;
952
+ const changes = this.fieldChanges();
953
+ const wantPropagate =
954
+ this.editor.propagateToSimilar &&
955
+ Object.keys(changes).length > 0 &&
956
+ this.matchingTokenCount() > 0;
957
+
958
+ this.editor.tok._corrected = true;
959
+
960
+ const r = await fetch(`/api/sentence/${sidx}/token/${tidx}`, {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
961
  method: 'POST',
962
  headers: {'Content-Type': 'application/json'},
963
+ body: JSON.stringify({token: this.editor.tok})
 
 
 
 
964
  });
965
 
966
+ if (!r.ok) {
967
+ this.toast('Save failed.', 'error');
968
+ return;
969
+ }
970
+
971
+ const data = await r.json();
972
+ this.applyTokenSavePayload(sidx, data);
973
+ let propagatedCount = 0;
974
 
975
+ if (wantPropagate) {
976
+ try {
977
+ const r2 = await fetch('/api/bulk_similar', {
978
+ method: 'POST',
979
+ headers: {'Content-Type': 'application/json'},
980
+ body: JSON.stringify({
981
+ surface,
982
+ updates: changes,
983
+ exclude: [{s: sidx, t: tidx}],
984
+ }),
985
+ });
986
+
987
+ if (r2.ok) {
988
+ const j = await r2.json();
989
+
990
+ for (const item of (j.sentences || [])) {
991
+ this.replaceSentence(item.idx, item.sentence);
992
+ }
993
+
994
+ propagatedCount = (j.affected || []).length;
995
+ }
996
+ } catch (e) {
997
+ this.toast('Propagation failed: ' + e.message, 'error');
998
  }
999
+ }
1000
+
1001
+ let iclMsg = '';
1002
 
1003
+ if (data.icl_add_result === 'updated') {
1004
+ iclMsg = ` + updated ICL v${this.state.icl_pool.version}`;
1005
+ } else if (data.icl_add_result === 'inserted') {
1006
+ iclMsg = ` + added to ICL v${this.state.icl_pool.version}`;
1007
+ } else if (data.icl_add_result === 'unchanged') {
1008
+ iclMsg = ` + ICL unchanged`;
1009
  }
 
 
 
 
1010
 
1011
+ // auto-advance
1012
+ if (this.editor.autoAdvance) {
1013
+ const next = this.findNextDisagreement(sidx, tidx);
1014
 
1015
+ if (next) {
1016
+ this.openTokenEditor(next.s, next.t);
 
 
 
 
 
1017
 
1018
+ this.toast(
1019
+ propagatedCount > 0
1020
+ ? `✓ Saved + propagated to ${propagatedCount} other "${surface}"${iclMsg}.`
1021
+ : `✓ Saved${iclMsg}.`,
1022
+ 'ok'
1023
+ );
1024
 
1025
+ return;
1026
+ }
1027
+ }
1028
+
1029
+ this.closeModal();
1030
 
1031
  this.toast(
1032
  propagatedCount > 0
 
1034
  : `✓ Saved${iclMsg}.`,
1035
  'ok'
1036
  );
1037
+ },
 
 
 
 
 
 
 
 
 
 
 
 
 
1038
 
1039
  findNextDisagreement(sidx, tidx) {
1040
  const sents = this.state.sentences;