File size: 3,434 Bytes
03c0888
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
import click
import sys
import asyncio
from typing import List
from .docs_manager import DocsManager
from .async_logger import AsyncLogger

logger = AsyncLogger(verbose=True)
docs_manager = DocsManager(logger)

def print_table(headers: List[str], rows: List[List[str]], padding: int = 2):
    """Print formatted table with headers and rows"""
    widths = [max(len(str(cell)) for cell in col) for col in zip(headers, *rows)]
    border = '+' + '+'.join('-' * (w + 2 * padding) for w in widths) + '+'
    
    def format_row(row):
        return '|' + '|'.join(f"{' ' * padding}{str(cell):<{w}}{' ' * padding}" 
                             for cell, w in zip(row, widths)) + '|'
    
    click.echo(border)
    click.echo(format_row(headers))
    click.echo(border)
    for row in rows:
        click.echo(format_row(row))
    click.echo(border)

@click.group()
def cli():
    """Crawl4AI Command Line Interface"""
    pass

@cli.group()
def docs():
    """Documentation operations"""
    pass

@docs.command()
@click.argument('sections', nargs=-1)
@click.option('--mode', type=click.Choice(['extended', 'condensed']), default='extended')
def combine(sections: tuple, mode: str):
    """Combine documentation sections"""
    try:
        asyncio.run(docs_manager.ensure_docs_exist())
        click.echo(docs_manager.generate(sections, mode))
    except Exception as e:
        logger.error(str(e), tag="ERROR")
        sys.exit(1)

@docs.command()
@click.argument('query')
@click.option('--top-k', '-k', default=5)
@click.option('--build-index', is_flag=True, help='Build index if missing')
def search(query: str, top_k: int, build_index: bool):
    """Search documentation"""
    try:
        result = docs_manager.search(query, top_k)
        if result == "No search index available. Call build_search_index() first.":
            if build_index or click.confirm('No search index found. Build it now?'):
                asyncio.run(docs_manager.llm_text.generate_index_files())
                result = docs_manager.search(query, top_k)
        click.echo(result)
    except Exception as e:
        click.echo(f"Error: {str(e)}", err=True)
        sys.exit(1)

@docs.command()
def update():
    """Update docs from GitHub"""
    try:
        asyncio.run(docs_manager.fetch_docs())
        click.echo("Documentation updated successfully")
    except Exception as e:
        click.echo(f"Error: {str(e)}", err=True)
        sys.exit(1)

@docs.command()
@click.option('--force-facts', is_flag=True, help='Force regenerate fact files')
@click.option('--clear-cache', is_flag=True, help='Clear BM25 cache')
def index(force_facts: bool, clear_cache: bool):
    """Build or rebuild search indexes"""
    try:
        asyncio.run(docs_manager.ensure_docs_exist())
        asyncio.run(docs_manager.llm_text.generate_index_files(
            force_generate_facts=force_facts,
            clear_bm25_cache=clear_cache
        ))
        click.echo("Search indexes built successfully")
    except Exception as e:
        click.echo(f"Error: {str(e)}", err=True)
        sys.exit(1)

# Add docs list command
@docs.command()
def list():
    """List available documentation sections"""
    try:
        sections = docs_manager.list()
        print_table(["Sections"], [[section] for section in sections])
        
    except Exception as e:
        click.echo(f"Error: {str(e)}", err=True)
        sys.exit(1)

if __name__ == '__main__':
    cli()