fix_bug_adopt_suggest (#3)
Browse files- bugfix adopt suggestion bug (2bc2c4da823502330dea5f3a41924435ed503821)
- provider.py +1 -1
- 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={
|
| 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
|
| 881 |
-
|
| 882 |
-
|
|
|
|
| 883 |
const surface = this.editor.tok.surface;
|
| 884 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 885 |
this.toast(`Adopted from ${this.modelShort(model)}.`, 'ok');
|
| 886 |
},
|
| 887 |
|
|
@@ -912,76 +946,87 @@ function annotator() {
|
|
| 912 |
},
|
| 913 |
|
| 914 |
async saveToken() {
|
| 915 |
-
|
| 916 |
-
|
| 917 |
-
|
| 918 |
-
|
| 919 |
-
|
| 920 |
-
|
| 921 |
-
|
| 922 |
-
|
| 923 |
-
|
| 924 |
-
|
| 925 |
-
|
| 926 |
-
|
| 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 (
|
| 956 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 957 |
|
| 958 |
-
|
| 959 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 960 |
}
|
|
|
|
|
|
|
|
|
|
| 961 |
|
| 962 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 963 |
}
|
| 964 |
-
} catch (e) {
|
| 965 |
-
this.toast('Propagation failed: ' + e.message, 'error');
|
| 966 |
-
}
|
| 967 |
-
}
|
| 968 |
|
| 969 |
-
|
|
|
|
|
|
|
| 970 |
|
| 971 |
-
|
| 972 |
-
|
| 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 |
-
|
| 980 |
-
|
| 981 |
-
|
|
|
|
|
|
|
|
|
|
| 982 |
|
| 983 |
-
|
| 984 |
-
|
|
|
|
|
|
|
|
|
|
| 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;
|