wbnews 1.58.3__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- wbnews/.coveragerc +23 -0
- wbnews/__init__.py +1 -0
- wbnews/admin.py +30 -0
- wbnews/apps.py +9 -0
- wbnews/factories.py +36 -0
- wbnews/filters/__init__.py +1 -0
- wbnews/filters/news.py +46 -0
- wbnews/fixtures/wbnews.yaml +1 -0
- wbnews/import_export/__init__.py +0 -0
- wbnews/import_export/backends/__init__.py +1 -0
- wbnews/import_export/backends/news.py +36 -0
- wbnews/import_export/handlers/__init__.py +1 -0
- wbnews/import_export/handlers/news.py +57 -0
- wbnews/import_export/parsers/__init__.py +0 -0
- wbnews/import_export/parsers/emails/__init__.py +0 -0
- wbnews/import_export/parsers/emails/news.py +39 -0
- wbnews/import_export/parsers/emails/utils.py +65 -0
- wbnews/import_export/parsers/rss/__init__.py +0 -0
- wbnews/import_export/parsers/rss/news.py +58 -0
- wbnews/locale/de/LC_MESSAGES/django.mo +0 -0
- wbnews/locale/de/LC_MESSAGES/django.po +166 -0
- wbnews/locale/de/LC_MESSAGES/django.po.translated +173 -0
- wbnews/locale/en/LC_MESSAGES/django.mo +0 -0
- wbnews/locale/en/LC_MESSAGES/django.po +159 -0
- wbnews/locale/fr/LC_MESSAGES/django.mo +0 -0
- wbnews/locale/fr/LC_MESSAGES/django.po +162 -0
- wbnews/migrations/0001_initial_squashed_0005_alter_news_import_source.py +349 -0
- wbnews/migrations/0006_alter_news_language.py +122 -0
- wbnews/migrations/0007_auto_20240103_0955.py +43 -0
- wbnews/migrations/0008_alter_news_language.py +123 -0
- wbnews/migrations/0009_newsrelationship_analysis_newsrelationship_sentiment.py +94 -0
- wbnews/migrations/0010_newsrelationship_important.py +17 -0
- wbnews/migrations/0011_newsrelationship_content_object_repr.py +18 -0
- wbnews/migrations/0012_alter_news_unique_together_news_identifier_and_more.py +91 -0
- wbnews/migrations/0013_alter_news_datetime.py +19 -0
- wbnews/migrations/0014_newsrelationship_unique_news_relationship.py +27 -0
- wbnews/migrations/__init__.py +0 -0
- wbnews/models/__init__.py +3 -0
- wbnews/models/llm/cleaned_news.py +66 -0
- wbnews/models/news.py +131 -0
- wbnews/models/relationships.py +45 -0
- wbnews/models/sources.py +73 -0
- wbnews/models/utils.py +15 -0
- wbnews/serializers.py +134 -0
- wbnews/signals.py +4 -0
- wbnews/tasks.py +16 -0
- wbnews/tests/__init__.py +0 -0
- wbnews/tests/conftest.py +6 -0
- wbnews/tests/parsers/__init__.py +0 -0
- wbnews/tests/parsers/test_emails.py +25 -0
- wbnews/tests/test_models.py +80 -0
- wbnews/tests/test_utils.py +7 -0
- wbnews/tests/tests.py +12 -0
- wbnews/urls.py +25 -0
- wbnews/utils.py +57 -0
- wbnews/viewsets/__init__.py +12 -0
- wbnews/viewsets/buttons.py +42 -0
- wbnews/viewsets/display.py +148 -0
- wbnews/viewsets/endpoints.py +34 -0
- wbnews/viewsets/menu.py +29 -0
- wbnews/viewsets/titles.py +44 -0
- wbnews/viewsets/views.py +168 -0
- wbnews-1.58.3.dist-info/METADATA +7 -0
- wbnews-1.58.3.dist-info/RECORD +65 -0
- wbnews-1.58.3.dist-info/WHEEL +5 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
# Generated by Django 4.2.6 on 2023-10-18 13:27
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
dependencies = [
|
|
8
|
+
("wbnews", "0001_initial_squashed_0005_alter_news_import_source"),
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
operations = [
|
|
12
|
+
migrations.AlterField(
|
|
13
|
+
model_name="news",
|
|
14
|
+
name="language",
|
|
15
|
+
field=models.CharField(
|
|
16
|
+
blank=True,
|
|
17
|
+
choices=[
|
|
18
|
+
("af", "Afrikaans"),
|
|
19
|
+
("ar", "Arabic"),
|
|
20
|
+
("ar-dz", "Algerian Arabic"),
|
|
21
|
+
("ast", "Asturian"),
|
|
22
|
+
("az", "Azerbaijani"),
|
|
23
|
+
("bg", "Bulgarian"),
|
|
24
|
+
("be", "Belarusian"),
|
|
25
|
+
("bn", "Bengali"),
|
|
26
|
+
("br", "Breton"),
|
|
27
|
+
("bs", "Bosnian"),
|
|
28
|
+
("ca", "Catalan"),
|
|
29
|
+
("ckb", "Central Kurdish (Sorani)"),
|
|
30
|
+
("cs", "Czech"),
|
|
31
|
+
("cy", "Welsh"),
|
|
32
|
+
("da", "Danish"),
|
|
33
|
+
("de", "German"),
|
|
34
|
+
("dsb", "Lower Sorbian"),
|
|
35
|
+
("el", "Greek"),
|
|
36
|
+
("en", "English"),
|
|
37
|
+
("en-au", "Australian English"),
|
|
38
|
+
("en-gb", "British English"),
|
|
39
|
+
("eo", "Esperanto"),
|
|
40
|
+
("es", "Spanish"),
|
|
41
|
+
("es-ar", "Argentinian Spanish"),
|
|
42
|
+
("es-co", "Colombian Spanish"),
|
|
43
|
+
("es-mx", "Mexican Spanish"),
|
|
44
|
+
("es-ni", "Nicaraguan Spanish"),
|
|
45
|
+
("es-ve", "Venezuelan Spanish"),
|
|
46
|
+
("et", "Estonian"),
|
|
47
|
+
("eu", "Basque"),
|
|
48
|
+
("fa", "Persian"),
|
|
49
|
+
("fi", "Finnish"),
|
|
50
|
+
("fr", "French"),
|
|
51
|
+
("fy", "Frisian"),
|
|
52
|
+
("ga", "Irish"),
|
|
53
|
+
("gd", "Scottish Gaelic"),
|
|
54
|
+
("gl", "Galician"),
|
|
55
|
+
("he", "Hebrew"),
|
|
56
|
+
("hi", "Hindi"),
|
|
57
|
+
("hr", "Croatian"),
|
|
58
|
+
("hsb", "Upper Sorbian"),
|
|
59
|
+
("hu", "Hungarian"),
|
|
60
|
+
("hy", "Armenian"),
|
|
61
|
+
("ia", "Interlingua"),
|
|
62
|
+
("id", "Indonesian"),
|
|
63
|
+
("ig", "Igbo"),
|
|
64
|
+
("io", "Ido"),
|
|
65
|
+
("is", "Icelandic"),
|
|
66
|
+
("it", "Italian"),
|
|
67
|
+
("ja", "Japanese"),
|
|
68
|
+
("ka", "Georgian"),
|
|
69
|
+
("kab", "Kabyle"),
|
|
70
|
+
("kk", "Kazakh"),
|
|
71
|
+
("km", "Khmer"),
|
|
72
|
+
("kn", "Kannada"),
|
|
73
|
+
("ko", "Korean"),
|
|
74
|
+
("ky", "Kyrgyz"),
|
|
75
|
+
("lb", "Luxembourgish"),
|
|
76
|
+
("lt", "Lithuanian"),
|
|
77
|
+
("lv", "Latvian"),
|
|
78
|
+
("mk", "Macedonian"),
|
|
79
|
+
("ml", "Malayalam"),
|
|
80
|
+
("mn", "Mongolian"),
|
|
81
|
+
("mr", "Marathi"),
|
|
82
|
+
("ms", "Malay"),
|
|
83
|
+
("my", "Burmese"),
|
|
84
|
+
("nb", "Norwegian Bokmål"),
|
|
85
|
+
("ne", "Nepali"),
|
|
86
|
+
("nl", "Dutch"),
|
|
87
|
+
("nn", "Norwegian Nynorsk"),
|
|
88
|
+
("os", "Ossetic"),
|
|
89
|
+
("pa", "Punjabi"),
|
|
90
|
+
("pl", "Polish"),
|
|
91
|
+
("pt", "Portuguese"),
|
|
92
|
+
("pt-br", "Brazilian Portuguese"),
|
|
93
|
+
("ro", "Romanian"),
|
|
94
|
+
("ru", "Russian"),
|
|
95
|
+
("sk", "Slovak"),
|
|
96
|
+
("sl", "Slovenian"),
|
|
97
|
+
("sq", "Albanian"),
|
|
98
|
+
("sr", "Serbian"),
|
|
99
|
+
("sr-latn", "Serbian Latin"),
|
|
100
|
+
("sv", "Swedish"),
|
|
101
|
+
("sw", "Swahili"),
|
|
102
|
+
("ta", "Tamil"),
|
|
103
|
+
("te", "Telugu"),
|
|
104
|
+
("tg", "Tajik"),
|
|
105
|
+
("th", "Thai"),
|
|
106
|
+
("tk", "Turkmen"),
|
|
107
|
+
("tr", "Turkish"),
|
|
108
|
+
("tt", "Tatar"),
|
|
109
|
+
("udm", "Udmurt"),
|
|
110
|
+
("uk", "Ukrainian"),
|
|
111
|
+
("ur", "Urdu"),
|
|
112
|
+
("uz", "Uzbek"),
|
|
113
|
+
("vi", "Vietnamese"),
|
|
114
|
+
("zh-hans", "Simplified Chinese"),
|
|
115
|
+
("zh-hant", "Traditional Chinese"),
|
|
116
|
+
],
|
|
117
|
+
max_length=16,
|
|
118
|
+
null=True,
|
|
119
|
+
verbose_name="Language",
|
|
120
|
+
),
|
|
121
|
+
),
|
|
122
|
+
]
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Generated by Django 4.2.8 on 2024-01-03 08:55
|
|
2
|
+
|
|
3
|
+
from contextlib import suppress
|
|
4
|
+
|
|
5
|
+
from django.apps import apps
|
|
6
|
+
from django.contrib.contenttypes.models import ContentType
|
|
7
|
+
from django.db import migrations
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def migrate_content_type(apps, schema_editor):
|
|
11
|
+
NewsRelationship = apps.get_model("wbnews", "NewsRelationship")
|
|
12
|
+
|
|
13
|
+
for model_name in [
|
|
14
|
+
"Classification",
|
|
15
|
+
"Instrument",
|
|
16
|
+
"ClassificationGroup",
|
|
17
|
+
"Deal",
|
|
18
|
+
"Exchange",
|
|
19
|
+
"InstrumentClassificationRelatedInstrument",
|
|
20
|
+
"InstrumentClassificationThroughModel",
|
|
21
|
+
"InstrumentFavoriteGroup",
|
|
22
|
+
"InstrumentList",
|
|
23
|
+
"InstrumentListThroughModel",
|
|
24
|
+
"InstrumentRequest",
|
|
25
|
+
"RelatedInstrumentThroughModel",
|
|
26
|
+
"InstrumentPrice",
|
|
27
|
+
]:
|
|
28
|
+
with suppress(ContentType.DoesNotExist):
|
|
29
|
+
old_ct = ContentType.objects.get(app_label="wbportfolio", model=model_name.lower())
|
|
30
|
+
new_ct = ContentType.objects.get(app_label="wbfdm", model=model_name.lower())
|
|
31
|
+
NewsRelationship.objects.filter(content_type_id=old_ct.id).update(content_type_id=new_ct.id)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class Migration(migrations.Migration):
|
|
35
|
+
dependencies = (
|
|
36
|
+
[
|
|
37
|
+
("wbnews", "0006_alter_news_language"),
|
|
38
|
+
("wbfdm", "0012_instrumentprice_created_instrumentprice_modified"),
|
|
39
|
+
]
|
|
40
|
+
if apps.is_installed("wbfdm")
|
|
41
|
+
else [("wbnews", "0006_alter_news_language")]
|
|
42
|
+
)
|
|
43
|
+
operations = [migrations.RunPython(migrate_content_type)]
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# Generated by Django 5.0.3 on 2024-04-11 08:24
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
dependencies = [
|
|
8
|
+
("wbnews", "0007_auto_20240103_0955"),
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
operations = [
|
|
12
|
+
migrations.AlterField(
|
|
13
|
+
model_name="news",
|
|
14
|
+
name="language",
|
|
15
|
+
field=models.CharField(
|
|
16
|
+
blank=True,
|
|
17
|
+
choices=[
|
|
18
|
+
("af", "Afrikaans"),
|
|
19
|
+
("ar", "Arabic"),
|
|
20
|
+
("ar-dz", "Algerian Arabic"),
|
|
21
|
+
("ast", "Asturian"),
|
|
22
|
+
("az", "Azerbaijani"),
|
|
23
|
+
("bg", "Bulgarian"),
|
|
24
|
+
("be", "Belarusian"),
|
|
25
|
+
("bn", "Bengali"),
|
|
26
|
+
("br", "Breton"),
|
|
27
|
+
("bs", "Bosnian"),
|
|
28
|
+
("ca", "Catalan"),
|
|
29
|
+
("ckb", "Central Kurdish (Sorani)"),
|
|
30
|
+
("cs", "Czech"),
|
|
31
|
+
("cy", "Welsh"),
|
|
32
|
+
("da", "Danish"),
|
|
33
|
+
("de", "German"),
|
|
34
|
+
("dsb", "Lower Sorbian"),
|
|
35
|
+
("el", "Greek"),
|
|
36
|
+
("en", "English"),
|
|
37
|
+
("en-au", "Australian English"),
|
|
38
|
+
("en-gb", "British English"),
|
|
39
|
+
("eo", "Esperanto"),
|
|
40
|
+
("es", "Spanish"),
|
|
41
|
+
("es-ar", "Argentinian Spanish"),
|
|
42
|
+
("es-co", "Colombian Spanish"),
|
|
43
|
+
("es-mx", "Mexican Spanish"),
|
|
44
|
+
("es-ni", "Nicaraguan Spanish"),
|
|
45
|
+
("es-ve", "Venezuelan Spanish"),
|
|
46
|
+
("et", "Estonian"),
|
|
47
|
+
("eu", "Basque"),
|
|
48
|
+
("fa", "Persian"),
|
|
49
|
+
("fi", "Finnish"),
|
|
50
|
+
("fr", "French"),
|
|
51
|
+
("fy", "Frisian"),
|
|
52
|
+
("ga", "Irish"),
|
|
53
|
+
("gd", "Scottish Gaelic"),
|
|
54
|
+
("gl", "Galician"),
|
|
55
|
+
("he", "Hebrew"),
|
|
56
|
+
("hi", "Hindi"),
|
|
57
|
+
("hr", "Croatian"),
|
|
58
|
+
("hsb", "Upper Sorbian"),
|
|
59
|
+
("hu", "Hungarian"),
|
|
60
|
+
("hy", "Armenian"),
|
|
61
|
+
("ia", "Interlingua"),
|
|
62
|
+
("id", "Indonesian"),
|
|
63
|
+
("ig", "Igbo"),
|
|
64
|
+
("io", "Ido"),
|
|
65
|
+
("is", "Icelandic"),
|
|
66
|
+
("it", "Italian"),
|
|
67
|
+
("ja", "Japanese"),
|
|
68
|
+
("ka", "Georgian"),
|
|
69
|
+
("kab", "Kabyle"),
|
|
70
|
+
("kk", "Kazakh"),
|
|
71
|
+
("km", "Khmer"),
|
|
72
|
+
("kn", "Kannada"),
|
|
73
|
+
("ko", "Korean"),
|
|
74
|
+
("ky", "Kyrgyz"),
|
|
75
|
+
("lb", "Luxembourgish"),
|
|
76
|
+
("lt", "Lithuanian"),
|
|
77
|
+
("lv", "Latvian"),
|
|
78
|
+
("mk", "Macedonian"),
|
|
79
|
+
("ml", "Malayalam"),
|
|
80
|
+
("mn", "Mongolian"),
|
|
81
|
+
("mr", "Marathi"),
|
|
82
|
+
("ms", "Malay"),
|
|
83
|
+
("my", "Burmese"),
|
|
84
|
+
("nb", "Norwegian Bokmål"),
|
|
85
|
+
("ne", "Nepali"),
|
|
86
|
+
("nl", "Dutch"),
|
|
87
|
+
("nn", "Norwegian Nynorsk"),
|
|
88
|
+
("os", "Ossetic"),
|
|
89
|
+
("pa", "Punjabi"),
|
|
90
|
+
("pl", "Polish"),
|
|
91
|
+
("pt", "Portuguese"),
|
|
92
|
+
("pt-br", "Brazilian Portuguese"),
|
|
93
|
+
("ro", "Romanian"),
|
|
94
|
+
("ru", "Russian"),
|
|
95
|
+
("sk", "Slovak"),
|
|
96
|
+
("sl", "Slovenian"),
|
|
97
|
+
("sq", "Albanian"),
|
|
98
|
+
("sr", "Serbian"),
|
|
99
|
+
("sr-latn", "Serbian Latin"),
|
|
100
|
+
("sv", "Swedish"),
|
|
101
|
+
("sw", "Swahili"),
|
|
102
|
+
("ta", "Tamil"),
|
|
103
|
+
("te", "Telugu"),
|
|
104
|
+
("tg", "Tajik"),
|
|
105
|
+
("th", "Thai"),
|
|
106
|
+
("tk", "Turkmen"),
|
|
107
|
+
("tr", "Turkish"),
|
|
108
|
+
("tt", "Tatar"),
|
|
109
|
+
("udm", "Udmurt"),
|
|
110
|
+
("ug", "Uyghur"),
|
|
111
|
+
("uk", "Ukrainian"),
|
|
112
|
+
("ur", "Urdu"),
|
|
113
|
+
("uz", "Uzbek"),
|
|
114
|
+
("vi", "Vietnamese"),
|
|
115
|
+
("zh-hans", "Simplified Chinese"),
|
|
116
|
+
("zh-hant", "Traditional Chinese"),
|
|
117
|
+
],
|
|
118
|
+
max_length=16,
|
|
119
|
+
null=True,
|
|
120
|
+
verbose_name="Language",
|
|
121
|
+
),
|
|
122
|
+
),
|
|
123
|
+
]
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# Generated by Django 5.0.9 on 2024-10-24 11:00
|
|
2
|
+
|
|
3
|
+
import django.contrib.postgres.fields
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def migrate_new_source(apps, schema_editor):
|
|
8
|
+
from wbcore.contrib.io.models import (
|
|
9
|
+
DataBackend,
|
|
10
|
+
ImportSource,
|
|
11
|
+
ParserHandler,
|
|
12
|
+
Source,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
parser_handler = ParserHandler.objects.get(parser="wbnews.import_export.parsers.rss.news")
|
|
16
|
+
io_news_sources = Source.objects.filter(parser_handler=parser_handler)
|
|
17
|
+
crontab = io_news_sources.last().crontab
|
|
18
|
+
data_backend = DataBackend.objects.get(backend_class_path="wbnews.import_export.backends.news")
|
|
19
|
+
default_news_source, created = Source.objects.get_or_create(
|
|
20
|
+
data_backend=data_backend,
|
|
21
|
+
defaults={
|
|
22
|
+
"crontab": crontab,
|
|
23
|
+
"title": "RSS Feeds -> News",
|
|
24
|
+
},
|
|
25
|
+
)
|
|
26
|
+
default_news_source.parser_handler.set([parser_handler])
|
|
27
|
+
ImportSource.objects.filter(source__in=io_news_sources).update(source=default_news_source)
|
|
28
|
+
io_news_sources.exclude(id=default_news_source.id).delete()
|
|
29
|
+
NewsSource = apps.get_model("wbnews", "NewsSource")
|
|
30
|
+
NewsSource.objects.filter(title__icontains="Email").update(type="EMAIL")
|
|
31
|
+
NewsSource.objects.filter(type="RSS").filter(url__isnull=True, identifier__isnull=False).update(
|
|
32
|
+
url=models.F("identifier")
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
unvalid_rss_feeds = [
|
|
36
|
+
"https://www.dailytelegraph.com.au/help-rss",
|
|
37
|
+
"https://techcrunch.com/rssfeeds/",
|
|
38
|
+
"https://www.bbc.co.uk/news/",
|
|
39
|
+
"https://www.nytimes.com/section/technology",
|
|
40
|
+
"http://online.wsj.com/page/2_0006.html",
|
|
41
|
+
"http://online.wsj.com",
|
|
42
|
+
"https://www.bbc.co.uk/news/technology",
|
|
43
|
+
"https://www.bbc.co.uk/news/world",
|
|
44
|
+
"https://www.bbc.co.uk/news/business",
|
|
45
|
+
"https://www.techworld.com/news/rss",
|
|
46
|
+
]
|
|
47
|
+
NewsSource.objects.filter(url__in=unvalid_rss_feeds).update(is_active=False)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
class Migration(migrations.Migration):
|
|
51
|
+
dependencies = [
|
|
52
|
+
("wbnews", "0008_alter_news_language"),
|
|
53
|
+
]
|
|
54
|
+
|
|
55
|
+
operations = [
|
|
56
|
+
migrations.AddField(
|
|
57
|
+
model_name="newsrelationship",
|
|
58
|
+
name="analysis",
|
|
59
|
+
field=models.TextField(blank=True, null=True),
|
|
60
|
+
),
|
|
61
|
+
migrations.AddField(
|
|
62
|
+
model_name="newsrelationship",
|
|
63
|
+
name="sentiment",
|
|
64
|
+
field=models.PositiveIntegerField(blank=True, null=True),
|
|
65
|
+
),
|
|
66
|
+
migrations.AddField(
|
|
67
|
+
model_name="newssource",
|
|
68
|
+
name="clean_content",
|
|
69
|
+
field=models.BooleanField(default=False),
|
|
70
|
+
),
|
|
71
|
+
migrations.AddField(
|
|
72
|
+
model_name="newssource",
|
|
73
|
+
name="is_active",
|
|
74
|
+
field=models.BooleanField(default=True),
|
|
75
|
+
),
|
|
76
|
+
migrations.AddField(
|
|
77
|
+
model_name="newssource",
|
|
78
|
+
name="type",
|
|
79
|
+
field=models.CharField(choices=[("RSS", "RSS"), ("EMAIL", "EMAIL")], default="RSS", max_length=6),
|
|
80
|
+
),
|
|
81
|
+
migrations.AlterField(
|
|
82
|
+
model_name="newssource",
|
|
83
|
+
name="description",
|
|
84
|
+
field=models.TextField(blank=True, default=""),
|
|
85
|
+
),
|
|
86
|
+
migrations.AlterField(
|
|
87
|
+
model_name="newssource",
|
|
88
|
+
name="tags",
|
|
89
|
+
field=django.contrib.postgres.fields.ArrayField(
|
|
90
|
+
base_field=models.CharField(max_length=16), blank=True, default=list, size=None
|
|
91
|
+
),
|
|
92
|
+
),
|
|
93
|
+
migrations.RunPython(migrate_new_source),
|
|
94
|
+
]
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Generated by Django 5.0.9 on 2024-12-19 09:39
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
dependencies = [
|
|
8
|
+
("wbnews", "0009_newsrelationship_analysis_newsrelationship_sentiment"),
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
operations = [
|
|
12
|
+
migrations.AddField(
|
|
13
|
+
model_name="newsrelationship",
|
|
14
|
+
name="important",
|
|
15
|
+
field=models.BooleanField(blank=True, null=True),
|
|
16
|
+
),
|
|
17
|
+
]
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Generated by Django 5.0.12 on 2025-02-13 10:08
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
|
|
8
|
+
dependencies = [
|
|
9
|
+
('wbnews', '0010_newsrelationship_important'),
|
|
10
|
+
]
|
|
11
|
+
|
|
12
|
+
operations = [
|
|
13
|
+
migrations.AddField(
|
|
14
|
+
model_name='newsrelationship',
|
|
15
|
+
name='content_object_repr',
|
|
16
|
+
field=models.CharField(default='', max_length=512),
|
|
17
|
+
),
|
|
18
|
+
]
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
# Generated by Django 5.0.12 on 2025-02-24 13:45
|
|
2
|
+
from collections import defaultdict
|
|
3
|
+
|
|
4
|
+
from django.core.exceptions import ValidationError
|
|
5
|
+
from django.core.validators import URLValidator
|
|
6
|
+
from django.db import migrations, models
|
|
7
|
+
from tqdm import tqdm
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def migrate_identifier( apps, schema_editor):
|
|
11
|
+
from wbnews.models.news import News as NewsClass
|
|
12
|
+
News = apps.get_model('wbnews', 'News')
|
|
13
|
+
objs = []
|
|
14
|
+
qs = News.objects.all()
|
|
15
|
+
guid = set()
|
|
16
|
+
for new in tqdm(qs, total=qs.count()):
|
|
17
|
+
new.guid = NewsClass.get_default_guid(new.title, new.link)
|
|
18
|
+
if new.guid not in guid:
|
|
19
|
+
guid.add(new.guid)
|
|
20
|
+
objs.append(new)
|
|
21
|
+
print(len(objs))
|
|
22
|
+
News.objects.bulk_update(objs, ['guid'], batch_size=10000)
|
|
23
|
+
|
|
24
|
+
leftovers = News.objects.filter(guid__isnull=True)
|
|
25
|
+
print(leftovers.count())
|
|
26
|
+
leftovers.delete()
|
|
27
|
+
|
|
28
|
+
qs = News.objects.all()
|
|
29
|
+
for new in tqdm(qs, total=qs.count()):
|
|
30
|
+
try:
|
|
31
|
+
URLValidator()(new.link)
|
|
32
|
+
except ValidationError:
|
|
33
|
+
new.link = None
|
|
34
|
+
objs.append(new)
|
|
35
|
+
|
|
36
|
+
News.objects.bulk_update(objs, ['link'], batch_size=10000)
|
|
37
|
+
|
|
38
|
+
class Migration(migrations.Migration):
|
|
39
|
+
|
|
40
|
+
dependencies = [
|
|
41
|
+
('io', '0008_importsource_resource_kwargs'),
|
|
42
|
+
('wbnews', '0011_newsrelationship_content_object_repr'),
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
operations = [
|
|
46
|
+
migrations.AlterUniqueTogether(
|
|
47
|
+
name='news',
|
|
48
|
+
unique_together=set(),
|
|
49
|
+
),
|
|
50
|
+
migrations.AddField(
|
|
51
|
+
model_name='news',
|
|
52
|
+
name='guid',
|
|
53
|
+
field=models.CharField(default=None, blank=True, null=True, max_length=1024),
|
|
54
|
+
preserve_default=False,
|
|
55
|
+
),
|
|
56
|
+
migrations.RunSQL(sql="SET CONSTRAINTS ALL IMMEDIATE;"),
|
|
57
|
+
migrations.RunPython(migrate_identifier),
|
|
58
|
+
migrations.RunSQL(sql="SET CONSTRAINTS ALL DEFERRED;"),
|
|
59
|
+
migrations.AlterField(
|
|
60
|
+
model_name='news',
|
|
61
|
+
name='guid',
|
|
62
|
+
field=models.CharField(max_length=1024, unique=True),
|
|
63
|
+
),
|
|
64
|
+
migrations.AlterField(
|
|
65
|
+
model_name='news',
|
|
66
|
+
name='link',
|
|
67
|
+
field=models.URLField(max_length=1024, blank=True, null=True, verbose_name='Link'),
|
|
68
|
+
),
|
|
69
|
+
migrations.AddField(
|
|
70
|
+
model_name='news',
|
|
71
|
+
name='mark_as_duplicate',
|
|
72
|
+
field=models.BooleanField(default=False, verbose_name='Mark as duplicate'),
|
|
73
|
+
),
|
|
74
|
+
migrations.AlterField(
|
|
75
|
+
model_name='newsrelationship',
|
|
76
|
+
name='sentiment',
|
|
77
|
+
field=models.PositiveIntegerField(blank=True, choices=[(4, 'Positive'), (3, 'Slightly Positive'),
|
|
78
|
+
(2, 'Slightly Negative'), (1, 'Negative')],
|
|
79
|
+
null=True),
|
|
80
|
+
),
|
|
81
|
+
migrations.RenameField(
|
|
82
|
+
model_name='newssource',
|
|
83
|
+
old_name='url',
|
|
84
|
+
new_name='endpoint',
|
|
85
|
+
),
|
|
86
|
+
migrations.AlterField(
|
|
87
|
+
model_name='newssource',
|
|
88
|
+
name='endpoint',
|
|
89
|
+
field=models.CharField(max_length=1024, unique=True),
|
|
90
|
+
),
|
|
91
|
+
]
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Generated by Django 5.0.12 on 2025-04-03 08:08
|
|
2
|
+
|
|
3
|
+
import django.utils.timezone
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
|
|
9
|
+
dependencies = [
|
|
10
|
+
('wbnews', '0012_alter_news_unique_together_news_identifier_and_more'),
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
operations = [
|
|
14
|
+
migrations.AlterField(
|
|
15
|
+
model_name='news',
|
|
16
|
+
name='datetime',
|
|
17
|
+
field=models.DateTimeField(default=django.utils.timezone.now, verbose_name='Datetime'),
|
|
18
|
+
),
|
|
19
|
+
]
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# Generated by Django 5.0.14 on 2025-05-06 14:44
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
from django.db.models import Count
|
|
5
|
+
from tqdm import tqdm
|
|
6
|
+
|
|
7
|
+
def handle_duplicated_relationship(apps, schema_editor):
|
|
8
|
+
NewsRelationship = apps.get_model("wbnews", "NewsRelationship")
|
|
9
|
+
qs = NewsRelationship.objects.values('content_type', 'object_id', 'news').annotate(c=Count('*')).filter(c__gt=1)
|
|
10
|
+
for row in tqdm(qs, total=qs.count()):
|
|
11
|
+
for rel in NewsRelationship.objects.filter(content_type=row['content_type'], news=row['news'], object_id=row["object_id"])[1:]:
|
|
12
|
+
rel.delete()
|
|
13
|
+
|
|
14
|
+
class Migration(migrations.Migration):
|
|
15
|
+
|
|
16
|
+
dependencies = [
|
|
17
|
+
('contenttypes', '0002_remove_content_type_name'),
|
|
18
|
+
('wbnews', '0013_alter_news_datetime'),
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
operations = [
|
|
22
|
+
migrations.RunPython(handle_duplicated_relationship),
|
|
23
|
+
migrations.AddConstraint(
|
|
24
|
+
model_name='newsrelationship',
|
|
25
|
+
constraint=models.UniqueConstraint(fields=('content_type', 'object_id', 'news'), name='unique_news_relationship'),
|
|
26
|
+
),
|
|
27
|
+
]
|
|
File without changes
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
from langchain_core.messages import HumanMessage, SystemMessage
|
|
4
|
+
from pydantic import BaseModel, Field
|
|
5
|
+
from wbcore.contrib.ai.llm.config import LLMConfig
|
|
6
|
+
|
|
7
|
+
if TYPE_CHECKING:
|
|
8
|
+
from wbnews.models import News # noqa
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
class CleanNewsModel(BaseModel):
|
|
12
|
+
title: str = Field(
|
|
13
|
+
...,
|
|
14
|
+
description="The news title cleaned from the email subject without any formatting only meaningful information",
|
|
15
|
+
)
|
|
16
|
+
description: str = Field(
|
|
17
|
+
...,
|
|
18
|
+
description="The news description cleaned from the email body without any formatting and retaining only meaningful information",
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class SummarizedNewsModel(BaseModel):
|
|
23
|
+
summary: str = Field(
|
|
24
|
+
...,
|
|
25
|
+
description="A summary of the news description in English.",
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def get_clean_news_config_query(instance):
|
|
30
|
+
return {"description": instance.description, "title": instance.title}
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
clean_news_config = LLMConfig["News"](
|
|
34
|
+
key="clean",
|
|
35
|
+
output_model=CleanNewsModel,
|
|
36
|
+
prompt=[
|
|
37
|
+
SystemMessage(
|
|
38
|
+
content="I have an HTML email title and body, and I want to extract only the meaningful content in plain text format, removing all metadata, subscription links, and non-essential parts. The output should be HTML- and Markdown-free and should exclude any text related to links, subscription information, or common phrases like 'Unsubscribe' or 'View online'. Only retain the main email content but do not remove any information related to news."
|
|
39
|
+
),
|
|
40
|
+
HumanMessage(
|
|
41
|
+
content="Title: {title}\n\nDescription: {description}",
|
|
42
|
+
),
|
|
43
|
+
],
|
|
44
|
+
on_save=True,
|
|
45
|
+
on_condition=lambda n: n.source.clean_content,
|
|
46
|
+
query=get_clean_news_config_query,
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def get_summarized_news_config_query(instance):
|
|
51
|
+
return {"description": instance.description}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
summarized_news_config = LLMConfig["News"](
|
|
55
|
+
key="summarize",
|
|
56
|
+
output_model=SummarizedNewsModel,
|
|
57
|
+
prompt=[
|
|
58
|
+
SystemMessage(content="Given this news description, please extract a short summary"),
|
|
59
|
+
HumanMessage(
|
|
60
|
+
content="Description: {description}",
|
|
61
|
+
),
|
|
62
|
+
],
|
|
63
|
+
on_save=True,
|
|
64
|
+
on_condition=lambda n: not n.summary,
|
|
65
|
+
query=get_summarized_news_config_query,
|
|
66
|
+
)
|