Skip to content

Commit 2a047cd

Browse files
author
Sebastian Braun
committed
feat(cli): add 'add-all' command and auto_delete_added_files config option
- New 'openkb add-all' command processes all files in raw/ directory - New config parameter 'auto_delete_added_files' (default: false) - When enabled, both 'add' and 'add-all' automatically delete successfully ingested files - Updated help texts to document the new cleanup behavior - Config applies to all ingest methods: direct files, directories, and URLs
1 parent ff54396 commit 2a047cd

2 files changed

Lines changed: 89 additions & 2 deletions

File tree

‎openkb/cli.py‎

Lines changed: 88 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -452,6 +452,29 @@ def add_single_file(
452452
return _add_single_file_locked(file_path, kb_dir, stage=stage, bundle=bundle)
453453

454454

455+
def _delete_if_auto_cleanup_enabled(
456+
file_path: Path, status: Literal["added", "skipped", "failed"], config: dict
457+
) -> bool:
458+
"""Delete file if addition succeeded and auto_delete_added_files is enabled.
459+
460+
Args:
461+
file_path: Path to the file to potentially delete.
462+
status: Result status from add_single_file ("added", "skipped", or "failed").
463+
config: Configuration dict (typically from resolve_effective_config).
464+
465+
Returns:
466+
True if file was deleted, False otherwise.
467+
"""
468+
if status == "added" and config.get("auto_delete_added_files", False):
469+
try:
470+
file_path.unlink(missing_ok=True)
471+
return True
472+
except Exception as exc:
473+
logger.warning(f"Failed to delete {file_path.name}: {exc}")
474+
return False
475+
return False
476+
477+
455478
def _add_single_file_locked(
456479
file_path: Path, kb_dir: Path, *, stage: bool = True, bundle=None
457480
) -> Literal["added", "skipped", "failed"]:
@@ -1086,6 +1109,9 @@ def add(ctx, path, from_pageindex_cloud):
10861109
Alternatively, pass --from-pageindex-cloud <DOC_ID> to import a document
10871110
that is already indexed in PageIndex Cloud, with no local file. Requires
10881111
the PAGEINDEX_API_KEY environment variable.
1112+
1113+
If ``auto_delete_added_files`` is enabled in config.yaml, successfully
1114+
added files are automatically deleted after ingestion.
10891115
"""
10901116
kb_dir = _find_kb_dir(ctx.obj.get("kb_dir_override"))
10911117
if kb_dir is None:
@@ -1106,6 +1132,8 @@ def add(ctx, path, from_pageindex_cloud):
11061132
click.echo("Provide a PATH or use --from-pageindex-cloud <DOC_ID>.")
11071133
return
11081134

1135+
config = resolve_effective_config(kb_dir)[0]
1136+
11091137
# URL ingest: download into raw/ first, then call add_single_file explicitly.
11101138
# Keep staged conversion enabled so converted source artifacts do not touch
11111139
# the live KB before the mutation snapshot exists. The tri-state outcome
@@ -1123,6 +1151,8 @@ def add(ctx, path, from_pageindex_cloud):
11231151
# indexing has already succeeded but compilation didn't.
11241152
if outcome == "skipped":
11251153
fetched.unlink(missing_ok=True)
1154+
else:
1155+
_delete_if_auto_cleanup_enabled(fetched, outcome, config)
11261156
return
11271157

11281158
target = Path(path)
@@ -1143,15 +1173,71 @@ def add(ctx, path, from_pageindex_cloud):
11431173
click.echo(f"Found {total} supported file(s) in {path}.")
11441174
for i, f in enumerate(files, 1):
11451175
click.echo(f"\n[{i}/{total}] ", nl=False)
1146-
add_single_file(f, kb_dir)
1176+
outcome = add_single_file(f, kb_dir)
1177+
_delete_if_auto_cleanup_enabled(f, outcome, config)
11471178
else:
11481179
if target.suffix.lower() not in SUPPORTED_EXTENSIONS:
11491180
click.echo(
11501181
f"Unsupported file type: {target.suffix}. "
11511182
f"Supported: {', '.join(sorted(SUPPORTED_EXTENSIONS))}"
11521183
)
11531184
return
1154-
add_single_file(target, kb_dir)
1185+
outcome = add_single_file(target, kb_dir)
1186+
_delete_if_auto_cleanup_enabled(target, outcome, config)
1187+
1188+
1189+
@cli.command()
1190+
@click.pass_context
1191+
@_with_kb_lock(exclusive=True)
1192+
def add_all(ctx):
1193+
"""Process all files in the ``raw/`` directory and add them to the knowledge base.
1194+
1195+
This command walks the ``raw/`` directory recursively for all supported
1196+
document types and ingests them into the KB. If ``auto_delete_added_files``
1197+
is enabled in config.yaml, successfully added files are automatically deleted
1198+
after ingestion.
1199+
1200+
Returns a summary of the operation (added, skipped, failed, deleted counts).
1201+
"""
1202+
kb_dir = _find_kb_dir(ctx.obj.get("kb_dir_override"))
1203+
if kb_dir is None:
1204+
click.echo("No knowledge base found. Run `openkb init` first.")
1205+
return
1206+
1207+
raw_dir = kb_dir / "raw"
1208+
if not raw_dir.is_dir():
1209+
click.echo(f"No raw/ directory found at {raw_dir}")
1210+
return
1211+
1212+
files = [
1213+
f
1214+
for f in sorted(raw_dir.rglob("*"))
1215+
if f.is_file() and f.suffix.lower() in SUPPORTED_EXTENSIONS
1216+
]
1217+
if not files:
1218+
click.echo("No supported files found in raw/ directory.")
1219+
return
1220+
1221+
config = resolve_effective_config(kb_dir)[0]
1222+
total = len(files)
1223+
added = skipped = failed = deleted = 0
1224+
1225+
click.echo(f"Processing {total} file(s) from raw/ directory...")
1226+
for i, f in enumerate(files, 1):
1227+
click.echo(f"\n[{i}/{total}] ", nl=False)
1228+
outcome = add_single_file(f, kb_dir)
1229+
if outcome == "added":
1230+
added += 1
1231+
elif outcome == "skipped":
1232+
skipped += 1
1233+
else:
1234+
failed += 1
1235+
if _delete_if_auto_cleanup_enabled(f, outcome, config):
1236+
deleted += 1
1237+
1238+
click.echo(
1239+
f"\n\nSummary: Added: {added}, Skipped: {skipped}, Failed: {failed}, Deleted: {deleted}"
1240+
)
11551241

11561242

11571243
def _stream_to_tty() -> bool:

‎openkb/config.py‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
# global/KB list overrides it wholesale; resolve_entity_types cleans the
3737
# effective value on read.
3838
"entity_types": list(DEFAULT_ENTITY_TYPES),
39+
"auto_delete_added_files": False,
3940
}
4041

4142
GLOBAL_CONFIG_DIR = Path.home() / ".config" / "openkb"

0 commit comments

Comments
 (0)