AI-assisted pipeline for reviewing FINN.no LEGO alert emails, researching current resale value, and surfacing only clear buy signals.
This project is built as a decision-support tool, not an automated purchasing bot. It reads saved-search emails from Gmail, extracts FINN listings, researches LEGO set prices with web search and OpenAI, converts prices to NOK, and writes structured JSON output for listings that pass the valuation rules.
Active prototype.
Important limitations:
- The system does not buy products automatically.
- The system does not scrape FINN listing pages directly in the current pipeline.
- The system depends on search-result quality, OpenAI output quality, and conservative valuation thresholds.
- This is not financial advice. Treat every result as a candidate that still needs human review.
- Fetch Gmail messages from the last 24 hours.
- Find the newest FINN.no notification email.
- Extract listing candidates from the email into
temp/finn_candidates.json. - Detect LEGO set numbers from each listing title.
- Remove candidates with missing or ambiguous LEGO set numbers.
- Ask OpenAI to plan price-focused web searches for each candidate.
- Run searches through DDGS/DuckDuckGo and extract price evidence.
- Ask OpenAI to judge whether the evidence is good enough.
- Convert supported currencies to NOK with Frankfurter.
- Calculate whether the estimated value clears the configured margin threshold.
- Write completed results to
output/YYYY-MM-DD/<source_email_id>/.
- Python 3.11 or newer.
- A Gmail account receiving FINN.no saved-search emails.
- A Google Cloud project with Gmail API enabled.
- An OpenAI API key.
- Network access for Gmail, OpenAI, DDGS/DuckDuckGo search, and Frankfurter currency conversion.
No Google Custom Search API key or Search Engine ID is required in the current version.
git clone https://github.com/wessel05j/BrickSignal.git
cd BrickSignalWindows PowerShell:
python -m venv .venv
.\.venv\Scripts\Activate.ps1macOS/Linux:
python3 -m venv .venv
source .venv/bin/activatepip install -r requirements.txtCopy the example file:
Windows PowerShell:
Copy-Item .env.example .envmacOS/Linux:
cp .env.example .envThen edit .env and replace the placeholder values.
- Go to the OpenAI API keys page.
- Create a new API key.
- Add it to
.env:
OPENAI_API_KEY=sk-proj-your-key-here
OPENAI_MODEL=gpt-4.1-miniThe default model is gpt-4.1-mini because it is a practical balance between price and reasoning quality for this research workflow.
Useful OpenAI references:
The project uses read-only Gmail access through OAuth. OAuth means you approve access in a browser, and Google gives the app a local token. The token is stored on your machine and is ignored by Git.
- Open Google Cloud Console.
- Create or select a project for BrickSignal.
- Enable the Gmail API:
- Go to "APIs & Services" -> "Library".
- Search for "Gmail API".
- Enable it.
- Configure the OAuth consent screen:
- Go to "APIs & Services" -> "OAuth consent screen".
- Use "External" for a personal/test app if needed.
- Add yourself as a test user if Google asks for test users.
- Create OAuth credentials:
- Go to "APIs & Services" -> "Credentials".
- Click "Create credentials" -> "OAuth client ID".
- Choose application type "Desktop app".
- Download the JSON file.
- Save the downloaded file as:
google/credentials.json
On the first run, the program opens a browser window for Google login. After you approve read-only Gmail access, it creates:
google/token.json
Both google/credentials.json and google/token.json are ignored by Git.
Useful Google references:
- Create a saved search on FINN.no for the LEGO category or query you want to monitor.
- Enable email notifications for that saved search.
- Let the notification email arrive in the Gmail account connected above.
- Run the pipeline after a new FINN email arrives.
The current pipeline expects FINN email notifications and normally processes only the newest FINN email from the last 24 hours.
python main.pyIf no new FINN email is available, the program exits without creating a new run.
If the newest FINN email was already processed, the program exits and points to the existing output.
All configuration is local and should live in .env.
| Variable | Default | Purpose |
|---|---|---|
OPENAI_API_KEY |
required | OpenAI API key. |
OPENAI_MODEL |
gpt-4.1-mini |
Model used for search planning and evidence judging. |
OPENAI_MAX_RESEARCH_RETRIES |
3 |
Maximum search/judge rounds per candidate. |
OPENAI_SEARCH_QUERIES_PER_ROUND |
5 |
Max AI-planned searches per round. |
OPENAI_MAX_OUTPUT_TOKENS |
4000 |
Max response size for structured OpenAI outputs. |
OPENAI_TIMEOUT_SECONDS |
90 |
OpenAI request timeout. |
AI_RESEARCH_MAX_CANDIDATES |
all |
Limit how many candidates are researched. Useful for testing. |
DDG_REGION |
no-no |
DDGS/DuckDuckGo search region. |
DDG_SAFESEARCH |
moderate |
Search safety setting. |
DDG_RESULTS_PER_QUERY |
10 |
Search results fetched per query. |
DDG_MAX_CANDIDATES |
all |
Legacy/manual DDG enrichment candidate limit. |
DDG_REQUEST_DELAY_SECONDS |
1.5 |
Delay between search requests. Helps reduce rate limits. |
VALUATION_DEFAULT_SHIPPING_NOK |
79 |
Assumed shipping cost. |
VALUATION_SAFETY_BUFFER_NOK |
100 |
Extra buffer for fees, uncertainty, and mistakes. |
VALUATION_BUY_MARGIN_PCT |
0.40 |
Required margin above total cost. 0.40 means 40%. |
VALUATION_MIN_USABLE_PRICES |
3 |
Minimum accepted price evidence count. |
VALUATION_MIN_AI_CONFIDENCE |
0.70 |
Minimum AI evidence confidence. |
TEMP_CONFLICT_ACTION |
empty | Optional non-interactive conflict action: continue or new. |
During a run, checkpoint data is stored in:
temp/finn_candidates.json
This allows interrupted runs to continue later. If a run is complete, the final output is written to:
output/YYYY-MM-DD/<source_email_id>/clear_buy_signals.json
output/YYYY-MM-DD/<source_email_id>/run_summary.json
After output is written, temp/ is deleted automatically.
If temp/ exists and a newer FINN email is available, the program asks whether to continue the previous run or delete temp and start the new one.
For non-interactive runs, set:
TEMP_CONFLICT_ACTION=continueor:
TEMP_CONFLICT_ACTION=newThe repository is configured to ignore local secrets and generated files:
.envgoogle/credentials.jsongoogle/token.jsoncredentials.jsontoken.jsonclient_secret_*.json.venv/temp/output/
Never commit API keys, OAuth credentials, Gmail tokens, or generated research output.
This project is licensed under the MIT License. See LICENSE.