Записки Kotlin Developer
78 subscribers
51 photos
5 videos
5 files
33 links
Hi, я Кирилл, Kotlin разработчик👋

Тут пишу заметки и tutorial: Kotlin, алгоритмы, Functional style, инфрастуктуру, микросервисы.

Начинаем с базы и дойдем до вершин📈

Subscribe, Let's upgrade skills together🤝

Автор: @kyrillP
Download Telegram
🚀 KronxRAG - ваш интеллектуальный помощник для работы с документами!

Представляю KronxRAG - RAG-приложение на базе Streamlit и GigaChat и GigaChain, которое превращает ваши документы в умную базу знаний.

🔥 Основные возможности:
📄 Загрузка TXT и PDF файлов
🔍 Умный поиск по документам с помощью RAG-технологии
🤖 AI-ответы на основе ваших материалов через GigaChat
📚 Управление базой знаний
💾 Сохранение данных между сессиями

💡 Как это работает:
1. Загружаете свои документы
2. Задаете любой вопрос
3. Получаете точный ответ, основанный только на ваших материалах

🛠 Технологический стек:
• Frontend: Streamlit
• AI: GigaChat (Сбер)
• Векторная база: ChromaD (хранится локально на вашем пк)
• Фреймворк: LangChain

🔗 Проект уже готов к использованию! Для запуска нужен только API ключ от GigaChat.

Проект доступен на https://gitverse.ru/kronx/KronxRAG

p.s Вообще я его затеял, потому что стало интересно потрогать RAG, на практики попробовать всякие алгоритмы для улучшения поиска по нему. Имея такой интерфейс гораздо удобнее тестировать...
🔥1
Больше прозрачности в RAG
Добавил в приложение при ответе формирования списка источников откуда были взяты данные, чтобы сделать систему более прозрачной для пользователя и упростить отладку при разработке более продвинутых RAG сценариев..

Как это работает?
Создаем функцию для чтения pdf
def read_pdf(file):
pdf_document = fitz.open(stream=file.read(), filetype="pdf")
pages = [] # список страниц для хранения всех страниц
for page_num in range(pdf_document.page_count):
page = pdf_document.load_page(page_num)
text = page.get_text() # извлекаем текст каждой страницы отдельно
pages.append((page_num + 1, text)) # добавляем номер страницы и её текст
return pages

Переработал функцию обработки файлов, теперь каждый документ langchain - это отдельная страница pdf документа, в каждом документе мы добавляем мето-данные
def process_files(files) -> list[Document]:
"""
Функция обрабатывает загруженные файлы, преобразуя их в документы с метаданными.
Теперь каждый чанк включает номер страницы.
"""
documents = []
for file in files:
if file.type == "application/pdf":
pages = read_pdf(file) # получаем страницы с номерами и текстом
for page_number, content in pages:

document = Document(
page_content=content,
metadata={
"source": file.name,
"page": page_number # добавляем номер страницы в метаданные
}
)
print(page_number)
documents.append(document)
else:
# Для текстовых файлов просто читаем и декодируем содержимое
content = file.read().decode()
cleaned_content = clean_html(content)
document = Document(
page_content=cleaned_content,
metadata={"source": file.name}
)
documents.append(document)

return documents


Эти документы потом будут разбиваться на чанки с помощью функции spit_docs

def split_docs(documents: list[Document], chunk_size: int = 1000, chunk_overlap: int = 200) -> list[Document]:
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=chunk_size,
chunk_overlap=chunk_overlap,
)
chunks = text_splitter.split_documents(documents)

return chunks



Ещё из важного нужен промт, который формирует итоговый ответ на основе RAG, пока я пришел к такому промту

template = """Используй приведённый ниже контекст, чтобы ответить на вопрос.
Если не знаешь ответ — просто скажи, что не знаешь, не выдумывай.
Используй только информацию из контекста
Всегда добавляй спискок источкников из запроса
Добавляй номера страниц из которых ты составил итоговый ответ
Контекст: {context}
Вопрос: {question}

Полезный ответ:"""
custom_rag_prompt = PromptTemplate.from_template(template)


Далее нам нужна RAG цепочка
    rag_chain = (
{"context": retriever | format_docs, "question": RunnablePassthrough()}
| custom_rag_prompt
| giga
| StrOutputParser()
)

Код функции для форматирования
def format_docs(docs: list[Document]):
formatted_contents = []
sources = []
for doc in docs:
page = None
source = ''
print(doc.metadata)
if hasattr(doc, 'metadata') and doc.metadata and 'source' in doc.metadata:
source = doc.metadata['source']
if hasattr(doc, 'metadata') and doc.metadata and 'page' in doc.metadata:
page = doc.metadata['page']
if source not in sources:
sources.append(source)
formatted_contents.append(f"""
[Источник: {source}{f' страница {page}' if page is not None else ''}]\n\n
{doc.page_content}\n\n
""")
return "\n\n".join(formatted_contents)

C полным кодом вы можете ознакомится тут

Далее планирую повысить качество ответов из таблиц в pdf, сейчас ответы из таблиц не очень...
Тут уже есть подсказка как это сделать
https://habr.com/ru/articles/893356
🔥2
Друзья, я рад сообщить вам приятную новость! Несмотря на недавние изменения в сервисе Evolution Foundation Models на cloud.ru, многие мощные модели остаются доступны абсолютно бесплатно.

Перечисляю бесплатные модели, которые остаются открытыми для всех пользователей:

- 🔥 GigaChat/GigaChat-2-Max
- 💡 Qwen/Qwen3-Next-80B-A3B-Instruct
- ⚙️ t-tech/T-lite-it-1.0
- t-tech/T-pro-it-1.0
- 🌐 t-tech/T-pro-it-2.0
- 🎧 openai/whisper-large-v3
- 📊 Qwen/Qwen3-Embedding-0.6B
- 🤖 Qwen/Qwen3-Reranker-0.6B
- 🏭 BAAI/bge-m3
- 👩‍💻 BAAI/bge-reranker-v2-m3

Не знаю, как долго продлится эта акция, вероятно, до конца ноября. Это отличная возможность провести вечер за вайбкодингом!

Мне особенно понравилась модель GLM 4.6, и я продолжаю использовать её на платной основе. До ноября она была бесплатной ...

Этот пост носит исключительно информационный характер и не является рекламой..