diff --git a/.env.template b/.env.template index 4f73039..f7a8895 100644 --- a/.env.template +++ b/.env.template @@ -2,3 +2,4 @@ DATABASE_URL=postgres://postgres:postgres@127.0.0.1:5432/passfinder CELERY_BROKER_URL=redis://localhost:6379/0 REDIS_URL=redis://localhost:6379/1 USE_DOCKER=no +YANDEX_TOKEN= diff --git a/config/settings/base.py b/config/settings/base.py index 4cf4c32..1a0dbfd 100644 --- a/config/settings/base.py +++ b/config/settings/base.py @@ -7,6 +7,7 @@ import environ import structlog +from celery.schedules import crontab from urllib3.connectionpool import InsecureRequestWarning ROOT_DIR = Path(__file__).resolve(strict=True).parent.parent.parent @@ -302,6 +303,18 @@ "schedule": timedelta(seconds=5), "options": {"expires": 1}, }, + "check_temperature": { + "task": "passfinder.events.tasks.check_temperature", + "schedule": crontab( + minute="0", hour="3", day_of_week="*", day_of_month="*", month_of_year="*" + ), + }, + "precalculate_nearest_points": { + "task": "passfinder.recomendations.tasks.run_precalc", + "schedule": crontab( + minute="0", hour="7", day_of_week="*", day_of_month="*", month_of_year="*" + ), + }, } # DRF # ------------------------------------------------------------------------------- @@ -363,3 +376,6 @@ "password": env("CLICKHOUSE_REDIS_PASSWORD", default=None), "socket_timeout": 10, } + + +YANDEX_TOKEN = env("YANDEX_TOKEN", default="") diff --git a/manage.py b/manage.py old mode 100644 new mode 100755 diff --git a/passfinder/events/migrations/0027_city_temperature_city_weather_condition.py b/passfinder/events/migrations/0027_city_temperature_city_weather_condition.py new file mode 100644 index 0000000..99b5af2 --- /dev/null +++ b/passfinder/events/migrations/0027_city_temperature_city_weather_condition.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.1 on 2023-05-27 15:36 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("events", "0026_baseuserroutedatepoint_userroute_and_more"), + ] + + operations = [ + migrations.AddField( + model_name="city", + name="temperature", + field=models.IntegerField(default=20), + ), + migrations.AddField( + model_name="city", + name="weather_condition", + field=models.CharField(default="clear", max_length=250), + ), + ] diff --git a/passfinder/events/models.py b/passfinder/events/models.py index d35714b..2edd96c 100644 --- a/passfinder/events/models.py +++ b/passfinder/events/models.py @@ -42,6 +42,8 @@ class City(OIDModel): ) lon = models.FloatField(default=0, db_index=True) lat = models.FloatField(default=0, db_index=True) + weather_condition = models.CharField(default="clear", max_length=250) + temperature = models.IntegerField(default=20) @property def location(self): diff --git a/passfinder/events/services.py b/passfinder/events/services.py new file mode 100644 index 0000000..7a2f32a --- /dev/null +++ b/passfinder/events/services.py @@ -0,0 +1,19 @@ +import requests + +from django.conf import settings + +api_url = "https://api.weather.yandex.ru/v2/forecast" + + +def get_position_weather(lat: float, lon: float) -> (int, str): + url = api_url + f"?lat={lat}&lon={lon}&lang=ru_RU&limit=1&hours=false" + response = requests.get( + url=url, headers={"X-Yandex-API-Key": settings.YANDEX_TOKEN} + ) + temp_feels = 20 + weather = "clear" + if response.status_code == 200: + data = response.json() + temp_feels = data["forecasts"][0]["parts"]["day"]["feels_like"] + weather = data["forecasts"][0]["parts"]["day_short"]["condition"] + return temp_feels, weather diff --git a/passfinder/events/tasks.py b/passfinder/events/tasks.py new file mode 100644 index 0000000..a8cb6f6 --- /dev/null +++ b/passfinder/events/tasks.py @@ -0,0 +1,15 @@ +from celery import shared_task + +from passfinder.events.models import City +from passfinder.events.services import get_position_weather + +api_url = "https://api.weather.yandex.ru/v2/forecast" + + +@shared_task +def check_temperature(): + for city in City.objects.all(): + temperature, weather_condition = get_position_weather(city.lat, city.lon) + city.temperature = temperature + city.weather_condition = weather_condition + city.save() diff --git a/passfinder/recomendations/tasks.py b/passfinder/recomendations/tasks.py new file mode 100644 index 0000000..802405e --- /dev/null +++ b/passfinder/recomendations/tasks.py @@ -0,0 +1,7 @@ +from celery import shared_task + + +@shared_task +def run_precalc(): + # TODO: add precal here + ... diff --git a/poetry.lock b/poetry.lock index 28275b5..25c3836 100644 --- a/poetry.lock +++ b/poetry.lock @@ -760,6 +760,24 @@ files = [ {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, ] +[[package]] +name = "deprecated" +version = "1.2.13" +description = "Python @deprecated decorator to deprecate old python classes, functions or methods." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "Deprecated-1.2.13-py2.py3-none-any.whl", hash = "sha256:64756e3e14c8c5eea9795d93c524551432a0be75629f8f29e67ab8caf076c76d"}, + {file = "Deprecated-1.2.13.tar.gz", hash = "sha256:43ac5335da90c31c24ba028af536a91d41d53f9e6901ddb021bcc572ce44e38d"}, +] + +[package.dependencies] +wrapt = ">=1.10,<2" + +[package.extras] +dev = ["PyTest", "PyTest (<5)", "PyTest-Cov", "PyTest-Cov (<2.6)", "bump2version (<1)", "configparser (<5)", "importlib-metadata (<3)", "importlib-resources (<4)", "sphinx (<2)", "sphinxcontrib-websupport (<2)", "tox", "zipp (<2)"] + [[package]] name = "dill" version = "0.3.6" @@ -2067,21 +2085,21 @@ files = [ [[package]] name = "networkx" -version = "3.1" +version = "2.8.8" description = "Python package for creating and manipulating graphs and networks" category = "main" optional = false python-versions = ">=3.8" files = [ - {file = "networkx-3.1-py3-none-any.whl", hash = "sha256:4f33f68cb2afcf86f28a45f43efc27a9386b535d567d2127f8f61d51dec58d36"}, - {file = "networkx-3.1.tar.gz", hash = "sha256:de346335408f84de0eada6ff9fafafff9bcda11f0a0dfaa931133debb146ab61"}, + {file = "networkx-2.8.8-py3-none-any.whl", hash = "sha256:e435dfa75b1d7195c7b8378c3859f0445cd88c6b0375c181ed66823a9ceb7524"}, + {file = "networkx-2.8.8.tar.gz", hash = "sha256:230d388117af870fce5647a3c52401fcf753e94720e6ea6b4197a5355648885e"}, ] [package.extras] -default = ["matplotlib (>=3.4)", "numpy (>=1.20)", "pandas (>=1.3)", "scipy (>=1.8)"] -developer = ["mypy (>=1.1)", "pre-commit (>=3.2)"] -doc = ["nb2plots (>=0.6)", "numpydoc (>=1.5)", "pillow (>=9.4)", "pydata-sphinx-theme (>=0.13)", "sphinx (>=6.1)", "sphinx-gallery (>=0.12)", "texext (>=0.6.7)"] -extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.10)", "sympy (>=1.10)"] +default = ["matplotlib (>=3.4)", "numpy (>=1.19)", "pandas (>=1.3)", "scipy (>=1.8)"] +developer = ["mypy (>=0.982)", "pre-commit (>=2.20)"] +doc = ["nb2plots (>=0.6)", "numpydoc (>=1.5)", "pillow (>=9.2)", "pydata-sphinx-theme (>=0.11)", "sphinx (>=5.2)", "sphinx-gallery (>=0.11)", "texext (>=0.6.6)"] +extra = ["lxml (>=4.6)", "pydot (>=1.4.2)", "pygraphviz (>=1.9)", "sympy (>=1.10)"] test = ["codecov (>=2.1)", "pytest (>=7.2)", "pytest-cov (>=4.0)"] [[package]] @@ -2782,6 +2800,23 @@ text-unidecode = ">=1.3" [package.extras] unidecode = ["Unidecode (>=1.1.1)"] +[[package]] +name = "python-tsp" +version = "0.3.1" +description = "Simple library to solve the Traveling Salesperson Problem in pure Python." +category = "main" +optional = false +python-versions = ">=3.7.1,<4.0.0" +files = [ + {file = "python_tsp-0.3.1-py3-none-any.whl", hash = "sha256:3af48a471505b392177b556a991203b95b1a2011cd9d66a7ca709a8a59d24bce"}, + {file = "python_tsp-0.3.1.tar.gz", hash = "sha256:e113daacc71987621718e5895817dfd50f3b76b87d5d50f4e118550c8c4a4423"}, +] + +[package.dependencies] +numpy = "*" +requests = ">=2.28.0,<3.0.0" +tsplib95 = ">=0.7.1,<0.8.0" + [[package]] name = "pytz" version = "2022.7.1" @@ -3216,6 +3251,21 @@ files = [ [package.dependencies] mpmath = ">=0.19" +[[package]] +name = "tabulate" +version = "0.8.10" +description = "Pretty-print tabular data" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "tabulate-0.8.10-py3-none-any.whl", hash = "sha256:0ba055423dbaa164b9e456abe7920c5e8ed33fcc16f6d1b2f2d152c8e1e8b4fc"}, + {file = "tabulate-0.8.10.tar.gz", hash = "sha256:6c57f3f3dd7ac2782770155f3adb2db0b1a269637e42f27599925e64b114f519"}, +] + +[package.extras] +widechars = ["wcwidth"] + [[package]] name = "termcolor" version = "2.3.0" @@ -3489,6 +3539,24 @@ torchhub = ["filelock", "huggingface-hub (>=0.14.1,<1.0)", "importlib-metadata", video = ["av (==9.2.0)", "decord (==0.6.0)"] vision = ["Pillow"] +[[package]] +name = "tsplib95" +version = "0.7.1" +description = "TSPLIB95 works with TSPLIB95 files." +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "tsplib95-0.7.1-py2.py3-none-any.whl", hash = "sha256:c481638e293baaa62134b491477aa5b2681e552e4dc28a6106ca1e157ae59184"}, + {file = "tsplib95-0.7.1.tar.gz", hash = "sha256:3da80175dfb0478b967b87c508f75def47371188b6401b719441f2cedc817e00"}, +] + +[package.dependencies] +Click = ">=6.0" +Deprecated = ">=1.2.9,<1.3.0" +networkx = ">=2.1,<3.0" +tabulate = ">=0.8.7,<0.9.0" + [[package]] name = "types-pytz" version = "2023.3.0.0" @@ -3914,4 +3982,4 @@ testing = ["coverage (>=5.0.3)", "zope.event", "zope.testing"] [metadata] lock-version = "2.0" python-versions = "^3.8" -content-hash = "6d0f15cfcbd7a0bdc564f1bb4b7f6f8c1c30128196b26b2de4929168725dde53" +content-hash = "34dfa67fe4a058d9c846306eb3e3392d4c55862f6ea060c40131f3f6d5566ca3" diff --git a/pyproject.toml b/pyproject.toml index decb22e..c06b4f6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -61,6 +61,7 @@ bitsandbytes = "^0.39.0" transformers = "^4.29.2" peft = "^0.3.0" gevent = "^22.10.2" +python-tsp = "^0.3.1" [build-system]