--- title: RPG-RAG emoji: 🎲 colorFrom: purple colorTo: blue sdk: gradio sdk_version: "6.9.0" python_version: "3.12" app_file: app.py pinned: false --- # RPG-RAG Um kit pessoal para organizar **lore/campanhas de RPG** e usar **LLMs locais** pra ajudar durante e depois das sessões. O repositório hoje tem 3 “pilares” principais: 1. **Session Helper (Tkinter)**: seleciona uma campanha, transcreve um áudio e gera um resumo via Ollama. 2. **UI protótipo (PyQt6)**: um menu básico para futuramente unir geração + pós-sessão. 3. **PDF reader (PyMuPDF)**: extrai texto de PDFs e detecta imagens (com placeholder para descrever as imagens). > Status: o projeto está em desenvolvimento e algumas partes ainda são rascunhos (ex.: `src/brain.py`, `src/get_data.py`, geradores em `src/gen/`). ## Funcionalidades - **Campanhas**: carrega campanhas em `Data/Campaings/campaings.json`. - **Transcrição**: usa Whisper para transcrever arquivo de áudio (ex.: MP3). - **Resumo**: usa um LLM via **Ollama** pra resumir a sessão. - **Extração de PDF**: pega texto e imagens e salva imagens extraídas. ## Estrutura do projeto - `Data/` - `Campaings/`: campanhas e sessões - `Ekalia/`: lore/mundo em `.txt` (obsidian-friendly) - `Audios/`: exemplos de áudio - `src/` - `main.py`: app Tkinter (Session Helper) - `main2.py`: protótipo PyQt6 - `ears/whisper.py`: transcrição e resumo - `pdf_reader/pdf_agent.py`: extrator de PDF (texto + imagens) - `brain.py`: experimentos com agentes/LLM (atenção: contém prompts inadequados e não representa o objetivo final) - `get_data.py`: experimento para ler dados e jogar em dataframe (precisa de ajustes) - `models/`: modelos locais (ex.: qwen) ## Pré-requisitos - Python 3.10+ (recomendado) - (Opcional) GPU/CUDA para Whisper acelerar — funciona em CPU também. - **Ollama instalado e rodando** (para o resumo): https://ollama.com ## Instalação Crie um ambiente virtual e instale dependências: ```bash python -m venv .venv source .venv/bin/activate pip install -r requirements.txt ``` ## Como rodar ### 1) Session Helper (Tkinter) Abre uma UI simples para: - listar campanhas - selecionar campanha - escolher um arquivo de áudio - transcrever e gerar resumo ```bash python src/main.py ``` **Observações** - O arquivo de campanhas precisa existir em `Data/Campaings/campaings.json`. - O resumo usa Ollama via LangChain. Ajuste o modelo em `src/ears/whisper.py` (variável `LLM_MODEL`). ### 2) Protótipo de UI (PyQt6) Interface base com navegação de telas. ```bash python src/main2.py ``` ### 3) Extrator de PDF Processa um PDF e salva imagens encontradas em `extracted_images/`. ```bash python src/pdf_reader/pdf_agent.py ``` Por padrão o script tenta ler `DH.pdf` na raiz. Se não existir, edite `test_pdf_path` no final do arquivo. ## LLM Local com vLLM (opcional) O projeto suporta rodar um LLM local via [vLLM](https://github.com/vllm-project/vllm) como alternativa à API da Groq. Útil pra desenvolvimento offline, custos zero e (futuramente) servir modelos fine-tuned. ### Por que um venv separado vLLM tem requisitos rígidos de torch/CUDA que conflitam com Whisper e `langchain-huggingface` no venv principal. A solução padrão é isolar o vLLM em seu próprio ambiente — o projeto principal só conversa com ele via HTTP. ``` .venv/ ← venv principal (Whisper, FAISS, embeddings, gradio…) .venv-vllm/ ← venv isolado, só com vllm + suas deps CUDA ``` ### Setup (uma vez) Pré-requisito: GPU NVIDIA com pelo menos 16GB VRAM (testado em RTX 5060 Ti). ```bash uv venv .venv-vllm --python 3.12 uv pip install --python .venv-vllm/bin/python vllm --torch-backend=auto ``` A flag `--torch-backend=auto` deixa o uv detectar a versão do CUDA pelo `nvidia-smi` e baixar o wheel compatível. Em GPUs Blackwell (RTX 50xx) com driver recente isso é o stack CUDA 13. ### Subindo o servidor ```bash python vllm/run_local.py ``` O script: - Aponta pro binário em `.venv-vllm/bin/vllm` - Configura `LD_LIBRARY_PATH` pra encontrar os `.so` de CUDA do venv isolado - Sobe um servidor **OpenAI-compatible** em `http://localhost:8000/v1` - Modelo padrão: `Qwen/Qwen2.5-7B-Instruct-AWQ` (4-bit, cabe folgado em 16GB) Primeira execução baixa o modelo (~5GB) em `vllm/Models/` (ignorado pelo git). ### Usando no código `src/llm/client.py` expõe três papéis (`Role`): ```python from src.llm.client import get_llm, Role llm = get_llm(Role.FAST) # → Groq llama-3.1-8b-instant (padrão) llm = get_llm(Role.CREATIVE) # → Groq llama-3.3-70b-versatile llm = get_llm(Role.LOCAL) # → vLLM local (Qwen2.5-7B-AWQ) ``` `Role.LOCAL` usa `ChatOpenAI` apontando pro endpoint local — não precisa de nenhum SDK específico do vLLM. ### Variáveis de ambiente (opcionais) Todas têm default sensato; só sobrescreva no `.env` se precisar mudar: | Variável | Default | Para quê | | --- | --- | --- | | `VLLM_BASE_URL` | `http://localhost:8000/v1` | URL do servidor local | | `VLLM_MODEL` | `Qwen/Qwen2.5-7B-Instruct-AWQ` | Modelo servido pelo vLLM | | `VLLM_API_KEY` | `EMPTY` | Token (vLLM aceita qualquer string por padrão) | ### Smoke test Com o servidor rodando em outro terminal: ```bash python -m src.llm.client --local ``` Deve imprimir uma resposta do Qwen local. Sem `--local`, usa Groq (`Role.CREATIVE`) — bom pra confirmar que o fallback continua funcionando. --- ## Notas importantes / TODOs - `src/brain.py` contém experimentos com agentes e prompts de teste. Use como referência de experimentação, não como “produção”. - `src/get_data.py` tem um bug (tenta imprimir `context['file_path']` mas a chave criada é `file name`). - Os geradores em `src/gen/` estão vazios no momento. - `src/main.py` tem um TODO antigo: “Trocar Tkinter por PySide6”. Hoje há um protótipo em PyQt6 (`main2.py`). ## Troubleshooting ### Whisper muito lento - Em CPU, o Whisper (principalmente `large`) pode demorar bastante. - Você pode trocar o modelo em `src/ears/whisper.py` (ex.: `base`, `small`, `medium`, `large`). ### Ollama não responde - Garanta que o daemon do Ollama está rodando. - Garanta que o modelo configurado em `LLM_MODEL` existe (ex.: `ollama pull deepseek-r1:latest`). ## Licença Se você quiser, posso adicionar uma licença explícita (MIT/Apache-2.0/etc). Por enquanto, o repositório não declara licença aqui no README.