📒 Confluence. Pipeline без вложений
Получение Keycloak токена.¶
Токен действует 1800 секунд
In [1]:
Copied!
import sys
sys.path.insert(0, '/app/backend')
import sys
sys.path.insert(0, '/app/backend')
In [ ]:
Copied!
import os
os.environ['WEBUI_SECRET_KEY']= '123'
from fast_implementation.main import app
from fast_implementation.keycloak.client import get_configured_keycloak_client
from fast_implementation.tasks.keycloak import UpdateKeycloakTokenConfig
import os
os.environ['WEBUI_SECRET_KEY']= '123'
from fast_implementation.main import app
from fast_implementation.keycloak.client import get_configured_keycloak_client
from fast_implementation.tasks.keycloak import UpdateKeycloakTokenConfig
In [7]:
Copied!
client = get_configured_keycloak_client(app)
config = UpdateKeycloakTokenConfig(app)
client = get_configured_keycloak_client(app)
config = UpdateKeycloakTokenConfig(app)
In [255]:
Copied!
token = client.token(grant_type='password', username=config.keycloak_username, password=config.keycloak_password)
token = client.token(grant_type='password', username=config.keycloak_username, password=config.keycloak_password)
Найдём все ID страниц¶
In [119]:
Copied!
from typing import Iterator
from time import sleep
import warnings
from urllib3.exceptions import InsecureRequestWarning
from langchain_community.document_loaders import ConfluenceLoader
from langchain_core.documents import Document
warnings.filterwarnings('ignore', category=InsecureRequestWarning)
confluence_cookies={'JSESSIONID': 'BD11701EAA9E1783642C8B9033B9A428'}
from typing import Iterator
from time import sleep
import warnings
from urllib3.exceptions import InsecureRequestWarning
from langchain_community.document_loaders import ConfluenceLoader
from langchain_core.documents import Document
warnings.filterwarnings('ignore', category=InsecureRequestWarning)
confluence_cookies={'JSESSIONID': 'BD11701EAA9E1783642C8B9033B9A428'}
In [185]:
Copied!
all_pages = set()
ROOT_PAGES_IDS = [
'339301633', # Выученные уроки
'305732501', # Лучшие практики
]
def get_all_pages_ids(root_pages_ids: list[str]) -> set[str]:
global all_pages
loader = ConfluenceLoader(
url='https://confluence.sibur.local/',
include_attachments=False,
limit=20,
max_pages=1000,
cookies=confluence_cookies,
confluence_kwargs={'verify_ssl': False},
page_ids=root_pages_ids,
include_restricted_content=True,
keep_markdown_format=False,
keep_newlines=True,
)
#print(f'{root_pages_ids=}', flush=True)
for root_page in root_pages_ids:
#print(f'{root_page=}', flush=True)
first_level_ids = loader.confluence.get_child_id_list(root_page)
all_pages.add(root_page)
if isinstance(first_level_ids, str):
first_level_ids = set([first_level_ids])
else:
first_level_ids = set(first_level_ids)
first_level_ids = first_level_ids - all_pages
#print(f'{firts_level_ids=}', flush=True)
if first_level_ids:
next_level_ids = get_all_pages_ids(list(first_level_ids))
#print(f'{next_level_ids=}', flush=True)
all_pages = set()
ROOT_PAGES_IDS = [
'339301633', # Выученные уроки
'305732501', # Лучшие практики
]
def get_all_pages_ids(root_pages_ids: list[str]) -> set[str]:
global all_pages
loader = ConfluenceLoader(
url='https://confluence.sibur.local/',
include_attachments=False,
limit=20,
max_pages=1000,
cookies=confluence_cookies,
confluence_kwargs={'verify_ssl': False},
page_ids=root_pages_ids,
include_restricted_content=True,
keep_markdown_format=False,
keep_newlines=True,
)
#print(f'{root_pages_ids=}', flush=True)
for root_page in root_pages_ids:
#print(f'{root_page=}', flush=True)
first_level_ids = loader.confluence.get_child_id_list(root_page)
all_pages.add(root_page)
if isinstance(first_level_ids, str):
first_level_ids = set([first_level_ids])
else:
first_level_ids = set(first_level_ids)
first_level_ids = first_level_ids - all_pages
#print(f'{firts_level_ids=}', flush=True)
if first_level_ids:
next_level_ids = get_all_pages_ids(list(first_level_ids))
#print(f'{next_level_ids=}', flush=True)
In [164]:
Copied!
get_all_pages_ids(ROOT_PAGES_IDS)
get_all_pages_ids(ROOT_PAGES_IDS)
In [165]:
Copied!
len(all_pages)
len(all_pages)
Out[165]:
3489
Создание итератора документов¶
In [178]:
Copied!
def get_documents_iterator(pages_ids: list[str], limit: int) -> Iterator[Document]:
print('PAGES:', len(pages_ids))
loader = ConfluenceLoader(
url='https://confluence.sibur.local/',
include_attachments=False,
limit=20,
max_pages=100000,
cookies=confluence_cookies,
confluence_kwargs={'verify_ssl': False},
page_ids=pages_ids,
include_restricted_content=True,
keep_markdown_format=False,
keep_newlines=True,
)
return loader.lazy_load()
def get_documents_iterator(pages_ids: list[str], limit: int) -> Iterator[Document]:
print('PAGES:', len(pages_ids))
loader = ConfluenceLoader(
url='https://confluence.sibur.local/',
include_attachments=False,
limit=20,
max_pages=100000,
cookies=confluence_cookies,
confluence_kwargs={'verify_ssl': False},
page_ids=pages_ids,
include_restricted_content=True,
keep_markdown_format=False,
keep_newlines=True,
)
return loader.lazy_load()
Подготовим Qdrant¶
In [171]:
Copied!
qdrant_url = 'http://owu-qdrant:6333'
qdrant_url = 'http://owu-qdrant:6333'
In [241]:
Copied!
from qdrant_client import QdrantClient, models
QDRANT_COLLECTION_NAME = 'test-confluence-api'
qdrant_client = QdrantClient(url=qdrant_url)
qdrant_client.delete_collection(QDRANT_COLLECTION_NAME)
qdrant_client.create_collection(
collection_name=QDRANT_COLLECTION_NAME,
strict_mode_config=models.StrictModeConfig(
enabled=True,
# max_payload_index_count=10,
max_query_limit=10,
max_timeout=10,
condition_max_size=10,
filter_max_conditions=10,
),
# Настройки из документации для "Высокой точности с Низким потреблением памяти"
vectors_config=models.VectorParams(
# size=768,
size=1024,
distance=models.Distance.COSINE,
on_disk=True,
),
hnsw_config=models.HnswConfigDiff(
on_disk=True,
),
# Из настроек с "Высокой скоростью и низким потреблением памяти"
#quantization_config=models.ScalarQuantization(
# type=models.ScalarQuantizationConfig(
# type=models.ScalarType.INT8,
# always_ram=True,
# )
)
from qdrant_client import QdrantClient, models
QDRANT_COLLECTION_NAME = 'test-confluence-api'
qdrant_client = QdrantClient(url=qdrant_url)
qdrant_client.delete_collection(QDRANT_COLLECTION_NAME)
qdrant_client.create_collection(
collection_name=QDRANT_COLLECTION_NAME,
strict_mode_config=models.StrictModeConfig(
enabled=True,
# max_payload_index_count=10,
max_query_limit=10,
max_timeout=10,
condition_max_size=10,
filter_max_conditions=10,
),
# Настройки из документации для "Высокой точности с Низким потреблением памяти"
vectors_config=models.VectorParams(
# size=768,
size=1024,
distance=models.Distance.COSINE,
on_disk=True,
),
hnsw_config=models.HnswConfigDiff(
on_disk=True,
),
# Из настроек с "Высокой скоростью и низким потреблением памяти"
#quantization_config=models.ScalarQuantization(
# type=models.ScalarQuantizationConfig(
# type=models.ScalarType.INT8,
# always_ram=True,
# )
)
/tmp/ipykernel_388/2650577708.py:5: UserWarning: Qdrant client version 1.14.3 is incompatible with server version 1.16.1. Major versions should match and minor version difference must not exceed 1. Set check_compatibility=False to skip version check. qdrant_client = QdrantClient(url=qdrant_url)
Out[241]:
True
Pipeline¶
In [256]:
Copied!
import time
from langchain_text_splitters import RecursiveCharacterTextSplitter, TextSplitter
from langchain_qdrant import QdrantVectorStore
from langchain_gigachat import GigaChatEmbeddings
embeddings = GigaChatEmbeddings(
base_url='https://s001tst-api-gchat.sibur.local/v1/',
verify_ssl_certs=False,
model="EmbeddingsGigaR",
access_token=token['access_token'],
)
vector_store = QdrantVectorStore(
client=qdrant_client,
collection_name=QDRANT_COLLECTION_NAME,
embedding=embeddings,
)
documents = get_documents_iterator(all_pages, limit=20)
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
import time
from langchain_text_splitters import RecursiveCharacterTextSplitter, TextSplitter
from langchain_qdrant import QdrantVectorStore
from langchain_gigachat import GigaChatEmbeddings
embeddings = GigaChatEmbeddings(
base_url='https://s001tst-api-gchat.sibur.local/v1/',
verify_ssl_certs=False,
model="EmbeddingsGigaR",
access_token=token['access_token'],
)
vector_store = QdrantVectorStore(
client=qdrant_client,
collection_name=QDRANT_COLLECTION_NAME,
embedding=embeddings,
)
documents = get_documents_iterator(all_pages, limit=20)
text_splitter = RecursiveCharacterTextSplitter(chunk_size=1000, chunk_overlap=200)
PAGES: 3489
In [244]:
Copied!
start_at = time.time()
pages_counter = 0
with open('vectorization.log', 'w') as f:
vectorized_at = start_at
for document in documents:
pages_counter += 1
loaded_at = time.time()
splits = text_splitter.split_documents([document])
vector_store.add_documents(splits)
vectorized_at = time.time()
message = f'{pages_counter:4d}:Parsed: {(loaded_at - vectorized_at):3.3f}. ' \
f'Page Size: {len(document.page_content):6d}. Vectorized: {(vectorized_at - loaded_at):3.3f}',
print(
message,
flush=True,
file=f,
)
start_at = time.time()
pages_counter = 0
with open('vectorization.log', 'w') as f:
vectorized_at = start_at
for document in documents:
pages_counter += 1
loaded_at = time.time()
splits = text_splitter.split_documents([document])
vector_store.add_documents(splits)
vectorized_at = time.time()
message = f'{pages_counter:4d}:Parsed: {(loaded_at - vectorized_at):3.3f}. ' \
f'Page Size: {len(document.page_content):6d}. Vectorized: {(vectorized_at - loaded_at):3.3f}',
print(
message,
flush=True,
file=f,
)
In [182]:
Copied!
print(time.time() - start_at)
print(time.time() - start_at)
485.7252779006958
Потестируем поиск¶
In [257]:
Copied!
from langchain_gigachat.chat_models import GigaChat
giga = GigaChat(
base_url='https://s001tst-api-gchat.sibur.local/v1/',
verify_ssl_certs=False,
model='GigaChat',
access_token=token['access_token'],
)
from langchain_gigachat.chat_models import GigaChat
giga = GigaChat(
base_url='https://s001tst-api-gchat.sibur.local/v1/',
verify_ssl_certs=False,
model='GigaChat',
access_token=token['access_token'],
)
In [258]:
Copied!
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages(
[
(
'human',
"""
Ты помощник в задачах поиска ответа на вопрос, котрый можно найти в документации.
Используй переданные части контекста для формулировки ответа.
Если ты не знаешь ответ, просто скажи, что не знаешь.
Объясняй свой ответ. Добавляй ссылки на источник.
Question: {question}
Context: {context}
Answer:"""
)
]
)
from langchain_core.prompts import ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages(
[
(
'human',
"""
Ты помощник в задачах поиска ответа на вопрос, котрый можно найти в документации.
Используй переданные части контекста для формулировки ответа.
Если ты не знаешь ответ, просто скажи, что не знаешь.
Объясняй свой ответ. Добавляй ссылки на источник.
Question: {question}
Context: {context}
Answer:"""
)
]
)
In [259]:
Copied!
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from rich import print as rich_print
retriever = vector_store.as_retriever()
rag_chain = (
{'context': retriever, 'question': RunnablePassthrough()}
| prompt
| giga
| StrOutputParser()
)
from langchain_core.output_parsers import StrOutputParser
from langchain_core.runnables import RunnablePassthrough
from rich import print as rich_print
retriever = vector_store.as_retriever()
rag_chain = (
{'context': retriever, 'question': RunnablePassthrough()}
| prompt
| giga
| StrOutputParser()
)
In [260]:
Copied!
rich_print(rag_chain.invoke('Причины забивки решетки реактора?'))
rich_print(rag_chain.invoke('Причины забивки решетки реактора?'))
### Причины забивки решетки реактора На основании предоставленного контекста, основные причины забивки решетки реактора включают следующие факторы: 1. **Забивка лопаток компрессора** - Высокая степень открытия лопаток на С1201 может свидетельствовать о забивке лопаток порошком или агломератами полиэтилена. Это приводит к неправильной работе лопаток и снижению расхода газа в системе. 2. **Снижение расхода циркуляционного газа** - Низкий расход циркуляционного газа в системе полимеризации R1201 вследствие забитых лопаток компрессора С1201 способствует забивке решетки реактора при наборе уровня в реакторе. 3. **Образование псевдосжиженого слоя** - При наборе уровня в реакторе R1201 образуется псевдосжиженый слой, который ложится на решетку и вызывает быструю забивку. #### Источники информации: - [Документ 1](https://confluence.sibur.local/pages/viewpage.action?pageId=349807043) - [Документ 2](https://confluence.sibur.local/pages/viewpage.action?pageId=376390645) Эти причины были выявлены в ходе анализа отклонений на производстве ПАО "Нижнекамскнефтехим". Они указывают на необходимость регулярного обслуживания и чистки лопаток компрессоров и трубопроводов, чтобы предотвратить повторение подобных событий.
In [261]:
Copied!
found_docs = retriever.get_relevant_documents('Причины забивки решетки реактора?')
rich_print(found_docs)
found_docs = retriever.get_relevant_documents('Причины забивки решетки реактора?')
rich_print(found_docs)
[ Document( metadata={ 'title': 'ВУ - 2024-07-30 - ПАО Нижнекамскнефтехим - Забивка решетки реактора R1201', 'id': '349807043', 'source': 'https://confluence.sibur.local/pages/viewpage.action?pageId=349807043', 'when': '2025-07-09T18:30:34.825+03:00', '_id': '525a470e-4ddd-4033-96a7-d94ea4664e7a', '_collection_name': 'test-confluence-api' }, page_content='Останов производства в связи с забивкой решетки, выгрузки из реактора R1201 Детальное описание отклонения \n Существенным отличием от прошлых пробегов является высокая степень открытия лопаток на С1201, что может указывать на забивку лопаток порошком/агломератоми ПЭ, которые привели к неправильной работе лопаток и снижению расхода газа в системе. В следствие при наборе уровня в реакторе R1201 псевдосжиженый слой лег на решётку и привел к быстрой забивке (гипотеза требует подтверждения при вскрытие лопаток компрессора С1201) Повторяемость события \n Такое случается на Локации более 1 раза в квартал Ключевые участники \n Назаров Валерий Вячеславович Локация события \n Республика Татарстан (Татарстан) Предприятие \n ПАО Нижнекамскнефтехим Производство Производство ЛПЭНП/ПЭВП Центр компетенций Полиолефины Тип оборудования \n (не релевантно) Процесс (другое) Проект (событие не в рамках проекта) Отклонение в сроках \n 7 дней Отклонение в деньгах \n 170 млн Прочие отклонения' ), Document( metadata={ 'title': 'ВУ - 2024-11-08 - ПАО Нижнекамскнефтехим - На Производстве полиэтилена НКНХ при пуске на катализаторе ВСС-518, после проведения ОР, произошла забивка решетки реактора R1201 с последующем остановом производства и выводом в ремонт.', 'id': '376390645', 'source': 'https://confluence.sibur.local/pages/viewpage.action?pageId=376390645', 'when': '2025-07-02T10:13:38.707+03:00', '_id': '60dba26f-6814-4c17-b2ab-3adc2f15234f', '_collection_name': 'test-confluence-api' }, page_content='false 1 false 400 auto hidden 307506879 false 1280 \n \n LL \n LL-content-v2 Статус \n Что произошло (кратко) На Производстве полиэтилена НКНХ при пуске на катализаторе ВСС-518, после проведения ОР, произошла забивка решетки реактора R1201 с последующем остановом производства и выводом в ремонт. Корневые причины\n Снижение расхода циркуляционного газа в системе полимеризации R1201 из-за забитых лопаток компрессора С1201 и последующей забивки решетки реактора R1201 при наборе уровня в реакторе Ключевые мероприятия\n Чистка лопаток С1201 и трубопроводов на всасе компрессора С1201 при проведение ОР. Учесть потенциальные места забивки системы/лопаток при последующих ремонтах. Когда произошло 2024-06-28 Предприятие ПАО Нижнекамскнефтехим Производство Пр-во полиэтилена. №5815 Установка Отделение полимеризации и дегазации Название единицы оборудования Реактор R1201 Компрессор С1201 Номер единицы оборудования' ), Document( metadata={ 'title': 'ВУ-1067 - 2025-05-26 - ПАО Нижнекамскнефтехим - Заслонка упала в реактор Р-5/1', 'id': '437497908', 'source': 'https://confluence.sibur.local/pages/viewpage.action?pageId=437497908', 'when': '2025-05-26T09:13:38.222+03:00', '_id': 'e6ff6aa0-d803-4cd3-9528-4e84c1ad06fb', '_collection_name': 'test-confluence-api' }, page_content='false 1 false 400 auto hidden 307506879 false 1280 \n \nAJS.$(document).ready(function(){\n $(".aui-header-primary .aui-buttons").append(" Назад ");\n});\n]]> \n LL LL-content-v2 Статус \n Что произошло (кратко) Заслонка упала в реактор Р-5/1 Корневые причины\n образование застойной зоны, повышенное образование кокса Ключевые мероприятия\n 1.Принято решение поставить ограничители на заслонку' ), Document( metadata={ 'title': 'ВУ-1066 - 2025-05-26 - ПАО Нижнекамскнефтехим - Заслонка упала в реактор Р-5/1', 'id': '437497871', 'source': 'https://confluence.sibur.local/pages/viewpage.action?pageId=437497871', 'when': '2025-05-26T09:11:35.901+03:00', '_id': 'e6ab3a18-0a78-4bd6-a74e-cee45abb1043', '_collection_name': 'test-confluence-api' }, page_content='false 1 false 400 auto hidden 307506879 false 1280 \n \nAJS.$(document).ready(function(){\n $(".aui-header-primary .aui-buttons").append(" Назад ");\n});\n]]> \n LL LL-content-v2 Статус \n Что произошло (кратко) Заслонка упала в реактор Р-5/1 Корневые причины\n образование застойной зоны, повышенное образование кокса Ключевые мероприятия\n 1.Принято решение поставить ограничители на заслонку' ) ]
In [ ]:
Copied!