{"id":350533,"date":"2023-07-20T09:01:15","date_gmt":"2023-07-20T09:01:15","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=350533"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=350533","title":{"rendered":"<span>\u041f\u0438\u0448\u0435\u043c \u0441\u0432\u043e\u0439 Chat GPT<\/span>"},"content":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w780q1\/getpro\/habr\/upload_files\/94d\/af4\/901\/94daf49012944e22e343fdacf64204a0.jpeg\" alt=\"\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0447\u0430\u0442\u0430\" title=\"\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0447\u0430\u0442\u0430\" width=\"1175\" height=\"610\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/94d\/af4\/901\/94daf49012944e22e343fdacf64204a0.jpeg\" data-blurred=\"true\"\/><\/p>\n<div><figcaption>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0447\u0430\u0442\u0430<\/figcaption><\/div>\n<\/figure>\n<p>\u0412 \u0438\u044e\u043d\u0435 \u0443 <a href=\"https:\/\/openai.com\/blog\/function-calling-and-other-api-updates\" rel=\"noopener noreferrer nofollow\">OpenAI \u0432\u044b\u0448\u043b\u0430 \u043d\u043e\u0432\u043e\u0441\u0442\u044c<\/a>, \u0447\u0442\u043e \u0432 \u043c\u043e\u0434\u0435\u043b\u044c GPT \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c API \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0447\u0442\u043e \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0448\u0438\u0440\u043e\u043a\u0438\u0439 \u043a\u0440\u0443\u0433 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0430\u0433\u0435\u043d\u0442\u043e\u0432. \u041c\u044b \u0441 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 \u0440\u0435\u0448\u0438\u043b\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u0447\u0430\u0442 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 <a href=\"https:\/\/platform.openai.com\/docs\/api-reference\" rel=\"noopener noreferrer nofollow\">GPT4 \u043e\u0442 Open AI<\/a> \u0438 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 ML\/LLM \u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438 c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u0434 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435 \u043d\u0443\u0436\u0434\u044b \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438. \u041f\u0440\u043e\u0435\u043a\u0442 \u0432\u044b\u043b\u043e\u0436\u0435\u043d \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0439 \u0434\u043e\u0441\u0442\u0443\u043f, \u0441\u043a\u0430\u0447\u0430\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u043e <a href=\"https:\/\/github.com\/soshace\/fosterflow\" rel=\"noopener noreferrer nofollow\">\u0441\u0441\u044b\u043b\u043a\u0435<\/a>. \u0421\u0435\u0439\u0447\u0430\u0441 \u043e\u043d \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435, \u0442\u0430\u043a \u0447\u0442\u043e \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0434\u044b \u0432\u0438\u0434\u0435\u0442\u044c \u0432\u0430\u0448\u0438 \u0437\u0430\u043c\u0435\u0447\u0430\u043d\u0438\u044f \/ \u043f\u043e\u0436\u0435\u043b\u0430\u043d\u0438\u044f \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445. \u0422\u0430\u043a\u0436\u0435 \u043f\u0440\u0438\u0441\u044b\u043b\u0430\u0439\u0442\u0435 \u0432\u0430\u0448\u0438 pull requests \u0441 \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f\u043c\u0438.\u00a0   <\/p>\n<p>\u041d\u0430 \u0431\u044d\u043a\u0435\u043d\u0434\u0435 \u0431\u044b\u043b \u0432\u044b\u0431\u0440\u0430\u043d <a href=\"https:\/\/www.python.org\/\" rel=\"noopener noreferrer nofollow\">Python<\/a>, <a href=\"https:\/\/www.django-rest-framework.org\/\" rel=\"noopener noreferrer nofollow\">Django Rest Framework<\/a>. \u041d\u0430 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0435 <a href=\"https:\/\/react.dev\/\" rel=\"noopener noreferrer nofollow\">React,<\/a> <a href=\"https:\/\/redux.js.org\/\" rel=\"noopener noreferrer nofollow\">Redux<\/a>, <a href=\"https:\/\/redux-saga.js.org\/\" rel=\"noopener noreferrer nofollow\">Saga<\/a>, <a href=\"https:\/\/sass-lang.com\/\" rel=\"noopener noreferrer nofollow\">Sass<\/a>. \u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0431\u044d\u043a\u0435\u043d\u0434\u0430. \u0418\u043c \u0437\u0430\u043d\u0438\u043c\u0430\u043b\u0441\u044f<a href=\"https:\/\/github.com\/egortaran\" rel=\"noopener noreferrer nofollow\"> \u0415\u0433\u043e\u0440<\/a>. \u0414\u0430\u043b\u0435\u0435 \u043f\u0440\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043e\u043d \u043f\u0438\u0448\u0435\u0442 \u043e\u0442 \u0441\u0435\u0431\u044f.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/024\/e3c\/1d7\/024e3c1d7ecd13f4601ed0b6a781ea8c.gif\" alt=\"\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u0447\u0430\u0442\u0435\" title=\"\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u0447\u0430\u0442\u0435\" width=\"1066\" height=\"581\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/024\/e3c\/1d7\/024e3c1d7ecd13f4601ed0b6a781ea8c.gif\"\/><\/p>\n<div><figcaption>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u0447\u0430\u0442\u0435<\/figcaption><\/div>\n<\/figure>\n<h3>Backend<\/h3>\n<p>Backend \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0430\u044f \u043c\u043e\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0430 Django.\u00a0\u0422\u0430\u043a\u0436\u0435 \u0434\u043b\u044f API \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f Django Rest Framework. \u041d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u044d\u0442\u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u043c\u0438, \u0434\u043b\u044f \u043d\u0430 \u043d\u0438\u0445 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0433\u043e\u0442\u043e\u0432\u044b\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a, \u0447\u0442\u043e \u0443\u0441\u043a\u043e\u0440\u0438\u043b\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.  <\/p>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u043b\u0435\u0433\u0447\u0435 \u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u044e\u0442 \u0441\u0432\u043e\u0439 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u044b\u0439 \u0430\u0434\u0440\u0435\u0441, \u0447\u0435\u043c username, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0437\u0430\u043d\u044f\u0442 \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u044b. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0432\u043e\u044e \u043c\u043e\u0434\u0435\u043b\u044c User, \u0441 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u043c\u0438 \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0438 \u043e\u0442 \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 \u0432 Django. <strong>\u041d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0437\u0430\u0431\u044b\u0432\u0430\u0442\u044c, \u0447\u0442\u043e \u043c\u043e\u0434\u0435\u043b\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432\u0430\u0436\u043d\u043e \u043f\u0440\u043e\u0434\u0443\u043c\u0430\u0442\u044c \u043d\u0430 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0445 \u044d\u0442\u0430\u043f\u0430\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430!<\/strong>  <\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/28d\/522\/ad4\/28d522ad4727463d32e8efa35f5cf020.png\" alt=\"\u041c\u043e\u0434\u0435\u043b\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\" title=\"\u041c\u043e\u0434\u0435\u043b\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f\" width=\"575\" height=\"471\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/28d\/522\/ad4\/28d522ad4727463d32e8efa35f5cf020.png\"\/><\/p>\n<div><figcaption>\u041c\u043e\u0434\u0435\u043b\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f<\/figcaption><\/div>\n<\/figure>\n<h4>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f<\/h4>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439:<br \/>1. \u0421\u043e\u0437\u0434\u0430\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u044c User. \u042f \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u0444\u043b\u0430\u0433 <code>is_email_confirmed<\/code>, \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043e\u0442\u0441\u043b\u0435\u0434\u0438\u0442\u044c \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u043f\u043e\u0447\u0442\u044b. \u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0442\u0435\u043f\u0435\u0440\u044c \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0447\u0435\u0440\u0435\u0437 email.\u00a0 \u041e\u043f\u0446\u0438\u044e \u0441 \u0432\u044b\u0431\u043e\u0440\u043e\u043c \u0441\u0432\u043e\u0435\u0433\u043e username \u0440\u0435\u0448\u0438\u043b \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c.  <\/p>\n<pre><code class=\"python\">class User(AbstractBaseUser, PermissionsMixin):    username = models.CharField(db_index=True, max_length=25, unique=True)    email = models.EmailField(db_index=True, unique=True)      is_active = models.BooleanField(default=False)    is_staff = models.BooleanField(default=False)    is_email_confirmed = models.BooleanField(default=False)      created_at = models.DateTimeField(auto_now_add=True)    updated_at = models.DateTimeField(auto_now=True)      USERNAME_FIELD = 'email'    REQUIRED_FIELDS = ['username']    objects = UserManager()<\/code><\/pre>\n<p>2. \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c Manager, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u043b\u0438\u0441\u044c \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<pre><code class=\"python\">class UserManager(BaseUserManager):    def create_user(self, username, email, password=None):        if username is None:            raise TypeError('Users must have a username.')        if email is None:            raise TypeError('Users must have an email address.')        user = self.model(username=username, email=self.normalize_email(email))        user.set_password(password)        user.save()        return user      def create_superuser(self, username, email, password):        if password is None:            raise TypeError('Superusers must have a password.')        user = self.create_user(username, email, password)        user.is_superuser = True        user.is_email_confirmed = True        user.is_staff = True        user.save()        return user<\/code><\/pre>\n<p>3. \u041d\u0430\u0437\u043d\u0430\u0447\u0438\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u044c User \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 settings.py:<\/p>\n<p><code>AUTH_USER_MODEL = \"user_app.User\"<\/code><\/p>\n<p>\u0425\u043e\u0442\u0435\u043b\u043e\u0441\u044c, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0433 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u044e \u043b\u0438\u0447\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0437\u0430 \u0436\u0438\u0432\u043e\u0433\u043e \u043e\u0431\u0449\u0435\u043d\u0438\u044f\u00a0 \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u043e\u0444\u0438\u043b\u044c, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435,\u0430\u0432\u0430\u0442\u0430\u0440\u043a\u0430.  <\/p>\n<p>\u00a0Profile \u043c\u043e\u0434\u0435\u043b\u044c:<\/p>\n<pre><code class=\"python\">class Profile(models.Model):    user_id = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)    avatar = models.ImageField(upload_to=get_image_filename, blank=True)    first_name = models.TextField(max_length=32)    last_name = models.TextField(max_length=32)<\/code><\/pre>\n<p>\u041d\u043e \u0435\u0441\u043b\u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0435\u0439, \u0442\u043e \u0437\u0430\u043c\u0435\u0442\u0438\u043c, \u0447\u0442\u043e \u0443 \u0441\u043e\u0437\u0434\u0430\u0441\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u043e\u0434\u0435\u043b\u044c User, \u0431\u0435\u0437 Profile. \u0427\u0442\u043e\u0431\u044b \u044d\u0442\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c, \u0438 \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043c\u043e\u0434\u0435\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u043b\u0430\u0441\u044c \u043c\u043e\u0434\u0435\u043b\u044c \u043f\u0440\u043e\u0444\u0438\u043b\u044f, \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u0441\u0438\u0433\u043d\u0430\u043b. \u0414\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u0435\u043c\u043d\u0438\u043a\u043e\u0432 \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432 \u0432 Django \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440 receiver. \u0418 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043d\u0430\u0448 \u043f\u0440\u043e\u0444\u0438\u043b\u044c \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f:<\/p>\n<pre><code class=\"python\">@receiver(post_save, sender=User) def create_profile(sender, instance, created, **kwargs):    if created:        Profile.objects.create(user_id=instance)<\/code><\/pre>\n<h4>JWT-\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f<\/h4>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0447\u0442\u043e\u0431\u044b \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439, \u043d\u0443\u0436\u043d\u043e \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0440\u0435\u0448\u0438\u043b \u0432\u044b\u0431\u0440\u0430\u0442\u044c <a href=\"https:\/\/jwt.io\/\" rel=\"noopener noreferrer nofollow\">JWT-\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e<\/a>, \u0432\u0435\u0434\u044c \u043e\u043d\u0430 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u0438\u043c \u0438\u0437 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0445 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043c\u0435\u0436\u0434\u0443 \u0434\u0432\u0443\u043c\u044f \u0443\u0447\u0430\u0441\u0442\u043d\u0438\u043a\u0430\u043c\u0438.<\/p>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c: \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e access token \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u043c \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c, \u043d\u043e \u043a\u043e\u0433\u0434\u0430 \u0438\u0441\u0442\u0435\u043a\u0430\u0435\u0442 \u0441\u0440\u043e\u043a \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0442\u043e\u043a\u0435\u043d\u0430, \u043c\u044b \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c refresh token \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043d\u043e\u0432\u0443\u044e \u043f\u0430\u0440\u0443 access token + refresh token. Refresh token \u0442\u043e\u0436\u0435 \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u0442\u0435\u0447\u044c, \u043d\u043e \u043e\u043d \u0438\u043c\u0435\u0435\u0442 \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0431\u043e\u043b\u044c\u0448\u0438\u0439 \u0441\u0440\u043e\u043a \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0438 \u0435\u0441\u043b\u0438 \u0441\u0440\u043e\u043a \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f refresh token \u0438\u0441\u0442\u0435\u043a\u0430\u0435\u0442, \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u043f\u0440\u043e\u0439\u0442\u0438 \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u0443 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c JWT.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/a25\/256\/d30\/a25256d30ec02766476f1cac483f2c6a.png\" alt=\"\u0426\u0438\u043a\u043b JWT  \" title=\"\u0426\u0438\u043a\u043b JWT  \" width=\"1674\" height=\"730\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/a25\/256\/d30\/a25256d30ec02766476f1cac483f2c6a.png\"\/><\/p>\n<div><figcaption>\u0426\u0438\u043a\u043b JWT  <\/figcaption><\/div>\n<\/figure>\n<p>\u0414\u043b\u044f \u0434\u0430\u043d\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u0430\u044f <a href=\"https:\/\/django-rest-framework-simplejwt.readthedocs.io\/en\/latest\/\" rel=\"noopener noreferrer nofollow\">\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 Simple JWT<\/a>. \u041e\u043d\u0430 \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0435\u0439 access \u0438 refresh \u0442\u043e\u043a\u0435\u043d\u043e\u0432, \u043d\u043e \u0434\u043b\u044f \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u043e\u0442 CSRF-\u0430\u0442\u0430\u043a \u0438 XSS-\u0430\u0442\u0430\u043a \u044f \u0440\u0435\u0448\u0438\u043b \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c refresh \u0442\u043e\u043a\u0435\u043d \u0432 HttpOnly Cookie. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 JWT, \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 response cookie. \u041a\u043e\u0434 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f refresh \u0442\u043e\u043a\u0435\u043d\u0430 \u0432 cookie:<\/p>\n<pre><code class=\"python\">response.set_cookie(    key=settings.SIMPLE_JWT['AUTH_COOKIE_REFRESH'],    value=token,    expires=settings.SIMPLE_JWT['REFRESH_TOKEN_LIFETIME'],    secure=settings.SIMPLE_JWT['AUTH_COOKIE_SECURE'],    httponly=settings.SIMPLE_JWT['AUTH_COOKIE_HTTP_ONLY'],    samesite=settings.SIMPLE_JWT['AUTH_COOKIE_SAMESITE'] )<\/code><\/pre>\n<p>\u041d\u0435 \u043e\u0431\u043e\u0448\u043b\u043e\u0441\u044c \u0438 \u0431\u0435\u0437 \u0442\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u0435\u0439. \u0411\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0437\u0430\u043d\u044f\u043b \u0432\u043e\u043f\u0440\u043e\u0441, \u043f\u043e\u0447\u0435\u043c\u0443 \u0442\u043e\u043a\u0435\u043d \u043d\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0434\u043e\u043b\u0436\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u0435\u0441\u0438\u0442 \u0432 response? \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0444\u0430\u0439\u043b settings.py \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043d\u0435\u0433\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440<\/p>\n<p><code>CORS_ALLOW_CREDENTIALS = True<\/code><\/p>\n<p>\u0418 \u043d\u0435 \u0437\u0430\u0431\u044b\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 <code>SIMPLE_JWT<\/code> \u0432 \u044d\u0442\u043e\u043c \u0436\u0435 \u0444\u0430\u0439\u043b\u0435:<\/p>\n<p><code>'AUTH_COOKIE_SECURE': False<\/code> &#8212; \u043d\u0443\u0436\u043d\u043e, \u043f\u0440\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 https<\/p>\n<p><code>'AUTH_COOKIE_HTTP_ONLY' : True<\/code> &#8212; \u0424\u043b\u0430\u0433 HttpOnly\u00a0<\/p>\n<p><code>'AUTH_COOKIE_SAMESITE': 'Lax'<\/code> &#8212; \u0444\u0430\u0439\u043b\u044b Cookie \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u043c\u0435\u0436\u0441\u0430\u0439\u0442\u043e\u0432\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435, \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043f\u043e\u043c\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 Frontend \u0437\u0430\u043f\u0440\u043e\u0441 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c <code>withCredentials: true<\/code><\/p>\n<h4>\u041e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a NLP (GPT)<\/h4>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043b\u0438\u0441\u044c, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u043a \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043e\u0442 \u043d\u0435\u0451 \u043e\u0442\u0432\u0435\u0442. \u041e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u0438\u0434\u0435\u0442 \u043e\u0431\u044b\u0447\u043d\u044b\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435\u043c, \u0430 \u0447\u0442\u043e \u0435\u0441\u0442\u044c \u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f? \u041f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e, \u0441\u0432\u043e\u0439 \u0434\u0438\u0430\u043b\u043e\u0433, \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043e\u043d\u043e \u0438\u0434\u0435\u0442. \u041e\u043f\u0438\u0440\u0430\u044f\u0441\u044c \u043d\u0430 \u044d\u0442\u0443 \u043b\u043e\u0433\u0438\u043a\u0443, \u043c\u043e\u0436\u043d\u043e \u043e\u0431\u0449\u0430\u0442\u044c\u0441\u044f \u0441 nlp \u0441 \u0443\u0447\u0451\u0442\u043e\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u041f\u043e\u0436\u0430\u043b\u0443\u0439, \u043d\u0430\u0441\u0442\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441. \u0422\u0435\u043a\u0441\u0442 \u043d\u0430\u0448\u0435\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0431\u0443\u0434\u0435\u0442 \u0442\u0430\u043a\u0438\u043c \u201cWrite bubble sort in Python\u201d, \u0432\u0435\u0434\u044c \u043a\u0442\u043e \u043d\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u043b \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u043f\u0443\u0437\u044b\u0440\u044c\u043a\u043e\u043c :). \u041a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0436\u0430\u043b\u0438 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 Enter, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0437\u0430\u043f\u0440\u043e\u0441 \u043a \u043d\u0430\u0448\u0435\u043c\u0443 API, \u043e\u0442 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u044b \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u043e\u0442\u0432\u0435\u0442. \u041e\u0442\u0432\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>take_answer()<\/code>, \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441:<\/p>\n<pre><code class=\"python\">answer_text = take_answer(validated_data['message_text'], validated_data['dialog_id']) message = Message.objects.create(answer_text=answer_text, **validated_data)<\/code><\/pre>\n<p>OpenAI \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0441\u0432\u043e\u0435\u043c\u0443 API (\u0441\u0441\u044b\u043b\u043a\u0430 <a href=\"https:\/\/platform.openai.com\/overview\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/platform.openai.com\/overview<\/u><\/a>). \u0412 \u043f\u0440\u043e\u0435\u043a\u0442\u043a\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 API \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u043d\u043e \u043f\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c\u0443 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0443:<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/c3e\/199\/bbe\/c3e199bbefa3d6f0c9cf2e96c6485e63.png\" alt=\"\u0414\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441\u043b\u043e\u0435\u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\" title=\"\u0414\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441\u043b\u043e\u0435\u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f\" width=\"521\" height=\"411\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/c3e\/199\/bbe\/c3e199bbefa3d6f0c9cf2e96c6485e63.png\"\/><\/p>\n<div><figcaption>\u0414\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441\u043b\u043e\u0435\u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/figcaption><\/div>\n<\/figure>\n<p>\u041e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a OpenAI \u0438\u0434\u0435\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>ChatCompletion.create()<\/code>, \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0435\u0451 \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u0435\u0435 \u0438\u0437\u0443\u0447\u0438\u0442\u044c:<\/p>\n<pre><code class=\"python\"> previous_messages = Message.objects.filter(dialog_id=dialog_id).order_by('-id')[:5]     messages = [         {\"role\": \"system\", \"content\": \"You are a helpful assistant.\"}     ]      for message in previous_messages:         user_message = {\"role\": \"user\", \"content\": message.message_text}         ai_message = {\"role\": \"assistant\", \"content\": message.answer_text}         messages.extend([user_message, ai_message])      user_prompt = {\"role\": \"user\", \"content\": prompt}     messages.append(user_prompt)      response = openai.ChatCompletion.create(         model=\"gpt-4\",         messages=messages     )<\/code><\/pre>\n<p>\u041c\u044b \u0431\u0435\u0440\u0435\u043c \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0438 \u043e\u0442\u0432\u0435\u0442\u044b \u0432 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435 5 \u0448\u0442\u0443\u043a \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c OpenAI \u0432 ChatCompletion ( \u0441\u0441\u044b\u043b\u043a\u0430 \u00a0 <a href=\"https:\/\/platform.openai.com\/docs\/api-reference\/completions\/create\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/platform.openai.com\/docs\/api-reference\/completions\/create<\/u><\/a> ), \u00a0\u043c\u043e\u0434\u0435\u043b\u044c \u0440\u0435\u0448\u0438\u043b \u043f\u043e\u043a\u0430 \u043d\u0435 \u043c\u0435\u043d\u044f\u0442\u044c \u0431\u0435\u0437 \u043e\u0441\u043e\u0431\u044b\u0445 \u043d\u0443\u0436\u0434. \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0441\u0442\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c response, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u0436\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u0440\u0438\u0434\u0442\u0438:<\/p>\n<pre><code class=\"json\">{   \"id\": 1,   \"message_text\": \"Write bubble sort in Python\",   \"answer_text\": \"Certainly! Here's an example of the bubble sort algorithm implemented in Python:\\n\\n```python\\ndef bubble_sort(arr):\\n    n = len(arr)\\n    \\n    for i in range(n):\\n        # Last i elements are already in place\\n        for j in range(0, n-i-1):\\n            # Swap if the element found is greater than the next element\\n            if arr[j] > arr[j+1]:\\n                arr[j], arr[j+1] = arr[j+1], arr[j]\\n\\n# Example usage\\narr = [64, 34, 25, 12, 22, 11, 90]\\nbubble_sort(arr)\\nprint(\\\"Sorted array: \\\", arr)\\n```\\n\\nThis implementation sorts the input list in ascending order using the bubble sort algorithm.\",   \"dialog_id\": 1 } <\/code><\/pre>\n<p>\u0418 \u043a\u0430\u043a \u0436\u0435 \u044f \u043e\u0431\u0440\u0430\u0434\u043e\u0432\u0430\u043b\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043d\u044f\u043b, \u0447\u0442\u043e \u0434\u0430\u043d\u043d\u044b\u0439 response \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u0432  <a href=\"https:\/\/www.markdownguide.org\/\" rel=\"noopener noreferrer nofollow\">Markdown<\/a> \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0418\u043d\u0430\u0447\u0435 \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u043d\u0435\u0447\u0438\u0442\u0430\u0435\u043c\u043e \u0438 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0431\u044b \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u0442\u044c \u0438\u043b\u0438 \u0438\u0441\u043a\u0430\u0442\u044c \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u043a\u0430\u043a \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u043e\u0442\u0432\u0435\u0442 \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435.   <\/p>\n<h3>Frontend<\/h3>\n<p>\u0414\u0430\u043b\u0435\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043f\u0440\u043e \u0441\u0432\u043e\u044e \u0447\u0430\u0441\u0442\u044c (<a href=\"https:\/\/www.linkedin.com\/in\/nikita-bragin-82296b29\/\" rel=\"noopener noreferrer nofollow\">\u041d\u0438\u043a\u0438\u0442\u0430<\/a>). \u042f \u0440\u0430\u0437\u0431\u0438\u043b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 Redux \u043c\u043e\u0434\u0443\u043b\u0438:<\/p>\n<ul>\n<li>\n<p>Auth (\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f, \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f, \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0430\u0440\u043e\u043b\u044f);<\/p>\n<\/li>\n<li>\n<p>Chat (\u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438, \u0434\u0438\u0430\u043b\u043e\u0433\u0430\u043c\u0438)<\/p>\n<\/li>\n<li>\n<p>User (\u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f username, emai, loading, error)<\/p>\n<\/li>\n<li>\n<p>Profile (\u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a \u0418\u043c\u044f, \u0424\u0430\u043c\u0438\u043b\u044f, \u0424\u043e\u0442\u043e).<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u0430\u043b\u0435\u0435 \u044f \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u044e\u0441\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043d\u0430 \u0442\u043e\u043c \u043a\u0430\u043a \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u043d \u0440\u043e\u0443\u0442\u0438\u043d\u0433, \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f, \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0438 \u0447\u0430\u0442.<\/p>\n<h4>\u0420\u043e\u0443\u0442\u0438\u043d\u0433<\/h4>\n<p>\u0420\u043e\u0443\u0442\u0438\u043d\u0433 \u044f \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u0434\u043b\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0441\u0442\u0440\u0430\u043d\u0438\u0446 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438, \u0447\u0430\u0442\u0430, \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a, \u043f\u0440\u043e\u0444\u0438\u043b\u044f. \u0414\u043b\u044f \u0447\u0430\u0442\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u043e\u0443\u0442\u0438\u043d\u0433\u0430 \u043e\u0447\u0435\u043d\u044c \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443 \u0434\u043b\u044f \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f. <\/p>\n<p>\u0420\u043e\u0443\u0442\u0438\u043d\u0433 \u044f \u0440\u0430\u0437\u0431\u0438\u043b \u043d\u0430 \u0434\u0432\u0430 \u0444\u0430\u0439\u043b\u0430: routes \u0438 index. \u0412 routes.js \u044f \u0441\u043e\u0437\u0434\u0430\u043b \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u0432 \u0440\u043e\u0443\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u044e\u0442 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0443\u0440\u043e\u0432\u043d\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u0430. \u041d\u0430\u043f\u0440\u0438\u043c\u0440\u0435, \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438 \u043d\u0435\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e, \u0430 \u0442\u0430\u043a\u0436\u0435 \u043f\u0443\u0431\u043b\u0438\u0447\u043d\u044b\u0435 \u0440\u043e\u0443\u0442\u044b, \u043f\u043e\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u043a\u043e\u0442\u043e\u0440\u044b\u0445 \u043d\u0435 \u0434\u043e\u043b\u0436\u043d\u043e \u043c\u0435\u043d\u044f\u0442\u044c\u0441\u044f \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u043e\u0433\u043e \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0438\u043b\u0438 \u043d\u0435\u0442. \u0422\u0430\u043a\u043e\u0439 \u043f\u043e\u0434\u0445\u043e\u0434 \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0441\u043e\u043a\u0440\u0430\u0442\u0438\u0442\u044c \u0447\u0438\u0441\u043b\u043e \u0440\u0435\u0434\u0438\u0440\u0435\u043a\u0442\u043e\u0432 \u0438 \u043f\u0440\u043e\u0432\u0435\u0440\u043e\u043a, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044e\u0442\u0441\u044f \u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0438. \u0418 \u0435\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c, \u043e\u043a\u0430\u0437\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0435, \u043a\u0443\u0434\u0430 \u0443 \u043d\u0435\u0433\u043e \u0434\u043e\u0441\u0442\u0443\u043f\u0430 \u043d\u0435\u0442, \u0442\u043e \u0440\u043e\u0443\u0442\u0435\u0440 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442 \u0435\u0433\u043e \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438. <\/p>\n<pre><code class=\"javascript\">onst authProtectedRoutes = [   { path: \"\/chats\/\", component: &lt;Chats \/> },   { path: \"\/chats\/:id\", component: &lt;Chats \/> },   { path: \"\/profile\", component: &lt;Profile \/> },   { path: \"\/settings\", component: &lt;Settings \/> },   { path: \"\/logout\", component: &lt;Logout \/> },     \/\/ this route should be at the end of all other routes   \/\/ eslint-disable-next-line react\/display-name   {     path: \"\/\",     exact: true,     component: &lt;Navigate to=\"\/chats\" \/>,   }, ];   const publicRoutes = [   { path: \"\/email-verify\/:token\", component: &lt;EmailVerification\/> },   { path: \"\/password-reset\/:token\", component: &lt;PasswordReset\/> },   { path: \"\/forget-password\", component: &lt;ForgetPassword \/> }, ];   const authRoutes = [   { path: \"\/login\", component: &lt;Login \/> },   { path: \"\/register\", component: &lt;Register \/> }, ];<\/code><\/pre>\n<p>Index.js \u043e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0440\u043e\u0443\u0442\u0435\u0440\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u0441\u043f\u0438\u0441\u043e\u043a \u0440\u043e\u0443\u0442\u0435\u0440\u043e\u0432 \u0438 \u0432 \u0437\u0430\u0432\u0438\u0441\u0438\u043c\u043e\u0441\u0442\u0438 \u043e\u0442 \u0442\u0438\u043f\u0430 \u0441\u043f\u0438\u0441\u043a\u0430 \u0443\u0441\u0442\u0430\u043d\u0430\u0432\u043b\u0438\u0432\u0430\u0435\u0442 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u043f\u0440\u0430\u0432\u0438\u043b\u0430 \u0434\u043b\u044f \u043a\u0430\u0436\u0434\u043e\u0433\u043e \u0440\u043e\u0443\u0442\u0430. \u041f\u0440\u0438\u043c\u0435\u0440 \u0440\u043e\u0443\u0442\u0430 \u0438\u0437 index.js \u0434\u043b\u044f \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0433\u043e \u0434\u0430\u0448\u0431\u043e\u0440\u0434\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0435 \u0434\u043e\u0441\u0442\u0443\u043f\u0435\u043d \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439:<\/p>\n<pre><code class=\"javascript\">{\/* private\/auth protected routes *\/} {authProtectedRoutes.map((route, idx) =>   &lt;Route     path={route.path}     layout={AuthLayout}     element={       &lt;AuthProtected>         &lt;AuthLayout>           {route.component}         &lt;\/AuthLayout>       &lt;\/AuthProtected>     }     key={idx}   \/> )}<\/code><\/pre>\n<h4>\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f \/ \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f<\/h4>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9a2\/895\/825\/9a2895825be58ab199c3dd71fc957249.gif\" alt=\"\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438\" title=\"\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438\" width=\"684\" height=\"484\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/9a2\/895\/825\/9a2895825be58ab199c3dd71fc957249.gif\"\/><\/p>\n<div><figcaption>\u041f\u0440\u043e\u0446\u0435\u0441\u0441 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438<\/figcaption><\/div>\n<\/figure>\n<p><strong>\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f<\/strong><\/p>\n<p>\u0420\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f\u00a0 \u0441\u043e\u0441\u0442\u043e\u0438\u0442 \u0438\u0437 \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u0438\u0445 \u044d\u0442\u0430\u043f\u043e\u0432:<\/p>\n<ul>\n<li>\n<p>\u041e\u043a\u043d\u043e \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438, \u0432\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u0441\u043a\u0438\u0445 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 email \u0441\u043e \u0441\u0441\u044b\u043b\u043a\u043e\u0439 \u0434\u043b\u044f \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f \u0434\u0430\u043d\u043d\u044b\u0445 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0435\u0439.<\/p>\n<\/li>\n<li>\n<p>\u0421\u0440\u0430\u0437\u0443 \u043f\u043e\u0441\u043b\u0435 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043f\u0435\u0440\u0435\u043d\u0430\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \/chats \u0441 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u043d\u044b\u043c \u0434\u043e\u0441\u0442\u0443\u043f\u043e\u043c. \u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u0443 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0441\u0442\u043e\u0438\u0442 \u0444\u043b\u0430\u0433 <code>\u201cis_email_confirmed\u201d = false<\/code>.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0441\u043b\u0435 \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u044f email \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u043e \u0432\u044b\u0432\u0435\u0441\u0442\u0438 \u0443\u0432\u0435\u0434\u043e\u043c\u043b\u0435\u043d\u0438\u0435 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e email \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d \u0432 dashboard, \u0435\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0443\u0436\u0435 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d. \u0415\u0441\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043d\u0435 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d, \u0442\u043e \u043f\u0435\u0440\u0435\u0430\u0434\u0440\u0435\u0441\u0443\u0435\u043c \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u043b\u043e\u0433\u0438\u043d\u0430 \u0438 \u0432\u044b\u0432\u043e\u0434\u0438\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e email \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d.<\/p>\n<\/li>\n<\/ul>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/3e2\/950\/5bb\/3e29505bb8e70c93626e4cb7c4fff2cb.png\" alt=\"\u0414\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438\" title=\"\u0414\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438\" width=\"631\" height=\"771\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/3e2\/950\/5bb\/3e29505bb8e70c93626e4cb7c4fff2cb.png\"\/><\/p>\n<div><figcaption>\u0414\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438<\/figcaption><\/div>\n<\/figure>\n<p><strong>\u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u043f\u0440\u0438 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438<\/strong><\/p>\n<p>\u0412\u0430\u043b\u0438\u0434\u0430\u0446\u0438\u044f \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u043d\u0430 \u0447\u0435\u0440\u0435\u0437 ReactHook <a href=\"https:\/\/formik.org\/docs\/api\/useFormik\" rel=\"noopener noreferrer nofollow\"><u>useFormik<\/u><\/a><u>.<\/u><\/p>\n<pre><code class=\"javascript\">const formik = useFormik({         initialValues: {                         email: '',             password: ''         },         validationSchema: Yup.object({                         email: Yup.string().email('Enter proper email').required('Required'),             password: Yup.string()                 .required('Required')         }),         onSubmit: values => {             console.log('Register page', 'onSubmit', values.email, values.password );             props.registerUser(values.email, values.password );         },     });<\/code><\/pre>\n<p>\u041f\u0440\u0438 \u044d\u0442\u043e\u043c \u0432 \u0447\u0435\u0440\u0435\u0437 Hook useEffect \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u0435\u043c \u043e\u0448\u0438\u0431\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0438\u0445\u043e\u0434\u044f\u0442 \u0441 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u0438 \u0442\u043e\u0436\u0435 \u0438\u0445 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0435\u043c \u0432\u043e View:<\/p>\n<pre><code class=\"javascript\">useEffect(() => {         if (props.error &amp;&amp; props.error.errors) {             const propsErrors = props.error.errors;             setErrors(propsErrors);             let formErrors = {};             for (let key in propsErrors) {                 formErrors[key] = propsErrors[key][0];             }             formik.setErrors(formErrors);         }     }, [props.error]);<\/code><\/pre>\n<p><strong>\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 email<\/strong><\/p>\n<p>\u041f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 email \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u0447\u0435\u0440\u0435\u0437 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 EmailVerification.js. \u0415\u0441\u043b\u0438 \u0442\u043e\u043a\u0435\u043d \u043f\u0440\u0438\u0448\u0435\u043b \u0432\u0435\u0440\u043d\u044b\u0439, \u0442\u043e \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043f\u0435\u0440\u0435\u0430\u0434\u0440\u0435\u0441\u0443\u0435\u0442 \u043d\u0430 \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u0443 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u0435\u0441\u043b\u0438 \u043d\u0435\u0432\u0435\u0440\u043d\u044b\u0439, \u0442\u043e \u0432\u044b\u0432\u043e\u0434\u0438\u0442 \u043e\u0448\u0438\u0431\u043a\u0443.<\/p>\n<pre><code class=\"javascript\">&lt;CardBody className=\"p-4\">   {\/* In case if user is already logged in it manages at router *\/}     {props.emailConfirmed ? (     \/\/ We have to show successfull message at login page       &lt;Navigate to={{ pathname: \"\/login\", state: { from: props.location } }} \/>         ) : (           &lt;Alert color=\"danger\">             Confirmation failed.           &lt;\/Alert>         )}         &lt;Link to=\"\/login\" className=\"font-weight-medium text-primary\"> {t('Signin now')} &lt;\/Link>   &lt;\/CardBody> <\/code><\/pre>\n<p><strong>\u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f\u00a0<\/strong><\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/87b\/c42\/5fb\/87bc425fb2d50abdc8596af5a1cef1c7.png\" alt=\"\u0414\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438\" title=\"\u0414\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438\" width=\"763\" height=\"1231\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/87b\/c42\/5fb\/87bc425fb2d50abdc8596af5a1cef1c7.png\"\/><\/p>\n<div><figcaption>\u0414\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u0439 \u043f\u0440\u043e\u0446\u0435\u0441\u0441\u0430 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438<\/figcaption><\/div>\n<\/figure>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u0443\u044e \u043b\u043e\u0433\u0438\u043a\u0443 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0435\u0439, \u044f \u043f\u0435\u0440\u0435\u043d\u0435\u0441 \u0432 helper autUtils.js \u0414\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0435\u0439 \u043c\u044b \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u043c \u043c\u0435\u0445\u0430\u043d\u0438\u0437\u043c <a href=\"https:\/\/oauth.net\/2\/\" rel=\"noopener noreferrer nofollow\">OAuth2<\/a>. \u0414\u043b\u044f \u043e\u0442\u0441\u043b\u0435\u0436\u0438\u0432\u0430\u043d\u0438\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u0432\u0430 \u0442\u043e\u043a\u0435\u043d\u0430 access \u0438 refresh \u0442\u043e\u043a\u0435\u043d\u0430\u043c\u0438. \u0421\u043e\u043e\u0442\u0432\u0435\u0442\u0441\u0442\u0432\u0435\u043d\u043d\u043e \u043f\u043e\u043a\u0430 access \u0442\u043e\u043a\u0435\u043d \u0430\u043a\u0442\u0438\u0432\u0435\u043d \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u0438\u043c\u0435\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0435\u0439 \u0441\u0442\u0440\u0443\u043a\u0442\u0443\u0440\u0435 \u043f\u0440\u043e\u0435\u043a\u0442\u0430. \u041a\u043e\u0433\u0434\u0430 \u0442\u043e\u043a\u0435\u043d \u0438\u0441\u0442\u0435\u043a\u0430\u0435\u0442, \u044f \u0437\u0430\u043f\u0440\u0430\u0448\u0438\u0432\u0430\u044e \u043e\u0431\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u0442\u043e\u043a\u0435\u043d\u0430 \u0447\u0435\u0440\u0435\u0437 API \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u044f refresh \u0442\u043e\u043a\u0435\u043d. \u0414\u043b\u044f \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0438 \u0441\u0440\u043e\u043a\u0430 \u0434\u0430\u0432\u043d\u043e\u0441\u0442\u0438 \u0442\u043e\u043a\u0435\u043d\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u043c\u043e\u0434\u0443\u043b\u044c<a href=\"https:\/\/www.npmjs.com\/package\/jwt-decode\" rel=\"noopener noreferrer nofollow\"><u> jwtDecode<\/u><\/a><u>.<\/u><\/p>\n<pre><code class=\"javascript\">\/**  * Refresh the access token  * We use API here, because we use it in middleware in ApiAuthorizedClient  *\/ const refreshAccessToken = async () => {     let tokens = getTokens();     if (tokens &amp;&amp; tokens.access) {         const decoded = jwtDecode(tokens.access);         const currentTime = Date.now() \/ 1000;         if (decoded.exp > currentTime) {             \/\/ Token is still valid, return it             return tokens.access;         }     }       \/\/ Token is not in localStorage or is expired, refresh it     try {         const response = await axios.post(`${API_URL}\/token\/refresh\/`, { refresh: tokens.refresh });         if (response.data &amp;&amp; response.data.access) {             setTokens(response.data); \/\/ Save the new token to localStorage             return response.data.access;         }     } catch (error) {         console.error('Error refreshing access token:', error);         localStorage.removeItem(\"tokens\");         throw error;     } }   \/**  * Checks if access token is expired and refreshes it if necessary  *\/ const checkAndRefreshToken = async () => {     const tokens = getTokens();     if (!tokens) {         throw new Error('User not authenticated');     }       try {         const decoded = jwtDecode(tokens.access);         const currentTime = Date.now() \/ 1000;         if (decoded.exp &lt; currentTime) {             console.warn('Access token expired. Refreshing...');             const newAccessToken = await refreshAccessToken();             return newAccessToken;         } else {             return tokens.access;         }     } catch(error) {         console.warn('Error decoding token:', error);         throw error;     } }<\/code><\/pre>\n<h4>\u0427\u0430\u0442<\/h4>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f6f\/a7a\/f1b\/f6fa7af1b85ffbd60ac4fc5c2f971a86.gif\" alt=\"\u0414\u043e\u0441\u0442\u0443\u043f\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0447\u0430\u0442\u0430\" title=\"\u0414\u043e\u0441\u0442\u0443\u043f\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0447\u0430\u0442\u0430\" width=\"1216\" height=\"642\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/f6f\/a7a\/f1b\/f6fa7af1b85ffbd60ac4fc5c2f971a86.gif\"\/><\/p>\n<div><figcaption>\u0414\u043e\u0441\u0442\u0443\u043f\u043d\u0430\u044f \u0444\u0443\u043d\u043a\u0446\u0438\u043e\u043d\u0430\u043b\u044c\u043d\u043e\u0441\u0442\u044c \u0447\u0430\u0442\u0430<\/figcaption><\/div>\n<\/figure>\n<p>\u0427\u0430\u0442 \u0440\u0430\u0437\u0434\u0435\u043b\u0435\u043d \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b:<\/p>\n<ul>\n<li>\n<p>Chats.js \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043f\u0435\u0440\u0435\u0447\u0435\u043d\u044c \u0447\u0430\u0442\u043e\u0432 \u0438\u0437 \u043b\u0435\u0432\u043e\u0439 \u043a\u043e\u043b\u043e\u043d\u043a\u0438. \u041a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043b\u043e\u0433\u0438\u043a\u0443 \u043f\u043e \u0440\u0430\u0431\u043e\u0442\u0435 \u0441 \u043f\u0443\u0442\u044f\u043c\u0438 \u0442\u0430\u043a\u0438\u043c\u0438 \u043a\u0430\u043a chats\/:id<\/p>\n<\/li>\n<li>\n<p>ChatInput.js \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u0440\u0430\u0431\u043e\u0442\u0443 \u043f\u043e\u043b\u044f \u0432\u0432\u043e\u0434\u0430.<\/p>\n<\/li>\n<li>\n<p>Index.js \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043b\u043e\u0433\u0438\u043a\u0443 \u0432\u044b\u0432\u043e\u0434\u0430 \u0441\u043f\u0438\u0441\u043a\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439.<\/p>\n<\/li>\n<li>\n<p>UserHead \u0441\u043e\u0434\u0435\u0440\u0436\u0438\u0442 \u043b\u043e\u0433\u0438\u043a\u0443 \u0440\u0430\u0431\u043e\u0442\u044b \u0447\u0430\u0442\u044b: \u0443\u0434\u0430\u043b\u0435\u043d\u0438\u0435, \u0432\u043e\u0437\u0432\u0440\u0430\u0442 \u043a \u0441\u043f\u0438\u0441\u043a\u0443 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432 \u0434\u043b\u044f \u043c\u043e\u0431\u0438\u043b\u044c\u043d\u043e\u0439 \u0432\u0435\u0440\u0441\u0438\u0438.<\/p>\n<\/li>\n<\/ul>\n<p>API \u043e\u0442 OpenAI \u0432\u043e\u0437\u0432\u0440\u0430\u0449\u0430\u0435\u0442 \u043e\u0442\u0432\u0435\u0442\u044b \u0432 \u0444\u043e\u0440\u043c\u0430\u0442\u0435 <a href=\"https:\/\/www.markdownguide.org\/\" rel=\"noopener noreferrer nofollow\"><u>Markdown<\/u><\/a>. \u0414\u043b\u044f \u0432\u044b\u0432\u043e\u0434\u0430 \u043e\u0442\u0432\u0435\u0442\u043e\u0432 \u043e\u0442 \u0447\u0430\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0441\u043e\u0434\u0435\u0440\u0436\u0430\u0442 \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u044f \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043b \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442 <a href=\"https:\/\/www.npmjs.com\/package\/react-markdown\" rel=\"noopener noreferrer nofollow\"><u>ReactMarkdown<\/u><\/a>. \u0414\u043b\u044f \u043a\u043e\u0434\u043e\u0432\u044b\u0445 \u0432\u0441\u0442\u0430\u0432\u043e\u043a <a href=\"https:\/\/www.npmjs.com\/package\/react-syntax-highlighter\" rel=\"noopener noreferrer nofollow\"><u>React Syntax Highlighter<\/u><\/a><\/p>\n<p>\u0418\u043c\u043f\u043e\u0440\u0442\u0438\u0440\u0443\u0435\u043c \u043d\u0435\u043e\u0431\u0445\u043e\u0434\u0438\u043c\u044b\u0435 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u044b:<\/p>\n<pre><code>import React, { useRef } from 'react'; import ReactMarkdown from 'react-markdown'; import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; import { solarizedlight } from 'react-syntax-highlighter\/dist\/esm\/styles\/prism';<\/code><\/pre>\n<p>\u0412\u044b\u0432\u043e\u0434\u0438\u043c \u043e\u0442\u0432\u0435\u0442\u044b \u043e\u0442 GPT \u0441 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435\u043c \u0444\u043e\u0440\u043c\u0430\u0442\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f:<\/p>\n<pre><code class=\"xml\">&lt;div className=\"conversation-list\">   &lt;div className=\"user-chat-content\">     &lt;div className=\"ctext-wrap\">       &lt;div className=\"ctext-wrap-content\">         &lt;ReactMarkdown components={{code: CodeBlock}} className=\"mb-0\">           {chat.answer_text}         &lt;\/ReactMarkdown>       &lt;\/div>   &lt;\/div> &lt;\/div><\/code><\/pre>\n<p>\u041d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u043d\u0435 \u043e\u0447\u0435\u0432\u0438\u0434\u043d\u043e \u0431\u044b\u043b\u043e \u043a\u0430\u043a \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u0442\u044c \u043a\u043e\u0440\u0440\u0435\u043a\u0442\u043d\u043e \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u0441 \u044d\u043a\u0440\u0430\u043d\u0430 \u043d\u043e\u0432\u043e\u0433\u043e \u0447\u0430\u0442\u0430, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u043f\u043e \u043f\u0443\u0442\u0438 \/chats \u043d\u0430 \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u044b\u0439 \u0447\u0430\u0442 \/chats:id.<\/p>\n<p>\u041b\u043e\u0433\u0438\u043a\u0430 \u0441\u0435\u0439\u0447\u0430\u0441 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0430\u044f:<\/p>\n<ol>\n<li>\n<p>\u041f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043f\u0435\u0440\u0432\u043e\u0433\u043e \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0438\u0434\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 \u043d\u0430 POST \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0434\u0438\u0430\u043b\u043e\u0433\u0430.\u00a0<\/p>\n<\/li>\n<li>\n<p>\u041f\u0440\u0438 \u043f\u043e\u043b\u0443\u0447\u0435\u043d\u0438\u0438 \u043e\u0442\u0432\u0435\u0442\u0430 \u043e \u0442\u043e\u043c, \u0447\u0442\u043e \u0434\u0438\u0430\u043b\u043e\u0433 \u0441\u043e\u0437\u0434\u0430\u043d \u0438\u0434\u0435\u0442 \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0430 \u043d\u043e\u0432\u043e\u0433\u043e \u0441\u043f\u0438\u0441\u043a\u0430 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432.<\/p>\n<\/li>\n<li>\n<p>\u0418\u0434\u0435\u0442 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0430 POST \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u043d\u0430 \u043e\u0442\u043f\u0440\u0430\u0432\u043a\u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u043a LLM \u043c\u043e\u0434\u0435\u043b\u0438.<\/p>\n<\/li>\n<li>\n<p>\u041f\u043e\u0441\u043b\u0435 \u0437\u0430\u0432\u0435\u0440\u0448\u0435\u043d\u0438\u044f \u043e\u0442\u0440\u0438\u0441\u043e\u0432\u043a\u0438 \u0441\u043f\u0438\u0441\u043a\u0430 \u0434\u0438\u0430\u043b\u043e\u0433\u043e\u0432 \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442\u0441\u044f \u0440\u0435\u0434\u0438\u0440\u0435\u043a\u0442 \u043d\u0430 \u043d\u043e\u0432\u0443\u044e \u0432\u043a\u043b\u0430\u0434\u043a\u0443.<\/p>\n<\/li>\n<li>\n<p>\u041e\u0436\u0438\u0434\u0430\u0435\u043c \u043e\u0442\u0432\u0435\u0442\u0430 \u043e\u0442 \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u0432\u044b\u0432\u043e\u0434\u0438\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u0432 \u0447\u0430\u0442\u0435.<\/p>\n<\/li>\n<\/ol>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c \u0431\u0438\u0437\u043d\u0435\u0441 \u043b\u043e\u0433\u0438\u043a\u0438, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u043e\u0442\u0432\u0435\u0447\u0430\u0435\u0442 \u0437\u0430 \u043f\u0435\u0440\u0435\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0435 \u043d\u0430 \u043d\u043e\u0432\u044b\u0439 \u0434\u0438\u0430\u043b\u043e\u0433, \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u0430 \u0432 \u043a\u043e\u043c\u043f\u043e\u043d\u0435\u043d\u0442\u0435 Chats.js<\/p>\n<pre><code class=\"javascript\">useEffect(() => {         props.getAuthorizedUser();         props.fetchDialogues();     }, []);       useEffect(() => {         const dialogues = props.dialogues;         if (dialogues &amp;&amp; dialogues.length === 0) {             return;         }           setRecentChatList(dialogues);                 const activeDialogueId = props.activeDialogueId;         if (id === 0 &amp;&amp; activeDialogueId > 0) {             \/\/added new dialogue             navigate(`\/chats\/${activeDialogueId}`);         }     }, [props.dialogues]);       useEffect(() => {         if (props.activeDialogueId === id){             return;         }         props.setActiveDialogue(id);         openUserChat(id);     }, [id]);       const openUserChat = (dialogueId) => {         \/\/check \/chats page or initalStage         if (dialogueId === 0) {             return;         }         \/\/TODO: we have to check if we already have actual messages into state         props.fetchMessages(dialogueId);     };<\/code><\/pre>\n<p>\u0424\u0443\u043d\u043a\u0446\u0438\u044f \u0432 Chat\/saga.js, \u043a\u043e\u0442\u043e\u0440\u0430\u044f \u0440\u0435\u0430\u043b\u0438\u0437\u0443\u0435\u0442 POST \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u043a \u0441\u0435\u0440\u0432\u0435\u0440\u0443 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043d\u043e\u0432\u043e\u0433\u043e \u0434\u0438\u0430\u043b\u043e\u0433\u0430 \u0438 \u0447\u0430\u0442\u0430:<\/p>\n<pre><code class=\"javascript\">function* addDialogue(action) {   const data = action.payload;   try {       const dialogue = yield api.post('\/dialogues\/', {           \"user_id\": data.user_id,           \"name\": data.name       });       yield put({ type: ADD_DIALOGUE_SUCCESS, payload: dialogue });       if (data.message) {         yield put({ type: ADD_MESSAGE_REQUEST, payload: {           \"message_text\": data.message,           \"dialog_id\": dialogue.id         }});           }   } catch (error) {     console.log(error);   } }<\/code><\/pre>\n<h3>\u0411\u043b\u0438\u0436\u0430\u0439\u0448\u0438\u0435 \u043f\u043b\u0430\u043d\u044b<\/h3>\n<ol>\n<li>\n<p>\u0412\u044b\u0432\u043e\u0434 \u043e\u0448\u0438\u0431\u043e\u043a \u0438 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 &#8212; \u0441\u0435\u0439\u0447\u0430\u0441 \u044d\u0442\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043e \u0447\u0430\u0441\u0442\u0438\u0447\u043d\u043e \u0434\u043b\u044f \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438 \u0438 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438. \u0412\u044b\u0432\u043e\u0434 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043e \u0437\u0430\u0433\u0440\u0443\u0437\u043a\u0435.<\/p>\n<\/li>\n<li>\n<p>\u0412\u044b\u0432\u043e\u0434 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u043e\u0442 \u0441\u0435\u0440\u0432\u0435\u0440\u0430 \u043f\u043e\u0442\u043e\u043a\u043e\u043c, \u043a\u0430\u043a \u044d\u0442\u043e \u0440\u0435\u0430\u043b\u0438\u0437\u043e\u0432\u0430\u043d\u043e \u0432 ChatGpt. \u0421\u0440\u0430\u0437\u0443 \u043e\u0442\u043e\u0431\u0440\u0430\u0436\u0430\u0442\u044c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435 \u043e\u0442 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043b\u043e\u0433\u0438\u043a\u0443 \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u043f\u0440\u043e\u0444\u0438\u043b\u0435\u043c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f.<\/p>\n<\/li>\n<li>\n<p>\u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c \u0440\u0430\u0431\u043e\u0442\u044b \u0441 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u043c\u0438 \u0442\u0438\u043f\u0430\u043c\u0438 \u0430\u0433\u0435\u043d\u0442\u043e\u0432 (ML \u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438)<\/p>\n<\/li>\n<\/ol>\n<p><a href=\"https:\/\/github.com\/soshace\/fosterflow\" rel=\"noopener noreferrer nofollow\">\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 Github<\/a><br \/><a href=\"https:\/\/fosterflow.com\" rel=\"noopener noreferrer nofollow\">\u0421\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442<\/a><\/p>\n<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p> <!----> <!----><\/div>\n<p> <!----> <!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/749234\/\"> https:\/\/habr.com\/ru\/articles\/749234\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<figure class=\"full-width\">\n<div><figcaption>\u0418\u043d\u0442\u0435\u0440\u0444\u0435\u0439\u0441 \u0447\u0430\u0442\u0430<\/figcaption><\/div>\n<\/figure>\n<p>\u0412 \u0438\u044e\u043d\u0435 \u0443 <a href=\"https:\/\/openai.com\/blog\/function-calling-and-other-api-updates\" rel=\"noopener noreferrer nofollow\">OpenAI \u0432\u044b\u0448\u043b\u0430 \u043d\u043e\u0432\u043e\u0441\u0442\u044c<\/a>, \u0447\u0442\u043e \u0432 \u043c\u043e\u0434\u0435\u043b\u044c GPT \u043c\u043e\u0436\u043d\u043e \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c API \u0441\u0442\u043e\u0440\u043e\u043d\u043d\u0438\u0445 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0439, \u0447\u0442\u043e \u043e\u0442\u043a\u0440\u044b\u0432\u0430\u0435\u0442 \u0448\u0438\u0440\u043e\u043a\u0438\u0439 \u043a\u0440\u0443\u0433 \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u0435\u0439 \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u0441\u043f\u0435\u0446\u0438\u0430\u043b\u0438\u0437\u0438\u0440\u043e\u0432\u0430\u043d\u043d\u044b\u0445 \u0430\u0433\u0435\u043d\u0442\u043e\u0432. \u041c\u044b \u0441 \u043a\u043e\u043c\u0430\u043d\u0434\u043e\u0439 \u0440\u0435\u0448\u0438\u043b\u0438 \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0441\u0432\u043e\u0439 \u0447\u0430\u0442 \u0434\u043b\u044f \u0440\u0430\u0431\u043e\u0442\u044b \u0441 <a href=\"https:\/\/platform.openai.com\/docs\/api-reference\" rel=\"noopener noreferrer nofollow\">GPT4 \u043e\u0442 Open AI<\/a> \u0438 \u0434\u0440\u0443\u0433\u0438\u043c\u0438 ML\/LLM \u043c\u043e\u0434\u0435\u043b\u044f\u043c\u0438 c \u0432\u043e\u0437\u043c\u043e\u0436\u043d\u043e\u0441\u0442\u044c\u044e \u043a\u0430\u0441\u0442\u043e\u043c\u0438\u0437\u0430\u0446\u0438\u0438 \u043f\u043e\u0434 \u0432\u043d\u0443\u0442\u0440\u0435\u043d\u043d\u0438\u0435 \u043d\u0443\u0436\u0434\u044b \u043a\u043e\u043c\u043f\u0430\u043d\u0438\u0438. \u041f\u0440\u043e\u0435\u043a\u0442 \u0432\u044b\u043b\u043e\u0436\u0435\u043d \u0432 \u043e\u0442\u043a\u0440\u044b\u0442\u044b\u0439 \u0434\u043e\u0441\u0442\u0443\u043f, \u0441\u043a\u0430\u0447\u0430\u0442\u044c \u043c\u043e\u0436\u043d\u043e \u043f\u043e <a href=\"https:\/\/github.com\/soshace\/fosterflow\" rel=\"noopener noreferrer nofollow\">\u0441\u0441\u044b\u043b\u043a\u0435<\/a>. \u0421\u0435\u0439\u0447\u0430\u0441 \u043e\u043d \u043d\u0430\u0445\u043e\u0434\u0438\u0442\u0441\u044f \u0432 \u0430\u043a\u0442\u0438\u0432\u043d\u043e\u0439 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u043a\u0435, \u0442\u0430\u043a \u0447\u0442\u043e \u0431\u0443\u0434\u0435\u043c \u0440\u0430\u0434\u044b \u0432\u0438\u0434\u0435\u0442\u044c \u0432\u0430\u0448\u0438 \u0437\u0430\u043c\u0435\u0447\u0430\u043d\u0438\u044f \/ \u043f\u043e\u0436\u0435\u043b\u0430\u043d\u0438\u044f \u0432 \u043a\u043e\u043c\u043c\u0435\u043d\u0442\u0430\u0440\u0438\u044f\u0445. \u0422\u0430\u043a\u0436\u0435 \u043f\u0440\u0438\u0441\u044b\u043b\u0430\u0439\u0442\u0435 \u0432\u0430\u0448\u0438 pull requests \u0441 \u0438\u0441\u043f\u0440\u0430\u0432\u043b\u0435\u043d\u0438\u044f\u043c\u0438.\u00a0   <\/p>\n<p>\u041d\u0430 \u0431\u044d\u043a\u0435\u043d\u0434\u0435 \u0431\u044b\u043b \u0432\u044b\u0431\u0440\u0430\u043d <a href=\"https:\/\/www.python.org\/\" rel=\"noopener noreferrer nofollow\">Python<\/a>, <a href=\"https:\/\/www.django-rest-framework.org\/\" rel=\"noopener noreferrer nofollow\">Django Rest Framework<\/a>. \u041d\u0430 \u0444\u0440\u043e\u043d\u0442\u0435\u043d\u0434\u0435 <a href=\"https:\/\/react.dev\/\" rel=\"noopener noreferrer nofollow\">React,<\/a> <a href=\"https:\/\/redux.js.org\/\" rel=\"noopener noreferrer nofollow\">Redux<\/a>, <a href=\"https:\/\/redux-saga.js.org\/\" rel=\"noopener noreferrer nofollow\">Saga<\/a>, <a href=\"https:\/\/sass-lang.com\/\" rel=\"noopener noreferrer nofollow\">Sass<\/a>. \u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0431\u044d\u043a\u0435\u043d\u0434\u0430. \u0418\u043c \u0437\u0430\u043d\u0438\u043c\u0430\u043b\u0441\u044f<a href=\"https:\/\/github.com\/egortaran\" rel=\"noopener noreferrer nofollow\"> \u0415\u0433\u043e\u0440<\/a>. \u0414\u0430\u043b\u0435\u0435 \u043f\u0440\u043e \u0441\u0435\u0440\u0432\u0435\u0440\u043d\u0443\u044e \u0447\u0430\u0441\u0442\u044c \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u043e\u043d \u043f\u0438\u0448\u0435\u0442 \u043e\u0442 \u0441\u0435\u0431\u044f.<\/p>\n<figure class=\"full-width\">\n<div><figcaption>\u0421\u043e\u0437\u0434\u0430\u043d\u0438\u0435 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f \u0432 \u0447\u0430\u0442\u0435<\/figcaption><\/div>\n<\/figure>\n<h3>Backend<\/h3>\n<p>Backend \u0441\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u044e\u0449\u0430\u044f \u043c\u043e\u0435\u0433\u043e \u043f\u0440\u043e\u0435\u043a\u0442\u0430 \u0440\u0430\u0431\u043e\u0442\u0430\u0435\u0442 \u043d\u0430 Django.\u00a0\u0422\u0430\u043a\u0436\u0435 \u0434\u043b\u044f API \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f Django Rest Framework. \u041d\u0430 \u0441\u0435\u0433\u043e\u0434\u043d\u044f \u044d\u0442\u0438 \u0438\u043d\u0441\u0442\u0440\u0443\u043c\u0435\u043d\u0442\u044b \u044f\u0432\u043b\u044f\u044e\u0442\u0441\u044f \u043e\u0447\u0435\u043d\u044c \u043f\u043e\u043f\u0443\u043b\u044f\u0440\u043d\u044b\u043c\u0438, \u0434\u043b\u044f \u043d\u0430 \u043d\u0438\u0445 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c \u043c\u043d\u043e\u0436\u0435\u0441\u0442\u0432\u043e \u0433\u043e\u0442\u043e\u0432\u044b\u0445 \u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a, \u0447\u0442\u043e \u0443\u0441\u043a\u043e\u0440\u0438\u043b\u043e \u043f\u0440\u043e\u0446\u0435\u0441\u0441 \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u044f.  <\/p>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0442\u043e\u0433\u043e, \u0447\u0442\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u043b\u0435\u0433\u0447\u0435 \u0437\u0430\u043f\u043e\u043c\u0438\u043d\u0430\u044e\u0442 \u0441\u0432\u043e\u0439 \u044d\u043b\u0435\u043a\u0442\u0440\u043e\u043d\u043d\u044b\u0439 \u0430\u0434\u0440\u0435\u0441, \u0447\u0435\u043c username, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u043c\u043e\u0436\u0435\u0442 \u0431\u044b\u0442\u044c \u0437\u0430\u043d\u044f\u0442 \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0435 \u043e\u0442 \u0443\u043d\u0438\u043a\u0430\u043b\u044c\u043d\u043e\u0439 \u043f\u043e\u0447\u0442\u044b. \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u0441\u0432\u043e\u044e \u043c\u043e\u0434\u0435\u043b\u044c User, \u0441 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u043c\u0438 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u044f\u043c\u0438 \u0432 \u043e\u0442\u043b\u0438\u0447\u0438\u0438 \u043e\u0442 \u0431\u0430\u0437\u043e\u0432\u043e\u0439 \u043c\u043e\u0434\u0435\u043b\u0438 \u0432 Django. <strong>\u041d\u0435 \u0441\u0442\u043e\u0438\u0442 \u0437\u0430\u0431\u044b\u0432\u0430\u0442\u044c, \u0447\u0442\u043e \u043c\u043e\u0434\u0435\u043b\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0432\u0430\u0436\u043d\u043e \u043f\u0440\u043e\u0434\u0443\u043c\u0430\u0442\u044c \u043d\u0430 \u043d\u0430\u0447\u0430\u043b\u044c\u043d\u044b\u0445 \u044d\u0442\u0430\u043f\u0430\u0445 \u043f\u0440\u043e\u0435\u043a\u0442\u0430!<\/strong>  <\/p>\n<figure class=\"full-width\">\n<div><figcaption>\u041c\u043e\u0434\u0435\u043b\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f<\/figcaption><\/div>\n<\/figure>\n<h4>\u0421\u043e\u0431\u0441\u0442\u0432\u0435\u043d\u043d\u0430\u044f \u043c\u043e\u0434\u0435\u043b\u044c \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f<\/h4>\n<p>\u041d\u0430\u0447\u043d\u0435\u043c \u0441 \u0438\u0437\u043c\u0435\u043d\u0435\u043d\u0438\u0439:<br \/>1. \u0421\u043e\u0437\u0434\u0430\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u044c User. \u042f \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u0444\u043b\u0430\u0433 <code>is_email_confirmed<\/code>, \u0447\u0442\u043e\u0431\u044b \u043c\u043e\u0436\u043d\u043e \u0431\u044b\u043b\u043e \u043e\u0442\u0441\u043b\u0435\u0434\u0438\u0442\u044c \u043f\u043e\u0434\u0442\u0432\u0435\u0440\u0436\u0434\u0435\u043d\u0438\u0435 \u043f\u043e\u0447\u0442\u044b. \u0410\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0442\u0435\u043f\u0435\u0440\u044c \u0431\u0443\u0434\u0435\u0442 \u043f\u0440\u043e\u0438\u0441\u0445\u043e\u0434\u0438\u0442\u044c \u0447\u0435\u0440\u0435\u0437 email.\u00a0 \u041e\u043f\u0446\u0438\u044e \u0441 \u0432\u044b\u0431\u043e\u0440\u043e\u043c \u0441\u0432\u043e\u0435\u0433\u043e username \u0440\u0435\u0448\u0438\u043b \u043e\u0441\u0442\u0430\u0432\u0438\u0442\u044c.  <\/p>\n<pre><code class=\"python\">class User(AbstractBaseUser, PermissionsMixin):    username = models.CharField(db_index=True, max_length=25, unique=True)    email = models.EmailField(db_index=True, unique=True)      is_active = models.BooleanField(default=False)    is_staff = models.BooleanField(default=False)    is_email_confirmed = models.BooleanField(default=False)      created_at = models.DateTimeField(auto_now_add=True)    updated_at = models.DateTimeField(auto_now=True)      USERNAME_FIELD = 'email'    REQUIRED_FIELDS = ['username']    objects = UserManager()<\/code><\/pre>\n<p>2. \u0414\u043e\u0431\u0430\u0432\u0438\u0442\u044c Manager, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u0438 \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u043b\u0438\u0441\u044c \u0432 \u0431\u0430\u0437\u0443 \u0434\u0430\u043d\u043d\u044b\u0445.<\/p>\n<pre><code class=\"python\">class UserManager(BaseUserManager):    def create_user(self, username, email, password=None):        if username is None:            raise TypeError('Users must have a username.')        if email is None:            raise TypeError('Users must have an email address.')        user = self.model(username=username, email=self.normalize_email(email))        user.set_password(password)        user.save()        return user      def create_superuser(self, username, email, password):        if password is None:            raise TypeError('Superusers must have a password.')        user = self.create_user(username, email, password)        user.is_superuser = True        user.is_email_confirmed = True        user.is_staff = True        user.save()        return user<\/code><\/pre>\n<p>3. \u041d\u0430\u0437\u043d\u0430\u0447\u0438\u0442\u044c \u043c\u043e\u0434\u0435\u043b\u044c User \u0432 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0430 settings.py:<\/p>\n<p><code>AUTH_USER_MODEL = \"user_app.User\"<\/code><\/p>\n<p>\u0425\u043e\u0442\u0435\u043b\u043e\u0441\u044c, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044c \u043c\u043e\u0433 \u0440\u0435\u0434\u0430\u043a\u0442\u0438\u0440\u043e\u0432\u0430\u0442\u044c \u0441\u0432\u043e\u044e \u043b\u0438\u0447\u043d\u0443\u044e \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044e, \u0434\u043b\u044f \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u044f \u043e\u0431\u0440\u0430\u0437\u0430 \u0436\u0438\u0432\u043e\u0433\u043e \u043e\u0431\u0449\u0435\u043d\u0438\u044f\u00a0 \u041f\u043e\u044d\u0442\u043e\u043c\u0443 \u044f \u0440\u0435\u0448\u0438\u043b \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u043f\u0440\u043e\u0444\u0438\u043b\u044c, \u0432 \u043a\u043e\u0442\u043e\u0440\u043e\u043c \u0445\u0440\u0430\u043d\u0438\u0442\u0441\u044f \u043f\u0435\u0440\u0441\u043e\u043d\u0430\u043b\u044c\u043d\u0430\u044f \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u044f, \u0432 \u0442\u043e\u043c \u0447\u0438\u0441\u043b\u0435,\u0430\u0432\u0430\u0442\u0430\u0440\u043a\u0430.  <\/p>\n<p>\u00a0Profile \u043c\u043e\u0434\u0435\u043b\u044c:<\/p>\n<pre><code class=\"python\">class Profile(models.Model):    user_id = models.OneToOneField(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)    avatar = models.ImageField(upload_to=get_image_filename, blank=True)    first_name = models.TextField(max_length=32)    last_name = models.TextField(max_length=32)<\/code><\/pre>\n<p>\u041d\u043e \u0435\u0441\u043b\u0438 \u0441\u0434\u0435\u043b\u0430\u0442\u044c \u043f\u0440\u043e\u0432\u0435\u0440\u043a\u0443 \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0435\u0439, \u0442\u043e \u0437\u0430\u043c\u0435\u0442\u0438\u043c, \u0447\u0442\u043e \u0443 \u0441\u043e\u0437\u0434\u0430\u0441\u0442\u0441\u044f \u0442\u043e\u043b\u044c\u043a\u043e \u043c\u043e\u0434\u0435\u043b\u044c User, \u0431\u0435\u0437 Profile. \u0427\u0442\u043e\u0431\u044b \u044d\u0442\u043e \u0438\u0441\u043f\u0440\u0430\u0432\u0438\u0442\u044c, \u0438 \u043f\u0440\u0438 \u0441\u043e\u0437\u0434\u0430\u043d\u0438\u0438 \u043c\u043e\u0434\u0435\u043b\u0438 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0434\u043e\u0431\u0430\u0432\u043b\u044f\u043b\u0430\u0441\u044c \u043c\u043e\u0434\u0435\u043b\u044c \u043f\u0440\u043e\u0444\u0438\u043b\u044f, \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043f\u0440\u0438\u043c\u0435\u043d\u0438\u0442\u044c \u0441\u0438\u0433\u043d\u0430\u043b. \u0414\u043b\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u0438\u044f \u043f\u0440\u0438\u0435\u043c\u043d\u0438\u043a\u043e\u0432 \u0441\u0438\u0433\u043d\u0430\u043b\u043e\u0432 \u0432 Django \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u0443\u0435\u0442\u0441\u044f \u0434\u0435\u043a\u043e\u0440\u0430\u0442\u043e\u0440 receiver. \u0418 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0439 \u043a\u043e\u0434 \u0430\u0432\u0442\u043e\u043c\u0430\u0442\u0438\u0447\u0435\u0441\u043a\u0438 \u0431\u0443\u0434\u0435\u0442 \u0441\u043e\u0437\u0434\u0430\u0432\u0430\u0442\u044c \u043d\u0430\u0448 \u043f\u0440\u043e\u0444\u0438\u043b\u044c \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f:<\/p>\n<pre><code class=\"python\">@receiver(post_save, sender=User) def create_profile(sender, instance, created, **kwargs):    if created:        Profile.objects.create(user_id=instance)<\/code><\/pre>\n<h4>JWT-\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f<\/h4>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c \u0447\u0442\u043e\u0431\u044b \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u043e\u0432\u0430\u0442\u044c \u0441 \u0441\u0438\u0441\u0442\u0435\u043c\u043e\u0439, \u043d\u0443\u0436\u043d\u043e \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u0442\u044c\u0441\u044f. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043d\u0430 \u043f\u0440\u043e\u0435\u043a\u0442\u0435 \u0440\u0435\u0448\u0438\u043b \u0432\u044b\u0431\u0440\u0430\u0442\u044c <a href=\"https:\/\/jwt.io\/\" rel=\"noopener noreferrer nofollow\">JWT-\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044e<\/a>, \u0432\u0435\u0434\u044c \u043e\u043d\u0430 \u0441\u0447\u0438\u0442\u0430\u0435\u0442\u0441\u044f \u043e\u0434\u043d\u0438\u043c \u0438\u0437 \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u044b\u0445 \u0441\u043f\u043e\u0441\u043e\u0431\u043e\u0432 \u043f\u0435\u0440\u0435\u0434\u0430\u0447\u0438 \u0438\u043d\u0444\u043e\u0440\u043c\u0430\u0446\u0438\u0438 \u043c\u0435\u0436\u0434\u0443 \u0434\u0432\u0443\u043c\u044f \u0443\u0447\u0430\u0441\u0442\u043d\u0438\u043a\u0430\u043c\u0438.<\/p>\n<p>\u041e\u0441\u043d\u043e\u0432\u043d\u043e\u0439 \u0441\u0446\u0435\u043d\u0430\u0440\u0438\u0439 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u044f \u0432\u044b\u0433\u043b\u044f\u0434\u0438\u0442 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c: \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e access token \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0431\u0440\u0430\u0449\u0430\u0442\u044c\u0441\u044f \u043a \u043f\u0440\u0438\u0432\u0430\u0442\u043d\u044b\u043c \u0440\u0435\u0441\u0443\u0440\u0441\u0430\u043c, \u043d\u043e \u043a\u043e\u0433\u0434\u0430 \u0438\u0441\u0442\u0435\u043a\u0430\u0435\u0442 \u0441\u0440\u043e\u043a \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0434\u0430\u043d\u043d\u043e\u0433\u043e \u0442\u043e\u043a\u0435\u043d\u0430, \u043c\u044b \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c refresh token \u0438 \u043f\u043e\u043b\u0443\u0447\u0430\u0435\u043c \u043d\u043e\u0432\u0443\u044e \u043f\u0430\u0440\u0443 access token + refresh token. Refresh token \u0442\u043e\u0436\u0435 \u043c\u043e\u0436\u0435\u0442 \u0438\u0441\u0442\u0435\u0447\u044c, \u043d\u043e \u043e\u043d \u0438\u043c\u0435\u0435\u0442 \u0433\u043e\u0440\u0430\u0437\u0434\u043e \u0431\u043e\u043b\u044c\u0448\u0438\u0439 \u0441\u0440\u043e\u043a \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0438 \u0435\u0441\u043b\u0438 \u0441\u0440\u043e\u043a \u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f refresh token \u0438\u0441\u0442\u0435\u043a\u0430\u0435\u0442, \u0434\u043e\u0441\u0442\u0430\u0442\u043e\u0447\u043d\u043e \u043f\u043e\u0432\u0442\u043e\u0440\u043d\u043e \u043f\u0440\u043e\u0439\u0442\u0438 \u043f\u0440\u043e\u0446\u0435\u0434\u0443\u0440\u0443 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u0447\u0442\u043e\u0431\u044b \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c JWT.<\/p>\n<figure class=\"full-width\">\n<div><figcaption>\u0426\u0438\u043a\u043b JWT  <\/figcaption><\/div>\n<\/figure>\n<p>\u0414\u043b\u044f \u0434\u0430\u043d\u043d\u043e\u0439 \u0440\u0435\u0430\u043b\u0438\u0437\u0430\u0446\u0438\u0438 \u0443\u0436\u0435 \u0435\u0441\u0442\u044c \u0433\u043e\u0442\u043e\u0432\u0430\u044f <a href=\"https:\/\/django-rest-framework-simplejwt.readthedocs.io\/en\/latest\/\" rel=\"noopener noreferrer nofollow\">\u0431\u0438\u0431\u043b\u0438\u043e\u0442\u0435\u043a\u0430 Simple JWT<\/a>. \u041e\u043d\u0430 \u043e\u0442\u043b\u0438\u0447\u043d\u043e \u0441\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0441 \u0433\u0435\u043d\u0435\u0440\u0430\u0446\u0438\u0435\u0439 access \u0438 refresh \u0442\u043e\u043a\u0435\u043d\u043e\u0432, \u043d\u043e \u0434\u043b\u044f \u043e\u0431\u0435\u0441\u043f\u0435\u0447\u0435\u043d\u0438\u044f \u0431\u0435\u0437\u043e\u043f\u0430\u0441\u043d\u043e\u0441\u0442\u0438 \u043e\u0442 CSRF-\u0430\u0442\u0430\u043a \u0438 XSS-\u0430\u0442\u0430\u043a \u044f \u0440\u0435\u0448\u0438\u043b \u043f\u0435\u0440\u0435\u0434\u0430\u0432\u0430\u0442\u044c refresh \u0442\u043e\u043a\u0435\u043d \u0432 HttpOnly Cookie. \u0414\u043b\u044f \u044d\u0442\u043e\u0433\u043e \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u0431\u0430\u0437\u043e\u0432\u044b\u0435 \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 JWT, \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 response cookie. \u041a\u043e\u0434 \u0434\u043e\u0431\u0430\u0432\u043b\u0435\u043d\u0438\u044f refresh \u0442\u043e\u043a\u0435\u043d\u0430 \u0432 cookie:<\/p>\n<pre><code class=\"python\">response.set_cookie(    key=settings.SIMPLE_JWT['AUTH_COOKIE_REFRESH'],    value=token,    expires=settings.SIMPLE_JWT['REFRESH_TOKEN_LIFETIME'],    secure=settings.SIMPLE_JWT['AUTH_COOKIE_SECURE'],    httponly=settings.SIMPLE_JWT['AUTH_COOKIE_HTTP_ONLY'],    samesite=settings.SIMPLE_JWT['AUTH_COOKIE_SAMESITE'] )<\/code><\/pre>\n<p>\u041d\u0435 \u043e\u0431\u043e\u0448\u043b\u043e\u0441\u044c \u0438 \u0431\u0435\u0437 \u0442\u0440\u0443\u0434\u043d\u043e\u0441\u0442\u0435\u0439. \u0411\u043e\u043b\u044c\u0448\u0435 \u0432\u0441\u0435\u0433\u043e \u0432\u0440\u0435\u043c\u0435\u043d\u0438 \u0437\u0430\u043d\u044f\u043b \u0432\u043e\u043f\u0440\u043e\u0441, \u043f\u043e\u0447\u0435\u043c\u0443 \u0442\u043e\u043a\u0435\u043d \u043d\u0435 \u0441\u043e\u0445\u0440\u0430\u043d\u044f\u0435\u0442\u0441\u044f \u0434\u043e\u043b\u0436\u043d\u044b\u043c \u043e\u0431\u0440\u0430\u0437\u043e\u043c \u0438 \u043f\u0440\u043e\u0441\u0442\u043e \u0432\u0435\u0441\u0438\u0442 \u0432 response? \u0412 \u0434\u0430\u043d\u043d\u043e\u043c \u0441\u043b\u0443\u0447\u0430\u0435 \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c \u0444\u0430\u0439\u043b settings.py \u0438 \u0434\u043e\u0431\u0430\u0432\u0438\u0442\u044c \u0432 \u043d\u0435\u0433\u043e \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440<\/p>\n<p><code>CORS_ALLOW_CREDENTIALS = True<\/code><\/p>\n<p>\u0418 \u043d\u0435 \u0437\u0430\u0431\u044b\u0442\u044c \u0438\u0437\u043c\u0435\u043d\u0438\u0442\u044c \u043d\u0430\u0441\u0442\u0440\u043e\u0439\u043a\u0438 <code>SIMPLE_JWT<\/code> \u0432 \u044d\u0442\u043e\u043c \u0436\u0435 \u0444\u0430\u0439\u043b\u0435:<\/p>\n<p><code>'AUTH_COOKIE_SECURE': False<\/code> &#8212; \u043d\u0443\u0436\u043d\u043e, \u043f\u0440\u0438 \u043f\u043e\u0434\u043a\u043b\u044e\u0447\u0435\u043d\u0438\u0438 https<\/p>\n<p><code>'AUTH_COOKIE_HTTP_ONLY' : True<\/code> &#8212; \u0424\u043b\u0430\u0433 HttpOnly\u00a0<\/p>\n<p><code>'AUTH_COOKIE_SAMESITE': 'Lax'<\/code> &#8212; \u0444\u0430\u0439\u043b\u044b Cookie \u043f\u043e\u043b\u043d\u043e\u0441\u0442\u044c\u044e \u0431\u043b\u043e\u043a\u0438\u0440\u0443\u044e\u0442\u0441\u044f \u0434\u043b\u044f \u043c\u0435\u0436\u0441\u0430\u0439\u0442\u043e\u0432\u044b\u0445 \u0437\u0430\u043f\u0440\u043e\u0441\u043e\u0432<\/p>\n<p>\u0422\u0430\u043a\u0436\u0435, \u0441\u043b\u0435\u0434\u0443\u0435\u0442 \u043f\u043e\u043c\u043d\u0438\u0442\u044c, \u0447\u0442\u043e \u043d\u0430 \u0441\u0442\u043e\u0440\u043e\u043d\u0435 Frontend \u0437\u0430\u043f\u0440\u043e\u0441 \u0434\u043e\u043b\u0436\u0435\u043d \u0431\u044b\u0442\u044c \u0441 \u043f\u0430\u0440\u0430\u043c\u0435\u0442\u0440\u043e\u043c <code>withCredentials: true<\/code><\/p>\n<h4>\u041e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a NLP (GPT)<\/h4>\n<p>\u0422\u0435\u043f\u0435\u0440\u044c, \u043a\u043e\u0433\u0434\u0430 \u043c\u044b \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043b\u0438\u0441\u044c, \u043c\u044b \u043c\u043e\u0436\u0435\u043c \u043e\u0431\u0440\u0430\u0442\u0438\u0442\u044c\u0441\u044f \u043a \u043c\u043e\u0434\u0435\u043b\u0438 \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u0442\u044c \u043e\u0442 \u043d\u0435\u0451 \u043e\u0442\u0432\u0435\u0442. \u041e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u0438\u0434\u0435\u0442 \u043e\u0431\u044b\u0447\u043d\u044b\u043c \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0435\u043c, \u0430 \u0447\u0442\u043e \u0435\u0441\u0442\u044c \u0443 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f? \u041f\u0440\u0430\u0432\u0438\u043b\u044c\u043d\u043e, \u0441\u0432\u043e\u0439 \u0434\u0438\u0430\u043b\u043e\u0433, \u0432 \u0440\u0430\u043c\u043a\u0430\u0445 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043e\u043d\u043e \u0438\u0434\u0435\u0442. \u041e\u043f\u0438\u0440\u0430\u044f\u0441\u044c \u043d\u0430 \u044d\u0442\u0443 \u043b\u043e\u0433\u0438\u043a\u0443, \u043c\u043e\u0436\u043d\u043e \u043e\u0431\u0449\u0430\u0442\u044c\u0441\u044f \u0441 nlp \u0441 \u0443\u0447\u0451\u0442\u043e\u043c \u043a\u043e\u043d\u0442\u0435\u043a\u0441\u0442\u0430 \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0445 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u041f\u043e\u0436\u0430\u043b\u0443\u0439, \u043d\u0430\u0441\u0442\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u043d\u0430\u043f\u0438\u0441\u0430\u0442\u044c \u0437\u0430\u043f\u0440\u043e\u0441. \u0422\u0435\u043a\u0441\u0442 \u043d\u0430\u0448\u0435\u0433\u043e \u0437\u0430\u043f\u0440\u043e\u0441\u0430 \u0431\u0443\u0434\u0435\u0442 \u0442\u0430\u043a\u0438\u043c \u201cWrite bubble sort in Python\u201d, \u0432\u0435\u0434\u044c \u043a\u0442\u043e \u043d\u0435 \u043d\u0430\u0447\u0438\u043d\u0430\u043b \u043f\u0440\u043e\u0433\u0440\u0430\u043c\u043c\u0438\u0440\u043e\u0432\u0430\u043d\u0438\u0435 \u0441 \u043d\u0430\u043f\u0438\u0441\u0430\u043d\u0438\u0435\u043c \u0441\u043e\u0440\u0442\u0438\u0440\u043e\u0432\u043a\u0438 \u043f\u0443\u0437\u044b\u0440\u044c\u043a\u043e\u043c :). \u041a\u0430\u043a \u0442\u043e\u043b\u044c\u043a\u043e \u043d\u0430\u0436\u0430\u043b\u0438 \u043d\u0430 \u043a\u043d\u043e\u043f\u043a\u0443 Enter, \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u0442\u0441\u044f \u0437\u0430\u043f\u0440\u043e\u0441 \u043a \u043d\u0430\u0448\u0435\u043c\u0443 API, \u043e\u0442 \u043a\u043e\u0442\u043e\u0440\u043e\u0433\u043e \u043c\u044b \u0438 \u043f\u043e\u043b\u0443\u0447\u0438\u043c \u043e\u0442\u0432\u0435\u0442. \u041e\u0442\u0432\u0435\u0442 \u0437\u0430\u043f\u0438\u0441\u044b\u0432\u0430\u0435\u0442\u0441\u044f \u043f\u0440\u0438 \u043f\u043e\u043c\u043e\u0449\u0438 \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>take_answer()<\/code>, \u043a \u043a\u043e\u0442\u043e\u0440\u043e\u0439 \u043f\u0435\u0440\u0435\u0434\u0430\u0435\u043c \u0437\u0430\u043f\u0440\u043e\u0441:<\/p>\n<pre><code class=\"python\">answer_text = take_answer(validated_data['message_text'], validated_data['dialog_id']) message = Message.objects.create(answer_text=answer_text, **validated_data)<\/code><\/pre>\n<p>OpenAI \u043f\u0440\u0435\u0434\u043e\u0441\u0442\u0430\u0432\u043b\u044f\u0435\u0442 \u0434\u043e\u0441\u0442\u0443\u043f \u043a \u0441\u0432\u043e\u0435\u043c\u0443 API (\u0441\u0441\u044b\u043b\u043a\u0430 <a href=\"https:\/\/platform.openai.com\/overview\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/platform.openai.com\/overview<\/u><\/a>). \u0412 \u043f\u0440\u043e\u0435\u043a\u0442\u043a\u0435 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u0435 \u0441 API \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u043d\u043e \u043f\u043e \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0435\u043c\u0443 \u043f\u0440\u0438\u043d\u0446\u0438\u043f\u0443:<\/p>\n<figure class=\"full-width\">\n<div><figcaption>\u0414\u0438\u0430\u0433\u0440\u0430\u043c\u043c\u0430 \u043f\u043e\u0441\u043b\u0435\u0434\u043e\u0432\u0430\u0442\u0435\u043b\u044c\u043d\u043e\u0441\u0442\u0438 \u0432\u0437\u0430\u0438\u043c\u043e\u0434\u0435\u0439\u0441\u0442\u0432\u0438\u044f \u0441\u043b\u043e\u0435\u0432 \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u044f<\/figcaption><\/div>\n<\/figure>\n<p>\u041e\u0431\u0440\u0430\u0449\u0435\u043d\u0438\u0435 \u043a OpenAI \u0438\u0434\u0435\u0442 \u0441 \u043f\u043e\u043c\u043e\u0449\u044c\u044e \u0444\u0443\u043d\u043a\u0446\u0438\u0438 <code>ChatCompletion.create()<\/code>, \u043f\u0440\u0435\u0434\u043b\u0430\u0433\u0430\u044e \u0435\u0451 \u0434\u0435\u0442\u0430\u043b\u044c\u043d\u0435\u0435 \u0438\u0437\u0443\u0447\u0438\u0442\u044c:<\/p>\n<pre><code class=\"python\"> previous_messages = Message.objects.filter(dialog_id=dialog_id).order_by('-id')[:5]     messages = [         {\"role\": \"system\", \"content\": \"You are a helpful assistant.\"}     ]      for message in previous_messages:         user_message = {\"role\": \"user\", \"content\": message.message_text}         ai_message = {\"role\": \"assistant\", \"content\": message.answer_text}         messages.extend([user_message, ai_message])      user_prompt = {\"role\": \"user\", \"content\": prompt}     messages.append(user_prompt)      response = openai.ChatCompletion.create(         model=\"gpt-4\",         messages=messages     )<\/code><\/pre>\n<p>\u041c\u044b \u0431\u0435\u0440\u0435\u043c \u043f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0438\u0435 \u0437\u0430\u043f\u0440\u043e\u0441\u044b \u0438 \u043e\u0442\u0432\u0435\u0442\u044b \u0432 \u043a\u043e\u043b\u0438\u0447\u0435\u0441\u0442\u0432\u0435 5 \u0448\u0442\u0443\u043a \u0438 \u043e\u0442\u043f\u0440\u0430\u0432\u043b\u044f\u0435\u043c OpenAI \u0432 ChatCompletion ( \u0441\u0441\u044b\u043b\u043a\u0430 \u00a0 <a href=\"https:\/\/platform.openai.com\/docs\/api-reference\/completions\/create\" rel=\"noopener noreferrer nofollow\"><u>https:\/\/platform.openai.com\/docs\/api-reference\/completions\/create<\/u><\/a> ), \u00a0\u043c\u043e\u0434\u0435\u043b\u044c \u0440\u0435\u0448\u0438\u043b \u043f\u043e\u043a\u0430 \u043d\u0435 \u043c\u0435\u043d\u044f\u0442\u044c \u0431\u0435\u0437 \u043e\u0441\u043e\u0431\u044b\u0445 \u043d\u0443\u0436\u0434. \u0422\u0435\u043f\u0435\u0440\u044c \u043d\u0430\u0441\u0442\u0430\u043b\u043e \u0432\u0440\u0435\u043c\u044f \u0440\u0430\u0441\u0441\u043c\u043e\u0442\u0440\u0435\u0442\u044c response, \u043a\u043e\u0442\u043e\u0440\u044b\u0439 \u0443\u0436\u0435 \u0434\u043e\u043b\u0436\u0435\u043d \u043f\u0440\u0438\u0434\u0442\u0438:<\/p>\n<pre><code class=\"json\">{   \"id\": 1,   \"message_text\": \"Write bubble sort in Python\",   \"answer_text\": \"Certainly! Here's an example of the bubble sort algorithm implemented in Python:\\n\\n```python\\ndef bubble_sort(arr):\\n    n = len(arr)\\n    \\n    for i in range(n):\\n        # Last i elements are already in place\\n        for j in range(0, n-i-1):\\n            # Swap if the element found is greater than the next element\\n            if arr[j] > arr[j+1]:\\n                arr[j], arr[j+1] = arr[j+1], arr[j]\\n\\n# Example usage\\narr = [64, 34, 25, 12, 22, 11, 90]\\nbubble_sort(arr)\\nprint(\\\"Sorted array: \\\", arr)\\n```\\n\\nThis implementation sorts the input list in ascending order using the bubble sort algorithm.\",   \"dialog_id\": 1 } <\/code><\/pre>\n<p>\u0418 \u043a\u0430\u043a \u0436\u0435 \u044f \u043e\u0431\u0440\u0430\u0434\u043e\u0432\u0430\u043b\u0441\u044f, \u043a\u043e\u0433\u0434\u0430 \u043f\u043e\u043d\u044f\u043b, \u0447\u0442\u043e \u0434\u0430\u043d\u043d\u044b\u0439 response \u043c\u043e\u0436\u043d\u043e \u043f\u0440\u0435\u043e\u0431\u0440\u0430\u0437\u043e\u0432\u0430\u0442\u044c \u0432  <a href=\"https:\/\/www.markdownguide.org\/\" rel=\"noopener noreferrer nofollow\">Markdown<\/a> \u0434\u043b\u044f \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f. \u0418\u043d\u0430\u0447\u0435 \u044d\u0442\u043e \u0431\u044b\u043b\u043e \u0431\u044b \u0441\u043e\u0432\u0435\u0440\u0448\u0435\u043d\u043d\u043e \u043d\u0435\u0447\u0438\u0442\u0430\u0435\u043c\u043e \u0438 \u043f\u0440\u0438\u0448\u043b\u043e\u0441\u044c \u0431\u044b \u043f\u0440\u0438\u0434\u0443\u043c\u0430\u0442\u044c \u0438\u043b\u0438 \u0438\u0441\u043a\u0430\u0442\u044c \u0440\u0435\u0448\u0435\u043d\u0438\u0435, \u043a\u0430\u043a \u043e\u0442\u043e\u0431\u0440\u0430\u0437\u0438\u0442\u044c \u043e\u0442\u0432\u0435\u0442 \u043d\u0430 \u044d\u043a\u0440\u0430\u043d\u0435.   <\/p>\n<h3>Frontend<\/h3>\n<p>\u0414\u0430\u043b\u0435\u0435 \u044f \u0440\u0430\u0441\u0441\u043a\u0430\u0436\u0443 \u043f\u0440\u043e \u0441\u0432\u043e\u044e \u0447\u0430\u0441\u0442\u044c (<a href=\"https:\/\/www.linkedin.com\/in\/nikita-bragin-82296b29\/\" rel=\"noopener noreferrer nofollow\">\u041d\u0438\u043a\u0438\u0442\u0430<\/a>). \u042f \u0440\u0430\u0437\u0431\u0438\u043b \u043f\u0440\u0438\u043b\u043e\u0436\u0435\u043d\u0438\u0435 \u043d\u0430 \u0441\u043b\u0435\u0434\u0443\u044e\u0449\u0438\u0435 Redux \u043c\u043e\u0434\u0443\u043b\u0438:<\/p>\n<ul>\n<li>\n<p>Auth (\u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f, \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f, \u0432\u043e\u0441\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u0435\u043d\u0438\u0435 \u043f\u0430\u0440\u043e\u043b\u044f);<\/p>\n<\/li>\n<li>\n<p>Chat (\u0440\u0430\u0431\u043e\u0442\u0430 \u0441 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438, \u0434\u0438\u0430\u043b\u043e\u0433\u0430\u043c\u0438)<\/p>\n<\/li>\n<li>\n<p>User (\u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f username, emai, loading, error)<\/p>\n<\/li>\n<li>\n<p>Profile (\u0434\u0430\u043d\u043d\u044b\u0435 \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0442\u0430\u043a\u0438\u0435 \u043a\u0430\u043a \u0418\u043c\u044f, \u0424\u0430\u043c\u0438\u043b\u044f, \u0424\u043e\u0442\u043e).<\/p>\n<\/li>\n<\/ul>\n<p>\u0414\u0430\u043b\u0435\u0435 \u044f \u043e\u0441\u0442\u0430\u043d\u043e\u0432\u043b\u044e\u0441\u044c \u043f\u043e\u0434\u0440\u043e\u0431\u043d\u0435\u0435 \u043d\u0430 \u0442\u043e\u043c \u043a\u0430\u043a \u043e\u0440\u0433\u0430\u043d\u0438\u0437\u043e\u0432\u0430\u043d \u0440\u043e\u0443\u0442\u0438\u043d\u0433, \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u044f, \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u044f \u0438 \u0447\u0430\u0442.<\/p>\n<h4>\u0420\u043e\u0443\u0442\u0438\u043d\u0433<\/h4>\n<p>\u0420\u043e\u0443\u0442\u0438\u043d\u0433 \u044f \u0434\u043e\u0431\u0430\u0432\u0438\u043b \u0434\u043b\u044f \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u0441\u0442\u0440\u0430\u043d\u0438\u0446 \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u0430\u0446\u0438\u0438, \u0440\u0435\u0433\u0438\u0441\u0442\u0440\u0430\u0446\u0438\u0438, \u0447\u0430\u0442\u0430, \u0441\u0442\u0440\u0430\u043d\u0438\u0446\u044b \u043d\u0430\u0441\u0442\u0440\u043e\u0435\u043a, \u043f\u0440\u043e\u0444\u0438\u043b\u044f. \u0414\u043b\u044f \u0447\u0430\u0442\u0430 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u043d\u0438\u0435 \u0440\u043e\u0443\u0442\u0438\u043d\u0433\u0430 \u043e\u0447\u0435\u043d\u044c \u0430\u043a\u0442\u0443\u0430\u043b\u044c\u043d\u043e, \u043f\u043e\u0437\u0432\u043e\u043b\u044f\u0435\u0442 \u0438\u0441\u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u044c \u0441\u0441\u044b\u043b\u043a\u0443 \u0434\u043b\u044f \u043e\u0442\u043a\u0440\u044b\u0442\u0438\u044f \u043e\u043f\u0440\u0435\u0434\u0435\u043b\u0435\u043d\u043d\u043e\u0433\u043e \u0441\u043e\u0441\u0442\u043e\u044f\u043d\u0438\u044f. <\/p>\n<p>\u0420\u043e\u0443\u0442\u0438\u043d\u0433 \u044f \u0440\u0430\u0437\u0431\u0438\u043b \u043d\u0430 \u0434\u0432\u0430 \u0444\u0430\u0439\u043b\u0430: routes \u0438 index. \u0412 routes.js \u044f \u0441\u043e\u0437\u0434\u0430\u043b \u043d\u0435\u0441\u043a\u043e\u043b\u044c\u043a\u043e \u0441\u043f\u0438\u0441\u043a\u043e\u0432 \u0440\u043e\u0443\u0442\u043e\u0432, \u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043f\u0440\u0435\u0434\u043f\u043e\u043b\u0430\u0433\u0430\u044e\u0442 \u0440\u0430\u0437\u043b\u0438\u0447\u043d\u044b\u0435 \u0443\u0440\u043e\u0432\u043d\u0438 \u0434\u043e\u0441\u0442\u0443\u043f\u0430. \u041d\u0430\u043f\u0440\u0438\u043c\u0440\u0435, \u0434\u043b\u044f \u0430\u0432\u0442\u043e\u0440\u0438\u0437\u043e\u0432\u0430\u043d\u043d\u043e\u0433\u043e \u043f\u043e\u043b\u044c\u0437\u043e\u0432\u0430\u0442\u0435\u043b\u044f \u0438<\/p>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-350533","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/350533","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=350533"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/350533\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=350533"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=350533"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=350533"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}