Files
New-planet-ai-agent/agents/recommendation_engine.py

131 lines
4.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""Рекомендательная система для заданий (MVP-1)."""
from typing import Dict, List, Optional
import numpy as np
from sklearn.feature_extraction.text import TfidfVectorizer
from sklearn.metrics.pairwise import cosine_similarity
class RecommendationEngine:
"""Простая рекомендательная система на основе TF-IDF."""
def __init__(self):
self.vectorizer = TfidfVectorizer(max_features=100, stop_words="english")
self.task_vectors = None
self.tasks = []
def fit(self, tasks: List[Dict]):
"""
Обучить модель на исторических данных.
Args:
tasks: Список заданий с полями: title, description, category, completed
"""
self.tasks = tasks
# Создаем текстовые описания для векторизации
texts = []
for task in tasks:
text = f"{task.get('title', '')} {task.get('description', '')} {task.get('category', '')}"
texts.append(text)
if texts:
self.task_vectors = self.vectorizer.fit_transform(texts)
def recommend(
self,
preferences: List[str],
completed_tasks: Optional[List[str]] = None,
top_k: int = 5,
) -> List[Dict]:
"""
Рекомендовать задания на основе предпочтений.
Args:
preferences: Предпочтения пользователя
completed_tasks: Список уже выполненных заданий (для исключения)
top_k: Количество рекомендаций
Returns:
Список рекомендованных заданий
"""
if not self.tasks or self.task_vectors is None:
return []
# Векторизуем предпочтения
preferences_text = " ".join(preferences)
preference_vector = self.vectorizer.transform([preferences_text])
# Вычисляем схожесть
similarities = cosine_similarity(preference_vector, self.task_vectors)[0]
# Исключаем уже выполненные задания
if completed_tasks:
for i, task in enumerate(self.tasks):
if task.get("title") in completed_tasks or task.get("id") in completed_tasks:
similarities[i] = -1
# Получаем топ-K индексов
top_indices = np.argsort(similarities)[::-1][:top_k]
top_indices = [idx for idx in top_indices if similarities[idx] > 0]
return [self.tasks[idx] for idx in top_indices]
def recommend_by_category(
self,
category: str,
completed_tasks: Optional[List[str]] = None,
top_k: int = 3,
) -> List[Dict]:
"""
Рекомендовать задания по категории.
Args:
category: Категория заданий
completed_tasks: Выполненные задания
top_k: Количество рекомендаций
Returns:
Список рекомендованных заданий
"""
category_tasks = [task for task in self.tasks if task.get("category") == category]
if completed_tasks:
category_tasks = [
task
for task in category_tasks
if task.get("title") not in completed_tasks
and task.get("id") not in completed_tasks
]
# Сортируем по популярности (можно добавить поле rating)
return category_tasks[:top_k]
def get_popular_tasks(self, top_k: int = 10) -> List[Dict]:
"""
Получить популярные задания.
Args:
top_k: Количество заданий
Returns:
Список популярных заданий
"""
# Простая эвристика: задания, которые чаще выполняются
task_scores: Dict[str, float] = {}
for task in self.tasks:
task_id = task.get("id") or task.get("title")
if task.get("completed", False):
task_scores[task_id] = task_scores.get(task_id, 0) + 1
# Сортируем по популярности
sorted_tasks = sorted(
self.tasks,
key=lambda t: task_scores.get(t.get("id") or t.get("title"), 0),
reverse=True,
)
return sorted_tasks[:top_k]