Skip to content

Commit d88cc20

Browse files
committed
chore: update .gitignore to exclude additional cache and build files
This commit enhances the .gitignore file by adding entries to ignore various cache directories, compiled Python files, and build artifacts, ensuring a cleaner project structure and preventing unnecessary files from being tracked in the repository.
1 parent c10c6cb commit d88cc20

3 files changed

Lines changed: 37 additions & 186 deletions

File tree

.gitignore

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,18 @@
11
.env
2+
3+
.pytest_cache/
4+
5+
**/__pycache__/
6+
*.py[cod]
7+
*$py.class
8+
*.so
9+
10+
content/
11+
.venv/
12+
.venv_readme_check/
13+
.ruff_cache/
14+
.mypy_cache/
15+
dist/
16+
build/
17+
*.egg-info/
18+
scripts/

README.md

Lines changed: 20 additions & 186 deletions
Original file line numberDiff line numberDiff line change
@@ -1,186 +1,20 @@
1-
<p align="center">
2-
<img src="frontend/assets/images/KernelBanner.webp" alt="KernelBot" width="100%" />
3-
</p>
4-
5-
# KernelBot
6-
7-
**Chatbot RAG local-first que transforma Markdown em base de conhecimento consultável via chat.**
8-
9-
---
10-
11-
## O que é
12-
13-
O KernelBot — internamente chamado **ACL (Agente de Contexto Local)** — é um sistema que indexa arquivos Markdown de um diretório local (`content/`) usando BM25, recupera trechos relevantes e os injeta como contexto para um LLM via OpenRouter. A resposta chega em streaming (SSE) com rastreabilidade: você sabe de onde veio cada trecho usado.
14-
15-
Sem banco de dados, sem fila, sem infra pesada. Índice e estado ficam na memória do processo.
16-
17-
---
18-
19-
## Problema que resolve
20-
21-
Alunos precisam revisar gravações de aulas de ~2h para tirar dúvidas simples. Sem o KernelBot, a alternativa é reassistir o material bruto ou esperar resposta da secretaria/professores.
22-
23-
O sistema usa resumos estruturados das aulas como corpus RAG, permitindo perguntas diretas com respostas ancoradas no conteúdo real — não em "achismo" do modelo.
24-
25-
---
26-
27-
## Como funciona
28-
29-
```
30-
content/*.md ──► SearchEngine (BM25 por silo) ──► ContextManager ──► ChatProvider ──► SSE
31-
▲ │
32-
│ ▼
33-
Watchdog OpenRouter API
34-
(rebuild automático) (LLM com fallback)
35-
```
36-
37-
**Três etapas:**
38-
39-
1. **Indexação**`SearchEngine``content/**/*.md`, divide por headers em chunks e cria um índice BM25 separado por silo (subpasta). O Watchdog monitora alterações e reconstrói o índice automaticamente (~1.5s de debounce).
40-
41-
2. **Decisão de contexto**`ContextManager.build_messages()` interpreta comandos (`/python`, `/doc`, `/content`), campo `discipline` do JSON e pinned context por sessão para decidir quais chunks injetar no system prompt.
42-
43-
3. **Geração**`ChatProvider` chama o LLM via OpenRouter em streaming SSE. Suporta fallback automático entre modelos. Antes dos tokens, emite metadados (`[ACL_META]`) com rótulo do silo e fontes usadas.
44-
45-
---
46-
47-
## Diferenciais
48-
49-
| Recurso | O que faz |
50-
|---------|-----------|
51-
| **Silos BM25** | Cada subpasta de `content/` é um domínio isolado com índice próprio — evita mistura de contextos entre disciplinas |
52-
| **Comandos de escopo** | `/python`, `/doc`, `/content` etc. forçam onde a busca acontece |
53-
| **Pinned context** | Mantém contexto entre mensagens da mesma sessão para follow-ups curtos não "perderem o fio" |
54-
| **File watching** | Editou um `.md` em `content/`? Em ~1.5s o índice já reflete a mudança |
55-
| **Rastreabilidade** | Respostas incluem breadcrumbs com os arquivos fonte usados (via `[ACL_META]` no SSE) |
56-
| **Zero infra** | Sem banco, sem Redis, sem Docker obrigatório — `python main.py` e pronto |
57-
58-
---
59-
60-
## Estrutura de pastas
61-
62-
```
63-
KernelBot/
64-
├── main.py # Orquestração: serviços, watchdog, app FastAPI
65-
├── core/ # Settings (.env), logging centralizado
66-
├── engine/ # SearchEngine, ContentWatcher, ContextManager, ChatProvider, PinnedSessionStore
67-
├── api/ # Rotas FastAPI (GET /, POST /chat)
68-
├── app/ # create_app(), estado injetado (AppServices)
69-
├── content/ # Base de conhecimento — silos por subpasta
70-
│ ├── python/ # 16 aulas
71-
│ ├── visualizacao-sql/# 17 aulas
72-
│ ├── projeto-bloco/ # 9 aulas
73-
│ ├── planejamento-curso-carreira/ # 7 aulas
74-
│ └── doc/ # Documentação interna (silo /doc)
75-
├── frontend/ # Assets CSS e módulos JS da UI
76-
├── templates/ # index.html (Jinja2)
77-
├── tests/ # Smoke tests (pytest)
78-
└── requirements.txt
79-
```
80-
81-
---
82-
83-
## Como rodar
84-
85-
### Pré-requisitos
86-
87-
- Python 3.10+
88-
- Chave de API do [OpenRouter](https://openrouter.ai/)
89-
90-
### Instalação
91-
92-
```bash
93-
git clone https://github.com/seu-usuario/KernelBot.git
94-
cd KernelBot
95-
pip install -r requirements.txt
96-
```
97-
98-
### Configuração
99-
100-
Crie um arquivo `.env` na raiz:
101-
102-
```
103-
OPENROUTER_API_KEY=sua-chave-aqui
104-
```
105-
106-
Variáveis opcionais:
107-
108-
| Variável | Default | Descrição |
109-
|----------|---------|-----------|
110-
| `ACL_GLOBAL_CONTEXT` | `geral` | Escopo BM25 sem filtro: `geral` (só silo geral) ou `all` (todos os silos) |
111-
| `ACL_PINNED_MAX_TURNS` | `5` | Turnos antes do pinned context expirar |
112-
| `ACL_PINNED_MAX_CHARS` | `24000` | Limite de caracteres no pinned context |
113-
| `ACL_PINNED_WEAK_SCORE` | `0.4` | Score BM25 abaixo do qual se reutiliza o pin |
114-
115-
### Executar
116-
117-
```bash
118-
python main.py
119-
```
120-
121-
Ou com reload para desenvolvimento:
122-
123-
```bash
124-
uvicorn main:app --host 127.0.0.1 --port 8000 --reload
125-
```
126-
127-
Acesse `http://127.0.0.1:8000`.
128-
129-
---
130-
131-
## Comandos do chat
132-
133-
| Comando | Efeito |
134-
|---------|--------|
135-
| `/python <pergunta>` | Busca RAG restrita ao silo `python` |
136-
| `/visualizacao-sql <pergunta>` | Busca RAG restrita ao silo `visualizacao-sql` |
137-
| `/projeto-bloco <pergunta>` | Busca RAG restrita ao silo `projeto-bloco` |
138-
| `/planejamento-curso-carreira <pergunta>` | Busca RAG restrita ao silo `planejamento-curso-carreira` |
139-
| `/doc <pergunta>` | Injeta todo o conteúdo de `content/doc/` no prompt |
140-
| `/content <pergunta>` | Força RAG no escopo global (com fallback para os primeiros chunks se não houver hit) |
141-
| `/reset` ou `/limpar` | Limpa o pinned context da sessão |
142-
143-
Sem comando, o sistema usa o campo `discipline` do JSON (se enviado) ou o escopo global configurado.
144-
145-
---
146-
147-
## Testes
148-
149-
```bash
150-
python -m pytest tests/ -v
151-
```
152-
153-
---
154-
155-
## Limitações
156-
157-
- **BM25 é lexical, não semântico** — se o vocabulário da pergunta divergir do corpus, o retrieval pode falhar. Use `/content` para forçar contexto.
158-
- **Sem autenticação** — adequado para uso local (`127.0.0.1`). Não expor em rede sem proteção adicional.
159-
- **Pinned context em RAM** — reiniciar o servidor perde o estado de sessão.
160-
- **Comandos de silo não são automáticos** — novas subpastas em `content/` indexam automaticamente, mas o atalho `/nome` precisa ser adicionado manualmente em `_DISCIPLINE_COMMAND_PREFIXES` (`engine/context.py`).
161-
- **Versões não fixadas**`requirements.txt` sem pins exatos; risco de drift em novas instalações.
162-
163-
---
164-
165-
## Por que existe
166-
167-
Criado para resolver uma dor real: alunos do INFNET gastavam horas revisando gravações de aula para tirar dúvidas pontuais. O KernelBot transforma resumos estruturados dessas aulas em uma base pesquisável via chat — com controle de escopo, rastreabilidade e zero dependência de infra complexa.
168-
169-
---
170-
171-
## Stack
172-
173-
| Camada | Tecnologia |
174-
|--------|------------|
175-
| Servidor HTTP | FastAPI + Uvicorn |
176-
| Índice de busca | BM25Okapi (`rank-bm25`) |
177-
| File watching | Watchdog |
178-
| LLM gateway | OpenRouter API (`httpx` async) |
179-
| Frontend | HTML/CSS/JS puro (Jinja2) |
180-
| Streaming | Server-Sent Events (SSE) |
181-
182-
---
183-
184-
## Licença
185-
186-
Veja o arquivo [LICENSE](LICENSE).
1+
<div align="center">
2+
<img src="frontend/assets/images/KernelBanner.webp" alt="Banner" width="100%" />
3+
</div>
4+
5+
<br />
6+
7+
<div>
8+
<img align="right" width="50%" src="frontend/assets/images/spiderMan.webp" alt="Work in Progress" />
9+
10+
<strong><h3>Em obras (ou quase isso)</h3></strong>
11+
12+
<p>O código já está performando mais que muito sênior por aí, mas a documentação ainda está sendo "indexada" pela minha produtividade.</p>
13+
14+
<p>
15+
<strong>Se você é um recrutador:</strong> O código fala mais que mil palavras. Olhe a pasta <code>engine/</code>.<br />
16+
<strong>Se você é um curioso:</strong> Volte em breve. Ou dê um <code>python main.py</code> e descubra.
17+
</p>
18+
19+
<br clear="all" />
20+
</div>
1010 KB
Loading

0 commit comments

Comments
 (0)