Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 81 additions & 71 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,6 +1,61 @@
# Created by https://www.toptal.com/developers/gitignore/api/python,emacs
# Edit at https://www.toptal.com/developers/gitignore?templates=python,emacs

### Emacs ###
# -*- mode: gitignore; -*-
*~
\#*\#
/.emacs.desktop
/.emacs.desktop.lock
*.elc
auto-save-list
tramp
.\#*

# Org-mode
.org-id-locations
*_archive

# flymake-mode
*_flymake.*

# eshell files
/eshell/history
/eshell/lastdir

# elpa packages
/elpa/

# reftex files
*.rel

# AUCTeX auto folder
/auto/

# cask packages
.cask/
dist/

# Flycheck
flycheck_*.el

# server auth directory
/server/

# projectiles files
.projectile

# directory configuration
.dir-locals.el

# network security
/network-security.data


### Python ###
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[codz]
*.py[cod]
*$py.class

# C extensions
Expand All @@ -10,7 +65,6 @@ __pycache__/
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
Expand All @@ -27,8 +81,8 @@ share/python-wheels/
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

Expand All @@ -46,7 +100,7 @@ htmlcov/
nosetests.xml
coverage.xml
*.cover
*.py.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
Expand Down Expand Up @@ -92,37 +146,22 @@ ipython_config.py
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
# Pipfile.lock

# UV
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# uv.lock
#Pipfile.lock

# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
# poetry.lock
# poetry.toml
#poetry.lock

# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
# pdm.lock
# pdm.toml
.pdm-python
.pdm-build/

# pixi
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
# pixi.lock
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
# in the .venv directory. It is recommended not to include this directory in version control.
.pixi
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
Expand All @@ -131,25 +170,11 @@ __pypackages__/
celerybeat-schedule
celerybeat.pid

# Redis
*.rdb
*.aof
*.pid

# RabbitMQ
mnesia/
rabbitmq/
rabbitmq-data/

# ActiveMQ
activemq-data/

# SageMath parsed files
*.sage.py

# Environments
.env
.envrc
.venv
env/
venv/
Expand Down Expand Up @@ -182,37 +207,22 @@ dmypy.json
cython_debug/

# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
# .idea/

# Abstra
# Abstra is an AI-powered process automation framework.
# Ignore directories containing user credentials, local state, and settings.
# Learn more at https://abstra.io/docs
.abstra/

# Visual Studio Code
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
# and can be added to the global gitignore or merged into this file. However, if you prefer,
# you could uncomment the following to ignore the entire vscode folder
# .vscode/
# Temporary file for partial code execution
tempCodeRunnerFile.py

# Ruff stuff:
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

### Python Patch ###
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
poetry.toml

# ruff
.ruff_cache/

# PyPI configuration file
.pypirc
# LSP config files
pyrightconfig.json

# Marimo
marimo/_static/
marimo/_lsp/
__marimo__/
# End of https://www.toptal.com/developers/gitignore/api/python,emacs

# Streamlit
.streamlit/secrets.toml
config.yaml
27 changes: 27 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
FROM nvidia/cuda:12.8.2-runtime-ubuntu24.04

ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
PIP_NO_CACHE_DIR=1 \
DEBIAN_FRONTEND=noninteractive

WORKDIR /app

RUN apt-get update \
&& apt-get install -y --no-install-recommends ffmpeg \
python3 \
python3-pip \
&& rm -rf /var/lib/apt/lists/*

COPY requirements.txt ./
RUN pip install --no-cache-dir --break-system-packages -r requirements.txt

COPY call_archive ./call_archive
COPY pyproject.toml .
COPY transcribe.py .

RUN pip install --no-cache-dir --break-system-packages -e .

ENV PYTHONPATH=/app
ENTRYPOINT ["call-archive"]
CMD ["--help"]
135 changes: 134 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1,134 @@
# call-archive
# call-archive

Local, privacy-first pipeline for processing phone call recordings:
- transcription (faster-whisper),
- semantic summarization (local LLM),
- categorization,
- retention decision support.

No data leaves your machine.

## Context

This project is designed to work with **BCR (Basic Call Recorder)**.

Recordings are produced on the phone and synchronized to the computer (e.g. via Syncthing, rsync, etc.).
That synchronization step is **out of scope** for this project.

The only assumption:
- new recordings (audio + JSON metadata) appear in configured `ingest_dir`.

## Goals

* Reduce storage usage of call recordings over time
* Keep **structured knowledge** (transcripts + notes)
* Retain only recordings that have **real value** (legal, business, commitments, disputes, etc.)
* Maintain full **local control and privacy**

## Directory layout

```text
/data/calls/
new/ # incoming recordings (from phone sync)
2026/ # organized by year (after scan)
rm/ # "deleted" recordings (manual cleanup)
transcripts/
notes/
calls.sqlite
```

### Lifecycle

1. Files appear in `new/`
2. `scan` moves them to `{year}/`
3. `process`:

* transcribes audio
* analyzes content using local LLM
* assigns category + retention proposal
4. `review`:

* you confirm or override decision
5. `delete-approved`:

* audio is moved to `rm/` (never hard-deleted)

## Features

* Directory-based ingestion model (`ingest_dir/ → storage_dir/{year}/ → storage_dir/rm/`)
* Full local processing (no cloud dependency)
* Structured outputs (JSON + SQLite)
* Extensible **categories** (configured in YAML)
* Per-number retention heuristics
* Safe deletion (only after manual review)

## Categories

Categories are defined in `config.yaml`:

```yaml
categories:
- work
- family
- spam
- friends
- unknown
```

The local LLM:

* always receives the current list
* must choose exactly one category

You can freely extend this list.

## Requirements

* Python 3.11+
* faster-whisper
* Local LLM (recommended: Ollama)

## Installation

```bash
python3 -m venv .venv
. .venv/bin/activate
pip install -e .
```

## Usage

```bash
call-archive init --config config.yaml
call-archive scan --config config.yaml
call-archive process --config config.yaml
call-archive list --config config.yaml
call-archive show --config config.yaml 1
call-archive review --config config.yaml 1 --decision delete_audio_keep_transcript
call-archive delete-approved --config config.yaml
```

## Safety model

* No automatic deletion
* All decisions require explicit review
* Audio is moved to `rm/`, not deleted
* Full audit trail in SQLite

## Intended use

This is useful if:

* you record calls for **memory / accountability**
* you want **automatic summarization**
* you want to **control storage growth**
* you need to keep everything **local**

## Non-goals

* Call recording itself (handled by BCR)
* File synchronization (external tools)
* Cloud integrations

## License
GPL-3.0 license
3 changes: 3 additions & 0 deletions call_archive/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
__all__ = ["__version__"]

__version__ = "0.1.0"
Loading