Compare commits

..
Author SHA1 Message Date
stumpylog 1c17543ec5 chore(deps): bump imap-tools and python-gnupg
- imap-tools 1.15.0 -> 1.16.0 (1.15.1 fixes a ReDoS in the MailMessage.html parser; 1.16.0 fixes silent no-op mailbox actions with iterables and mixed ASCII/encoded-word address decoding)
- python-gnupg 0.5.6 -> 0.5.7
2026-11-09 10:53:59 -08:00
GitHub Actions 936b1b3bfa Auto translate strings 2026-11-09 06:53:56 +00:00
shamoon e0c33b3d39 Tweak: chat reference tweaks (#14723) 2026-11-08 22:52:34 -08:00
9 changed files with 64 additions and 40 deletions

No files matched your search

+2 -2
View File
@@ -47,7 +47,7 @@ dependencies = [
"gotenberg-client[httpx]~=1.0",
"httpx-oauth~=0.17",
"ijson>=3.5.1",
"imap-tools>=1.14,<1.16",
"imap-tools>=1.16,<1.17",
"jinja2~=3.1.6",
"langdetect~=1.0.9",
"llama-index-core>=0.14.23",
@@ -62,7 +62,7 @@ dependencies = [
"pdf2image~=1.17.0",
"python-dateutil~=2.9.0",
"python-dotenv~=1.2.1",
"python-gnupg~=0.5.4",
"python-gnupg~=0.5.7",
"python-ipware~=3.0.0",
"python-magic~=0.4.27",
"rapidfuzz~=3.14.5",
+15 -8
View File
@@ -4030,14 +4030,21 @@
<source>Sources</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/chat/chat/chat.component.html</context>
<context context-type="linenumber">46,47</context>
<context context-type="linenumber">47,48</context>
</context-group>
</trans-unit>
<trans-unit id="6025275430560167531" datatype="html">
<source>+<x id="INTERPOLATION" equiv-text="{{ hiddenReferenceCount(message) }}"/> more</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/chat/chat/chat.component.html</context>
<context context-type="linenumber">49,50</context>
</context-group>
</trans-unit>
<trans-unit id="8066608938393600549" datatype="html">
<source>Message</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/chat/chat/chat.component.html</context>
<context context-type="linenumber">61,62</context>
<context context-type="linenumber">66,67</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/common/email-document-dialog/email-document-dialog.component.html</context>
@@ -4048,22 +4055,22 @@
<source>Stop</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/chat/chat/chat.component.html</context>
<context context-type="linenumber">74</context>
<context context-type="linenumber">79</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/chat/chat/chat.component.html</context>
<context context-type="linenumber">74</context>
<context context-type="linenumber">79</context>
</context-group>
</trans-unit>
<trans-unit id="6490688569532630280" datatype="html">
<source>Send</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/chat/chat/chat.component.html</context>
<context context-type="linenumber">78</context>
<context context-type="linenumber">83</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/chat/chat/chat.component.html</context>
<context context-type="linenumber">78</context>
<context context-type="linenumber">83</context>
</context-group>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/document-detail/document-detail.component.html</context>
@@ -4090,14 +4097,14 @@
<source>Ask a question about this document...</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/chat/chat/chat.component.ts</context>
<context context-type="linenumber">61</context>
<context context-type="linenumber">83</context>
</context-group>
</trans-unit>
<trans-unit id="224049052163028286" datatype="html">
<source>Ask a question about a document...</source>
<context-group purpose="location">
<context context-type="sourcefile">src/app/components/chat/chat/chat.component.ts</context>
<context context-type="linenumber">62</context>
<context context-type="linenumber">84</context>
</context-group>
</trans-unit>
<trans-unit id="8700121026680200191" datatype="html">
@@ -42,11 +42,16 @@
<span class="text-break">{{ message.content }}</span>
}
@if (message.role === 'assistant' && !message.isStreaming && message.references?.length) {
<div class="chat-references list-group mt-3">
<div class="list-group-item text-muted small py-1" i18n>Sources</div>
@for (reference of message.references; track reference.id) {
<a class="list-group-item list-group-item-action d-flex align-items-center text-primary" [routerLink]="['/documents', reference.id]" [title]="reference.title">
<pngx-bs-icon width="0.9em" height="0.9em" name="file-text" class="me-2 flex-shrink-0"></pngx-bs-icon><span class="text-truncate">{{ reference.title }}</span>
<div class="chat-references mt-2 pt-2 border-top">
<div class="d-flex align-items-center text-muted mb-1">
<span i18n>Sources</span>
@if (hiddenReferenceCount(message) > 0 && !expandedReferences().has(message)) {
<button type="button" class="badge rounded-pill bg-body-secondary text-body-secondary fw-normal border-0 ms-2" (click)="expandReferences(message)" i18n>+{{ hiddenReferenceCount(message) }} more</button>
}
</div>
@for (reference of visibleReferences(message); track reference.id) {
<a class="reference-link d-flex align-items-center lh-sm text-primary text-decoration-none py-1" [routerLink]="['/documents', reference.id]" [title]="reference.title">
<pngx-bs-icon width="0.8em" height="0.8em" name="file-text" class="me-2 flex-shrink-0"></pngx-bs-icon><span class="text-truncate">{{ reference.title }}</span>
</a>
}
</div>
@@ -12,6 +12,10 @@
display: none;
}
.message .flex-grow-1 {
min-width: 0;
}
.dropdown-item {
white-space: initial;
}
@@ -14,6 +14,7 @@ import { BootstrapIconComponent } from 'src/app/components/common/bootstrap-icon
import { MarkdownPipe } from 'src/app/pipes/markdown.pipe'
import {
ChatMessage,
ChatReference,
ChatService,
parseChatResponse,
} from 'src/app/services/chat.service'
@@ -40,8 +41,29 @@ export class ChatComponent implements OnInit {
readonly input = signal('')
readonly documentId = signal<number>(undefined)
readonly slowResponse = signal(false)
readonly expandedReferences = signal<Set<ChatMessage>>(new Set())
public popperOptions = pngxPopperOptions
static readonly COLLAPSED_REFERENCE_COUNT = 2
public visibleReferences(message: ChatMessage): ChatReference[] {
if (this.expandedReferences().has(message)) {
return message.references
}
return message.references.slice(0, ChatComponent.COLLAPSED_REFERENCE_COUNT)
}
public hiddenReferenceCount(message: ChatMessage): number {
return Math.max(
0,
message.references.length - ChatComponent.COLLAPSED_REFERENCE_COUNT
)
}
public expandReferences(message: ChatMessage): void {
this.expandedReferences.update((expanded) => new Set(expanded).add(message))
}
private chatService: ChatService = inject(ChatService)
private router: Router = inject(Router)
@@ -260,18 +260,6 @@ describe('SettingsService', () => {
).toBe(false)
})
it('handles null values for sidebar hidden items', () => {
httpTestingController
.expectOne(`${environment.apiBaseUrl}ui_settings/`)
.flush(ui_settings)
settingsService.set(SETTINGS_KEYS.SIDEBAR_HIDDEN_ITEMS, null)
expect(
settingsService.sidebarItemIsHidden(HideableSidebarItemID.Workflows)
).toBe(false)
})
it('updates setting signals when settings are reinitialized', () => {
let req = httpTestingController.expectOne(
`${environment.apiBaseUrl}ui_settings/`
+2 -4
View File
@@ -765,9 +765,7 @@ export class SettingsService {
sidebarItemIsHidden(item: HideableSidebarItemID): boolean {
return (
this.sidebarHiddenItemsEditing() ??
this.hiddenSidebarItems() ??
[]
this.sidebarHiddenItemsEditing() ?? this.hiddenSidebarItems()
).includes(item)
}
@@ -776,7 +774,7 @@ export class SettingsService {
visible: boolean
): void {
const hiddenItems = new Set(
this.sidebarHiddenItemsEditing() ?? this.hiddenSidebarItems() ?? []
this.sidebarHiddenItemsEditing() ?? this.hiddenSidebarItems()
)
if (visible) {
hiddenItems.delete(item)
+1 -1
View File
@@ -22,8 +22,8 @@ logger = logging.getLogger("paperless_ai.chat")
CHAT_METADATA_DELIMITER = "\n\n__PAPERLESS_CHAT_METADATA__"
CHAT_ERROR_MESSAGE = "Sorry, something went wrong while generating a response."
CHAT_NO_CONTENT_MESSAGE = "Sorry, I couldn't find any content to answer your question."
MAX_CHAT_REFERENCES = 3
CHAT_RETRIEVER_TOP_K = 5
MAX_CHAT_REFERENCES = CHAT_RETRIEVER_TOP_K
def _build_chat_prompt(output_language: str | None) -> str:
Generated
+8 -8
View File
@@ -1958,11 +1958,11 @@ wheels = [
[[package]]
name = "imap-tools"
version = "1.15.0"
version = "1.16.0"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/59/4e/acf9a7d59932548bc749fe0f5ae852e6da00b640303ed72786f697944b69/imap_tools-1.15.0.tar.gz", hash = "sha256:a90f948549ab000d96caf17c90e63b114f8788ba4a0d3f9274a96c0e108c3805", size = 48497, upload-time = "2026-08-06T10:25:26.567Z" }
sdist = { url = "https://files.pythonhosted.org/packages/47/ff/013a8cc97cc3d7a74a5cc0d05c5eb637d47a5114efe10312ba7b72b11609/imap_tools-1.16.0.tar.gz", hash = "sha256:70cc760915965f9efd3ce2b43cbdafeca40849aedbea3623019536dc1def95b6", size = 49867, upload-time = "2026-10-14T10:17:57.817Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/50/eb/a4ad6ec962af2806c3484adb1869c24a04d8ef8c2034f2dd2b0f48459b0a/imap_tools-1.15.0-py3-none-any.whl", hash = "sha256:7bb0003c8bf124b80968c7bef786e4577d8365e9afb6551dc15b13161b688bdc", size = 36512, upload-time = "2026-08-06T10:25:24.377Z" },
{ url = "https://files.pythonhosted.org/packages/92/d8/b9797cfdbfb885c0ebce581234e5e09ec1805f5d8b42247f8d9cde23ca92/imap_tools-1.16.0-py3-none-any.whl", hash = "sha256:8ae0860d626d44ad21c3b917309d135eb4d112159d4ce78b90a03b9bb9ba0de9", size = 36716, upload-time = "2026-10-14T10:17:54.494Z" },
]
[[package]]
@@ -3258,7 +3258,7 @@ requires-dist = [
{ name = "granian", extras = ["uvloop"], marker = "extra == 'webserver'", specifier = ">=2.7,<2.9" },
{ name = "httpx-oauth", specifier = "~=0.17" },
{ name = "ijson", specifier = ">=3.5.1" },
{ name = "imap-tools", specifier = ">=1.14,<1.16" },
{ name = "imap-tools", specifier = ">=1.16,<1.17" },
{ name = "jinja2", specifier = "~=3.1.6" },
{ name = "langdetect", specifier = "~=1.0.9" },
{ name = "llama-index-core", specifier = ">=0.14.23" },
@@ -3281,7 +3281,7 @@ requires-dist = [
{ name = "psycopg-pool", marker = "extra == 'postgres'", specifier = "==3.3.3" },
{ name = "python-dateutil", specifier = "~=2.9.0" },
{ name = "python-dotenv", specifier = "~=1.2.1" },
{ name = "python-gnupg", specifier = "~=0.5.4" },
{ name = "python-gnupg", specifier = "~=0.5.7" },
{ name = "python-ipware", specifier = "~=3.0.0" },
{ name = "python-magic", specifier = "~=0.4.27" },
{ name = "rapidfuzz", specifier = "~=3.14.5" },
@@ -4196,11 +4196,11 @@ wheels = [
[[package]]
name = "python-gnupg"
version = "0.5.6"
version = "0.5.7"
source = { registry = "https://pypi.org/simple" }
sdist = { url = "https://files.pythonhosted.org/packages/98/2c/6cd2c7cff4bdbb434be5429ef6b8e96ee6b50155551361f30a1bb2ea3c1d/python_gnupg-0.5.6.tar.gz", hash = "sha256:5743e96212d38923fc19083812dc127907e44dbd3bcf0db4d657e291d3c21eac", size = 66825, upload-time = "2025-12-31T17:19:33.19Z" }
sdist = { url = "https://files.pythonhosted.org/packages/bb/d4/47aa0f34b6a06a976063e3e0bf1512b140ec1e6efda83bc717fac58071db/python_gnupg-0.5.7.tar.gz", hash = "sha256:73ea46219f992b361eb1ce54cb0968101670654454916a3ee5df8bb9bf0cc8cc", size = 63974, upload-time = "2026-09-29T16:40:09.487Z" }
wheels = [
{ url = "https://files.pythonhosted.org/packages/d2/ab/0ea9de971caf3cd2e268d2b05dfe9883b21cfe686a59249bd2dccb4bae33/python_gnupg-0.5.6-py2.py3-none-any.whl", hash = "sha256:b5050a55663d8ab9fcc8d97556d229af337a87a3ebebd7054cbd8b7e2043394a", size = 22082, upload-time = "2025-12-31T17:16:22.743Z" },
{ url = "https://files.pythonhosted.org/packages/7c/38/ffad2b8a27e7295e70616ab4d938cead165a56db4496558491f485fa3a87/python_gnupg-0.5.7-py2.py3-none-any.whl", hash = "sha256:dc7afba57a9bc50163c27c726c66cb2fc9692248597f5201f4f7d9eb6097dd1d", size = 22362, upload-time = "2026-09-29T16:40:08.189Z" },
]
[[package]]