|
|
from qdrant_client import QdrantClient |
|
|
from langchain_huggingface import HuggingFaceEmbeddings |
|
|
|
|
|
from langchain_core.runnables import RunnablePassthrough |
|
|
from langchain_core.output_parsers import StrOutputParser |
|
|
from langchain_core.prompts import ChatPromptTemplate |
|
|
from langchain_qdrant import QdrantVectorStore |
|
|
from langchain_community.cross_encoders import HuggingFaceCrossEncoder |
|
|
from langchain.retrievers.document_compressors import CrossEncoderReranker |
|
|
from langchain.retrievers import ContextualCompressionRetriever |
|
|
from sentence_transformers import CrossEncoder |
|
|
from langchain_groq import ChatGroq |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
client = QdrantClient( |
|
|
url="https://7acfa434-9e7d-4ff3-bc16-98679211cca6.europe-west3-0.gcp.cloud.qdrant.io", |
|
|
api_key="eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhY2Nlc3MiOiJtIn0.Fb6pTw9_wQqEPMe3kcAW0o-VobmCUOjlpIMHJep5UpU", |
|
|
https=True |
|
|
) |
|
|
|
|
|
|
|
|
model_name = "sentence-transformers/paraphrase-multilingual-mpnet-base-v2" |
|
|
model_kwargs = {'device': 'cuda'} |
|
|
encode_kwargs = {'normalize_embeddings': True, 'batch_size':1024} |
|
|
|
|
|
embeddings_model = HuggingFaceEmbeddings( |
|
|
model_name="sentence-transformers/paraphrase-multilingual-mpnet-base-v2", |
|
|
model_kwargs={'device': 'cpu'}, |
|
|
encode_kwargs={'normalize_embeddings': True, 'batch_size':1024}, |
|
|
) |
|
|
|
|
|
|
|
|
vector_store = QdrantVectorStore( |
|
|
client=client, |
|
|
collection_name='film_col_1', |
|
|
embedding=embeddings_model |
|
|
) |
|
|
|
|
|
llm = ChatGroq( |
|
|
model="llama-3.1-8b-instant", |
|
|
api_key="your_key", |
|
|
temperature=0.7, |
|
|
max_tokens=512, |
|
|
) |
|
|
|
|
|
|
|
|
|
|
|
base_retriever = vector_store.as_retriever( |
|
|
search_type="similarity", |
|
|
search_kwargs={"k": 20} |
|
|
) |
|
|
|
|
|
model_r = HuggingFaceCrossEncoder(model_name="BAAI/bge-reranker-v2-m3") |
|
|
compressor = CrossEncoderReranker(model=model_r, top_n=5) |
|
|
|
|
|
retriever = ContextualCompressionRetriever( |
|
|
base_compressor=compressor, |
|
|
base_retriever=base_retriever |
|
|
) |
|
|
|
|
|
def format_docs(docs): |
|
|
"""Форматирует документы для передачи в промпт""" |
|
|
formatted = [] |
|
|
|
|
|
for i, doc in enumerate(docs, 1): |
|
|
metadata = doc.metadata |
|
|
|
|
|
vacancy_info = f""" |
|
|
=== ФИЛЬМ {i} === |
|
|
Название: {metadata.get('title', 'Не указано')} |
|
|
Год: {metadata.get('year', 'Не указано')} |
|
|
Жанр: {metadata.get('genres', 'Не указано')} |
|
|
Директор: {metadata.get('directors', 'Не указано')} |
|
|
Оценка: {metadata.get('vote_average', 'Не указано')} |
|
|
Количество оценок: {metadata.get('vote_count', 'Не указано')} |
|
|
Ссылка: {metadata.get('tmdb_url', 'Не указано')} |
|
|
Описание: {doc.page_content[:300]}... |
|
|
""" |
|
|
|
|
|
formatted.append(vacancy_info) |
|
|
|
|
|
return "\n".join(formatted) |
|
|
|
|
|
|
|
|
rag_prompt = ChatPromptTemplate.from_messages([ |
|
|
( |
|
|
"system", |
|
|
"""Ты — кинокритик с 20-летним стажем, бывший сценарист, а ныне саркастичный эксперт по мировому кинематографу! 🎬 |
|
|
Твоя задача — проанализировать предоставленные фильмы и дать остроумную, но профессиональную оценку с лёгкой долей цинизма и любви к кино. |
|
|
|
|
|
Стиль анализа: |
|
|
- Глубоко разбирай контекст: жанры, режиссёры, годы, рейтинги — но без занудства |
|
|
- Используй кинематографические мемы и отсылки («Оскар убежал», «это не фильм — это терапия», «как в советском») |
|
|
- Подмечай абсурдные или трогательные детали: «режиссёр снял 3 фильма, а актёр — 200», «рейтинг 2.0, но постер шедевр» |
|
|
- Давай рекомендации с иронией: «Смотреть только если вы фанат страданий» или «Идеально для просмотра после третьего кофе» |
|
|
- Структурируй ответ с эмодзи, краткими заголовками и живыми комментариями |
|
|
- Отвечай на русском языке — умно, ярко и с характером! |
|
|
|
|
|
|
|
|
Помни: сарказм — да, злоба — нет. Цель — чтобы читатель улыбнулся и захотел посмотреть фильм (или хотя бы посмеялся над ним). 😏 |
|
|
|
|
|
Если среди фильмов есть что-то эпически странное, гениальное или настолько плохое, что становится хорошим — обязательно выдели это! 🍿""" |
|
|
), |
|
|
|
|
|
( |
|
|
"human", |
|
|
"""📽️ КОНТЕКСТ (или как говорят в индустрии — «наши материалы»): |
|
|
{context} |
|
|
|
|
|
🎯 ЗАПРОС ОТ РЕДАКЦИИ: {question}""" |
|
|
) |
|
|
]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
rag_chain = ( |
|
|
{ |
|
|
"context": retriever | format_docs, |
|
|
"question": RunnablePassthrough() |
|
|
} |
|
|
| rag_prompt |
|
|
| llm |
|
|
| StrOutputParser() |
|
|
) |