mirror of
https://github.com/paperless-ngx/paperless-ngx.git
synced 2025-12-22 22:46:53 +01:00
Merge branch 'dev' into copilot/add-webhook-system-ai-events
Resolved merge conflicts in: - src/documents/ai_deletion_manager.py: Kept webhook integration alongside dev changes - src/documents/ai_scanner.py: Kept webhook integration and applied_fields tracking - src/documents/models.py: Integrated AISuggestionFeedback model with webhook imports All conflicts resolved maintaining both webhook functionality and new AI suggestions features from dev branch. Co-authored-by: dawnsystem <42047891+dawnsystem@users.noreply.github.com>
This commit is contained in:
parent
ebc906b713
commit
5ae18e03b5
24 changed files with 5421 additions and 299 deletions
26
src/documents/migrations/1073_add_ai_permissions.py
Normal file
26
src/documents/migrations/1073_add_ai_permissions.py
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
# Generated migration for adding AI-related custom permissions
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("documents", "1072_workflowtrigger_filter_custom_field_query_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name="document",
|
||||
options={
|
||||
"ordering": ("-created",),
|
||||
"permissions": [
|
||||
("can_view_ai_suggestions", "Can view AI suggestions"),
|
||||
("can_apply_ai_suggestions", "Can apply AI suggestions"),
|
||||
("can_approve_deletions", "Can approve AI-recommended deletions"),
|
||||
("can_configure_ai", "Can configure AI settings"),
|
||||
],
|
||||
"verbose_name": "document",
|
||||
"verbose_name_plural": "documents",
|
||||
},
|
||||
),
|
||||
]
|
||||
148
src/documents/migrations/1076_add_deletion_request.py
Normal file
148
src/documents/migrations/1076_add_deletion_request.py
Normal file
|
|
@ -0,0 +1,148 @@
|
|||
# Generated manually for DeletionRequest model
|
||||
# Based on model definition in documents/models.py
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
"""
|
||||
Add DeletionRequest model for AI-initiated deletion requests.
|
||||
|
||||
This model tracks deletion requests that require user approval,
|
||||
implementing the safety requirement from agents.md to ensure
|
||||
no documents are deleted without explicit user consent.
|
||||
"""
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
("documents", "1075_add_performance_indexes"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="DeletionRequest",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"created_at",
|
||||
models.DateTimeField(auto_now_add=True),
|
||||
),
|
||||
(
|
||||
"updated_at",
|
||||
models.DateTimeField(auto_now=True),
|
||||
),
|
||||
(
|
||||
"requested_by_ai",
|
||||
models.BooleanField(default=True),
|
||||
),
|
||||
(
|
||||
"ai_reason",
|
||||
models.TextField(
|
||||
help_text="Detailed explanation from AI about why deletion is recommended"
|
||||
),
|
||||
),
|
||||
(
|
||||
"status",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("pending", "Pending"),
|
||||
("approved", "Approved"),
|
||||
("rejected", "Rejected"),
|
||||
("cancelled", "Cancelled"),
|
||||
("completed", "Completed"),
|
||||
],
|
||||
default="pending",
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
(
|
||||
"impact_summary",
|
||||
models.JSONField(
|
||||
default=dict,
|
||||
help_text="Summary of what will be affected by this deletion",
|
||||
),
|
||||
),
|
||||
(
|
||||
"reviewed_at",
|
||||
models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
(
|
||||
"review_comment",
|
||||
models.TextField(
|
||||
blank=True,
|
||||
help_text="User's comment when reviewing",
|
||||
),
|
||||
),
|
||||
(
|
||||
"completed_at",
|
||||
models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
(
|
||||
"completion_details",
|
||||
models.JSONField(
|
||||
default=dict,
|
||||
help_text="Details about the deletion execution",
|
||||
),
|
||||
),
|
||||
(
|
||||
"documents",
|
||||
models.ManyToManyField(
|
||||
help_text="Documents that would be deleted if approved",
|
||||
related_name="deletion_requests",
|
||||
to="documents.document",
|
||||
),
|
||||
),
|
||||
(
|
||||
"reviewed_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="User who reviewed and approved/rejected",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="reviewed_deletion_requests",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
help_text="User who must approve this deletion",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="deletion_requests",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "deletion request",
|
||||
"verbose_name_plural": "deletion requests",
|
||||
"ordering": ["-created_at"],
|
||||
},
|
||||
),
|
||||
# Add composite index for status + user (common query pattern)
|
||||
migrations.AddIndex(
|
||||
model_name="deletionrequest",
|
||||
index=models.Index(
|
||||
fields=["status", "user"],
|
||||
name="del_req_status_user_idx",
|
||||
),
|
||||
),
|
||||
# Add index for created_at (for chronological queries)
|
||||
migrations.AddIndex(
|
||||
model_name="deletionrequest",
|
||||
index=models.Index(
|
||||
fields=["created_at"],
|
||||
name="del_req_created_idx",
|
||||
),
|
||||
),
|
||||
]
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
# Generated manually for DeletionRequest performance optimization
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
"""
|
||||
Add performance indexes for DeletionRequest model.
|
||||
|
||||
These indexes optimize common query patterns:
|
||||
- Filtering by user + status + created_at (most common listing query)
|
||||
- Filtering by reviewed_at (for finding reviewed requests)
|
||||
- Filtering by completed_at (for finding completed requests)
|
||||
|
||||
Expected performance improvement:
|
||||
- List queries: <100ms
|
||||
- Filter queries: <50ms
|
||||
|
||||
Addresses Issue: [AI Scanner] Índices de Performance para DeletionRequest
|
||||
Epic: Migraciones de Base de Datos
|
||||
"""
|
||||
|
||||
dependencies = [
|
||||
("documents", "1075_add_performance_indexes"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
# Composite index for user + status + created_at (most common query pattern)
|
||||
# This supports queries like: DeletionRequest.objects.filter(user=user, status='pending').order_by('-created_at')
|
||||
migrations.AddIndex(
|
||||
model_name="deletionrequest",
|
||||
index=models.Index(
|
||||
fields=["user", "status", "created_at"],
|
||||
name="delreq_user_status_created_idx",
|
||||
),
|
||||
),
|
||||
# Index for reviewed_at (for filtering reviewed requests)
|
||||
# Supports queries like: DeletionRequest.objects.filter(reviewed_at__isnull=False)
|
||||
migrations.AddIndex(
|
||||
model_name="deletionrequest",
|
||||
index=models.Index(
|
||||
fields=["reviewed_at"],
|
||||
name="delreq_reviewed_at_idx",
|
||||
),
|
||||
),
|
||||
# Index for completed_at (for filtering completed requests)
|
||||
# Supports queries like: DeletionRequest.objects.filter(completed_at__isnull=False)
|
||||
migrations.AddIndex(
|
||||
model_name="deletionrequest",
|
||||
index=models.Index(
|
||||
fields=["completed_at"],
|
||||
name="delreq_completed_at_idx",
|
||||
),
|
||||
),
|
||||
]
|
||||
164
src/documents/migrations/1076_aisuggestionfeedback.py
Normal file
164
src/documents/migrations/1076_aisuggestionfeedback.py
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
# Generated manually for AI Suggestions API
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import django.core.validators
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
"""
|
||||
Add AISuggestionFeedback model for tracking user feedback on AI suggestions.
|
||||
|
||||
This model enables:
|
||||
- Tracking of applied vs rejected AI suggestions
|
||||
- Accuracy statistics and improvement of AI models
|
||||
- User feedback analysis
|
||||
"""
|
||||
|
||||
dependencies = [
|
||||
("documents", "1075_add_performance_indexes"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="AISuggestionFeedback",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.BigAutoField(
|
||||
auto_created=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"suggestion_type",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("tag", "Tag"),
|
||||
("correspondent", "Correspondent"),
|
||||
("document_type", "Document Type"),
|
||||
("storage_path", "Storage Path"),
|
||||
("custom_field", "Custom Field"),
|
||||
("workflow", "Workflow"),
|
||||
("title", "Title"),
|
||||
],
|
||||
max_length=50,
|
||||
verbose_name="suggestion type",
|
||||
),
|
||||
),
|
||||
(
|
||||
"suggested_value_id",
|
||||
models.IntegerField(
|
||||
blank=True,
|
||||
help_text="ID of the suggested object (tag, correspondent, etc.)",
|
||||
null=True,
|
||||
verbose_name="suggested value ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"suggested_value_text",
|
||||
models.TextField(
|
||||
blank=True,
|
||||
help_text="Text representation of the suggested value",
|
||||
verbose_name="suggested value text",
|
||||
),
|
||||
),
|
||||
(
|
||||
"confidence",
|
||||
models.FloatField(
|
||||
help_text="AI confidence score (0.0 to 1.0)",
|
||||
validators=[
|
||||
django.core.validators.MinValueValidator(0.0),
|
||||
django.core.validators.MaxValueValidator(1.0),
|
||||
],
|
||||
verbose_name="confidence",
|
||||
),
|
||||
),
|
||||
(
|
||||
"status",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("applied", "Applied"),
|
||||
("rejected", "Rejected"),
|
||||
],
|
||||
max_length=20,
|
||||
verbose_name="status",
|
||||
),
|
||||
),
|
||||
(
|
||||
"created_at",
|
||||
models.DateTimeField(
|
||||
auto_now_add=True,
|
||||
verbose_name="created at",
|
||||
),
|
||||
),
|
||||
(
|
||||
"applied_at",
|
||||
models.DateTimeField(
|
||||
auto_now=True,
|
||||
verbose_name="applied/rejected at",
|
||||
),
|
||||
),
|
||||
(
|
||||
"metadata",
|
||||
models.JSONField(
|
||||
blank=True,
|
||||
default=dict,
|
||||
help_text="Additional metadata about the suggestion",
|
||||
verbose_name="metadata",
|
||||
),
|
||||
),
|
||||
(
|
||||
"document",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="ai_suggestion_feedbacks",
|
||||
to="documents.document",
|
||||
verbose_name="document",
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="User who applied or rejected the suggestion",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
related_name="ai_suggestion_feedbacks",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="user",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "AI suggestion feedback",
|
||||
"verbose_name_plural": "AI suggestion feedbacks",
|
||||
"ordering": ["-created_at"],
|
||||
},
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="aisuggestionfeedback",
|
||||
index=models.Index(
|
||||
fields=["document", "suggestion_type"],
|
||||
name="documents_a_documen_idx",
|
||||
),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="aisuggestionfeedback",
|
||||
index=models.Index(
|
||||
fields=["status", "created_at"],
|
||||
name="documents_a_status_idx",
|
||||
),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="aisuggestionfeedback",
|
||||
index=models.Index(
|
||||
fields=["suggestion_type", "status"],
|
||||
name="documents_a_suggest_idx",
|
||||
),
|
||||
),
|
||||
]
|
||||
Loading…
Add table
Add a link
Reference in a new issue