File size: 2,799 Bytes
380e7c5
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
ff78bf9
380e7c5
 
 
 
 
 
 
 
ff78bf9
380e7c5
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# Contributing to Focus Buddy

Thanks for taking a look. Issues and pull requests are both welcome.

## Getting set up

```bash
git clone https://github.com/dormoyi/focus_buddy
cd focus_buddy
python -m venv .venv && source .venv/bin/activate
pip install -e . --group dev
cp .env.example .env      # add your OPENAI_API_KEY
```

Check that everything works:

```bash
pytest                          # no network, camera or models needed
ruff check . && ruff format --check .
mypy src/
```

## Running it

```bash
focus-buddy --desktop --debug   # laptop webcam, short intervals
focus-buddy                     # connect to a Reachy Mini
```

`--debug` shortens the nudge cooldown to 15 seconds and the summary interval to three
minutes, which makes a full demo take a minute rather than an hour.

## The shape of the code

The loop is one tick: grab a frame, classify it into an `Observation`, record it, and
sometimes speak. Four things are pluggable, each behind a `Protocol` with a small factory
that reads `Settings`:

| Thing | Protocol | Factory |
|---|---|---|
| Vision | `perception.base.VisionBackend` | `perception.build_vision_backend` |
| Nudge phrasing | `brain.base.NudgeWriter` | `brain.build_nudge_writer` |
| Speech | `speech.base.SpeechBackend` | `speech.build_speech_backend` |
| Camera + speaker | `hardware.base.Body` | constructed in `main` |

Adding a backend means adding a file and one branch in the relevant factory. It should not
mean touching `loop.py`.

Two conventions worth respecting:

- **Import heavy dependencies inside functions.** The robot dashboard imports `main.py` just
  to list installed apps; it should not pull in OpenCV or a model as a side effect.
- **Never read the environment at import time.** Configuration is resolved once, into
  `Settings`, and passed down. This is what keeps the tests hermetic.

## Tests

`tests/conftest.py` has fakes for every collaborator, so the whole loop can run without a
camera, a robot, a model or a network. New behaviour in `loop.py` should be testable there.

`tests/test_captions.py` is a regression suite: every case is something a real vision model
actually said. If you tune a pattern in `perception/captions.py`, run it - those tests are
the only thing that catches a change that silently breaks detection for a phrasing you
were not thinking about. When you fix a new misclassification, add the caption that caused
it.

## Pull requests

- Keep `ruff`, `mypy` and `pytest` green.
- One concern per PR.
- If you change what the buddy says or when it says it, say so in the description - that is
  the part users actually experience.

## Code of conduct

Be decent to each other. Harassment or personal attacks are not welcome here, and
maintainers will remove contributions and contributors that involve them.