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
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ repos:
rev: v1.7.7
hooks:
- id: docformatter
language_version: python3.12
args: [
--in-place,
--wrap-summaries=0, # 0 means disable wrap
Expand Down
2 changes: 2 additions & 0 deletions EdgeCraftRAG/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -329,12 +329,14 @@ The CLI will display error messages from the API in JSON format. Network errors
## Tips

- Use `--help` with any command to see detailed help:

```bash
ecrag pipeline --help
ecrag pipeline create --help
```

- Pipe JSON output to other tools:

```bash
ecrag kb list | jq '.[]' | head -n 20
```
Expand Down
19 changes: 12 additions & 7 deletions EdgeCraftRAG/cli/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,18 @@
# SPDX-License-Identifier: Apache-2.0

import json
import requests
from typing import Optional, Dict, Any
from typing import Any, Dict, Optional
from urllib.parse import urljoin

import requests


class EcragApiClient:
"""API client for Edge Craft RAG."""

def __init__(self, host: str = "http://localhost", server_port: int = 16010, mega_port: int = 16011):
"""Initialize the API client.

Args:
host: The host URL (default: http://localhost)
server_port: The server port (default: 16010)
Expand All @@ -21,10 +22,10 @@ def __init__(self, host: str = "http://localhost", server_port: int = 16010, meg
# Normalize host URL
if not host.startswith(("http://", "https://")):
host = f"http://{host}"

# Remove trailing slash if present
host = host.rstrip("/")

self.server_url = f"{host}:{server_port}"
self.mega_url = f"{host}:{mega_port}"

Expand Down Expand Up @@ -170,12 +171,16 @@ def delete_knowledge_base(self, kb_name: str) -> Dict[str, Any]:
def add_files_to_kb(self, kb_name: str, local_paths: list) -> Dict[str, Any]:
"""Add files to a knowledge base."""
url = urljoin(self.server_url, f"/v1/knowledge/{kb_name}/files")
return self._request("POST", url, json={"local_paths": local_paths}, headers={"Content-Type": "application/json"})
return self._request(
"POST", url, json={"local_paths": local_paths}, headers={"Content-Type": "application/json"}
)

def delete_files_from_kb(self, kb_name: str, local_paths: list) -> Dict[str, Any]:
"""Delete files from a knowledge base."""
url = urljoin(self.server_url, f"/v1/knowledge/{kb_name}/files")
return self._request("DELETE", url, json={"local_paths": local_paths}, headers={"Content-Type": "application/json"})
return self._request(
"DELETE", url, json={"local_paths": local_paths}, headers={"Content-Type": "application/json"}
)

# Experience Management
def get_experiences(self) -> Dict[str, Any]:
Expand Down
1 change: 0 additions & 1 deletion EdgeCraftRAG/cli/config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

"""Configuration for EdgeCraft RAG CLI."""

import os
Expand Down
55 changes: 28 additions & 27 deletions EdgeCraftRAG/cli/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
# SPDX-License-Identifier: Apache-2.0

import json
import click
import os
from pathlib import Path
from typing import Optional

import click
from cli.client import EcragApiClient
from cli.config import get_config

Expand Down Expand Up @@ -34,26 +35,26 @@ def run_chatqna_query(client: EcragApiClient, query: str, top_n: int, max_tokens
@click.pass_context
def cli(ctx, host: Optional[str], port: Optional[int], mega_port: Optional[int]):
"""EdgeCraft RAG CLI Tool.

Configure server connection via command-line options or environment variables:
- ECRAG_HOST: Server host (default: http://localhost)
- ECRAG_PORT: Server port (default: 16010)
- ECRAG_MEGA_PORT: Mega service port (default: 16011)
"""
ctx.ensure_object(dict)

# Get defaults from config
config = get_config()

# Use provided options or environment/defaults
final_host = host or config.host
final_port = port or config.port
final_mega_port = mega_port or config.mega_port

# Normalize host URL
if not final_host.startswith(("http://", "https://")):
final_host = f"http://{final_host}"

ctx.obj["client"] = EcragApiClient(host=final_host, server_port=final_port, mega_port=final_mega_port)


Expand Down Expand Up @@ -204,7 +205,7 @@ def load(ctx, model_type: str, model_id: str, model_path: str, device: str, weig

@model.command()
@click.pass_context
def list(ctx):
def list(ctx): # noqa: F811
"""List all models."""
client = ctx.obj["client"]
result = client.get_models()
Expand All @@ -214,7 +215,7 @@ def list(ctx):
@model.command()
@click.option("--id", "model_id", required=True, help="Model ID")
@click.pass_context
def get(ctx, model_id: str):
def get(ctx, model_id: str): # noqa: F811
"""Get a specific model."""
client = ctx.obj["client"]
result = client.get_model(model_id)
Expand All @@ -241,7 +242,7 @@ def update(ctx, model_id: str, device: Optional[str], weight: Optional[str]):
@model.command()
@click.option("--id", "model_id", required=True, help="Model ID")
@click.pass_context
def delete(ctx, model_id: str):
def delete(ctx, model_id: str): # noqa: F811
"""Delete a model."""
client = ctx.obj["client"]
if click.confirm(f"Are you sure you want to delete model '{model_id}'?"):
Expand Down Expand Up @@ -284,7 +285,7 @@ def kb():
@click.option("--description", help="Knowledge base description")
@click.option("-f", "--file", type=click.Path(exists=True), help="KB config JSON file")
@click.pass_context
def create(ctx, name: str, description: Optional[str], file: Optional[str]):
def create(ctx, name: str, description: Optional[str], file: Optional[str]): # noqa: F811
"""Create a knowledge base."""
client = ctx.obj["client"]

Expand All @@ -302,7 +303,7 @@ def create(ctx, name: str, description: Optional[str], file: Optional[str]):

@kb.command()
@click.pass_context
def list(ctx):
def list(ctx): # noqa: F811
"""List all knowledge bases."""
client = ctx.obj["client"]
result = client.get_knowledge_bases()
Expand All @@ -312,7 +313,7 @@ def list(ctx):
@kb.command()
@click.option("-n", "--name", required=True, help="Knowledge base name")
@click.pass_context
def get(ctx, name: str):
def get(ctx, name: str): # noqa: F811
"""Get a specific knowledge base."""
client = ctx.obj["client"]
result = client.get_knowledge_base(name)
Expand All @@ -322,7 +323,7 @@ def get(ctx, name: str):
@kb.command()
@click.option("-n", "--name", required=True, help="Knowledge base name")
@click.pass_context
def get_json(ctx, name: str):
def get_json(ctx, name: str): # noqa: F811
"""Get knowledge base JSON data."""
client = ctx.obj["client"]
result = client.get_knowledge_base_json(name)
Expand All @@ -346,7 +347,7 @@ def filemap(ctx, name: str, page_num: int, page_size: int):
@click.option("--active", type=bool, help="Set active status")
@click.option("--description", help="Update description")
@click.pass_context
def update(ctx, name: str, active: Optional[bool], description: Optional[str]):
def update(ctx, name: str, active: Optional[bool], description: Optional[str]): # noqa: F811
"""Update a knowledge base."""
client = ctx.obj["client"]
kb_data = {"name": name}
Expand All @@ -361,7 +362,7 @@ def update(ctx, name: str, active: Optional[bool], description: Optional[str]):
@kb.command()
@click.option("-n", "--name", required=True, help="Knowledge base name")
@click.pass_context
def delete(ctx, name: str):
def delete(ctx, name: str): # noqa: F811
"""Delete a knowledge base."""
client = ctx.obj["client"]
if click.confirm(f"Are you sure you want to delete knowledge base '{name}'?"):
Expand Down Expand Up @@ -402,7 +403,7 @@ def experience():

@experience.command()
@click.pass_context
def list(ctx):
def list(ctx): # noqa: F811
"""List all experiences."""
client = ctx.obj["client"]
result = client.get_experiences()
Expand All @@ -412,7 +413,7 @@ def list(ctx):
@experience.command()
@click.option("--id", required=True, help="Experience ID")
@click.pass_context
def get(ctx, id: str):
def get(ctx, id: str): # noqa: F811
"""Get a specific experience."""
client = ctx.obj["client"]
result = client.get_experience(id)
Expand All @@ -424,7 +425,7 @@ def get(ctx, id: str):
@click.option("--question", required=True, help="Question")
@click.option("--content", multiple=True, required=True, help="Answer content")
@click.pass_context
def create(ctx, id: str, question: str, content: tuple):
def create(ctx, id: str, question: str, content: tuple): # noqa: F811
"""Create or update an experience."""
client = ctx.obj["client"]
exp_data = {"idx": id, "question": question, "content": list(content)}
Expand All @@ -435,7 +436,7 @@ def create(ctx, id: str, question: str, content: tuple):
@experience.command()
@click.option("--id", required=True, help="Experience ID")
@click.pass_context
def delete(ctx, id: str):
def delete(ctx, id: str): # noqa: F811
"""Delete an experience."""
client = ctx.obj["client"]
if click.confirm(f"Are you sure you want to delete experience '{id}'?"):
Expand Down Expand Up @@ -464,7 +465,7 @@ def agent():

@agent.command()
@click.pass_context
def list(ctx):
def list(ctx): # noqa: F811
"""List all agents."""
client = ctx.obj["client"]
result = client.get_agents()
Expand All @@ -474,7 +475,7 @@ def list(ctx):
@agent.command()
@click.option("-n", "--name", required=True, help="Agent name")
@click.pass_context
def get(ctx, name: str):
def get(ctx, name: str): # noqa: F811
"""Get a specific agent."""
client = ctx.obj["client"]
result = client.get_agent(name)
Expand All @@ -496,7 +497,7 @@ def configs(ctx, type: str):
@click.option("--type", required=True, help="Agent type")
@click.option("--pipeline", required=True, help="Pipeline index or name")
@click.pass_context
def create(ctx, name: str, type: str, pipeline: str):
def create(ctx, name: str, type: str, pipeline: str): # noqa: F811
"""Create an agent."""
client = ctx.obj["client"]
agent_data = {"name": name, "type": type, "pipeline_idx": pipeline}
Expand All @@ -508,7 +509,7 @@ def create(ctx, name: str, type: str, pipeline: str):
@click.option("-n", "--name", required=True, help="Agent name")
@click.option("--active", type=bool, help="Active status")
@click.pass_context
def update(ctx, name: str, active: Optional[bool]):
def update(ctx, name: str, active: Optional[bool]): # noqa: F811
"""Update an agent."""
client = ctx.obj["client"]
agent_data = {}
Expand All @@ -521,7 +522,7 @@ def update(ctx, name: str, active: Optional[bool]):
@agent.command()
@click.option("-n", "--name", required=True, help="Agent name")
@click.pass_context
def delete(ctx, name: str):
def delete(ctx, name: str): # noqa: F811
"""Delete an agent."""
client = ctx.obj["client"]
if click.confirm(f"Are you sure you want to delete agent '{name}'?"):
Expand All @@ -540,7 +541,7 @@ def prompt():

@prompt.command()
@click.pass_context
def get(ctx):
def get(ctx): # noqa: F811
"""Get the current system prompt."""
client = ctx.obj["client"]
result = client.get_prompt()
Expand Down Expand Up @@ -674,7 +675,7 @@ def session():

@session.command()
@click.pass_context
def list(ctx):
def list(ctx): # noqa: F811
"""List all sessions."""
client = ctx.obj["client"]
result = client.get_sessions()
Expand All @@ -684,7 +685,7 @@ def list(ctx):
@session.command()
@click.option("--id", required=True, help="Session ID")
@click.pass_context
def get(ctx, id: str):
def get(ctx, id: str): # noqa: F811
"""Get a specific session."""
client = ctx.obj["client"]
result = client.get_session(id)
Expand Down
10 changes: 5 additions & 5 deletions EdgeCraftRAG/cli/quickstart.py
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

"""Quick start guide for EdgeCraft RAG CLI."""

import json
import sys

from cli.client import EcragApiClient


def test_connection(host: str = "http://localhost", port: int = 16010):
"""Test connection to EdgeCraft RAG server."""
client = EcragApiClient(host=host, server_port=port)

try:
print(f"Testing connection to {client.server_url}...")
result = client.get_system_info()

if "error" in result:
print(f"❌ Connection failed: {result['error']}")
return False

print("✓ Connection successful!")
print(f" System Info: {json.dumps(result, indent=2)}")
return True
Expand Down Expand Up @@ -62,7 +62,7 @@ def quick_start_guide():
export ECRAG_MEGA_PORT=16011

COMMON COMMANDS:

Pipeline Management:
ecrag pipeline list
ecrag pipeline get --name <name>
Expand Down
4 changes: 1 addition & 3 deletions EdgeCraftRAG/cli/setup.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
#!/usr/bin/env python3
# Copyright (C) 2024 Intel Corporation
# SPDX-License-Identifier: Apache-2.0

"""Canonical setup script for EdgeCraft RAG CLI."""

from setuptools import setup


setup(
name="ecrag-cli",
version="0.1.0",
Expand Down Expand Up @@ -35,4 +33,4 @@
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
],
)
)
Loading
Loading