dav729 commited on
Commit
b37bb66
·
verified ·
1 Parent(s): cf91a31

Update index.html

Browse files

changing text model

Files changed (1) hide show
  1. index.html +81 -40
index.html CHANGED
@@ -33,6 +33,11 @@
33
  <h2>Refined caption</h2>
34
  <p id="caption"></p>
35
 
 
 
 
 
 
36
  <script type="module">
37
  import {
38
  Florence2ForConditionalGeneration,
@@ -48,9 +53,11 @@
48
  const status = document.getElementById("status");
49
  const rawCaptionEl = document.getElementById("rawCaption");
50
  const caption = document.getElementById("caption");
 
51
 
52
  const MODEL_ID = "onnx-community/Florence-2-base-ft";
53
- const REFINER_ID = "onnx-community/Qwen2.5-0.5B-Instruct";
 
54
 
55
  let selectedFile = null;
56
  let model = null;
@@ -58,15 +65,22 @@
58
  let tokenizer = null;
59
  let refiner = null;
60
 
 
 
 
 
 
 
 
61
  // ---------- filename helpers ----------
62
  function cleanFilename(name) {
63
- let base = name.replace(/\.[^.]+$/, ""); // drop extension
64
- base = base.replace(/[_-]+/g, " "); // _ and - -> space
65
  base = base.replace(
66
  /\b(img|dsc|photo|image|picture|pic|file|screenshot|final|copy|edit|v\d+)\b/gi,
67
  " "
68
- ); // drop generic tokens
69
- base = base.replace(/\b\d+\b/g, " "); // drop bare numbers
70
  base = base.replace(/\s+/g, " ").trim();
71
  return base;
72
  }
@@ -94,45 +108,59 @@
94
  async function loadRefiner() {
95
  if (refiner) return;
96
  status.textContent = "Loading caption refiner...";
97
- refiner = await pipeline("text-generation", REFINER_ID, {
98
- dtype: "q4",
99
- device: "webgpu",
100
  });
101
  }
102
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  // ---------- refinement ----------
104
  async function refine(rawCaption, filename) {
105
  const hints = cleanFilename(filename);
106
 
107
- const system =
108
- "You rewrite image captions into ONE natural, fluent sentence. " +
109
- "Use the filename hints only if they add useful information for describing " +
110
- "the image; ignore them if they are generic or irrelevant. " +
111
- "Do not invent details that are not in the caption or hints. " +
112
- "Output only the rewritten sentence, nothing else.";
113
-
114
- const user = hints
115
- ? `Raw caption: ${rawCaption}\nFilename hints: ${hints}\nRewritten caption:`
116
- : `Raw caption: ${rawCaption}\n(No useful filename hints.)\nRewritten caption:`;
117
-
118
- const out = await refiner(
119
- [
120
- { role: "system", content: system },
121
- { role: "user", content: user },
122
- ],
123
- { max_new_tokens: 60, do_sample: false }
124
- );
 
 
 
 
 
125
 
126
- const generated = out[0].generated_text;
127
 
128
- // transformers.js returns either a string or the full messages array
129
- let text;
130
- if (Array.isArray(generated)) {
131
- text = generated[generated.length - 1].content;
132
- } else {
133
- text = generated;
134
- }
135
- return (text || "").trim();
136
  }
137
 
138
  // ---------- file input ----------
@@ -149,6 +177,7 @@
149
  caption.textContent = "";
150
  rawCaptionEl.textContent = "";
151
  status.textContent = "";
 
152
  });
153
 
154
  // ---------- main ----------
@@ -157,6 +186,7 @@
157
  captionButton.disabled = true;
158
  caption.textContent = "";
159
  rawCaptionEl.textContent = "";
 
160
 
161
  await loadCaptionModel();
162
  status.textContent = "Preparing image...";
@@ -183,19 +213,30 @@
183
  );
184
  const rawCaption = result[task] || "";
185
 
 
 
 
 
186
  rawCaptionEl.textContent = rawCaption || "(no caption)";
187
 
188
  await loadRefiner();
189
  status.textContent = "Refining caption...";
190
  const refined = await refine(rawCaption, selectedFile.name);
191
 
192
- caption.textContent =
193
- refined || rawCaption || "No caption generated.";
194
- status.textContent = "Done.";
 
 
 
 
 
 
 
195
  } catch (error) {
196
  console.error(error);
197
- status.textContent =
198
- "Error: " + (error.message || error);
199
  } finally {
200
  captionButton.disabled = false;
201
  }
 
33
  <h2>Refined caption</h2>
34
  <p id="caption"></p>
35
 
36
+ <details>
37
+ <summary>Debug</summary>
38
+ <pre id="debug" style="white-space: pre-wrap;"></pre>
39
+ </details>
40
+
41
  <script type="module">
42
  import {
43
  Florence2ForConditionalGeneration,
 
53
  const status = document.getElementById("status");
54
  const rawCaptionEl = document.getElementById("rawCaption");
55
  const caption = document.getElementById("caption");
56
+ const debugEl = document.getElementById("debug");
57
 
58
  const MODEL_ID = "onnx-community/Florence-2-base-ft";
59
+ // Text2text model: much more robust for rewrite tasks than a tiny chat LLM.
60
+ const REFINER_ID = "Xenova/LaMini-Flan-T5-248M";
61
 
62
  let selectedFile = null;
63
  let model = null;
 
65
  let tokenizer = null;
66
  let refiner = null;
67
 
68
+ function log(...args) {
69
+ console.log(...args);
70
+ debugEl.textContent += args.map(a =>
71
+ typeof a === "string" ? a : JSON.stringify(a)
72
+ ).join(" ") + "\n";
73
+ }
74
+
75
  // ---------- filename helpers ----------
76
  function cleanFilename(name) {
77
+ let base = name.replace(/\.[^.]+$/, "");
78
+ base = base.replace(/[_-]+/g, " ");
79
  base = base.replace(
80
  /\b(img|dsc|photo|image|picture|pic|file|screenshot|final|copy|edit|v\d+)\b/gi,
81
  " "
82
+ );
83
+ base = base.replace(/\b\d+\b/g, " ");
84
  base = base.replace(/\s+/g, " ").trim();
85
  return base;
86
  }
 
108
  async function loadRefiner() {
109
  if (refiner) return;
110
  status.textContent = "Loading caption refiner...";
111
+ refiner = await pipeline("text2text-generation", REFINER_ID, {
112
+ dtype: "q8",
113
+ device: "wasm", // safer than webgpu for this model
114
  });
115
  }
116
 
117
+ // ---------- sanity checks ----------
118
+ function looksBroken(text, rawCaption) {
119
+ if (!text) return true;
120
+ const t = text.trim();
121
+ if (t.length < 5) return true;
122
+ if (t.length > 220) return true; // runaway generation
123
+ if (/\b(\w+)\s+\1\s+\1\b/i.test(t)) return true; // "the the the"
124
+ // If it contains words like "Raw caption:" or "Filename hints:", it echoed the prompt
125
+ if (/raw caption|filename hints|rewritten caption/i.test(t)) return true;
126
+ // If it is basically the raw caption, prefer the raw caption (no loss)
127
+ const norm = s => s.toLowerCase().replace(/[^a-z0-9 ]/g, "").trim();
128
+ if (norm(t) === norm(rawCaption)) return true;
129
+ return false;
130
+ }
131
+
132
  // ---------- refinement ----------
133
  async function refine(rawCaption, filename) {
134
  const hints = cleanFilename(filename);
135
 
136
+ // Flan-T5 wants a plain string prompt, and explicit instructions
137
+ // about the output format work best.
138
+ const prompt = hints
139
+ ? `Rewrite the caption into one fluent natural sentence. ` +
140
+ `Use the filename hints only if they help describe the image; ` +
141
+ `otherwise ignore them. Do not add details that are not present. ` +
142
+ `Caption: ${rawCaption} ` +
143
+ `Filename hints: ${hints} ` +
144
+ `Rewritten caption:`
145
+ : `Rewrite the caption into one fluent natural sentence. ` +
146
+ `Do not add details that are not present. ` +
147
+ `Caption: ${rawCaption} ` +
148
+ `Rewritten caption:`;
149
+
150
+ log("[refine prompt]", prompt);
151
+
152
+ const out = await refiner(prompt, {
153
+ max_new_tokens: 60,
154
+ do_sample: false,
155
+ num_beams: 4,
156
+ repetition_penalty: 1.3,
157
+ no_repeat_ngram_size: 3,
158
+ });
159
 
160
+ log("[refine raw output]", JSON.stringify(out));
161
 
162
+ const text = (out?.[0]?.generated_text || "").trim();
163
+ return text;
 
 
 
 
 
 
164
  }
165
 
166
  // ---------- file input ----------
 
177
  caption.textContent = "";
178
  rawCaptionEl.textContent = "";
179
  status.textContent = "";
180
+ debugEl.textContent = "";
181
  });
182
 
183
  // ---------- main ----------
 
186
  captionButton.disabled = true;
187
  caption.textContent = "";
188
  rawCaptionEl.textContent = "";
189
+ debugEl.textContent = "";
190
 
191
  await loadCaptionModel();
192
  status.textContent = "Preparing image...";
 
213
  );
214
  const rawCaption = result[task] || "";
215
 
216
+ log("[raw caption]", rawCaption);
217
+ log("[filename]", selectedFile.name);
218
+ log("[cleaned filename]", cleanFilename(selectedFile.name));
219
+
220
  rawCaptionEl.textContent = rawCaption || "(no caption)";
221
 
222
  await loadRefiner();
223
  status.textContent = "Refining caption...";
224
  const refined = await refine(rawCaption, selectedFile.name);
225
 
226
+ log("[refined]", refined);
227
+
228
+ if (looksBroken(refined, rawCaption)) {
229
+ log("[fallback] refined output rejected, using raw caption");
230
+ caption.textContent = rawCaption || "No caption generated.";
231
+ status.textContent = "Done (kept raw caption).";
232
+ } else {
233
+ caption.textContent = refined;
234
+ status.textContent = "Done.";
235
+ }
236
  } catch (error) {
237
  console.error(error);
238
+ status.textContent = "Error: " + (error.message || error);
239
+ log("[error]", String(error));
240
  } finally {
241
  captionButton.disabled = false;
242
  }