Індексація баз знань (Confluence, Notion, SharePoint) для RAG

Проектуємо та впроваджуємо системи штучного інтелекту: від прототипу до production-ready рішення. Наша команда поєднує експертизу в машинному навчанні, дата-інжинірингу та MLOps, щоб AI працював не в лабораторії, а в реальному бізнесі.
Показано 1 з 1 послугУсі 1566 послуг
Індексація баз знань (Confluence, Notion, SharePoint) для RAG
Середня
від 1 тижня до 3 місяців
Часті питання

Напрямки AI-розробки

Етапи розробки AI-рішення

Останні роботи

  • image_website-b2b-advance_0.webp
    Розробка сайту компанії B2B ADVANCE
    1262
  • image_web-applications_feedme_466_0.webp
    Розробка веб-додатків для компанії FEEDME
    1171
  • image_websites_belfingroup_462_0.webp
    Розробка веб-сайту для компанії БЕЛФІНГРУП
    874
  • image_ecommerce_furnoro_435_0.webp
    Розробка інтернет магазину для компанії FURNORO
    1094
  • image_logo-advance_0.webp
    Розробка логотипу компанії B2B Advance
    563
  • image_crm_enviok_479_0.webp
    Розробка веб-додатків для компанії Enviok
    832

Індексація баз знань (Confluence, Notion, SharePoint) для RAG

Корпоративні бази знань — головне джерело контексту для enterprise RAG систем. Ключові виклики: інкрементальна синхронізація (не переіндексовувати все при кожному запуску), управління правами доступу (користувач не повинен отримати відповідь з документа, до якого у них нема доступу) та обробка Confluence/Notion-специфічної розмітки.

Confluence інтеграція

from atlassian import Confluence
from datetime import datetime

class ConfluenceIndexer:
    def __init__(self, url: str, username: str, api_token: str):
        self.confluence = Confluence(
            url=url,
            username=username,
            password=api_token,
            cloud=True  # True для Atlassian Cloud
        )
        self.watermark_store = WatermarkStore()

    def get_updated_pages(self, space_key: str) -> list[dict]:
        """Інкрементальне завантаження: лише оновлені сторінки"""
        last_indexed = self.watermark_store.get(f"confluence:{space_key}")

        pages = self.confluence.get_all_pages_from_space(
            space=space_key,
            start=0,
            limit=100,
            expand='body.storage,metadata,version,ancestors'
        )

        if last_indexed:
            pages = [
                p for p in pages
                if datetime.fromisoformat(p['version']['when']) > last_indexed
            ]

        return pages

    def parse_page(self, page: dict) -> dict:
        from bs4 import BeautifulSoup
        from markdownify import markdownify

        # Confluence зберігає контент у форматі storage (XHTML)
        html_content = page['body']['storage']['value']
        soup = BeautifulSoup(html_content, 'html.parser')

        # Обробка Confluence-специфічних тегів
        for macro in soup.find_all('ac:structured-macro'):
            macro_name = macro.get('ac:name', '')
            if macro_name == 'code':
                # Code blocks → markdown code blocks
                body = macro.find('ac:plain-text-body')
                lang = macro.find('ac:parameter', {'ac:name': 'language'})
                code = body.get_text() if body else ''
                lang_str = lang.get_text() if lang else ''
                macro.replace_with(f'\n```{lang_str}\n{code}\n```\n')
            else:
                macro.decompose()

        text = markdownify(str(soup), heading_style="ATX")

        return {
            'id': page['id'],
            'title': page['title'],
            'text': text,
            'url': f"{self.confluence.url}/wiki{page['_links']['webui']}",
            'space': page['space']['key'],
            'ancestors': [a['title'] for a in page.get('ancestors', [])],
            'labels': [l['name'] for l in page.get('metadata', {}).get('labels', {}).get('results', [])],
            'last_modified': page['version']['when'],
            'author': page['version']['by']['displayName'],
            # Права доступу для пошуку з урахуванням дозволів
            'restrictions': self._get_page_restrictions(page['id'])
        }

Notion інтеграція

from notion_client import Client

class NotionIndexer:
    def __init__(self, token: str):
        self.notion = Client(auth=token)

    def get_database_pages(self, database_id: str,
                            last_sync: datetime = None) -> list:
        filter_params = {}
        if last_sync:
            filter_params = {
                "filter": {
                    "timestamp": "last_edited_time",
                    "last_edited_time": {"after": last_sync.isoformat()}
                }
            }

        results = self.notion.databases.query(
            database_id=database_id,
            **filter_params
        )
        return results.get('results', [])

    def extract_page_content(self, page_id: str) -> str:
        """Рекурсивне вилучення блоків зі сторінки"""
        blocks = self.notion.blocks.children.list(block_id=page_id)
        return self._blocks_to_text(blocks.get('results', []))

    def _blocks_to_text(self, blocks: list) -> str:
        text_parts = []
        for block in blocks:
            block_type = block['type']
            if block_type in ['paragraph', 'heading_1', 'heading_2', 'heading_3']:
                rich_text = block[block_type].get('rich_text', [])
                text = ''.join([rt['plain_text'] for rt in rich_text])
                if block_type.startswith('heading'):
                    level = int(block_type[-1])
                    text = '#' * level + ' ' + text
                text_parts.append(text)

Інкрементальна індексація запобігає повній переробці, а фільтрування з урахуванням дозволів забезпечує безпеку.