Automated search over RAG-pipeline configurations with reusable trial artifacts for training and inference
Project description
RAGotron
RAGotron – это инструмент, предназначенный для автоматического построения пайплайнов на основе технологии Retrieval-Augmented Generation (RAG). RAG-пайплайны используются для повышения качества ответов генеративных моделей путём дополнения генерации релевантной информацией из баз данных и документов.
Основная идея RAGotron заключается в том, чтобы автоматизировать создание и подбор оптимальных комбинаций отдельных компонент RAG-пайплайна. Каждый RAG-пайплайн состоит из нескольких самостоятельных компонент, таких как:
- Разбиение документов (Splitter) — разбиение текста на фрагменты (чанки) для последующего индексирования.
- Эмбеддер (Embedder) — преобразование чанков текста в числовые векторные представления.
- База данных (Data Base) — хранение и поиск наиболее релевантных текстовых фрагментов по пользовательским запросам.
- Генерация ответов (Generation) — формирование ответа на основе извлечённых данных.
- Валидация (Validation) — оценка качества и точности ответов, полученных из пайплайна.
Каждая из перечисленных компонент может быть реализована различными способами, с использованием разных подходов и технологий (см. пример на изображении ниже). В RAGotron пока реализован ограниченный набор компонент, однако архитектура фреймворка позволяет легко добавлять и экспериментировать с новыми решениями. В будущем планируется расширять и улучшать RAGotron путём добавления новых видов компонент и реализации современных подходов к построению эффективных RAG-пайплайнов.
Текущие возможности RAGotron
На данный момент RAGotron поддерживает:
- Продвинутые методы Query Translation: Multi-query и RAG-fusion
- Выбор сплиттера: RecursiveCharacterTextSplitter и tiktoken
- Выбор векторной БД: FAISS и ChromaDB
- Поддержка OpenAI-совместимых API через OpenRouter для различных этапов пайплайна (генерация вопросов, генерация ответов, валидация)
- Выбор эмбеддера: кастомные SentenceTransformers эмбеддеры (например,
intfloat/multilingual-e5-large)
Архитектура RAGotron
Общий процесс работы RAGotron
-
Настройка конфигурации (
AppConfig)- Задаются параметры base стейджа и дополнительных стейджей.
-
Циклический перебор (
Cyclic Run)- Программа многократно запускает пайплайн для различных стейджей.
-
Запуск основного пайплайна (
Run Pipeline)- Загрузка документов (
document loader) – распаковка zip-архива, обработка файлов.txt,.docx,.pdf - Разбиение (
splitter) – деление текста на чанки (RecursiveCharacterTextSplitter,tiktoken) - Преобразование в эмбеддинги (
embedder) – векторизация чанков с помощьюall-MiniLM-L6-v2и других моделей - Retrieval (
retriever) – поиск по документам: dense (Faiss / ChromaDB), sparse (BM25S) или hybrid (dense + sparse с weighted fusion) - Генерация вопросов – создаются три типа вопросов:
- Открытые (
Open) – свободные вопросы по содержимому документов - Закрытые (
Closed) – вопросы с единственно верным ответом - MMLU – вопросы с несколькими вариантами ответов для оценки знаний модели
- Открытые (
- Генерация ответов (
question answering) – обработка вопросов через LLM (OpenAI-совместимые модели через OpenRouter) - Валидация (
validation)- Формирование отчетов – создаются детализированные отчеты по каждому типу вопросов
- Подсчет метрик:
- Метрики эмбеддера – анализируются
retrieval metrics, отражающие качество поиска - Метрики токенайзера – рассчитываются
ROUGE,BLEU,METEORна открытых вопросах
- Метрики эмбеддера – анализируются
- Загрузка документов (
Как запустить RAGotron
Установим RAGotron:
git clone <repository-url>
pip install -e .
Настройка API ключа
RAGotron использует OpenRouter для доступа к LLM. Создайте файл .env в корне проекта:
OPENROUTER_API_KEY=your_openrouter_api_key_here
Получить API ключ можно на сайте OpenRouter.
Веб-интерфейс
Обращатся с RAGotron можно через UI. Подробнее можно посмотреть в разделе Запуск UI
Запуск и использование конфига
Актуальный сценарий запуска — через RagFactory: задается base_config, пространство перебора SearchSpace и optimizer.
base_config хранится в YAML-файле и загружается через OmegaConf, а валидируется по-прежнему через Pydantic (AppConfig) — OmegaConf отвечает только за загрузку YAML, интерполяцию и резолв путей. Пример configs/base.yaml:
splitter:
model_type: semantic # RecursiveCharacterTextSplitter | tiktoken | SentenceWindowNodeParser | semantic
chunk_size: 512
chunk_overlap: 0
semantic_breakpoint_percentile: 90
retriever:
mode: hybrid # dense | sparse | hybrid
dense_backend: faiss
top_n: 5
dense_top_k: 10
sparse_top_k: 10
dense_weight: 0.5
sparse_weight: 0.5
query_strategy:
type: none # none | multi_query | rag_fusion
embedder:
name: custom # custom | openrouter
model_path: intfloat/multilingual-e5-large
reranker:
model_type: bge_reranker_v2_m3 # none | flashrank | bge_reranker_v2_m3 | jina_reranker_v2_base_multilingual
candidate_top_k: 15
llm:
# модель задается один раз, остальные роли ссылаются на нее через интерполяцию
question_answer_model: openai/gpt-4o-mini
validation_model: ${llm.question_answer_model}
question_generation_model: ${llm.question_answer_model}
base_url: https://openrouter.ai/api/v1
validation:
questions_per_index: 3
paths:
# ${repo_root:...} резолвится в абсолютный путь от корня репозитория,
# независимо от текущей рабочей директории
documents: ${repo_root:data/corpus_debug.zip}
credentials:
# секрет берется из .env (OPENROUTER_API_KEY), в YAML его не хранят;
# null включает fallback в CredentialsConfig
openrouter_api_key: null
Загрузка конфига и запуск (по мотивам notebooks/run_rag_factory_work.ipynb):
from pathlib import Path
from dotenv import load_dotenv
from ragotron.config import load_base_config
from ragotron.orchestration import RagFactory
from ragotron.orchestration.optimizers import OptunaTPEOptimizer
from ragotron.orchestration.search_space import (
CategoricalParam,
FloatRangeParam,
IntRangeParam,
SearchSpace,
)
load_dotenv() # подхватывает OPENROUTER_API_KEY из .env
repo_root = Path.cwd().resolve().parent # из notebooks/ -> корень репозитория
base_config = load_base_config(repo_root / "configs" / "base.yaml")
# При необходимости можно переопределить поля без правки YAML:
# base_config = load_base_config(
# repo_root / "configs" / "base.yaml",
# overrides=["retriever.mode=dense", "splitter.chunk_size=256"],
# )
search_space = SearchSpace(
{
"retriever": {
"mode": CategoricalParam(["dense", "hybrid"]),
"top_n": IntRangeParam(3, 8, 1),
"dense_top_k": IntRangeParam(5, 30, 5),
"sparse_top_k": IntRangeParam(5, 30, 5),
"dense_weight": FloatRangeParam(0.2, 0.8, 0.1),
},
"query_strategy": {
"type": CategoricalParam(["none", "multi_query", "rag_fusion"]),
"n_queries": IntRangeParam(2, 8, 1),
"per_query_top_k": IntRangeParam(5, 20, 5),
"rrf_k": CategoricalParam([20, 40, 60]),
},
"reranker": {
"model_type": CategoricalParam(
["none", "flashrank", "bge_reranker_v2_m3", "jina_reranker_v2_base_multilingual"]
),
"candidate_top_k": IntRangeParam(10, 40, 5),
},
}
)
optimizer = OptunaTPEOptimizer(
n_trials=6,
direction="maximize",
n_startup_trials=2,
multivariate=True,
group=True,
seed=42,
)
factory = RagFactory(base_config=base_config, search_space=search_space, optimizer=optimizer)
# result = await factory.run_async()
load_base_config(...) возвращает обычный dict, поэтому весь прежний код (deep-merge overrides в RagFactory, ручная сборка конфига) работает без изменений — YAML лишь удобнее для хранения, переиспользования и версионирования. Для inference-only сценариев есть load_app_config(...), который сразу возвращает валидированный AppConfig.
OptunaTPEOptimizer — основной оптимизатор для широкого пространства параметров.
Для простого baseline-поиска также доступен GreedyOptimizer.
Для работы доступны следующие ноутбуки:
RAGotron_run_rag_factory.ipynb
Запуск оптимизации черезRagFactory, настройкаSearchSpace, запуск trial и анализ результатов.
Inference из сохраненного trial
После запуска оптимизации через RagFactory можно поднять inference runtime для любого trial по сохраненным артефактам (trial_config.json, индексы, bm25-данные), без пересборки пайплайна и без FastAPI.
from ragotron.inference import RagPipelineInference, resolve_trial_path
# result = await factory.run_async()
best_trial_path = result.get_best_trial_path()
engine = RagPipelineInference.from_trial_path(best_trial_path)
answer = await engine.infer_async("Какие основные этапы RAG-пайплайна?")
print(answer.answer)
Выбор конкретного trial:
from ragotron.inference import RagPipelineInference, resolve_trial_path
# results/experiment_17 + trial_id=1 -> results/experiment_17/trial_1
trial_path = resolve_trial_path("results/experiment_17", trial_id=1)
engine = RagPipelineInference.from_trial_path(trial_path)
df = engine.infer_batch(["Что такое RAG?", "Как работает reranker?"], top_n=3)
print(df[["query", "answer"]])
RagFactory: Search Space и оптимизаторы
RagFactory строит несколько trial-конфигураций и сравнивает их по целевой метрике (например open.correct_pct).
Логика подбора задается двумя сущностями:
SearchSpace— какие параметры можно менять между trial.- Optimizer — как выбирать следующую комбинацию параметров.
Базовые типы параметров для SearchSpace:
CategoricalParam([...])— дискретный выбор из набора значений.IntRangeParam(start, stop, step)— целочисленный диапазон.FloatRangeParam(start, stop, step)— вещественный диапазон.
В пространстве поиска можно задавать gate/conditional-поля: например, при query_strategy.type="none" параметры n_queries/rrf_k не влияют на рантайм, а для reranker логика может зависеть от model_type.
Сокращенный пример:
search_space = SearchSpace(
{
"retriever": {
"mode": CategoricalParam(["dense", "hybrid"]),
"top_n": IntRangeParam(3, 8, 1),
"dense_top_k": IntRangeParam(5, 30, 5),
"sparse_top_k": IntRangeParam(5, 30, 5),
"dense_weight": FloatRangeParam(0.2, 0.8, 0.1),
},
"query_strategy": {
"type": CategoricalParam(["none", "multi_query", "rag_fusion"]),
"n_queries": IntRangeParam(2, 8, 1),
"per_query_top_k": IntRangeParam(5, 20, 5),
"rrf_k": CategoricalParam([20, 40, 60]),
},
"reranker": {
"model_type": CategoricalParam(["none", "flashrank", "bge_reranker_v2_m3"]),
"candidate_top_k": IntRangeParam(10, 40, 5),
},
}
)
optimizer = OptunaTPEOptimizer(
n_trials=6,
direction="maximize",
n_startup_trials=2,
multivariate=True,
group=True,
seed=42,
)
По умолчанию основная стратегия оптимизации — OptunaTPEOptimizer (эффективен для широкого пространства поиска).
В проекте также доступен GreedyOptimizer как более простой baseline-вариант для ограниченного перебора и быстрых smoke-проверок.
FastAPI + Streamlit inference (select + infer)
Можно поднять единый FastAPI-бэкенд и подключить к нему Streamlit-интерфейс. Рекомендуемый порядок запуска:
- Поднять FastAPI (
uvicorn ragotron.serve.app:app ...). - Проверить
/health. - Выполнить
POST /v1/pipelines/selectдля выбора trial. - Выполнять
POST /v1/inferсpipeline_idили без него (если настроен preload). - Поднять Streamlit UI для интерактивной работы.
Схема API:
POST /v1/pipelines/select— выбрать/загрузить trial поtrial_pathилиexperiment_path + trial_id.POST /v1/infer— выполнить инференс поpipeline_idизselect; еслиpipeline_idне передан, используется preloaded pipeline.GET /v1/experiments— discovery experiment/trial только внутриRAGOTRON_SERVE_ALLOWED_ROOTS.GET /health— liveness-check API.
Переменные окружения:
RAGOTRON_SERVE_ALLOWED_ROOTS— список разрешенных корней для артефактов trial (через разделительos.pathsep::на macOS/Linux,;на Windows).
Если переменная не задана, доступ к путям не ограничивается allowlist-правилом.RAGOTRON_SERVE_CACHE_SIZE— размер LRU-кэша загруженных пайплайнов (по умолчанию4).RAGOTRON_SERVE_DEFAULT_TRIAL_PATH— явный путь к trial для preload на старте API.RAGOTRON_SERVE_DEPLOY_MANIFEST— путь кdeploy_manifest.jsonдля preload (используется, еслиRAGOTRON_SERVE_DEFAULT_TRIAL_PATHне задан).
Формат deploy_manifest.json:
- не хранит host absolute paths;
- содержит
best_trial_relative_path(напримерtrial_2), который резолвится относительно директории manifest-файла; - это позволяет использовать один и тот же набор артефактов и на host, и в Docker mount-пути (
/artifacts/...).
Запуск FastAPI:
uvicorn ragotron.serve.app:app --host 0.0.0.0 --port 8000 --workers 1
Проверка здоровья:
curl "http://127.0.0.1:8000/health"
Выбор trial:
curl -X POST "http://127.0.0.1:8000/v1/pipelines/select" \
-H "Content-Type: application/json" \
-d '{"experiment_path":"results/experiment_17","trial_id":1}'
Инференс:
curl -X POST "http://127.0.0.1:8000/v1/infer" \
-H "Content-Type: application/json" \
-d '{"pipeline_id":"<PIPELINE_ID_FROM_SELECT>","query":"Как работает RAG?"}'
Инференс с preloaded pipeline (без pipeline_id):
curl -X POST "http://127.0.0.1:8000/v1/infer" \
-H "Content-Type: application/json" \
-d '{"query":"Как работает RAG?"}'
Discovery experiments/trials:
curl "http://127.0.0.1:8000/v1/experiments"
Запуск Streamlit UI:
streamlit run ragotron/serve/streamlit_app.py
Ограничение текущей реализации: кэш пайплайнов хранится в памяти процесса. При нескольких воркерах/репликах без общего хранилища pipeline_id может отсутствовать в конкретном процессе, поэтому для предсказуемого поведения рекомендуется --workers 1.
Docker deploy (FastAPI + Streamlit)
Для production-ориентированного запуска используйте docker-compose.yml:
- Скопируйте
.env.exampleв.envи заполните значения. - Убедитесь, что
RAGOTRON_RESULTS_HOST_PATHуказывает на папку, где лежатexperiment_*. - Укажите
RAGOTRON_SERVE_DEPLOY_MANIFEST(илиRAGOTRON_SERVE_DEFAULT_TRIAL_PATH) для preload нужного trial. - Поднимите сервисы:
docker compose up -d --build
Особенности docker-потока:
- trial-артефакты не запекаются в образ, а читаются из внешнего read-only volume (
/artifacts); - добавление новых
experiment_*на host не требует пересборки (docker build); - новые эксперименты становятся доступны через
GET /v1/experiments(и после рестарта контейнера); - HuggingFace/Transformers cache вынесен в persistent volume (
ragotron-hf-cache) черезHF_HOME,TRANSFORMERS_CACHE,SENTENCE_TRANSFORMERS_HOME.
Быстрые команды через Makefile:
make up # build + up
make health # проверка /health
make logs # логи сервисов
make refresh # пересоздать контейнеры (подхватить новые experiment_*)
make down # остановить и удалить контейнеры
Как дообучить свой эмбеддер
Эмбеддер можно дообучить под свой корпус прямо в RAGotron — без ручной разметки. Весь сценарий собран в ноутбуке notebooks/Embedder_trainer_pipeline.ipynb:
- конфиг загружается из
configs/finetune.yamlчерезload_app_config(...)(модель из семейства E5, напримерintfloat/multilingual-e5-small, и путь к zip-корпусу), после чегоpipeline.build_indexes()строит индексы из документов; generate_train_data(pipeline, n_samples=100)синтезирует обучающую выборку пар «вопрос ↔ чанк» через LLM (поровну между открытыми и закрытыми вопросами; размер выборки задается параметромn_samples);E5RetrievalTrainerдообучает эмбеддер на этих парах (MultipleNegativesRankingLoss) и сохраняет результат;autometrics_embedderсравнивает retrieval-метрики (MRR / nDCG / MAP) базовой и дообученной модели на валидации.
Дообученную модель затем можно подставить в embedder.model_path обычного пайплайна. Реализация — в ragotron/embedder_trainer/train_embedder.py.
Линтинг и форматирование
Перед коммитом стоит прогнать код через линтер и форматтер. RAGotron использует Ruff — он совмещает в себе линтер и форматтер (замена flake8 + isort + black). Настройки лежат в pyproject.toml (секция [tool.ruff]): включены правила E/F (pyflakes + pycodestyle) и I (сортировка импортов), длина строки контролируется форматтером.
В Makefile есть три команды:
make lint # проверка кода без изменений (ruff check)
make format # форматирование кода (ruff format)
make fix # автоисправление проблем, включая порядок импортов (ruff check --fix)
Рекомендуемый порядок перед коммитом:
make fix— автоматически чинит то, что чинится (сортировка импортов, часть мелких замечаний);make format— приводит форматирование к единому стилю;make lint— финальная проверка; если выводитAll checks passed!, можно коммитить.
Ruff не установлен по умолчанию вместе с пакетом, поставить его можно через pip install ruff.
Файловая структура
Структура проекта:
RAGotron
├── README.md
├── ragotron/
│ ├── core/ # пайплайн, конфиги, retrieval/generation/validation-компоненты
│ ├── orchestration/ # RagFactory, SearchSpace, optimizers (OptunaTPE, Greedy)
│ ├── inference/ # загрузка trial-артефактов и inference runtime
│ ├── serve/ # FastAPI + Streamlit интерфейсы
│ ├── autovalidation/ # метрики и валидация ответов
│ ├── llm/ # фабрики и structured-output утилиты
│ ├── config/ # prompt templates + OmegaConf YAML loader
│ └── utils/ # workspace/saver/logging утилиты
├── configs/ # YAML-конфиги (base.yaml, finetune.yaml), грузятся через ragotron.config
├── docs/
├── notebooks/
├── tests/
├── setup.cfg
└── setup.py
Доступные параметры конфига
SplitterConfig:
-
model_type
RecursiveCharacterTextSplitter - рекурсивное разбиение текста на чанки по символам
tiktoken - разбиение текста с использованием токенизатора tiktoken -
chunk_size
Размер одного текстового фрагмента (чанка) в токенах/символах
По умолчанию: 512 -
chunk_overlap
Размер перекрытия между соседними чанками в токенах/символах
По умолчанию: 0 -
window_size
Количество предложений в окне контекста при использовании SentenceWindowNodeParser
По умолчанию: 3
EmbedderConfig:
-
name
custom - SentenceTransformers эмбеддер, можно использовать название модели из HuggingFace Hub.openrouter - эмбеддер через OpenRouter API (
openrouter.embeddings.generate).По умолчанию: "custom"
-
model_pathНазвание модели эмбеддингов. Дляcustom- модель HuggingFace/локальный путь. Дляopenrouter- название модели OpenRouter. По умолчанию:"intfloat/multilingual-e5-large"
RetrieverConfig:
-
mode
dense— только векторный поиск (Faiss / Chroma)
sparse— только лексический поиск BM25S
hybrid— оба поиска + взвешенная fusion
По умолчанию:"dense" -
dense_backend
faiss— FAISS,chroma— ChromaDB
По умолчанию:"faiss" -
top_n
Количество финальных чанков, которые будут извлекаться
По умолчанию:5 -
dense_top_k/sparse_top_k
Количество кандидатов из каждого ретривера перед fusion (для hybrid)
По умолчанию:10 -
dense_weight/sparse_weight
Веса для взвешенной нормализованной fusion; автоматически нормализуются так, чтобы сумма = 1
По умолчанию:0.5/0.5
QueryStrategyConfig:
-
type
none— обычный single-query retrieval
multi_query— несколько rewrite-запросов, затем объединение и дедупликация документов
rag_fusion— несколько rewrite-запросов + Reciprocal Rank Fusion
По умолчанию:"none" -
n_queries
Количество альтернативных запросов, генерируемых LLM
По умолчанию:4 -
include_original_query
Добавлять ли исходный вопрос в список запросов перед retrieval
По умолчанию:True -
per_query_top_k
Сколько документов забирать на каждый rewrite-запрос
По умолчанию:10 -
rrf_k
Параметр формулы RRF1 / (rrf_k + rank)(используется только приrag_fusion)
По умолчанию:60
LLMConfig:
-
question_answer_model
Название модели для генерации ответов на вопросы (в формате OpenRouter)
Пример:"openai/gpt-4o-mini" -
validation_model
Название модели для валидации ответов
Пример:"openai/gpt-4o-mini" -
question_generation_model
Название модели для генерации вопросов
Пример:"openai/gpt-4o-mini" -
base_url
URL API-эндпоинта для LLM
По умолчанию:"https://openrouter.ai/api/v1" -
temperature
Температура генерации для LLM
По умолчанию: 0.0 -
max_tokens
Максимальное количество токенов в ответе
По умолчанию: 4096 -
system_prompt_template
Шаблон системного промпта для генерации ответов
По умолчанию уже задан -
user_query_list
Список пользовательских вопросов на которые сгенерируются ответы во время сборки пайплайна По умолчанию: пустой список
ValidationConfig:
-
compare_with_benchmark
Флаг для включения сравнения с ответами benchmark-модели По умолчанию: False -
benchmark_model
Название модели для benchmark-сравнения
Пример:"openai/gpt-4o" -
questions_per_index
Количество вопросов, генерируемых для каждого индекса. Если значениеNone, ограничение не задается и вопросы генерируются по всем чанкам в индеках По умолчанию: 3
PathsConfig:
-
documents
Путь к zip архиву в котором только docx файлы для создания поискового индекса.Важно!
- Все файлы должны быть названы на английском языке для корректной работы создания индекса. - Архив должен содержать только документы (без вложенных папок). -
results_path
Путь для сохранения результатов
По умолчанию: "./results" -
experiment_folder_name
Название папки для текущего эксперимента. По умолчанию: None
CredentialsConfig:
openrouter_api_key
API ключ для OpenRouter. Если не указан, будет использована переменная окруженияOPENROUTER_API_KEY
Описание Артефактов
При запуске оптимизации через RagFactory результаты сохраняются в results/<experiment_name>/.
Актуальная структура ориентирована на trial (trial_0, trial_1, ...), а не на stage-папки.
Артефакты уровня эксперимента
leaderboard.csv— агрегированная таблица метрик по всем trial.optimization_summary.json— подробный список trial с метриками, overrides и статусами.best_config.yaml— лучшая конфигурация по целевой метрике.pairwise_tournament_params.json— параметры турнирного сравнения (если включено).run.log— общий лог запуска эксперимента.
Артефакты уровня trial (trial_<id>/)
trial_config.json— полный конфиг конкретного trial.trial_result.json— финальные метрики, latency/runtime и служебная информация.trial.logиrun.log— логи выполнения trial.<doc>.json— document-level артефакты с чанками/метаданными для dense retrieval.bm25_<doc>/— sparse-индекс (corpus.jsonl,corpus.mmindex.json,params.index.json,vocab.index.json).source_files/corpus_debug/— копии исходных документов для отладки корпуса.
Пример актуальной структуры артефактов:
results/
└── experiment_1/
├── leaderboard.csv
├── pipeline_trials_detailed.xlsx
├── optimization_summary.json
├── best_config.yaml
├── pairwise_tournament_params.json
├── run.log
├── trial_0/
│ ├── trial_config.json
│ ├── trial_result.json
│ ├── trial.log
│ ├── run.log
│ ├── fastapi__dependencies__index.json
│ ├── bm25_fastapi__dependencies__index/
│ │ ├── corpus.jsonl
│ │ ├── corpus.mmindex.json
│ │ ├── params.index.json
│ │ └── vocab.index.json
│ └── source_files/corpus_debug/
├── trial_1/
└── ...
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ragotron-0.0.1.tar.gz.
File metadata
- Download URL: ragotron-0.0.1.tar.gz
- Upload date:
- Size: 156.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fcfccaf173b61092adc763013c7c780b4c3849f79652358f38a058a52af27d1a
|
|
| MD5 |
ae637bf279b1278a7c9bddbb2504c6c1
|
|
| BLAKE2b-256 |
da91b54e91ba8d77ff7c2c6e4bfe4ff07c9b9a6f5732bc2aecbef3402f502912
|
File details
Details for the file ragotron-0.0.1-py3-none-any.whl.
File metadata
- Download URL: ragotron-0.0.1-py3-none-any.whl
- Upload date:
- Size: 174.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.5
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ef127407083b7dee7c2721df955f69af95b28d5b1977f1ef78245e84113e95eb
|
|
| MD5 |
cc588651f8ae785d38f201e55efdb912
|
|
| BLAKE2b-256 |
6ba84636071e7926ff50e4f00696b91e291eb368265a6aa21ce6095c2b2a7abc
|