Add AI knowledge exclude list
This commit is contained in:
parent
af75f2c608
commit
3c24b7fbc4
|
|
@ -1113,7 +1113,8 @@ Build the local homelab knowledge index separately from the main deployment:
|
||||||
```
|
```
|
||||||
|
|
||||||
The index is built from the non-secret source list in
|
The index is built from the non-secret source list in
|
||||||
`infra/ai/knowledge-sources.txt` and defaults to `/data/homelab-ai/index`.
|
`infra/ai/knowledge-sources.txt`, skips paths in
|
||||||
|
`infra/ai/knowledge-excludes.txt`, and defaults to `/data/homelab-ai/index`.
|
||||||
Doctor commands use it as extra context when it exists, but infrastructure
|
Doctor commands use it as extra context when it exists, but infrastructure
|
||||||
deployment does not depend on it.
|
deployment does not depend on it.
|
||||||
Use `ask` as the runbook and command finder. It returns the closest indexed
|
Use `ask` as the runbook and command finder. It returns the closest indexed
|
||||||
|
|
|
||||||
|
|
@ -1113,7 +1113,8 @@ Build the local homelab knowledge index separately from the main deployment:
|
||||||
```
|
```
|
||||||
|
|
||||||
The index is built from the non-secret source list in
|
The index is built from the non-secret source list in
|
||||||
`infra/ai/knowledge-sources.txt` and defaults to `/data/homelab-ai/index`.
|
`infra/ai/knowledge-sources.txt`, skips paths in
|
||||||
|
`infra/ai/knowledge-excludes.txt`, and defaults to `/data/homelab-ai/index`.
|
||||||
Doctor commands use it as extra context when it exists, but infrastructure
|
Doctor commands use it as extra context when it exists, but infrastructure
|
||||||
deployment does not depend on it.
|
deployment does not depend on it.
|
||||||
Use `ask` as the runbook and command finder. It returns the closest indexed
|
Use `ask` as the runbook and command finder. It returns the closest indexed
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
# Files and globs excluded from the local homelab AI helper.
|
||||||
|
# Keep inactive reference material out of answers about the active lab.
|
||||||
|
archive/**
|
||||||
|
labs/**
|
||||||
|
apps/arr-stack/**
|
||||||
|
apps/mlops-platform/**
|
||||||
|
|
@ -16,6 +16,7 @@ from collections import Counter
|
||||||
|
|
||||||
REPO_ROOT = pathlib.Path(__file__).resolve().parents[1]
|
REPO_ROOT = pathlib.Path(__file__).resolve().parents[1]
|
||||||
DEFAULT_SOURCES_FILE = REPO_ROOT / "infra" / "ai" / "knowledge-sources.txt"
|
DEFAULT_SOURCES_FILE = REPO_ROOT / "infra" / "ai" / "knowledge-sources.txt"
|
||||||
|
DEFAULT_EXCLUDES_FILE = REPO_ROOT / "infra" / "ai" / "knowledge-excludes.txt"
|
||||||
DEFAULT_INDEX_DIR = pathlib.Path(os.environ.get("LAB_AI_KNOWLEDGE_INDEX_DIR", "/data/homelab-ai/index"))
|
DEFAULT_INDEX_DIR = pathlib.Path(os.environ.get("LAB_AI_KNOWLEDGE_INDEX_DIR", "/data/homelab-ai/index"))
|
||||||
TOKEN_RE = re.compile(r"[A-Za-z0-9_./:-]{2,}")
|
TOKEN_RE = re.compile(r"[A-Za-z0-9_./:-]{2,}")
|
||||||
MAX_FILE_BYTES = 512 * 1024
|
MAX_FILE_BYTES = 512 * 1024
|
||||||
|
|
@ -54,7 +55,11 @@ def path_is_secret(path: pathlib.Path) -> bool:
|
||||||
return any(marker in lowered for marker in secret_markers)
|
return any(marker in lowered for marker in secret_markers)
|
||||||
|
|
||||||
|
|
||||||
def candidate_files(patterns: list[str]) -> list[pathlib.Path]:
|
def path_matches_any(rel_path: str, patterns: list[str]) -> bool:
|
||||||
|
return any(fnmatch.fnmatch(rel_path, pattern) for pattern in patterns)
|
||||||
|
|
||||||
|
|
||||||
|
def candidate_files(patterns: list[str], exclude_patterns: list[str]) -> list[pathlib.Path]:
|
||||||
files: set[pathlib.Path] = set()
|
files: set[pathlib.Path] = set()
|
||||||
all_files = [path for path in REPO_ROOT.rglob("*") if path.is_file()]
|
all_files = [path for path in REPO_ROOT.rglob("*") if path.is_file()]
|
||||||
|
|
||||||
|
|
@ -69,7 +74,12 @@ def candidate_files(patterns: list[str]) -> list[pathlib.Path]:
|
||||||
if path.is_file():
|
if path.is_file():
|
||||||
files.add(path)
|
files.add(path)
|
||||||
|
|
||||||
return sorted(path for path in files if not path_is_secret(path))
|
return sorted(
|
||||||
|
path
|
||||||
|
for path in files
|
||||||
|
if not path_is_secret(path)
|
||||||
|
and not path_matches_any(path.relative_to(REPO_ROOT).as_posix(), exclude_patterns)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def read_text(path: pathlib.Path) -> str | None:
|
def read_text(path: pathlib.Path) -> str | None:
|
||||||
|
|
@ -155,6 +165,7 @@ def build_index(files: list[pathlib.Path]) -> dict[str, object]:
|
||||||
def main() -> int:
|
def main() -> int:
|
||||||
parser = argparse.ArgumentParser(description=__doc__)
|
parser = argparse.ArgumentParser(description=__doc__)
|
||||||
parser.add_argument("--sources-file", type=pathlib.Path, default=DEFAULT_SOURCES_FILE)
|
parser.add_argument("--sources-file", type=pathlib.Path, default=DEFAULT_SOURCES_FILE)
|
||||||
|
parser.add_argument("--excludes-file", type=pathlib.Path, default=DEFAULT_EXCLUDES_FILE)
|
||||||
parser.add_argument("--index-dir", type=pathlib.Path, default=DEFAULT_INDEX_DIR)
|
parser.add_argument("--index-dir", type=pathlib.Path, default=DEFAULT_INDEX_DIR)
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
|
@ -163,7 +174,8 @@ def main() -> int:
|
||||||
return 1
|
return 1
|
||||||
|
|
||||||
patterns = load_patterns(args.sources_file)
|
patterns = load_patterns(args.sources_file)
|
||||||
files = candidate_files(patterns)
|
exclude_patterns = load_patterns(args.excludes_file) if args.excludes_file.is_file() else []
|
||||||
|
files = candidate_files(patterns, exclude_patterns)
|
||||||
index = build_index(files)
|
index = build_index(files)
|
||||||
|
|
||||||
args.index_dir.mkdir(parents=True, exist_ok=True)
|
args.index_dir.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
@ -174,6 +186,7 @@ def main() -> int:
|
||||||
json.dumps(
|
json.dumps(
|
||||||
{
|
{
|
||||||
"sources_file": str(args.sources_file.relative_to(REPO_ROOT)),
|
"sources_file": str(args.sources_file.relative_to(REPO_ROOT)),
|
||||||
|
"excludes_file": str(args.excludes_file.relative_to(REPO_ROOT)) if args.excludes_file.is_file() else None,
|
||||||
"file_count": len(files),
|
"file_count": len(files),
|
||||||
"chunk_count": index["chunk_count"],
|
"chunk_count": index["chunk_count"],
|
||||||
"repo_root": str(REPO_ROOT),
|
"repo_root": str(REPO_ROOT),
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue