From aade25cd3aca00acf9bc09dead72c91bfcb8eb69 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Mon, 9 Feb 2026 04:37:40 +0000 Subject: [PATCH] various bugs --- celery.log | 154 ++++++++++++++ check_import.py | 6 + config/__pycache__/settings.cpython-311.pyc | Bin 6432 -> 6432 bytes config/__pycache__/urls.cpython-311.pyc | Bin 859 -> 1228 bytes config/settings.py | 2 +- config/urls.py | 7 +- core/__pycache__/api_views.cpython-311.pyc | Bin 3502 -> 3864 bytes core/__pycache__/serializers.cpython-311.pyc | Bin 3990 -> 4490 bytes core/__pycache__/tasks.cpython-311.pyc | Bin 8991 -> 11493 bytes core/__pycache__/tests.cpython-311.pyc | Bin 0 -> 3340 bytes core/__pycache__/views.cpython-311.pyc | Bin 12069 -> 13656 bytes core/api_views.py | 9 +- core/serializers.py | 18 +- core/tasks.py | 68 ++++++- core/templates/base.html | 5 +- core/templates/core/bookmark_detail.html | 199 ++++++++++++++----- core/templates/core/bookmark_form.html | 58 +++++- core/templates/core/index.html | 84 +++++++- core/tests.py | 57 +++++- core/views.py | 32 ++- debug_tags.py | 63 ++++++ repro_api_tags.py | 66 ++++++ requirements.txt | 4 +- 23 files changed, 746 insertions(+), 86 deletions(-) create mode 100644 celery.log create mode 100644 check_import.py create mode 100644 core/__pycache__/tests.cpython-311.pyc create mode 100644 debug_tags.py create mode 100644 repro_api_tags.py diff --git a/celery.log b/celery.log new file mode 100644 index 0000000..4cefb20 --- /dev/null +++ b/celery.log @@ -0,0 +1,154 @@ + + -------------- celery@pool-python-d07be985 v5.4.0 (opalescent) +--- ***** ----- +-- ******* ---- Linux-6.1.0-42-cloud-amd64-x86_64-with-glibc2.36 2026-02-08 16:57:58 +- *** --- * --- +- ** ---------- [config] +- ** ---------- .> app: config:0x7f0365fc7010 +- ** ---------- .> transport: redis://localhost:6379/0 +- ** ---------- .> results: redis://localhost:6379/0 +- *** --- * --- .> concurrency: 2 (prefork) +-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker) +--- ***** ----- + -------------- [queues] + .> celery exchange=celery(direct) key=celery + + +[tasks] + . config.celery.debug_task + . core.tasks.generate_summary + . core.tasks.process_bookmark + +[2026-02-08 16:57:58,648: WARNING/MainProcess] /home/ubuntu/.local/lib/python3.11/site-packages/celery/worker/consumer/consumer.py:508: CPendingDeprecationWarning: The broker_connection_retry configuration setting will no longer determine +whether broker connection retries are made during startup in Celery 6.0 and above. +If you wish to retain the existing behavior for retrying connections on startup, +you should set broker_connection_retry_on_startup to True. + warnings.warn( + +[2026-02-08 16:57:58,669: INFO/MainProcess] Connected to redis://localhost:6379/0 +[2026-02-08 16:57:58,672: WARNING/MainProcess] /home/ubuntu/.local/lib/python3.11/site-packages/celery/worker/consumer/consumer.py:508: CPendingDeprecationWarning: The broker_connection_retry configuration setting will no longer determine +whether broker connection retries are made during startup in Celery 6.0 and above. +If you wish to retain the existing behavior for retrying connections on startup, +you should set broker_connection_retry_on_startup to True. + warnings.warn( + +[2026-02-08 16:57:58,676: INFO/MainProcess] mingle: searching for neighbors +[2026-02-08 16:57:59,699: INFO/MainProcess] mingle: all alone +[2026-02-08 16:57:59,722: INFO/MainProcess] celery@pool-python-d07be985 ready. +[2026-02-08 16:58:54,807: INFO/MainProcess] Task core.tasks.process_bookmark[6aeefd1e-df28-42d3-bb17-d6836c389361] received +[2026-02-08 16:58:55,106: INFO/ForkPoolWorker-2] HTTP Request: GET https://openai.com "HTTP/1.1 403 Forbidden" +[2026-02-08 16:58:55,121: WARNING/ForkPoolWorker-2] Error fetching bookmark 9 (https://openai.com): Client error '403 Forbidden' for url 'https://openai.com' +For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403. Trying base domain backup. +[2026-02-08 16:58:55,121: ERROR/ForkPoolWorker-2] Error fetching base domain for bookmark 9: Client error '403 Forbidden' for url 'https://openai.com' +For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403 +[2026-02-08 16:58:55,222: INFO/MainProcess] Task core.tasks.generate_summary[b7f3ce50-3949-4d4b-8124-986fc6fed32d] received +[2026-02-08 16:58:55,230: INFO/ForkPoolWorker-2] Task core.tasks.process_bookmark[6aeefd1e-df28-42d3-bb17-d6836c389361] succeeded in 0.41664800100261346s: 'Processed bookmark 9' +[2026-02-08 16:59:06,405: INFO/ForkPoolWorker-1] Task core.tasks.generate_summary[b7f3ce50-3949-4d4b-8124-986fc6fed32d] succeeded in 11.157703020959161s: 'Generated summary for bookmark 9' +[2026-02-08 17:49:01,106: INFO/MainProcess] Task core.tasks.process_bookmark[480f8119-0f34-4c8d-af74-8223f6d86777] received +[2026-02-08 17:49:01,495: INFO/ForkPoolWorker-2] HTTP Request: GET https://aimlapi.com/ "HTTP/1.1 200 OK" +[2026-02-08 17:49:01,833: INFO/MainProcess] Task core.tasks.generate_summary[5f9a1a29-9b56-4219-b073-86aa584fa574] received +[2026-02-08 17:49:01,840: INFO/ForkPoolWorker-2] Task core.tasks.process_bookmark[480f8119-0f34-4c8d-af74-8223f6d86777] succeeded in 0.7128028109436855s: 'Processed bookmark 10' +[2026-02-08 17:49:12,749: INFO/ForkPoolWorker-1] Task core.tasks.generate_summary[5f9a1a29-9b56-4219-b073-86aa584fa574] succeeded in 10.906358937965706s: 'Generated summary for bookmark 10' +[2026-02-08 17:50:13,199: INFO/MainProcess] Task core.tasks.process_bookmark[38a7f2f4-6b5e-48ab-8ce5-b973aecf0829] received +[2026-02-08 17:50:13,401: INFO/ForkPoolWorker-2] HTTP Request: GET https://dropoverapp.com/ "HTTP/1.1 200 OK" +[2026-02-08 17:50:13,476: INFO/MainProcess] Task core.tasks.generate_summary[f6142f4c-c377-44cf-8921-4de37564f845] received +[2026-02-08 17:50:13,486: INFO/ForkPoolWorker-2] Task core.tasks.process_bookmark[38a7f2f4-6b5e-48ab-8ce5-b973aecf0829] succeeded in 0.28576223901472986s: 'Processed bookmark 11' +[2026-02-08 17:50:19,030: INFO/ForkPoolWorker-1] Task core.tasks.generate_summary[f6142f4c-c377-44cf-8921-4de37564f845] succeeded in 5.548579726018943s: 'Generated summary for bookmark 11' +[2026-02-08 17:54:37,900: INFO/MainProcess] Task core.tasks.process_bookmark[49edb552-63b2-44e3-b6bf-29ea3921cbc0] received +[2026-02-08 17:54:39,151: INFO/ForkPoolWorker-2] HTTP Request: GET https://www.wikipedia.org/ "HTTP/1.1 200 OK" +[2026-02-08 17:54:39,938: INFO/MainProcess] Task core.tasks.generate_summary[62fbb6ba-951b-469a-ac79-19663a33d9a4] received +[2026-02-08 17:54:39,982: INFO/ForkPoolWorker-2] Task core.tasks.process_bookmark[49edb552-63b2-44e3-b6bf-29ea3921cbc0] succeeded in 1.9269755689892918s: 'Processed bookmark 12' +[2026-02-08 17:54:46,341: INFO/ForkPoolWorker-1] Task core.tasks.generate_summary[62fbb6ba-951b-469a-ac79-19663a33d9a4] succeeded in 6.309643072017934s: 'Generated summary for bookmark 12' +[2026-02-08 17:55:04,551: INFO/MainProcess] Task core.tasks.process_bookmark[20ea2b59-ed0f-4970-ad43-cea2bc3597e0] received +[2026-02-08 17:55:04,768: INFO/ForkPoolWorker-2] HTTP Request: GET https://www.wikipedia.org/ "HTTP/1.1 200 OK" +[2026-02-08 17:55:05,030: INFO/MainProcess] Task core.tasks.generate_summary[e29ad0ec-2683-44f9-964a-6883351d3e53] received +[2026-02-08 17:55:05,034: INFO/ForkPoolWorker-2] Task core.tasks.process_bookmark[20ea2b59-ed0f-4970-ad43-cea2bc3597e0] succeeded in 0.4778669200022705s: 'Processed bookmark 12' +[2026-02-08 17:55:15,878: INFO/ForkPoolWorker-1] Task core.tasks.generate_summary[e29ad0ec-2683-44f9-964a-6883351d3e53] succeeded in 10.846816856996156s: 'Generated summary for bookmark 12' +[2026-02-08 17:55:38,808: INFO/MainProcess] Task core.tasks.process_bookmark[631857db-83e4-448e-91bc-5964ff822b82] received +[2026-02-08 17:55:38,955: INFO/ForkPoolWorker-2] HTTP Request: GET https://openai.com "HTTP/1.1 403 Forbidden" +[2026-02-08 17:55:38,975: WARNING/ForkPoolWorker-2] Error fetching bookmark 9 (https://openai.com): Client error '403 Forbidden' for url 'https://openai.com' +For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403. Trying base domain backup. +[2026-02-08 17:55:38,976: ERROR/ForkPoolWorker-2] Error fetching base domain for bookmark 9: Client error '403 Forbidden' for url 'https://openai.com' +For more information check: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/403 +[2026-02-08 17:55:38,992: INFO/MainProcess] Task core.tasks.generate_summary[ac5da805-5c8e-4641-ba7d-594b569f9472] received +[2026-02-08 17:55:38,996: INFO/ForkPoolWorker-2] Task core.tasks.process_bookmark[631857db-83e4-448e-91bc-5964ff822b82] succeeded in 0.18439359701005742s: 'Processed bookmark 9' +[2026-02-08 17:55:49,704: INFO/ForkPoolWorker-1] Task core.tasks.generate_summary[ac5da805-5c8e-4641-ba7d-594b569f9472] succeeded in 10.710596179007553s: 'Generated summary for bookmark 9' +[2026-02-08 17:56:04,496: INFO/MainProcess] Task core.tasks.process_bookmark[8e44cfbd-da5d-4f2c-a670-205d1f35397c] received +[2026-02-08 17:56:06,477: INFO/ForkPoolWorker-2] HTTP Request: GET https://www.wikipedia.org/ "HTTP/1.1 200 OK" +[2026-02-08 17:56:10,002: INFO/MainProcess] Task core.tasks.generate_summary[d89d853b-545c-47ef-8d88-b3645948b928] received +[2026-02-08 17:56:10,231: INFO/ForkPoolWorker-2] Task core.tasks.process_bookmark[8e44cfbd-da5d-4f2c-a670-205d1f35397c] succeeded in 5.731945501989685s: 'Processed bookmark 12' +[2026-02-08 17:56:23,118: INFO/ForkPoolWorker-1] Task core.tasks.generate_summary[d89d853b-545c-47ef-8d88-b3645948b928] succeeded in 13.114061183994636s: 'Generated summary for bookmark 12' + + -------------- celery@pool-python-d07be985 v5.4.0 (opalescent) +--- ***** ----- +-- ******* ---- Linux-6.1.0-42-cloud-amd64-x86_64-with-glibc2.36 2026-02-08 19:37:54 +- *** --- * --- +- ** ---------- [config] +- ** ---------- .> app: config:0x7f7767509510 +- ** ---------- .> transport: redis://localhost:6379/0 +- ** ---------- .> results: redis://localhost:6379/0 +- *** --- * --- .> concurrency: 2 (prefork) +-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker) +--- ***** ----- + -------------- [queues] + .> celery exchange=celery(direct) key=celery + + +[tasks] + . config.celery.debug_task + . core.tasks.generate_summary + . core.tasks.process_bookmark + +[2026-02-08 19:37:55,136: WARNING/MainProcess] /home/ubuntu/.local/lib/python3.11/site-packages/celery/worker/consumer/consumer.py:508: CPendingDeprecationWarning: The broker_connection_retry configuration setting will no longer determine +whether broker connection retries are made during startup in Celery 6.0 and above. +If you wish to retain the existing behavior for retrying connections on startup, +you should set broker_connection_retry_on_startup to True. + warnings.warn( + +[2026-02-08 19:37:55,230: INFO/MainProcess] Connected to redis://localhost:6379/0 +[2026-02-08 19:37:55,233: WARNING/MainProcess] /home/ubuntu/.local/lib/python3.11/site-packages/celery/worker/consumer/consumer.py:508: CPendingDeprecationWarning: The broker_connection_retry configuration setting will no longer determine +whether broker connection retries are made during startup in Celery 6.0 and above. +If you wish to retain the existing behavior for retrying connections on startup, +you should set broker_connection_retry_on_startup to True. + warnings.warn( + +[2026-02-08 19:37:55,266: INFO/MainProcess] mingle: searching for neighbors +[2026-02-08 19:37:56,302: INFO/MainProcess] mingle: all alone +[2026-02-08 19:37:56,334: INFO/MainProcess] celery@pool-python-d07be985 ready. +[2026-02-08 19:37:56,351: INFO/MainProcess] Task core.tasks.process_bookmark[49276cb8-da4c-4e3b-a10c-1eff3e4358fc] received +[2026-02-08 19:37:56,364: INFO/MainProcess] Task core.tasks.process_bookmark[4cc4cf11-e28f-4a72-9d09-4da9b24bce6e] received +[2026-02-08 19:37:56,819: INFO/ForkPoolWorker-2] HTTP Request: GET https://dropoverapp.com/ "HTTP/1.1 200 OK" +[2026-02-08 19:37:56,955: INFO/ForkPoolWorker-1] HTTP Request: GET https://www.strella.io/ "HTTP/1.1 200 OK" +[2026-02-08 19:37:57,117: INFO/MainProcess] Task core.tasks.generate_summary[7ca1dbb6-005a-4fcf-b5d0-5fd6a2ae8ac5] received +[2026-02-08 19:37:57,130: INFO/ForkPoolWorker-2] Task core.tasks.process_bookmark[49276cb8-da4c-4e3b-a10c-1eff3e4358fc] succeeded in 0.7769331529852934s: 'Processed bookmark 13' +[2026-02-08 19:37:57,193: INFO/ForkPoolWorker-2] Generating summary/tags for bookmark 13... +[2026-02-08 19:37:57,361: INFO/MainProcess] Task core.tasks.generate_summary[71b0f9cb-36dc-4eb4-91f7-f6e8bba9c54d] received +[2026-02-08 19:37:57,389: INFO/ForkPoolWorker-1] Task core.tasks.process_bookmark[4cc4cf11-e28f-4a72-9d09-4da9b24bce6e] succeeded in 1.0219957570079714s: 'Processed bookmark 14' +[2026-02-08 19:37:57,419: INFO/ForkPoolWorker-1] Generating summary/tags for bookmark 14... +[2026-02-08 19:37:58,896: INFO/MainProcess] Events of group {task} enabled by remote. +[2026-02-08 19:38:07,952: INFO/ForkPoolWorker-2] AI Raw Response for 13: { + "summary": "Dropover is a macOS utility that provides floating shelves to collect, organize, and batch-move dragged items (files, folders, images, URLs, text) for streamlined file management. It offers built-in file actions, cloud uploads and sharing, plus extensive customization and automation features (custom actions, scripts, keyboard shortcuts, Siri Shortcuts) for power users.", + "tags": ["filesharing", "sharing", "documents", "productivity"] +} +[2026-02-08 19:38:07,953: INFO/ForkPoolWorker-2] Decoded JSON for 13: summary=True, tags=['filesharing', 'sharing', 'documents', 'productivity'] +[2026-02-08 19:38:08,022: INFO/ForkPoolWorker-2] Successfully added tags ['filesharing', 'sharing', 'documents', 'productivity'] to bookmark 13 +[2026-02-08 19:38:08,024: INFO/ForkPoolWorker-2] Task core.tasks.generate_summary[7ca1dbb6-005a-4fcf-b5d0-5fd6a2ae8ac5] succeeded in 10.876905062003061s: 'Generated summary and tags for bookmark 13' +[2026-02-08 19:38:08,341: INFO/ForkPoolWorker-1] AI Raw Response for 14: { + "summary": "Strella is an AI-powered customer research platform that runs AI-moderated interviews, recruits participants, generates discussion guides, and analyzes responses to deliver actionable insights within hours. It’s built for teams (UX, product, consumer insights, marketing) to accelerate market research, usability testing, and concept validation and to share findings with stakeholders.", + "tags": ["marketing", "company", "sharing", "development"] +} +[2026-02-08 19:38:08,342: INFO/ForkPoolWorker-1] Decoded JSON for 14: summary=True, tags=['marketing', 'company', 'sharing', 'development'] +[2026-02-08 19:38:08,422: INFO/ForkPoolWorker-1] Successfully added tags ['marketing', 'company', 'sharing', 'development'] to bookmark 14 +[2026-02-08 19:38:08,426: INFO/ForkPoolWorker-1] Task core.tasks.generate_summary[71b0f9cb-36dc-4eb4-91f7-f6e8bba9c54d] succeeded in 11.034683802979998s: 'Generated summary and tags for bookmark 14' +[2026-02-09 04:08:42,072: INFO/MainProcess] Task core.tasks.process_bookmark[cd622357-234e-4dc9-9fab-eefa651ea2a4] received +[2026-02-09 04:08:43,746: INFO/ForkPoolWorker-2] HTTP Request: GET https://www.strella.io/ "HTTP/1.1 200 OK" +[2026-02-09 04:08:45,048: INFO/MainProcess] Task core.tasks.generate_summary[ba68ccad-d413-41cc-8b1c-65384d2792ab] received +[2026-02-09 04:08:45,073: INFO/ForkPoolWorker-2] Task core.tasks.process_bookmark[cd622357-234e-4dc9-9fab-eefa651ea2a4] succeeded in 2.6813507160404697s: 'Processed bookmark 15' +[2026-02-09 04:08:45,647: INFO/ForkPoolWorker-1] Generating summary/tags for bookmark 15... +[2026-02-09 04:08:51,671: INFO/ForkPoolWorker-1] AI Raw Response for 15: { + "summary": "Strella is an AI-powered customer research platform that runs AI-moderated interviews, recruits targeted participants, and analyzes responses to generate actionable insights in hours. It’s designed for teams (UX, product, consumer insights, marketing) to accelerate research workflows, produce unbiased discussion guides, and share findings with stakeholders.", + "tags": ["marketing", "company", "productivity", "sharing"] +} +[2026-02-09 04:08:51,673: INFO/ForkPoolWorker-1] Decoded JSON for 15: summary=True, tags=['marketing', 'company', 'productivity', 'sharing'] +[2026-02-09 04:08:51,759: INFO/ForkPoolWorker-1] Successfully added tags ['marketing', 'company', 'productivity', 'sharing'] to bookmark 15 +[2026-02-09 04:08:51,894: INFO/ForkPoolWorker-1] Task core.tasks.generate_summary[ba68ccad-d413-41cc-8b1c-65384d2792ab] succeeded in 6.7007439360022545s: 'Generated summary and tags for bookmark 15' diff --git a/check_import.py b/check_import.py new file mode 100644 index 0000000..10a9ae9 --- /dev/null +++ b/check_import.py @@ -0,0 +1,6 @@ + +try: + from taggit.serializers import TagListSerializerField, TaggitSerializer + print("Import SUCCESS") +except ImportError as e: + print(f"Import FAILED: {e}") diff --git a/config/__pycache__/settings.cpython-311.pyc b/config/__pycache__/settings.cpython-311.pyc index 7eeb2e3d09dcb475db1476df6b71d7a0b4751b02..1dd5fe84691ecb7c79039f5726dc9155786de641 100644 GIT binary patch delta 35 pcmZ2rw7`gWIWI340}z-WZ_8BN$Q#DW=(IV7b*3<*;^co4N&u#v37h}` delta 35 pcmZ2rw7`gWIWI340}%X})tsrYkvEK$QE+n#>r7!rg~|UUlmM{f3Hks4 diff --git a/config/__pycache__/urls.cpython-311.pyc b/config/__pycache__/urls.cpython-311.pyc index 5d3b77da5cf15fd7c5608efcaf04eaed12f62b3c..a62b69c6517edccf41c3c75ea5dc2a6f9e2badde 100644 GIT binary patch literal 1228 zcma)4Jx|*}7(OTGe3I}b)QTom`6y~S*g%Df(g+qLL=`HeN=0&|rY1hXsU4?hn?NSU zj0{L+?3Aj4p<_pWf{iQ@dF|8JburN4`O9_UuL-z{j4ZvZ8B5^se8fzgRT zCjmNxUF5%Xl7G1zi;_A?x4@rc7@fG&{r*+`pn#QufAO|>X-FA-jdDXj znP`sld0ElbYA)>Knrv7(t!)}*D+yMX0z>>XB|A0d zh!FHN#t4t^Ze{j%2!cZ3TC!zOlg1ero2o^8%x>Vvi_9kGtsj-m-~>Mb7&sDuNnn8) z7NJ%1E4qa3=t>Z`4V{Sg2Ka1?WS5j}5EttP{b1JQG7;f}H`OhX9U#>9u3`ncc^vvnaHkx#LvyGOW-n@t)KEA)yynirvm_J-} z@q~vb+Bmkq&^9pw{B|8OO3gB+{5D+$w+@_Kgk}N0grwGm`6=& delta 381 zcmX@Zd7DjrIWI340}%98HD?wuGB7*_abSQG%J?iYQC(h%ks*a4g*k^cmo18&k%5UJ zl{tkal`)G0raFsraulO9KWi#`7T8FT_yX>U>y%a5*03*QW?)zi#1H`1%mGx$0}}x& zl;y;#kPE1sC53x(4Wq0fOB8PkPcVZf?@N$QO~zZSi7C06d74bOSPBwLGH$VF<|XHp zrlf*o$}&^SizokNbP~A5P{o;?UzDm>T9i}lr^z?Dmq};xJ|-~%HlQK5xDrcCGU6es zRhg@~C4hp!pkOFI#4vd^v$Tfl1qLkW27~bhR5V$FC0?DQ!KFi}BfKMgLi9ym#Vfpu X7g?09uqb`tWaVdS;0D1WF`(H1NFi50 diff --git a/config/settings.py b/config/settings.py index 9c8820b..19e2b83 100644 --- a/config/settings.py +++ b/config/settings.py @@ -207,7 +207,7 @@ CELERY_RESULT_SERIALIZER = 'json' CELERY_TIMEZONE = TIME_ZONE # Run tasks synchronously in development (no Redis required) -CELERY_TASK_ALWAYS_EAGER = True +CELERY_TASK_ALWAYS_EAGER = False CELERY_TASK_EAGER_PROPAGATES = True # Login/Logout Redirects diff --git a/config/urls.py b/config/urls.py index 4da058d..ff44bea 100644 --- a/config/urls.py +++ b/config/urls.py @@ -1,10 +1,13 @@ from django.contrib import admin -from django.urls import path, include +from django.urls import path, include, re_path from django.contrib.auth import views as auth_views +from revproxy.views import ProxyView +from django.contrib.admin.views.decorators import staff_member_required urlpatterns = [ path('admin/', admin.site.urls), path('accounts/login/', auth_views.LoginView.as_view(), name='login'), path('accounts/logout/', auth_views.LogoutView.as_view(), name='logout'), + re_path(r'^flower/(?P.*)$', staff_member_required(ProxyView.as_view(upstream='http://127.0.0.1:5555/flower/'))), path('', include('core.urls')), -] +] \ No newline at end of file diff --git a/core/__pycache__/api_views.cpython-311.pyc b/core/__pycache__/api_views.cpython-311.pyc index 4245aaf1ffeb89b602f64656643136659dce8519..d518a2074f835d0145db32098e4683158f27e79b 100644 GIT binary patch delta 1305 zcmZux-D@0G6u)<8XJ>bIW@nSlY`&Vb4V%Q-q-jjmh;AbVr3y7t3KiCp?YJ|TS!XtS z?<_IFQiUQ`1RHO`zL^I}2`M6|^v%COFsTDA19_r#h>5BYZ&WHl0NV4<(XCyImREP2cT^qRQA2}a!NSb*rv3Nhu9y$~-^MqJ+x zUB^n0E(lOt)Ft9QlmeX-CrA(bT|RvsdO%woK0}Yp?%P))b0{)LADZJ2%<&C#A~Gkw zR5y*z$TmMRWlNDVX9+&WUQBsiIwwFh4y#!3rO*PP_)F?F zJivBRB{2;31bdw9U=zwm1?XigJN%Xlal&&fiFC1Fl>ywt9w}$=Fw@d!#$bM?t#;DK zpQIn)I6#s^Y`jI!wZd7q8G3an6gkO)^uno02&e$O4ln?4IG-g@0SbK48*DV&%f>R3 zhAf}mLI;pz^O@n@;VrQrGWSQPc(j!~>>?S5JkJBX3W@eE3;HCxsrKR1?5;Za-Y)&j z|IsIJK=4U`90xv0F7a&NTjWiy`!=OST;wVG(-03Z!iKX`nz$FJ(^fb8ID4&}cN%u{ zgSj#1{jp$&x`m#FTeDGdWE&hi Ohu(1(>MteXuKxkk2OPEl delta 1044 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 ZFy4#vsL(wUk>ENT&I@amD{}>V{{l)(9tZ#c diff --git a/core/__pycache__/tests.cpython-311.pyc b/core/__pycache__/tests.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4c2935289b44bbd7dbb651f02ef85802bde47977 GIT binary patch literal 3340 zcmeHJO>7fK6rQzr?XevvA$F)8{@l_KToN0a0)@6gC9TS#jZ`&ouvD!!-X*cK_PVp{ zQlcPnKx(KWl~$49z`>`GC^>NKy_X(sYo%B#At6;9xEY00PJM6fUB^kF>b>Lfw{K?N zym>S8zPI}%91apFe~R~W>wZH1#)eabwy=Ezgoi{XGN+OPm*EPYjEBRvNA(u?3~$R` zRVer}K9G4?Q2hm(p&ap$uZZlsM`XXkt$GRBfPbrG0y6!MBm*z8ne$<|=>1WE13e%OB9O`lwy{c*R1&PgPTeez=gIKl`01t^mGMr2@9+|sG zGG5sO$je?pLFQp$!5Va|OiQ!ZOR{7r=t9;pgQk4&M~}C!LGMFiU|+lBUA>CO>D&F3 zIoY%6U4^j?cYKkE?*5HHM|%~-4Yvte&dHNSl6U0_db6(_v<^p%-j3ofPid#OBf%Q3 zS9o`_Z_~fZgGcah74XRQ7PMVCZ^sVmR6=dlu7^xl;gmMqlfpQ`JD;+s0Y_bi+qGy( z()C*!lQ9OcrzjN^76v;zkvYRC>6g=Kn{;T49S_s&+ag- zxS@$_J7tku+-t+TNGdLY96fw4dh;%wAWXYx$|3DsA1iqD`${)uamE|g*<~s3(og31 zu4qI$OYC0#-ze7YM>pN>@QZw_q-gCgR^^1wN2yD)K1u;!k8lGjCCM^ z#AbEY2P^G_TRBxuOd}CHO`EF={bf7j%A<**a%&8Dw9d0bFpUi$;9*!nWS5vLmdeJ< z6kNxGzpZNd+mn-FhL^~OP~B6SXYZiEmo(k5LXcJzW_1o~$2@RE=$3X@A(5v-%Oj^UNS z!j7X(KeAeEIVj=|7ET>Z>%DroXZ-~LFuZs0fwnfi`Mo*zS#@-x+Iywed&TU%vgB?0 zNHp0Pd>`x3XfxpN4>k$F65kvkkQYALikz%RPF5z@qP0lMjHH$*ObLXyXsk|Sk78zg zY)!Axag&Z$>G*R<5im4dr^7WmV$zW+9f7pbR*pVCX2wU?v>Kf-=|q)Iyy%NO_+sT7 zGkU6(eQME^8BNvt(q>W)^T=t37e|``0eJxcyy$%cFFGOm-&t{HD}JsXKUa&7oAL3d-`40wlU}Sk z)sF3{q|c(Fh^a&rt)M6tG`Xyz+#`yZlv*R~1ni5QN4NyAPVC8cDq;9_WdkNT{d0i3 z?yuQkwm`j2CimJE1o}78`ou%8sV)@#`_=aow{TWIL1Wb!N^wZY%V48KCLq sIIclXR}ZQUa;Dl{8{|Z_yEe$tYIkk&A9Aqw{qX48E9`xJz>w|eKeP1FumAu6 literal 0 HcmV?d00001 diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 9c74dc96743fd821c0311c5b1c0c33b27899c018..8790f1608578b77a480b346590fea45543687501 100644 GIT binary patch delta 4697 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 AN&o-= diff --git a/core/api_views.py b/core/api_views.py index 8f062f2..89c66f3 100644 --- a/core/api_views.py +++ b/core/api_views.py @@ -2,6 +2,7 @@ from rest_framework import viewsets, permissions, filters from rest_framework.views import APIView from rest_framework.response import Response from django_filters.rest_framework import DjangoFilterBackend +from django.db.models import Q from core.models import Bookmark, Team from core.serializers import BookmarkSerializer, BookmarkDetailSerializer, TeamSerializer from core.tasks import process_bookmark @@ -24,7 +25,11 @@ class BookmarkViewSet(viewsets.ModelViewSet): ordering = ['-created_at'] def get_queryset(self): - return Bookmark.objects.filter(user=self.request.user).select_related('extraction') + user_teams = self.request.user.teams.all() + return Bookmark.objects.filter( + Q(user=self.request.user) | + Q(shares__team__in=user_teams) + ).distinct().select_related('extraction', 'summary') def get_serializer_class(self): if self.action == 'retrieve': @@ -40,4 +45,4 @@ class TeamViewSet(viewsets.ModelViewSet): serializer_class = TeamSerializer def get_queryset(self): - return self.request.user.teams.all() \ No newline at end of file + return self.request.user.teams.all() diff --git a/core/serializers.py b/core/serializers.py index bd60b84..32a5784 100644 --- a/core/serializers.py +++ b/core/serializers.py @@ -13,12 +13,23 @@ class TeamSerializer(serializers.ModelSerializer): model = Team fields = ['id', 'name', 'description', 'created_at'] +class ExtractionSerializer(serializers.ModelSerializer): + class Meta: + model = Extraction + fields = ['content_text', 'extracted_at'] + +class SummarySerializer(serializers.ModelSerializer): + class Meta: + model = Summary + fields = ['content', 'generated_at'] + class BookmarkSerializer(TaggitSerializer, serializers.ModelSerializer): tags = TagListSerializerField(required=False) + summary = SummarySerializer(read_only=True) class Meta: model = Bookmark - fields = ['id', 'url', 'title', 'notes', 'is_favorite', 'tags', 'created_at', 'updated_at'] + fields = ['id', 'url', 'title', 'notes', 'is_favorite', 'tags', 'summary', 'created_at', 'updated_at'] read_only_fields = ['id', 'created_at', 'updated_at'] def create(self, validated_data): @@ -28,11 +39,6 @@ class BookmarkSerializer(TaggitSerializer, serializers.ModelSerializer): bookmark.tags.set(tags) return bookmark -class ExtractionSerializer(serializers.ModelSerializer): - class Meta: - model = Extraction - fields = ['content_text', 'extracted_at'] - class BookmarkDetailSerializer(BookmarkSerializer): extraction = ExtractionSerializer(read_only=True) diff --git a/core/tasks.py b/core/tasks.py index dc1829b..24cc8d1 100644 --- a/core/tasks.py +++ b/core/tasks.py @@ -7,6 +7,8 @@ from bs4 import BeautifulSoup import html2text import logging from urllib.parse import urlparse +from taggit.models import Tag +import json logger = logging.getLogger(__name__) @@ -100,12 +102,16 @@ def process_bookmark(self, bookmark_id): def generate_summary(bookmark_id): try: bookmark = Bookmark.objects.get(id=bookmark_id) - extraction = bookmark.extraction except Bookmark.DoesNotExist: return + + try: + extraction = bookmark.extraction except Extraction.DoesNotExist: - # If extraction doesn't exist yet, we might want to wait or just return - # But in EAGER mode it should be there. + Summary.objects.update_or_create( + bookmark=bookmark, + defaults={'content': "Content extraction failed or is still in progress. AI summary cannot be generated."} + ) return content_to_summarize = extraction.content_text.strip() @@ -118,29 +124,71 @@ def generate_summary(bookmark_id): ) return + # Check if we should generate tags (only if bookmark has no tags) + should_generate_tags = bookmark.tags.count() == 0 + existing_tags = list(Tag.objects.values_list('name', flat=True).distinct()[:50]) + existing_tags_str = ", ".join(existing_tags) + # Prepare prompt for AI - if used_backup: - prompt = f"The specific page '{bookmark.url}' could not be reached. Summarize the main domain front page content instead to describe what this website is about.\n\nContent:\n{content_to_summarize[:4000]}" + system_prompt = "You are a helpful assistant that summarizes web content and suggests tags for researchers. Be concise and professional. Always return response in JSON format." + + user_prompt = f"Analyze the following content from the webpage '{bookmark.title or bookmark.url}'.\n\n" + user_prompt += "1. Provide a summary in 2-3 concise sentences.\n" + + if should_generate_tags: + user_prompt += "2. Suggest 3-5 short and concise tags for this content.\n" + if existing_tags: + user_prompt += f"Prioritize these existing tags if they match: {existing_tags_str}\n" + + user_prompt += "\nReturn your response in valid JSON format:\n" + user_prompt += "{\n \"summary\": \"your summary here\"" + if should_generate_tags: + user_prompt += ",\n \"tags\": [\"tag1\", \"tag2\", \"tag3\"]\n" else: - prompt = f"Summarize the following content from the webpage '{bookmark.title or bookmark.url}' in 2-3 concise sentences. Focus on the main points for a researcher.\n\nContent:\n{content_to_summarize[:4000]}" + user_prompt += "\n" + user_prompt += "}\n\n" + user_prompt += f"Content:\n{content_to_summarize[:4000]}" try: + logger.info(f"Generating summary/tags for bookmark {bookmark_id}...") response = LocalAIApi.create_response({ "input": [ - {"role": "system", "content": "You are a helpful assistant that summarizes web content for researchers and knowledge workers. Be concise and professional."}, - {"role": "user", "content": prompt}, + {"role": "system", "content": system_prompt}, + {"role": "user", "content": user_prompt}, ], + # "response_format": {"type": "json_object"} # Some proxies might not like this }) summary_text = None + suggested_tags = [] + if response.get("success"): - summary_text = LocalAIApi.extract_text(response) + raw_text = LocalAIApi.extract_text(response) + logger.info(f"AI Raw Response for {bookmark_id}: {raw_text}") + data = LocalAIApi.decode_json_from_response(response) + if data: + summary_text = data.get("summary") + suggested_tags = data.get("tags", []) + logger.info(f"Decoded JSON for {bookmark_id}: summary={bool(summary_text)}, tags={suggested_tags}") + else: + logger.warning(f"JSON decoding failed for {bookmark_id}. Fallback to text.") + summary_text = raw_text if summary_text and len(summary_text.strip()) > 10: Summary.objects.update_or_create( bookmark=bookmark, defaults={'content': summary_text.strip()} ) + + # Add tags if we should + if should_generate_tags and suggested_tags: + # Limit to 5 tags and ensure they are strings + valid_tags = [str(t)[:50] for t in suggested_tags if t][:5] + if valid_tags: + bookmark.tags.add(*valid_tags) + logger.info(f"Successfully added tags {valid_tags} to bookmark {bookmark_id}") + return f"Generated summary and tags for bookmark {bookmark_id}" + return f"Generated summary for bookmark {bookmark_id}" else: error_msg = response.get('error') or "Empty response from AI" @@ -161,7 +209,7 @@ def generate_summary(bookmark_id): ) return f"Failed to generate summary for bookmark {bookmark_id}, created fallback." except Exception as e: - logger.exception(f"Unexpected error in generate_summary for bookmark {bookmark_id}: {e}") + logger.error(f"Unexpected error in generate_summary for bookmark {bookmark_id}: {e}") Summary.objects.update_or_create( bookmark=bookmark, defaults={'content': "An unexpected error occurred while generating the AI summary."} diff --git a/core/templates/base.html b/core/templates/base.html index 4b6a3fd..293d348 100644 --- a/core/templates/base.html +++ b/core/templates/base.html @@ -136,7 +136,10 @@ {{ user.username }}