Download copilot/cli.py from Wardline/cloak-api: direct link, hf CLI and curl.
- Browser
- Download file 4.81 kB
-
https://huggingface.co/spaces/Wardline/cloak-api/resolve/main/copilot/cli.py
- Command line
-
hf download hf://spaces/Wardline/cloak-api/copilot/cli.py
-
curl -L -o cli.py https://huggingface.co/spaces/Wardline/cloak-api/resolve/main/copilot/cli.py
4.81 kB
| """Try the copilot in a terminal. | |
| python -m copilot.cli # interactive, typical test tenant | |
| python -m copilot.cli --context my_tenant.json # your own context file | |
| python -m copilot.cli "block aadhaar in chatgpt" # one request, then exit | |
| python -m copilot.cli --json "block usb for interns" # raw response JSON | |
| Questions are asked one by one; your answers are sent back exactly as the dashboard would. | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import json | |
| import sys | |
| from pathlib import Path | |
| from .pipeline import parse | |
| DEFAULT_CONTEXT = Path(__file__).parent.parent / 'corpus' / 'contexts' / 'typical.json' | |
| def load_context(path: str | None) -> dict: | |
| if not path and not DEFAULT_CONTEXT.exists(): | |
| return {} # installed without the test tenants: an empty tenant (built-in rules only) | |
| p = Path(path) if path else DEFAULT_CONTEXT | |
| try: | |
| return json.loads(p.read_text(encoding='utf-8')) | |
| except (OSError, json.JSONDecodeError) as e: | |
| print(f'Could not read context {p}: {e}. Using an empty tenant.', file=sys.stderr) | |
| return {} | |
| def show(r: dict, full: bool) -> None: | |
| print(f'\n[{r["status"]}] {r["message"]}') | |
| for i in r.get('issues', []): | |
| print(f' ({i["code"]}) {i["message"]}') | |
| for n, d in enumerate(r['drafts']): | |
| print(f'\n Draft {n}: {d["policyType"] or "?"} - {d["status"]}') | |
| print(f' {d["summary"]}') | |
| if d['policyBody']: | |
| print(f' name: {d["policyBody"]["name"]}') | |
| rd = d['ruleDecision'] | |
| if rd['mode'] != 'none': | |
| print(f' detection rule: {rd["mode"]} {rd["ruleIds"]}') | |
| for i in d['issues']: | |
| if i['code'] != 'CREATED_INACTIVE': | |
| print(f' {i["level"]:>8}: {i["message"]}') | |
| if full and d['policyBody']: | |
| for step in d['saveSteps']: | |
| print(f' {step["method"]} {step["path"]}') | |
| print(' ' + json.dumps(step['body'], indent=2).replace('\n', '\n ')) | |
| if r.get('examples') and not r['drafts']: | |
| print('\n Try for example:') | |
| for e in r['examples'][:4]: | |
| print(f' - {e}') | |
| def ask(r: dict, answers: dict) -> bool: | |
| """Ask every open question. Returns False when there was nothing to ask.""" | |
| asked = False | |
| for n, d in enumerate(r['drafts']): | |
| for q in d['questions']: | |
| key = f'{q["slot"]}@{n}' | |
| if key in answers: | |
| continue | |
| asked = True | |
| print(f'\n Draft {n} asks: {q["text"]}' + ('' if q['blocking'] else ' (optional, Enter to skip)')) | |
| for k, o in enumerate(q['options'][:12]): | |
| print(f' {k + 1}. {o["label"]}') | |
| raw = input(' > ').strip() | |
| if not raw: | |
| answers[key] = q.get('default') | |
| continue | |
| if raw.isdigit() and 1 <= int(raw) <= len(q['options']): | |
| answers[key] = q['options'][int(raw) - 1]['value'] | |
| elif q['slot'] in ('data', 'connector', 'mcp', 'sites'): | |
| answers[key] = [x.strip() for x in raw.split(',') if x.strip()] | |
| else: | |
| answers[key] = raw | |
| return asked | |
| def run_one(text: str, ctx: dict, as_json: bool, interactive: bool) -> None: | |
| answers: dict = {} | |
| r = parse(text, ctx, answers) | |
| if as_json: | |
| print(json.dumps(r, indent=2, ensure_ascii=False)) | |
| return | |
| if not interactive: | |
| show(r, full=True) | |
| return | |
| show(r, full=False) | |
| while r['status'] == 'needs_input' and ask(r, answers): | |
| r = parse(text, ctx, answers) | |
| show(r, full=False) | |
| if r['drafts'] and any(d['policyBody'] for d in r['drafts']): | |
| if input('\nShow the exact request bodies? [y/N] ').strip().lower() == 'y': | |
| show(r, full=True) | |
| def main() -> None: | |
| ap = argparse.ArgumentParser(description='Policy Copilot in the terminal') | |
| ap.add_argument('text', nargs='*') | |
| ap.add_argument('--context') | |
| ap.add_argument('--json', action='store_true') | |
| args = ap.parse_args() | |
| for stream in (sys.stdout, sys.stderr): | |
| try: | |
| stream.reconfigure(encoding='utf-8', errors='replace') | |
| except (AttributeError, ValueError): | |
| pass | |
| ctx = load_context(args.context) | |
| if args.text: | |
| run_one(' '.join(args.text), ctx, args.json, interactive=False) | |
| return | |
| print('Policy Copilot. Describe a policy (empty line to quit).') | |
| while True: | |
| try: | |
| text = input('\n> ').strip() | |
| except (EOFError, KeyboardInterrupt): | |
| break | |
| if not text: | |
| break | |
| run_one(text, ctx, False, interactive=True) | |
| if __name__ == '__main__': | |
| main() | |