Compare commits
No commits in common. "b224ef29d33a1df9ca79365843c4cddf21fd67bf" and "41b3a250a7524f0327fa1887f0f8d7ddd6ec3bde" have entirely different histories.
b224ef29d3
...
41b3a250a7
@ -1,14 +1,12 @@
|
|||||||
import asyncio
|
|
||||||
import io
|
import io
|
||||||
import os
|
import os
|
||||||
|
import asyncio
|
||||||
import traceback
|
import traceback
|
||||||
from typing import Literal
|
|
||||||
|
|
||||||
from asgiref.sync import sync_to_async
|
from asgiref.sync import sync_to_async
|
||||||
from langchain.agents import create_agent
|
from langchain.agents import create_agent
|
||||||
from langchain_openai import ChatOpenAI
|
from langchain_openai import ChatOpenAI
|
||||||
from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
|
from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
|
||||||
from pydantic import BaseModel
|
|
||||||
from pypdf import PdfReader
|
from pypdf import PdfReader
|
||||||
from telegram import (
|
from telegram import (
|
||||||
InlineKeyboardButton,
|
InlineKeyboardButton,
|
||||||
@ -25,6 +23,8 @@ from telegram.ext import (
|
|||||||
filters,
|
filters,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from typing import Literal
|
||||||
from vacancies.conf.settings import DB_URI
|
from vacancies.conf.settings import DB_URI
|
||||||
from vacancies.main.models import Customer, CustomerCV, JobTitle
|
from vacancies.main.models import Customer, CustomerCV, JobTitle
|
||||||
from vacancies.main.recommendations import get_next_vacancy
|
from vacancies.main.recommendations import get_next_vacancy
|
||||||
@ -59,7 +59,7 @@ async def start(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|||||||
|
|
||||||
|
|
||||||
async def next_vacancy(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
async def next_vacancy(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
await context.bot.send_message(update.effective_chat.id, "⏳ Обрабатываю твой запрос. Пожалуйста, подождите...")
|
await context.bot.send_message(update.effective_chat.id, "📝 Обрабатываю твой запрос. Пожалуйста, подождите...")
|
||||||
|
|
||||||
customer_cv = await CustomerCV.objects.filter(customer__telegram_id=update.effective_user.id).afirst()
|
customer_cv = await CustomerCV.objects.filter(customer__telegram_id=update.effective_user.id).afirst()
|
||||||
if not customer_cv:
|
if not customer_cv:
|
||||||
@ -75,8 +75,7 @@ async def next_vacancy(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|||||||
|
|
||||||
await context.bot.send_message(
|
await context.bot.send_message(
|
||||||
chat_id=update.effective_chat.id,
|
chat_id=update.effective_chat.id,
|
||||||
parse_mode="Markdown",
|
text=vacancy.content,
|
||||||
text=vacancy.get_formatted_response(),
|
|
||||||
reply_markup=InlineKeyboardMarkup([[
|
reply_markup=InlineKeyboardMarkup([[
|
||||||
InlineKeyboardButton("Откликнуться", url=vacancy.link),
|
InlineKeyboardButton("Откликнуться", url=vacancy.link),
|
||||||
]]),
|
]]),
|
||||||
@ -92,7 +91,7 @@ async def prompt(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
|||||||
checkpointer=checkpointer,
|
checkpointer=checkpointer,
|
||||||
)
|
)
|
||||||
|
|
||||||
message = await context.bot.send_message(update.effective_chat.id, "⏳ Обрабатываю твой запрос. Пожалуйста, подождите...")
|
message = await context.bot.send_message(update.effective_chat.id, "📝 Обрабатываю твой запрос. Пожалуйста, подождите...")
|
||||||
|
|
||||||
response = await agent.ainvoke(
|
response = await agent.ainvoke(
|
||||||
input={"messages": [{"role": "user", "content": f'user_id = {update.effective_user.id}\n{update.message.text}'}]},
|
input={"messages": [{"role": "user", "content": f'user_id = {update.effective_user.id}\n{update.message.text}'}]},
|
||||||
@ -108,7 +107,7 @@ async def error_handler(update: object, context: ContextTypes.DEFAULT_TYPE) -> N
|
|||||||
|
|
||||||
|
|
||||||
async def handle_document(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
async def handle_document(update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
message = await context.bot.send_message(update.effective_chat.id, "⏳ Обрабатываю твой запрос. Пожалуйста, подождите...")
|
message = await context.bot.send_message(update.effective_chat.id, "📝 Обрабатываю твой запрос. Пожалуйста, подождите...")
|
||||||
|
|
||||||
if not update.message.document:
|
if not update.message.document:
|
||||||
await context.bot.send_message(chat_id=update.effective_chat.id, text="Не удалось прочитать информацию из файла! Попробуйте другой формат.")
|
await context.bot.send_message(chat_id=update.effective_chat.id, text="Не удалось прочитать информацию из файла! Попробуйте другой формат.")
|
||||||
|
|||||||
@ -1,15 +1,14 @@
|
|||||||
from datetime import timedelta
|
|
||||||
from itertools import batched
|
from itertools import batched
|
||||||
|
from datetime import timedelta
|
||||||
|
from django.utils import timezone
|
||||||
|
from pydantic import BaseModel
|
||||||
from typing import Literal
|
from typing import Literal
|
||||||
|
from vacancies.main.models import Vacancy, JobTitle
|
||||||
|
from langchain_openai import ChatOpenAI
|
||||||
|
|
||||||
import clickhouse_connect
|
import clickhouse_connect
|
||||||
from django.conf import settings
|
|
||||||
from django.core.management import BaseCommand
|
from django.core.management import BaseCommand
|
||||||
from django.utils import timezone
|
from django.conf import settings
|
||||||
from langchain_openai import ChatOpenAI
|
|
||||||
from pydantic import BaseModel
|
|
||||||
|
|
||||||
from vacancies.main.models import JobTitle, Vacancy
|
|
||||||
|
|
||||||
query = """
|
query = """
|
||||||
SELECT DISTINCT ON (message) id, chat_username, telegram_id, message, timestamp
|
SELECT DISTINCT ON (message) id, chat_username, telegram_id, message, timestamp
|
||||||
@ -43,8 +42,6 @@ class Command(BaseCommand):
|
|||||||
job_title: Literal[tuple(job_titles)]
|
job_title: Literal[tuple(job_titles)]
|
||||||
min_salary_rub: int | None
|
min_salary_rub: int | None
|
||||||
max_salary_rub: int | None
|
max_salary_rub: int | None
|
||||||
company_name: str
|
|
||||||
requirements: str
|
|
||||||
|
|
||||||
openai_client = ChatOpenAI(model_name="gpt-5-mini", temperature=0, seed=42, top_p=1)
|
openai_client = ChatOpenAI(model_name="gpt-5-mini", temperature=0, seed=42, top_p=1)
|
||||||
structured_llm = openai_client.with_structured_output(Structure)
|
structured_llm = openai_client.with_structured_output(Structure)
|
||||||
@ -79,8 +76,6 @@ class Command(BaseCommand):
|
|||||||
job_title_id=job_title_map[response.job_title],
|
job_title_id=job_title_map[response.job_title],
|
||||||
min_salary_rub=response.min_salary_rub,
|
min_salary_rub=response.min_salary_rub,
|
||||||
max_salary_rub=response.max_salary_rub,
|
max_salary_rub=response.max_salary_rub,
|
||||||
company_name=response.company_name,
|
|
||||||
requirements=response.requirements,
|
|
||||||
content=message,
|
content=message,
|
||||||
timestamp=timezone.make_aware(timestamp),
|
timestamp=timezone.make_aware(timestamp),
|
||||||
link=f"https://t.me/{chat_username}/{telegram_id}",
|
link=f"https://t.me/{chat_username}/{telegram_id}",
|
||||||
|
|||||||
@ -1,11 +1,10 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
|
|
||||||
from django.core.management import BaseCommand
|
from django.core.management import BaseCommand
|
||||||
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
|
|
||||||
|
|
||||||
from vacancies.main.bot import application
|
|
||||||
from vacancies.main.models import CustomerCV
|
from vacancies.main.models import CustomerCV
|
||||||
|
from vacancies.main.bot import application
|
||||||
from vacancies.main.recommendations import get_next_vacancy
|
from vacancies.main.recommendations import get_next_vacancy
|
||||||
|
from telegram import InlineKeyboardButton, InlineKeyboardMarkup
|
||||||
|
|
||||||
|
|
||||||
class Command(BaseCommand):
|
class Command(BaseCommand):
|
||||||
@ -19,8 +18,7 @@ class Command(BaseCommand):
|
|||||||
if vacancy := get_next_vacancy(customer_cv):
|
if vacancy := get_next_vacancy(customer_cv):
|
||||||
await application.bot.send_message(
|
await application.bot.send_message(
|
||||||
chat_id=customer_cv.customer.chat_id,
|
chat_id=customer_cv.customer.chat_id,
|
||||||
text=vacancy.get_formatted_response(),
|
text=vacancy.content,
|
||||||
parse_mode="Markdown",
|
|
||||||
reply_markup=InlineKeyboardMarkup([[
|
reply_markup=InlineKeyboardMarkup([[
|
||||||
InlineKeyboardButton("Откликнуться", url=vacancy.link),
|
InlineKeyboardButton("Откликнуться", url=vacancy.link),
|
||||||
]]),
|
]]),
|
||||||
|
|||||||
@ -1,25 +0,0 @@
|
|||||||
# Generated by Django 5.2.7 on 2025-11-09 19:56
|
|
||||||
|
|
||||||
from django.db import migrations, models
|
|
||||||
|
|
||||||
|
|
||||||
class Migration(migrations.Migration):
|
|
||||||
|
|
||||||
dependencies = [
|
|
||||||
('main', '0011_remove_customercv_job_title_customercv_job_titles_and_more'),
|
|
||||||
]
|
|
||||||
|
|
||||||
operations = [
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='vacancy',
|
|
||||||
name='company_name',
|
|
||||||
field=models.CharField(default='test', max_length=255),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
migrations.AddField(
|
|
||||||
model_name='vacancy',
|
|
||||||
name='requirements',
|
|
||||||
field=models.TextField(default='test'),
|
|
||||||
preserve_default=False,
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@ -45,8 +45,6 @@ class Vacancy(models.Model):
|
|||||||
external_id = models.CharField(max_length=255, unique=True)
|
external_id = models.CharField(max_length=255, unique=True)
|
||||||
min_salary_rub = models.PositiveIntegerField(null=True, blank=True, default=None)
|
min_salary_rub = models.PositiveIntegerField(null=True, blank=True, default=None)
|
||||||
max_salary_rub = models.PositiveIntegerField(null=True, blank=True, default=None)
|
max_salary_rub = models.PositiveIntegerField(null=True, blank=True, default=None)
|
||||||
company_name = models.CharField(max_length=255)
|
|
||||||
requirements = models.TextField()
|
|
||||||
content = models.TextField()
|
content = models.TextField()
|
||||||
timestamp = models.DateTimeField()
|
timestamp = models.DateTimeField()
|
||||||
link = models.URLField()
|
link = models.URLField()
|
||||||
@ -54,25 +52,6 @@ class Vacancy(models.Model):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.job_title.title
|
return self.job_title.title
|
||||||
|
|
||||||
def get_formatted_response(self):
|
|
||||||
response = f"""
|
|
||||||
💼 **Вакансия**: {self.job_title}
|
|
||||||
\n🏢 **Компания**: {self.company_name}
|
|
||||||
\n📝 **Требования**: {self.requirements}
|
|
||||||
"""
|
|
||||||
if self.min_salary_rub:
|
|
||||||
if self.max_salary_rub:
|
|
||||||
response += f"\n💸 **ЗП**: от {self.min_salary_rub} т.р."
|
|
||||||
else:
|
|
||||||
response += f"\n💸 **ЗП**: {self.min_salary_rub} т.р. - {self.max_salary_rub} т.р."
|
|
||||||
elif self.max_salary_rub:
|
|
||||||
response += f"\n💸 **ЗП**: до {self.max_salary_rub} т.р."
|
|
||||||
|
|
||||||
return response
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
verbose_name_plural = 'Vacancies'
|
|
||||||
|
|
||||||
|
|
||||||
class RecommendedVacancy(models.Model):
|
class RecommendedVacancy(models.Model):
|
||||||
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name="recommended_vacancies")
|
customer = models.ForeignKey(Customer, on_delete=models.CASCADE, related_name="recommended_vacancies")
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
from django.db.models import Q
|
|
||||||
|
|
||||||
from vacancies.main.models import Vacancy
|
from vacancies.main.models import Vacancy
|
||||||
|
from django.db.models import Q
|
||||||
|
|
||||||
|
|
||||||
def get_next_vacancy(customer_cv):
|
def get_next_vacancy(customer_cv):
|
||||||
@ -8,7 +7,7 @@ def get_next_vacancy(customer_cv):
|
|||||||
~Q(id__in=customer_cv.customer.recommended_vacancies.values_list("vacancy_id", flat=True)),
|
~Q(id__in=customer_cv.customer.recommended_vacancies.values_list("vacancy_id", flat=True)),
|
||||||
Q(min_salary_rub__isnull=True) | Q(min_salary_rub__gt=customer_cv.min_salary_rub),
|
Q(min_salary_rub__isnull=True) | Q(min_salary_rub__gt=customer_cv.min_salary_rub),
|
||||||
job_title__title__in=customer_cv.job_titles.values_list("title", flat=True),
|
job_title__title__in=customer_cv.job_titles.values_list("title", flat=True),
|
||||||
).order_by("-timestamp").first()
|
).first()
|
||||||
if vacancy:
|
if vacancy:
|
||||||
customer_cv.customer.recommended_vacancies.create(vacancy=vacancy)
|
customer_cv.customer.recommended_vacancies.create(vacancy=vacancy)
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user