Compare commits
3 Commits
e366b62b52
...
789e7b4903
| Author | SHA1 | Date | |
|---|---|---|---|
|
789e7b4903
|
|||
|
1fa14207be
|
|||
|
b391de5d35
|
@@ -71,19 +71,23 @@ pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu
|
||||
|
||||
## Подготовка данных
|
||||
|
||||
### Выгрузка из Confluence
|
||||
### 1. Выгрузка из Confluence
|
||||
|
||||
Открыть страницу (раздел) Confluence, который необходимо получить.
|
||||
Например, `https://conf.company.ltd/pages/viewpage.action?pageId=123456789`.
|
||||
Открыть одну или несколько страниц (разделов) Confluence, которые необходимо получить.
|
||||
Например:
|
||||
```
|
||||
https://conf.company.ltd/pages/viewpage.action?pageId=123456789
|
||||
https://conf.company.ltd/pages/viewpage.action?pageId=987654321
|
||||
`
|
||||
|
||||
Скопировать значение `pageId` и подставить в команду `./download.sh <pageId>`.
|
||||
Скопировать значение `pageId` и подставить в команду `./download.sh <pageId1> [<pageId2>...]`.
|
||||
Например,
|
||||
|
||||
```bash
|
||||
./download.sh 123456789
|
||||
./download.sh 123456789 987654321
|
||||
```
|
||||
|
||||
В результате сама страница и все её дочерние будут сохранены в директорию `./input_html/`.
|
||||
В результате указанные страницы и все их дочерние будут сохранены в директорию `./input_html/`.
|
||||
Файлы будут названы по заголовкам страниц.
|
||||
|
||||
> [!IMPORTANT]
|
||||
@@ -92,13 +96,15 @@ pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu
|
||||
|
||||
> [!IMPORTANT]
|
||||
> Confluence не позволяет получить готовые макросы в HTML-виде.
|
||||
> В файлах будет находиться HTML-текст с готовыми к загрузками макросами, но не загруженными.
|
||||
> Хотя в них часто есть очень полезная информация, но её приходится выбрасывать просто потому, что загрузка макросов происходит при загрузке страницы браузером.
|
||||
> Хотя в макросах часто есть очень полезная информация, но её приходится выбрасывать просто потому, что загрузка макросов происходит при загрузке страницы браузером.
|
||||
> В файлах будет находиться HTML-текст с готовыми к загрузке макросами, но не загруженными.
|
||||
> Поэтому, например, содержания, списки дочерних страниц, встраиваемые диаграммы и пр. плюшечки будут вырезаны.
|
||||
>
|
||||
> Да, можно запросить страницы простым curl/wget, но (1) см. предыдущее замечание и (2) даже после очистки HTML-тегов в тексте останется очень много мусора (меню, футер, навигация...)
|
||||
> Да, можно запросить страницы простым curl/wget, но (1) будет сложнее получить мета-инфу о странице и (2) даже после очистки HTML-тегов в тексте останется очень много мусора (меню, футер, навигация...)
|
||||
>
|
||||
> Да, можно комбинировать разные подходы и всё сильно усложнить, но я не хочу.
|
||||
|
||||
### Конвертация страниц в Markdown
|
||||
### 2. Конвертация страниц в Markdown
|
||||
|
||||
Этот формат наиболее хорошо подходит для цитирования, потому что не содержит лишних символов, которые будут мешать хорошей токенизации и векторизации.
|
||||
|
||||
@@ -117,7 +123,7 @@ python3 convert.py
|
||||
python3 convert.py --help
|
||||
```
|
||||
|
||||
### Векторизация (индексирование)
|
||||
### 3. Векторизация (индексирование)
|
||||
|
||||
Файлы `./input_md/*.md` должны быть проиндексированы.
|
||||
|
||||
@@ -148,7 +154,7 @@ python3 vectorize.py
|
||||
python3 vectorize.py --help
|
||||
```
|
||||
|
||||
## Запуск
|
||||
## 4. Запуск
|
||||
|
||||
Для работы с RAG в интерактивном режиме (симуляция диалога) следует выполнить команду:
|
||||
|
||||
@@ -215,6 +221,6 @@ python3 rag.py --help
|
||||
1. облегчить поиск информации о проекте среди почти 2000 тысяч документов в корпоративной Confluence, относящихся к нему;
|
||||
2. обеспечить минимум телодвижений для развёртывания RAG с нуля внутри команды.
|
||||
|
||||
Здесь не было задачи сделать всё по красоте.
|
||||
Здесь не было задачи сделать всё сложно и по красоте.
|
||||
|
||||
Частично (в качестве агентов) в проекте участвовали семейства qwen3, clause-sonnet-4 и семейство chatgpt-4.
|
||||
Частично (в качестве агентов) в проекте участвовали модели семейств qwen, clause и chatgpt.
|
||||
|
||||
@@ -1,60 +1,62 @@
|
||||
#!/bin/bash
|
||||
# shellcheck disable=SC1091,SC2181
|
||||
|
||||
command -v curl >/dev/null 2>&1 || { echo >&2 "Ошибка: curl не установлен"; exit 1; }
|
||||
command -v jq >/dev/null 2>&1 || { echo >&2 "Ошибка: jq не установлен"; exit 1; }
|
||||
|
||||
if [ $# -lt 1 ]; then
|
||||
echo >&2 "Ошибка: не указан ID страницы для загрузки"
|
||||
echo "Использование: $0 <pageId>"
|
||||
echo "Использование: $0 <pageId1> [<pageId2>...]"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
[ ! -f .env ] && cp .env.example .env
|
||||
source .env
|
||||
[ ! -f ../.env ] && cp ../.env.example ../.env
|
||||
source ../.env
|
||||
|
||||
[ -z "$CONF_URL" ] && { echo >&2 "Ошибка: CONF_URL не указан в файле .env"; exit 1; }
|
||||
[ -z "$CONF_USERNAME" ] && { echo >&2 "Ошибка: CONF_USERNAME не указан в файле .env"; exit 1; }
|
||||
[ -z "$CONF_PASSWORD" ] && { echo >&2 "Ошибка: CONF_PASSWORD не указан в файле .env"; exit 1; }
|
||||
|
||||
PAGE_ID="$1"
|
||||
API_ENDPOINT="${CONF_URL}/rest/api/content/${PAGE_ID}?expand=body.view,children.page"
|
||||
|
||||
OUTPUT_PATH="./input_html"
|
||||
[ ! -d "$OUTPUT_PATH" ] && mkdir -p "$OUTPUT_PATH"
|
||||
|
||||
echo
|
||||
echo "Загрузка: $API_ENDPOINT"
|
||||
for PAGE_ID in "$@"; do
|
||||
API_ENDPOINT="${CONF_URL}/rest/api/content/${PAGE_ID}?expand=body.view,children.page"
|
||||
echo
|
||||
echo "Загрузка: $API_ENDPOINT"
|
||||
|
||||
response=$(curl -s -u "$CONF_USERNAME:$CONF_PASSWORD" -H "Accept: application/json" "${API_ENDPOINT}")
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "$response"
|
||||
exit 1
|
||||
fi
|
||||
RESPONSE=$(curl -s -u "$CONF_USERNAME:$CONF_PASSWORD" -H "Accept: application/json" "${API_ENDPOINT}")
|
||||
if [ $? -ne 0 ]; then
|
||||
echo "$RESPONSE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
error_message=$(echo "$response" | jq -r '.message' 2>/dev/null)
|
||||
if [ -n "$error_message" ] && [ "$error_message" != "null" ]; then
|
||||
echo "$response"
|
||||
exit 1
|
||||
fi
|
||||
ERROR_MESSAGE=$(echo "$RESPONSE" | jq -r '.message' 2>/dev/null)
|
||||
if [ -n "$ERROR_MESSAGE" ] && [ "$ERROR_MESSAGE" != "null" ]; then
|
||||
echo "$RESPONSE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
title=$(echo "$response" | jq -r .title)
|
||||
content=$(echo "$response" | jq -r .body.view.value)
|
||||
TITLE=$(echo "$RESPONSE" | jq -r .title)
|
||||
CONTENT=$(echo "$RESPONSE" | jq -r .body.view.value)
|
||||
|
||||
if [ -z "$content" ]; then
|
||||
echo "Пустая страница, пропущено"
|
||||
exit
|
||||
fi
|
||||
if [ -z "$CONTENT" ]; then
|
||||
echo "Пустая страница, пропущено"
|
||||
exit
|
||||
fi
|
||||
|
||||
path="$output_path/${title//\//_}.html"
|
||||
content=${content//href=\"\//href=\"$CONF_URL}
|
||||
content=${content//src=\"\//src=\"$CONF_URL}
|
||||
HTML_FILEPATH="$OUTPUT_PATH/${TITLE//\//_}.html"
|
||||
CONTENT=${CONTENT//href=\"\//href=\"$CONF_URL}
|
||||
CONTENT=${CONTENT//src=\"\//src=\"$CONF_URL}
|
||||
|
||||
url="$CONF_URL/pages/viewpage.action?pageId=$PAGE_ID"
|
||||
echo -e "@@$url@@\n<br><html><body>Исходная страница: <a href=$url>$url</a><br><br><h1>$title</h1>$content</body></html>" > "$path"
|
||||
echo "Сохранено: $output_path/$title.html"
|
||||
URL="$CONF_URL/pages/viewpage.action?pageId=$PAGE_ID"
|
||||
echo -e "@@$URL@@\n<br><html><body>Исходная страница: <a href=$URL>$URL</a><br><br><h1>$TITLE</h1>$CONTENT</body></html>" > "$HTML_FILEPATH"
|
||||
echo "Сохранено: $OUTPUT_PATH/$TITLE.html"
|
||||
|
||||
CHILD_IDS=$(echo "$RESPONSE" | jq -r '.children.page.results[]?.id' 2>/dev/null)
|
||||
for CHILD_ID in $CHILD_IDS; do
|
||||
echo "Переход к дочерней странице: $PAGE_ID => $CHILD_ID"
|
||||
$0 "$CHILD_ID"
|
||||
done
|
||||
|
||||
child_ids=$(echo "$response" | jq -r '.children.page.results[]?.id' 2>/dev/null)
|
||||
for child_id in $child_ids; do
|
||||
echo "Переход к дочерней странице: $child_id"
|
||||
$0 "$child_id"
|
||||
done
|
||||
|
||||
Reference in New Issue
Block a user