Skip to content

feat(web): render extracted images inline in the document reader - #201

Merged
KylinMountain merged 2 commits into
worktree-feat+workbench-doc-readerfrom
feat/doc-reader-images
Jul 22, 2026
Merged

feat(web): render extracted images inline in the document reader#201
KylinMountain merged 2 commits into
worktree-feat+workbench-doc-readerfrom
feat/doc-reader-images

Conversation

@KylinMountain

Copy link
Copy Markdown
Collaborator

What

Follow-up to the document reader (#199) — renders extracted images inline in the reader. Source docs embed ![image](sources/images/<doc>/…) references whose files are extracted at ingest but were never displayed (they showed as a literal !image). Now they render as real images.

Stacked on #199 (base = worktree-feat+workbench-doc-reader). Review/merge #199 first; this diff is just the image layer on top.

Changes

  • BackendGET /api/v1/document/image serves wiki/sources/images/**. Narrowed to the images dir + raster suffixes (.png/.jpg/.jpeg/.gif/.webp, no SVG) with a containment/traversal guard, so this read-only sink can never serve wiki pages, skills, or arbitrary files.
  • MarkdownView — gains an optional image token, enabled only when a resolveImageSrc prop is passed (the doc reader). Without it, the ![](…) alternative is omitted from the regex, so chat and wiki-page rendering are byte-for-byte unchanged. A new AuthedImage fetches the API path as a blob (the bearer token can't ride on <img src>; mirrors artifacts.ts) and revokes the object URL on unmount; it shows a placeholder while loading and renders nothing on failure.
  • Doc reader — passes a resolver that normalizes both source-path conventions (wiki-root sources/images/… for long-doc JSON, note-relative images/… for short-doc MD) to the image endpoint. External / data: URLs stay literal text.

Scope note

This makes images visible in the UI. LLM answers remain image-blind — ingestion does no caption/OCR (only extracts files + inserts placeholders), so figure/chart content still doesn't reach the model. That's a separate pipeline change, not attempted here.

Verification

  • Backend: 1251 passed (adds serve / traversal / non-image-suffix / 404 / auth tests); ruff + mypy clean.
  • Frontend: npm run build (i18n + tsc + vite) green.
  • Manually driven in a browser: the Soochow Securities research PDF's figures (previously !image) now render inline in the reader; chat/wiki rendering unaffected.

Follow-up to #197: long/short source docs embed `![image](sources/images/...)`
references whose files were extracted at ingest but never displayed (they showed
as a literal "!image"). Now they render inline in the reader.
- Backend: GET /api/v1/document/image serves wiki/sources/images/** — narrowed
to the images dir + raster suffixes with a traversal guard (read-only; cannot
reach wiki pages/skills/arbitrary files).
- MarkdownView: gain an optional image token, ENABLED ONLY when a resolveImageSrc
prop is passed (the doc reader). Without it the `![](…)` token is omitted from
the regex, so chat/wiki rendering is byte-for-byte unchanged. A new AuthedImage
fetches the API path as a blob (the bearer token can't ride on <img src>;
mirrors artifacts.ts) and revokes the object URL on unmount.
- Doc reader: passes a resolver that normalizes both source path conventions
(wiki-root `sources/images/...` and note-relative `images/...`) to the
image endpoint; external/data URLs stay literal text.
Images are now visible in the UI. (LLM answers are still image-blind — ingestion
does no caption/OCR — which is a separate pipeline change.)
Backend adds serve/traversal/suffix/404/auth tests (1251 passed). Verified in a
browser: the Soochow Securities report's figures render inline.
- Image URL regex now tolerates one level of balanced parens, so an image
whose path contains ')' (a legacy/cloud doc_name with ASCII parentheses,
e.g. 'report (1)') is no longer truncated to a broken path + stray text [#1].
- The image endpoint sets an explicit media type per suffix instead of letting
FileResponse guess: a .webp is served as image/webp even where mimetypes has
no webp entry (would otherwise be text/plain → a blob-loaded <img> refuses to
render it) [#2]. Adds a webp media-type test.
- AuthedImage shows a muted dashed placeholder (the alt) on load failure instead
of rendering nothing, so a missing image is visible rather than silently
dropped [#3].
Verified: the balanced-paren regex extracts full paths for 'report (1)' and
fullwidth-paren names; backend 1252 passed; frontend build green.
@KylinMountain
KylinMountain merged commit dda7f8e into worktree-feat+workbench-doc-readerJul 22, 2026
2 checks passed
@KylinMountain
KylinMountain deleted the feat/doc-reader-images branch July 22, 2026 03:44
TheNha pushed a commit to TheNha/OpenKB that referenced this pull request Jul 29, 2026
…tifyAI#201)
Cherry-picked from dda7f8e (origin/worktree-feat+workbench-doc-reader),
which was never merged into main/this branch. Documents pane was still
showing !<link> instead of rendering images.
Co-Authored-By: Nguyen The Nha @nha.nt
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@KylinMountain
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
feat(web): render extracted images inline in the document reader by KylinMountain · Pull Request #201 · VectifyAI/OpenKB · GitHub
Skip to content

feat(web): render extracted images inline in the document reader - #201

Merged
KylinMountain merged 2 commits into
worktree-feat+workbench-doc-readerfrom
feat/doc-reader-images
Jul 22, 2026
Merged

feat(web): render extracted images inline in the document reader#201
KylinMountain merged 2 commits into
worktree-feat+workbench-doc-readerfrom
feat/doc-reader-images

Conversation

@KylinMountain

Copy link
Copy Markdown
Collaborator

What

Follow-up to the document reader (#199) — renders extracted images inline in the reader. Source docs embed ![image](sources/images/<doc>/…) references whose files are extracted at ingest but were never displayed (they showed as a literal !image). Now they render as real images.

Stacked on #199 (base = worktree-feat+workbench-doc-reader). Review/merge #199 first; this diff is just the image layer on top.

Changes

  • BackendGET /api/v1/document/image serves wiki/sources/images/**. Narrowed to the images dir + raster suffixes (.png/.jpg/.jpeg/.gif/.webp, no SVG) with a containment/traversal guard, so this read-only sink can never serve wiki pages, skills, or arbitrary files.
  • MarkdownView — gains an optional image token, enabled only when a resolveImageSrc prop is passed (the doc reader). Without it, the ![](…) alternative is omitted from the regex, so chat and wiki-page rendering are byte-for-byte unchanged. A new AuthedImage fetches the API path as a blob (the bearer token can't ride on <img src>; mirrors artifacts.ts) and revokes the object URL on unmount; it shows a placeholder while loading and renders nothing on failure.
  • Doc reader — passes a resolver that normalizes both source-path conventions (wiki-root sources/images/… for long-doc JSON, note-relative images/… for short-doc MD) to the image endpoint. External / data: URLs stay literal text.

Scope note

This makes images visible in the UI. LLM answers remain image-blind — ingestion does no caption/OCR (only extracts files + inserts placeholders), so figure/chart content still doesn't reach the model. That's a separate pipeline change, not attempted here.

Verification

  • Backend: 1251 passed (adds serve / traversal / non-image-suffix / 404 / auth tests); ruff + mypy clean.
  • Frontend: npm run build (i18n + tsc + vite) green.
  • Manually driven in a browser: the Soochow Securities research PDF's figures (previously !image) now render inline in the reader; chat/wiki rendering unaffected.

Follow-up to #197: long/short source docs embed `![image](sources/images/...)`
references whose files were extracted at ingest but never displayed (they showed
as a literal "!image"). Now they render inline in the reader.
- Backend: GET /api/v1/document/image serves wiki/sources/images/** — narrowed
to the images dir + raster suffixes with a traversal guard (read-only; cannot
reach wiki pages/skills/arbitrary files).
- MarkdownView: gain an optional image token, ENABLED ONLY when a resolveImageSrc
prop is passed (the doc reader). Without it the `![](…)` token is omitted from
the regex, so chat/wiki rendering is byte-for-byte unchanged. A new AuthedImage
fetches the API path as a blob (the bearer token can't ride on <img src>;
mirrors artifacts.ts) and revokes the object URL on unmount.
- Doc reader: passes a resolver that normalizes both source path conventions
(wiki-root `sources/images/...` and note-relative `images/...`) to the
image endpoint; external/data URLs stay literal text.
Images are now visible in the UI. (LLM answers are still image-blind — ingestion
does no caption/OCR — which is a separate pipeline change.)
Backend adds serve/traversal/suffix/404/auth tests (1251 passed). Verified in a
browser: the Soochow Securities report's figures render inline.
- Image URL regex now tolerates one level of balanced parens, so an image
whose path contains ')' (a legacy/cloud doc_name with ASCII parentheses,
e.g. 'report (1)') is no longer truncated to a broken path + stray text [#1].
- The image endpoint sets an explicit media type per suffix instead of letting
FileResponse guess: a .webp is served as image/webp even where mimetypes has
no webp entry (would otherwise be text/plain → a blob-loaded <img> refuses to
render it) [#2]. Adds a webp media-type test.
- AuthedImage shows a muted dashed placeholder (the alt) on load failure instead
of rendering nothing, so a missing image is visible rather than silently
dropped [#3].
Verified: the balanced-paren regex extracts full paths for 'report (1)' and
fullwidth-paren names; backend 1252 passed; frontend build green.
@KylinMountain
KylinMountain merged commit dda7f8e into worktree-feat+workbench-doc-readerJul 22, 2026
2 checks passed
@KylinMountain
KylinMountain deleted the feat/doc-reader-images branch July 22, 2026 03:44
TheNha pushed a commit to TheNha/OpenKB that referenced this pull request Jul 29, 2026
…tifyAI#201)
Cherry-picked from dda7f8e (origin/worktree-feat+workbench-doc-reader),
which was never merged into main/this branch. Documents pane was still
showing !<link> instead of rendering images.
Co-Authored-By: Nguyen The Nha @nha.nt
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@KylinMountain
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(web): render extracted images inline in the document reader by KylinMountain · Pull Request #201 · VectifyAI/OpenKB · GitHub
Skip to content

feat(web): render extracted images inline in the document reader - #201

Merged
KylinMountain merged 2 commits into
worktree-feat+workbench-doc-readerfrom
feat/doc-reader-images
Jul 22, 2026
Merged

feat(web): render extracted images inline in the document reader#201
KylinMountain merged 2 commits into
worktree-feat+workbench-doc-readerfrom
feat/doc-reader-images

Conversation

@KylinMountain

Copy link
Copy Markdown
Collaborator

What

Follow-up to the document reader (#199) — renders extracted images inline in the reader. Source docs embed ![image](sources/images/<doc>/…) references whose files are extracted at ingest but were never displayed (they showed as a literal !image). Now they render as real images.

Stacked on #199 (base = worktree-feat+workbench-doc-reader). Review/merge #199 first; this diff is just the image layer on top.

Changes

  • BackendGET /api/v1/document/image serves wiki/sources/images/**. Narrowed to the images dir + raster suffixes (.png/.jpg/.jpeg/.gif/.webp, no SVG) with a containment/traversal guard, so this read-only sink can never serve wiki pages, skills, or arbitrary files.
  • MarkdownView — gains an optional image token, enabled only when a resolveImageSrc prop is passed (the doc reader). Without it, the ![](…) alternative is omitted from the regex, so chat and wiki-page rendering are byte-for-byte unchanged. A new AuthedImage fetches the API path as a blob (the bearer token can't ride on <img src>; mirrors artifacts.ts) and revokes the object URL on unmount; it shows a placeholder while loading and renders nothing on failure.
  • Doc reader — passes a resolver that normalizes both source-path conventions (wiki-root sources/images/… for long-doc JSON, note-relative images/… for short-doc MD) to the image endpoint. External / data: URLs stay literal text.

Scope note

This makes images visible in the UI. LLM answers remain image-blind — ingestion does no caption/OCR (only extracts files + inserts placeholders), so figure/chart content still doesn't reach the model. That's a separate pipeline change, not attempted here.

Verification

  • Backend: 1251 passed (adds serve / traversal / non-image-suffix / 404 / auth tests); ruff + mypy clean.
  • Frontend: npm run build (i18n + tsc + vite) green.
  • Manually driven in a browser: the Soochow Securities research PDF's figures (previously !image) now render inline in the reader; chat/wiki rendering unaffected.

Follow-up to #197: long/short source docs embed `![image](sources/images/...)`
references whose files were extracted at ingest but never displayed (they showed
as a literal "!image"). Now they render inline in the reader.
- Backend: GET /api/v1/document/image serves wiki/sources/images/** — narrowed
to the images dir + raster suffixes with a traversal guard (read-only; cannot
reach wiki pages/skills/arbitrary files).
- MarkdownView: gain an optional image token, ENABLED ONLY when a resolveImageSrc
prop is passed (the doc reader). Without it the `![](…)` token is omitted from
the regex, so chat/wiki rendering is byte-for-byte unchanged. A new AuthedImage
fetches the API path as a blob (the bearer token can't ride on <img src>;
mirrors artifacts.ts) and revokes the object URL on unmount.
- Doc reader: passes a resolver that normalizes both source path conventions
(wiki-root `sources/images/...` and note-relative `images/...`) to the
image endpoint; external/data URLs stay literal text.
Images are now visible in the UI. (LLM answers are still image-blind — ingestion
does no caption/OCR — which is a separate pipeline change.)
Backend adds serve/traversal/suffix/404/auth tests (1251 passed). Verified in a
browser: the Soochow Securities report's figures render inline.
- Image URL regex now tolerates one level of balanced parens, so an image
whose path contains ')' (a legacy/cloud doc_name with ASCII parentheses,
e.g. 'report (1)') is no longer truncated to a broken path + stray text [#1].
- The image endpoint sets an explicit media type per suffix instead of letting
FileResponse guess: a .webp is served as image/webp even where mimetypes has
no webp entry (would otherwise be text/plain → a blob-loaded <img> refuses to
render it) [#2]. Adds a webp media-type test.
- AuthedImage shows a muted dashed placeholder (the alt) on load failure instead
of rendering nothing, so a missing image is visible rather than silently
dropped [#3].
Verified: the balanced-paren regex extracts full paths for 'report (1)' and
fullwidth-paren names; backend 1252 passed; frontend build green.
@KylinMountain
KylinMountain merged commit dda7f8e into worktree-feat+workbench-doc-readerJul 22, 2026
2 checks passed
@KylinMountain
KylinMountain deleted the feat/doc-reader-images branch July 22, 2026 03:44
TheNha pushed a commit to TheNha/OpenKB that referenced this pull request Jul 29, 2026
…tifyAI#201)
Cherry-picked from dda7f8e (origin/worktree-feat+workbench-doc-reader),
which was never merged into main/this branch. Documents pane was still
showing !<link> instead of rendering images.
Co-Authored-By: Nguyen The Nha @nha.nt
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@KylinMountain
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(web): render extracted images inline in the document reader by KylinMountain · Pull Request #201 · VectifyAI/OpenKB · GitHub
Skip to content

feat(web): render extracted images inline in the document reader - #201

Merged
KylinMountain merged 2 commits into
worktree-feat+workbench-doc-readerfrom
feat/doc-reader-images
Jul 22, 2026
Merged

feat(web): render extracted images inline in the document reader#201
KylinMountain merged 2 commits into
worktree-feat+workbench-doc-readerfrom
feat/doc-reader-images

Conversation

@KylinMountain

Copy link
Copy Markdown
Collaborator

What

Follow-up to the document reader (#199) — renders extracted images inline in the reader. Source docs embed ![image](sources/images/<doc>/…) references whose files are extracted at ingest but were never displayed (they showed as a literal !image). Now they render as real images.

Stacked on #199 (base = worktree-feat+workbench-doc-reader). Review/merge #199 first; this diff is just the image layer on top.

Changes

  • BackendGET /api/v1/document/image serves wiki/sources/images/**. Narrowed to the images dir + raster suffixes (.png/.jpg/.jpeg/.gif/.webp, no SVG) with a containment/traversal guard, so this read-only sink can never serve wiki pages, skills, or arbitrary files.
  • MarkdownView — gains an optional image token, enabled only when a resolveImageSrc prop is passed (the doc reader). Without it, the ![](…) alternative is omitted from the regex, so chat and wiki-page rendering are byte-for-byte unchanged. A new AuthedImage fetches the API path as a blob (the bearer token can't ride on <img src>; mirrors artifacts.ts) and revokes the object URL on unmount; it shows a placeholder while loading and renders nothing on failure.
  • Doc reader — passes a resolver that normalizes both source-path conventions (wiki-root sources/images/… for long-doc JSON, note-relative images/… for short-doc MD) to the image endpoint. External / data: URLs stay literal text.

Scope note

This makes images visible in the UI. LLM answers remain image-blind — ingestion does no caption/OCR (only extracts files + inserts placeholders), so figure/chart content still doesn't reach the model. That's a separate pipeline change, not attempted here.

Verification

  • Backend: 1251 passed (adds serve / traversal / non-image-suffix / 404 / auth tests); ruff + mypy clean.
  • Frontend: npm run build (i18n + tsc + vite) green.
  • Manually driven in a browser: the Soochow Securities research PDF's figures (previously !image) now render inline in the reader; chat/wiki rendering unaffected.

Follow-up to #197: long/short source docs embed `![image](sources/images/...)`
references whose files were extracted at ingest but never displayed (they showed
as a literal "!image"). Now they render inline in the reader.
- Backend: GET /api/v1/document/image serves wiki/sources/images/** — narrowed
to the images dir + raster suffixes with a traversal guard (read-only; cannot
reach wiki pages/skills/arbitrary files).
- MarkdownView: gain an optional image token, ENABLED ONLY when a resolveImageSrc
prop is passed (the doc reader). Without it the `![](…)` token is omitted from
the regex, so chat/wiki rendering is byte-for-byte unchanged. A new AuthedImage
fetches the API path as a blob (the bearer token can't ride on <img src>;
mirrors artifacts.ts) and revokes the object URL on unmount.
- Doc reader: passes a resolver that normalizes both source path conventions
(wiki-root `sources/images/...` and note-relative `images/...`) to the
image endpoint; external/data URLs stay literal text.
Images are now visible in the UI. (LLM answers are still image-blind — ingestion
does no caption/OCR — which is a separate pipeline change.)
Backend adds serve/traversal/suffix/404/auth tests (1251 passed). Verified in a
browser: the Soochow Securities report's figures render inline.
- Image URL regex now tolerates one level of balanced parens, so an image
whose path contains ')' (a legacy/cloud doc_name with ASCII parentheses,
e.g. 'report (1)') is no longer truncated to a broken path + stray text [#1].
- The image endpoint sets an explicit media type per suffix instead of letting
FileResponse guess: a .webp is served as image/webp even where mimetypes has
no webp entry (would otherwise be text/plain → a blob-loaded <img> refuses to
render it) [#2]. Adds a webp media-type test.
- AuthedImage shows a muted dashed placeholder (the alt) on load failure instead
of rendering nothing, so a missing image is visible rather than silently
dropped [#3].
Verified: the balanced-paren regex extracts full paths for 'report (1)' and
fullwidth-paren names; backend 1252 passed; frontend build green.
@KylinMountain
KylinMountain merged commit dda7f8e into worktree-feat+workbench-doc-readerJul 22, 2026
2 checks passed
@KylinMountain
KylinMountain deleted the feat/doc-reader-images branch July 22, 2026 03:44
TheNha pushed a commit to TheNha/OpenKB that referenced this pull request Jul 29, 2026
…tifyAI#201)
Cherry-picked from dda7f8e (origin/worktree-feat+workbench-doc-reader),
which was never merged into main/this branch. Documents pane was still
showing !<link> instead of rendering images.
Co-Authored-By: Nguyen The Nha @nha.nt
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@KylinMountain
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' feat(web): render extracted images inline in the document reader by KylinMountain · Pull Request #201 · VectifyAI/OpenKB · GitHub
Skip to content

feat(web): render extracted images inline in the document reader - #201

Merged
KylinMountain merged 2 commits into
worktree-feat+workbench-doc-readerfrom
feat/doc-reader-images
Jul 22, 2026
Merged

feat(web): render extracted images inline in the document reader#201
KylinMountain merged 2 commits into
worktree-feat+workbench-doc-readerfrom
feat/doc-reader-images

Conversation

@KylinMountain

Copy link
Copy Markdown
Collaborator

What

Follow-up to the document reader (#199) — renders extracted images inline in the reader. Source docs embed ![image](sources/images/<doc>/…) references whose files are extracted at ingest but were never displayed (they showed as a literal !image). Now they render as real images.

Stacked on #199 (base = worktree-feat+workbench-doc-reader). Review/merge #199 first; this diff is just the image layer on top.

Changes

  • BackendGET /api/v1/document/image serves wiki/sources/images/**. Narrowed to the images dir + raster suffixes (.png/.jpg/.jpeg/.gif/.webp, no SVG) with a containment/traversal guard, so this read-only sink can never serve wiki pages, skills, or arbitrary files.
  • MarkdownView — gains an optional image token, enabled only when a resolveImageSrc prop is passed (the doc reader). Without it, the ![](…) alternative is omitted from the regex, so chat and wiki-page rendering are byte-for-byte unchanged. A new AuthedImage fetches the API path as a blob (the bearer token can't ride on <img src>; mirrors artifacts.ts) and revokes the object URL on unmount; it shows a placeholder while loading and renders nothing on failure.
  • Doc reader — passes a resolver that normalizes both source-path conventions (wiki-root sources/images/… for long-doc JSON, note-relative images/… for short-doc MD) to the image endpoint. External / data: URLs stay literal text.

Scope note

This makes images visible in the UI. LLM answers remain image-blind — ingestion does no caption/OCR (only extracts files + inserts placeholders), so figure/chart content still doesn't reach the model. That's a separate pipeline change, not attempted here.

Verification

  • Backend: 1251 passed (adds serve / traversal / non-image-suffix / 404 / auth tests); ruff + mypy clean.
  • Frontend: npm run build (i18n + tsc + vite) green.
  • Manually driven in a browser: the Soochow Securities research PDF's figures (previously !image) now render inline in the reader; chat/wiki rendering unaffected.

Follow-up to #197: long/short source docs embed `![image](sources/images/...)`
references whose files were extracted at ingest but never displayed (they showed
as a literal "!image"). Now they render inline in the reader.
- Backend: GET /api/v1/document/image serves wiki/sources/images/** — narrowed
to the images dir + raster suffixes with a traversal guard (read-only; cannot
reach wiki pages/skills/arbitrary files).
- MarkdownView: gain an optional image token, ENABLED ONLY when a resolveImageSrc
prop is passed (the doc reader). Without it the `![](…)` token is omitted from
the regex, so chat/wiki rendering is byte-for-byte unchanged. A new AuthedImage
fetches the API path as a blob (the bearer token can't ride on <img src>;
mirrors artifacts.ts) and revokes the object URL on unmount.
- Doc reader: passes a resolver that normalizes both source path conventions
(wiki-root `sources/images/...` and note-relative `images/...`) to the
image endpoint; external/data URLs stay literal text.
Images are now visible in the UI. (LLM answers are still image-blind — ingestion
does no caption/OCR — which is a separate pipeline change.)
Backend adds serve/traversal/suffix/404/auth tests (1251 passed). Verified in a
browser: the Soochow Securities report's figures render inline.
- Image URL regex now tolerates one level of balanced parens, so an image
whose path contains ')' (a legacy/cloud doc_name with ASCII parentheses,
e.g. 'report (1)') is no longer truncated to a broken path + stray text [#1].
- The image endpoint sets an explicit media type per suffix instead of letting
FileResponse guess: a .webp is served as image/webp even where mimetypes has
no webp entry (would otherwise be text/plain → a blob-loaded <img> refuses to
render it) [#2]. Adds a webp media-type test.
- AuthedImage shows a muted dashed placeholder (the alt) on load failure instead
of rendering nothing, so a missing image is visible rather than silently
dropped [#3].
Verified: the balanced-paren regex extracts full paths for 'report (1)' and
fullwidth-paren names; backend 1252 passed; frontend build green.
@KylinMountain
KylinMountain merged commit dda7f8e into worktree-feat+workbench-doc-readerJul 22, 2026
2 checks passed
@KylinMountain
KylinMountain deleted the feat/doc-reader-images branch July 22, 2026 03:44
TheNha pushed a commit to TheNha/OpenKB that referenced this pull request Jul 29, 2026
…tifyAI#201)
Cherry-picked from dda7f8e (origin/worktree-feat+workbench-doc-reader),
which was never merged into main/this branch. Documents pane was still
showing !<link> instead of rendering images.
Co-Authored-By: Nguyen The Nha @nha.nt
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@KylinMountain
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(web): render extracted images inline in the document reader by KylinMountain · Pull Request #201 · VectifyAI/OpenKB · GitHub
Skip to content

feat(web): render extracted images inline in the document reader - #201

Merged
KylinMountain merged 2 commits into
worktree-feat+workbench-doc-readerfrom
feat/doc-reader-images
Jul 22, 2026
Merged

feat(web): render extracted images inline in the document reader#201
KylinMountain merged 2 commits into
worktree-feat+workbench-doc-readerfrom
feat/doc-reader-images

Conversation

@KylinMountain

Copy link
Copy Markdown
Collaborator

What

Follow-up to the document reader (#199) — renders extracted images inline in the reader. Source docs embed ![image](sources/images/<doc>/…) references whose files are extracted at ingest but were never displayed (they showed as a literal !image). Now they render as real images.

Stacked on #199 (base = worktree-feat+workbench-doc-reader). Review/merge #199 first; this diff is just the image layer on top.

Changes

  • BackendGET /api/v1/document/image serves wiki/sources/images/**. Narrowed to the images dir + raster suffixes (.png/.jpg/.jpeg/.gif/.webp, no SVG) with a containment/traversal guard, so this read-only sink can never serve wiki pages, skills, or arbitrary files.
  • MarkdownView — gains an optional image token, enabled only when a resolveImageSrc prop is passed (the doc reader). Without it, the ![](…) alternative is omitted from the regex, so chat and wiki-page rendering are byte-for-byte unchanged. A new AuthedImage fetches the API path as a blob (the bearer token can't ride on <img src>; mirrors artifacts.ts) and revokes the object URL on unmount; it shows a placeholder while loading and renders nothing on failure.
  • Doc reader — passes a resolver that normalizes both source-path conventions (wiki-root sources/images/… for long-doc JSON, note-relative images/… for short-doc MD) to the image endpoint. External / data: URLs stay literal text.

Scope note

This makes images visible in the UI. LLM answers remain image-blind — ingestion does no caption/OCR (only extracts files + inserts placeholders), so figure/chart content still doesn't reach the model. That's a separate pipeline change, not attempted here.

Verification

  • Backend: 1251 passed (adds serve / traversal / non-image-suffix / 404 / auth tests); ruff + mypy clean.
  • Frontend: npm run build (i18n + tsc + vite) green.
  • Manually driven in a browser: the Soochow Securities research PDF's figures (previously !image) now render inline in the reader; chat/wiki rendering unaffected.

Follow-up to #197: long/short source docs embed `![image](sources/images/...)`
references whose files were extracted at ingest but never displayed (they showed
as a literal "!image"). Now they render inline in the reader.
- Backend: GET /api/v1/document/image serves wiki/sources/images/** — narrowed
to the images dir + raster suffixes with a traversal guard (read-only; cannot
reach wiki pages/skills/arbitrary files).
- MarkdownView: gain an optional image token, ENABLED ONLY when a resolveImageSrc
prop is passed (the doc reader). Without it the `![](…)` token is omitted from
the regex, so chat/wiki rendering is byte-for-byte unchanged. A new AuthedImage
fetches the API path as a blob (the bearer token can't ride on <img src>;
mirrors artifacts.ts) and revokes the object URL on unmount.
- Doc reader: passes a resolver that normalizes both source path conventions
(wiki-root `sources/images/...` and note-relative `images/...`) to the
image endpoint; external/data URLs stay literal text.
Images are now visible in the UI. (LLM answers are still image-blind — ingestion
does no caption/OCR — which is a separate pipeline change.)
Backend adds serve/traversal/suffix/404/auth tests (1251 passed). Verified in a
browser: the Soochow Securities report's figures render inline.
- Image URL regex now tolerates one level of balanced parens, so an image
whose path contains ')' (a legacy/cloud doc_name with ASCII parentheses,
e.g. 'report (1)') is no longer truncated to a broken path + stray text [#1].
- The image endpoint sets an explicit media type per suffix instead of letting
FileResponse guess: a .webp is served as image/webp even where mimetypes has
no webp entry (would otherwise be text/plain → a blob-loaded <img> refuses to
render it) [#2]. Adds a webp media-type test.
- AuthedImage shows a muted dashed placeholder (the alt) on load failure instead
of rendering nothing, so a missing image is visible rather than silently
dropped [#3].
Verified: the balanced-paren regex extracts full paths for 'report (1)' and
fullwidth-paren names; backend 1252 passed; frontend build green.
@KylinMountain
KylinMountain merged commit dda7f8e into worktree-feat+workbench-doc-readerJul 22, 2026
2 checks passed
@KylinMountain
KylinMountain deleted the feat/doc-reader-images branch July 22, 2026 03:44
TheNha pushed a commit to TheNha/OpenKB that referenced this pull request Jul 29, 2026
…tifyAI#201)
Cherry-picked from dda7f8e (origin/worktree-feat+workbench-doc-reader),
which was never merged into main/this branch. Documents pane was still
showing !<link> instead of rendering images.
Co-Authored-By: Nguyen The Nha @nha.nt
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@KylinMountain
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' feat(web): render extracted images inline in the document reader by KylinMountain · Pull Request #201 · VectifyAI/OpenKB · GitHub
Skip to content

feat(web): render extracted images inline in the document reader - #201

Merged
KylinMountain merged 2 commits into
worktree-feat+workbench-doc-readerfrom
feat/doc-reader-images
Jul 22, 2026
Merged

feat(web): render extracted images inline in the document reader#201
KylinMountain merged 2 commits into
worktree-feat+workbench-doc-readerfrom
feat/doc-reader-images

Conversation

@KylinMountain

Copy link
Copy Markdown
Collaborator

What

Follow-up to the document reader (#199) — renders extracted images inline in the reader. Source docs embed ![image](sources/images/<doc>/…) references whose files are extracted at ingest but were never displayed (they showed as a literal !image). Now they render as real images.

Stacked on #199 (base = worktree-feat+workbench-doc-reader). Review/merge #199 first; this diff is just the image layer on top.

Changes

  • BackendGET /api/v1/document/image serves wiki/sources/images/**. Narrowed to the images dir + raster suffixes (.png/.jpg/.jpeg/.gif/.webp, no SVG) with a containment/traversal guard, so this read-only sink can never serve wiki pages, skills, or arbitrary files.
  • MarkdownView — gains an optional image token, enabled only when a resolveImageSrc prop is passed (the doc reader). Without it, the ![](…) alternative is omitted from the regex, so chat and wiki-page rendering are byte-for-byte unchanged. A new AuthedImage fetches the API path as a blob (the bearer token can't ride on <img src>; mirrors artifacts.ts) and revokes the object URL on unmount; it shows a placeholder while loading and renders nothing on failure.
  • Doc reader — passes a resolver that normalizes both source-path conventions (wiki-root sources/images/… for long-doc JSON, note-relative images/… for short-doc MD) to the image endpoint. External / data: URLs stay literal text.

Scope note

This makes images visible in the UI. LLM answers remain image-blind — ingestion does no caption/OCR (only extracts files + inserts placeholders), so figure/chart content still doesn't reach the model. That's a separate pipeline change, not attempted here.

Verification

  • Backend: 1251 passed (adds serve / traversal / non-image-suffix / 404 / auth tests); ruff + mypy clean.
  • Frontend: npm run build (i18n + tsc + vite) green.
  • Manually driven in a browser: the Soochow Securities research PDF's figures (previously !image) now render inline in the reader; chat/wiki rendering unaffected.

Follow-up to #197: long/short source docs embed `![image](sources/images/...)`
references whose files were extracted at ingest but never displayed (they showed
as a literal "!image"). Now they render inline in the reader.
- Backend: GET /api/v1/document/image serves wiki/sources/images/** — narrowed
to the images dir + raster suffixes with a traversal guard (read-only; cannot
reach wiki pages/skills/arbitrary files).
- MarkdownView: gain an optional image token, ENABLED ONLY when a resolveImageSrc
prop is passed (the doc reader). Without it the `![](…)` token is omitted from
the regex, so chat/wiki rendering is byte-for-byte unchanged. A new AuthedImage
fetches the API path as a blob (the bearer token can't ride on <img src>;
mirrors artifacts.ts) and revokes the object URL on unmount.
- Doc reader: passes a resolver that normalizes both source path conventions
(wiki-root `sources/images/...` and note-relative `images/...`) to the
image endpoint; external/data URLs stay literal text.
Images are now visible in the UI. (LLM answers are still image-blind — ingestion
does no caption/OCR — which is a separate pipeline change.)
Backend adds serve/traversal/suffix/404/auth tests (1251 passed). Verified in a
browser: the Soochow Securities report's figures render inline.
- Image URL regex now tolerates one level of balanced parens, so an image
whose path contains ')' (a legacy/cloud doc_name with ASCII parentheses,
e.g. 'report (1)') is no longer truncated to a broken path + stray text [#1].
- The image endpoint sets an explicit media type per suffix instead of letting
FileResponse guess: a .webp is served as image/webp even where mimetypes has
no webp entry (would otherwise be text/plain → a blob-loaded <img> refuses to
render it) [#2]. Adds a webp media-type test.
- AuthedImage shows a muted dashed placeholder (the alt) on load failure instead
of rendering nothing, so a missing image is visible rather than silently
dropped [#3].
Verified: the balanced-paren regex extracts full paths for 'report (1)' and
fullwidth-paren names; backend 1252 passed; frontend build green.
@KylinMountain
KylinMountain merged commit dda7f8e into worktree-feat+workbench-doc-readerJul 22, 2026
2 checks passed
@KylinMountain
KylinMountain deleted the feat/doc-reader-images branch July 22, 2026 03:44
TheNha pushed a commit to TheNha/OpenKB that referenced this pull request Jul 29, 2026
…tifyAI#201)
Cherry-picked from dda7f8e (origin/worktree-feat+workbench-doc-reader),
which was never merged into main/this branch. Documents pane was still
showing !<link> instead of rendering images.
Co-Authored-By: Nguyen The Nha @nha.nt
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@KylinMountain
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); feat(web): render extracted images inline in the document reader by KylinMountain · Pull Request #201 · VectifyAI/OpenKB · GitHub
Skip to content

feat(web): render extracted images inline in the document reader - #201

Merged
KylinMountain merged 2 commits into
worktree-feat+workbench-doc-readerfrom
feat/doc-reader-images
Jul 22, 2026
Merged

feat(web): render extracted images inline in the document reader#201
KylinMountain merged 2 commits into
worktree-feat+workbench-doc-readerfrom
feat/doc-reader-images

Conversation

@KylinMountain

Copy link
Copy Markdown
Collaborator

What

Follow-up to the document reader (#199) — renders extracted images inline in the reader. Source docs embed ![image](sources/images/<doc>/…) references whose files are extracted at ingest but were never displayed (they showed as a literal !image). Now they render as real images.

Stacked on #199 (base = worktree-feat+workbench-doc-reader). Review/merge #199 first; this diff is just the image layer on top.

Changes

  • BackendGET /api/v1/document/image serves wiki/sources/images/**. Narrowed to the images dir + raster suffixes (.png/.jpg/.jpeg/.gif/.webp, no SVG) with a containment/traversal guard, so this read-only sink can never serve wiki pages, skills, or arbitrary files.
  • MarkdownView — gains an optional image token, enabled only when a resolveImageSrc prop is passed (the doc reader). Without it, the ![](…) alternative is omitted from the regex, so chat and wiki-page rendering are byte-for-byte unchanged. A new AuthedImage fetches the API path as a blob (the bearer token can't ride on <img src>; mirrors artifacts.ts) and revokes the object URL on unmount; it shows a placeholder while loading and renders nothing on failure.
  • Doc reader — passes a resolver that normalizes both source-path conventions (wiki-root sources/images/… for long-doc JSON, note-relative images/… for short-doc MD) to the image endpoint. External / data: URLs stay literal text.

Scope note

This makes images visible in the UI. LLM answers remain image-blind — ingestion does no caption/OCR (only extracts files + inserts placeholders), so figure/chart content still doesn't reach the model. That's a separate pipeline change, not attempted here.

Verification

  • Backend: 1251 passed (adds serve / traversal / non-image-suffix / 404 / auth tests); ruff + mypy clean.
  • Frontend: npm run build (i18n + tsc + vite) green.
  • Manually driven in a browser: the Soochow Securities research PDF's figures (previously !image) now render inline in the reader; chat/wiki rendering unaffected.

Follow-up to #197: long/short source docs embed `![image](sources/images/...)`
references whose files were extracted at ingest but never displayed (they showed
as a literal "!image"). Now they render inline in the reader.
- Backend: GET /api/v1/document/image serves wiki/sources/images/** — narrowed
to the images dir + raster suffixes with a traversal guard (read-only; cannot
reach wiki pages/skills/arbitrary files).
- MarkdownView: gain an optional image token, ENABLED ONLY when a resolveImageSrc
prop is passed (the doc reader). Without it the `![](…)` token is omitted from
the regex, so chat/wiki rendering is byte-for-byte unchanged. A new AuthedImage
fetches the API path as a blob (the bearer token can't ride on <img src>;
mirrors artifacts.ts) and revokes the object URL on unmount.
- Doc reader: passes a resolver that normalizes both source path conventions
(wiki-root `sources/images/...` and note-relative `images/...`) to the
image endpoint; external/data URLs stay literal text.
Images are now visible in the UI. (LLM answers are still image-blind — ingestion
does no caption/OCR — which is a separate pipeline change.)
Backend adds serve/traversal/suffix/404/auth tests (1251 passed). Verified in a
browser: the Soochow Securities report's figures render inline.
- Image URL regex now tolerates one level of balanced parens, so an image
whose path contains ')' (a legacy/cloud doc_name with ASCII parentheses,
e.g. 'report (1)') is no longer truncated to a broken path + stray text [#1].
- The image endpoint sets an explicit media type per suffix instead of letting
FileResponse guess: a .webp is served as image/webp even where mimetypes has
no webp entry (would otherwise be text/plain → a blob-loaded <img> refuses to
render it) [#2]. Adds a webp media-type test.
- AuthedImage shows a muted dashed placeholder (the alt) on load failure instead
of rendering nothing, so a missing image is visible rather than silently
dropped [#3].
Verified: the balanced-paren regex extracts full paths for 'report (1)' and
fullwidth-paren names; backend 1252 passed; frontend build green.
@KylinMountain
KylinMountain merged commit dda7f8e into worktree-feat+workbench-doc-readerJul 22, 2026
2 checks passed
@KylinMountain
KylinMountain deleted the feat/doc-reader-images branch July 22, 2026 03:44
TheNha pushed a commit to TheNha/OpenKB that referenced this pull request Jul 29, 2026
…tifyAI#201)
Cherry-picked from dda7f8e (origin/worktree-feat+workbench-doc-reader),
which was never merged into main/this branch. Documents pane was still
showing !<link> instead of rendering images.
Co-Authored-By: Nguyen The Nha @nha.nt
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@KylinMountain