Initial commit with translated description
This commit is contained in:
70
README.md
Normal file
70
README.md
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
# QVeris Skill for Claude Code
|
||||||
|
|
||||||
|
[中文文档](README.zh-CN.md) | English
|
||||||
|
|
||||||
|
A skill that enables Claude Code to dynamically search and execute tools via the QVeris API.
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- **Tool Discovery**: Search for APIs by describing what you need
|
||||||
|
- **Tool Execution**: Execute any discovered tool with parameters
|
||||||
|
- **Wide Coverage**: Access weather, stocks, search, currency, and thousands more APIs
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
This skill requires `uv`, a fast Python package manager. Install it first:
|
||||||
|
|
||||||
|
**macOS and Linux:**
|
||||||
|
```bash
|
||||||
|
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**Windows:**
|
||||||
|
```powershell
|
||||||
|
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
|
||||||
|
```
|
||||||
|
|
||||||
|
For other installation methods, see the [official uv installation guide](https://docs.astral.sh/uv/getting-started/installation/).
|
||||||
|
|
||||||
|
### Install the Skill
|
||||||
|
|
||||||
|
1. Copy this folder to your Claude Code skills directory:
|
||||||
|
```bash
|
||||||
|
cp -r qveris ~/.claude/skills/
|
||||||
|
```
|
||||||
|
|
||||||
|
2. Set your API key:
|
||||||
|
```bash
|
||||||
|
export QVERIS_API_KEY="your-api-key-here"
|
||||||
|
```
|
||||||
|
|
||||||
|
Get your API key at https://qveris.ai
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Once installed, Claude Code will automatically use this skill when you ask questions about:
|
||||||
|
- Weather data
|
||||||
|
- Stock prices and market analysis
|
||||||
|
- Web searches
|
||||||
|
- Currency exchange rates
|
||||||
|
- And more...
|
||||||
|
|
||||||
|
### Manual Commands
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Search for tools
|
||||||
|
uv run scripts/qveris_tool.py search "stock price data"
|
||||||
|
|
||||||
|
# Execute a tool
|
||||||
|
uv run scripts/qveris_tool.py execute <tool_id> --search-id <id> --params '{"symbol": "AAPL"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Author
|
||||||
|
|
||||||
|
[@hqmank](https://x.com/hqmank)
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
70
README.zh-CN.md
Normal file
70
README.zh-CN.md
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
# QVeris Skill for Claude Code
|
||||||
|
|
||||||
|
中文文档 | [English](README.md)
|
||||||
|
|
||||||
|
这是一个让 Claude Code 能够通过 QVeris API 动态搜索和执行工具的技能。
|
||||||
|
|
||||||
|
## 功能特性
|
||||||
|
|
||||||
|
- **工具发现**:通过描述您的需求来搜索 API
|
||||||
|
- **工具执行**:使用参数执行任何已发现的工具
|
||||||
|
- **广泛覆盖**:访问天气、股票、搜索、货币以及数千种其他 API
|
||||||
|
|
||||||
|
## 安装
|
||||||
|
|
||||||
|
### 前置要求
|
||||||
|
|
||||||
|
此技能需要 `uv`,一个快速的 Python 包管理工具。请先安装它:
|
||||||
|
|
||||||
|
**macOS 和 Linux:**
|
||||||
|
```bash
|
||||||
|
curl -LsSf https://astral.sh/uv/install.sh | sh
|
||||||
|
```
|
||||||
|
|
||||||
|
**Windows:**
|
||||||
|
```powershell
|
||||||
|
powershell -ExecutionPolicy ByPass -c "irm https://astral.sh/uv/install.ps1 | iex"
|
||||||
|
```
|
||||||
|
|
||||||
|
更多安装方式,请查看 [uv 官方安装指南](https://docs.astral.sh/uv/getting-started/installation/)。
|
||||||
|
|
||||||
|
### 安装技能
|
||||||
|
|
||||||
|
1. 将此文件夹复制到您的 Claude Code 技能目录:
|
||||||
|
```bash
|
||||||
|
cp -r qveris ~/.claude/skills/
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 设置您的 API 密钥:
|
||||||
|
```bash
|
||||||
|
export QVERIS_API_KEY="your-api-key-here"
|
||||||
|
```
|
||||||
|
|
||||||
|
在 https://qveris.ai 获取您的 API 密钥
|
||||||
|
|
||||||
|
## 使用方法
|
||||||
|
|
||||||
|
安装完成后,当您询问以下问题时,Claude Code 将自动使用此技能:
|
||||||
|
- 天气数据
|
||||||
|
- 股票价格和市场分析
|
||||||
|
- 网络搜索
|
||||||
|
- 货币汇率
|
||||||
|
- 更多...
|
||||||
|
|
||||||
|
### 手动命令
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# 搜索工具
|
||||||
|
uv run scripts/qveris_tool.py search "stock price data"
|
||||||
|
|
||||||
|
# 执行工具
|
||||||
|
uv run scripts/qveris_tool.py execute <tool_id> --search-id <id> --params '{"symbol": "AAPL"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## 作者
|
||||||
|
|
||||||
|
[@hqmank](https://x.com/hqmank)
|
||||||
|
|
||||||
|
## 许可证
|
||||||
|
|
||||||
|
MIT
|
||||||
87
SKILL.md
Normal file
87
SKILL.md
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
---
|
||||||
|
name: qveris
|
||||||
|
description: "通过QVeris API搜索和执行动态工具。在需要查找和调用外部API/工具时使用。"
|
||||||
|
triggers:
|
||||||
|
- pattern: "股票|stock|股价|股市"
|
||||||
|
description: "检测股票相关查询"
|
||||||
|
- pattern: "交易|trading|买卖|成交"
|
||||||
|
description: "检测交易相关查询"
|
||||||
|
- pattern: "分析|analysis|数据|指标|技术分析|基本面"
|
||||||
|
description: "检测分析相关查询"
|
||||||
|
- pattern: "市值|涨跌|收盘|开盘|市盈率|pe|pb"
|
||||||
|
description: "检测股票指标查询"
|
||||||
|
auto_invoke: true
|
||||||
|
examples:
|
||||||
|
- "帮我查一下特斯拉的股价"
|
||||||
|
- "分析一下苹果公司的财报数据"
|
||||||
|
- "查询今日A股涨停板"
|
||||||
|
- "获取比特币实时价格"
|
||||||
|
---
|
||||||
|
|
||||||
|
# QVeris Tool Search & Execution
|
||||||
|
|
||||||
|
QVeris provides dynamic tool discovery and execution - search for tools by capability, then execute them with parameters.
|
||||||
|
|
||||||
|
## Setup
|
||||||
|
|
||||||
|
Requires environment variable:
|
||||||
|
- `QVERIS_API_KEY` - Get from https://qveris.ai
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
### Search for tools
|
||||||
|
```bash
|
||||||
|
uv run scripts/qveris_tool.py search "weather forecast API"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Execute a tool
|
||||||
|
```bash
|
||||||
|
uv run scripts/qveris_tool.py execute openweathermap_current_weather --search-id <id> --params '{"city": "London", "units": "metric"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Script Usage
|
||||||
|
|
||||||
|
```
|
||||||
|
scripts/qveris_tool.py <command> [options]
|
||||||
|
|
||||||
|
Commands:
|
||||||
|
search <query> Search for tools matching a capability description
|
||||||
|
execute <tool_id> Execute a specific tool with parameters
|
||||||
|
|
||||||
|
Options:
|
||||||
|
--limit N Max results for search (default: 5)
|
||||||
|
--search-id ID Search ID from previous search (required for execute)
|
||||||
|
--params JSON Tool parameters as JSON string
|
||||||
|
--max-size N Max response size in bytes (default: 20480)
|
||||||
|
--json Output raw JSON instead of formatted display
|
||||||
|
```
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
1. **Search**: Describe the capability needed (not specific parameters)
|
||||||
|
- Good: "weather forecast API"
|
||||||
|
- Bad: "get weather for London"
|
||||||
|
|
||||||
|
2. **Select**: Review tools by `success_rate` and `avg_execution_time`
|
||||||
|
|
||||||
|
3. **Execute**: Call tool with `tool_id`, `search_id`, and `parameters`
|
||||||
|
|
||||||
|
## Example Session
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Find weather tools
|
||||||
|
uv run scripts/qveris_tool.py search "current weather data"
|
||||||
|
|
||||||
|
# Execute with returned tool_id and search_id
|
||||||
|
uv run scripts/qveris_tool.py execute openweathermap_current_weather \
|
||||||
|
--search-id abc123 \
|
||||||
|
--params '{"city": "Tokyo", "units": "metric"}'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Use Cases
|
||||||
|
|
||||||
|
- **Weather Data**: Get current weather, forecasts for any location
|
||||||
|
- **Stock Market**: Query stock prices, historical data, earnings calendars
|
||||||
|
- **Search**: Web search, news retrieval
|
||||||
|
- **Data APIs**: Currency exchange, geolocation, translations
|
||||||
|
- **And more**: QVeris aggregates thousands of API tools
|
||||||
6
_meta.json
Normal file
6
_meta.json
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"ownerId": "kn7cpk0s04wpxzfp5m4eefgzj98024p8",
|
||||||
|
"slug": "qveris",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"publishedAt": 1769858151112
|
||||||
|
}
|
||||||
8
pyproject.toml
Normal file
8
pyproject.toml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[project]
|
||||||
|
name = "qveris-skill"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "QVeris API tool search and execution skill for Claude Code"
|
||||||
|
requires-python = ">=3.10"
|
||||||
|
dependencies = [
|
||||||
|
"httpx>=0.25.0",
|
||||||
|
]
|
||||||
218
scripts/qveris_tool.py
Normal file
218
scripts/qveris_tool.py
Normal file
@@ -0,0 +1,218 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# /// script
|
||||||
|
# requires-python = ">=3.10"
|
||||||
|
# dependencies = [
|
||||||
|
# "httpx",
|
||||||
|
# ]
|
||||||
|
# ///
|
||||||
|
"""
|
||||||
|
QVeris Tool Search & Execution CLI
|
||||||
|
|
||||||
|
Search for tools by capability and execute them via QVeris API.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
uv run qveris_tool.py search "weather forecast"
|
||||||
|
uv run qveris_tool.py execute <tool_id> --search-id <id> --params '{"city": "London"}'
|
||||||
|
"""
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import asyncio
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
import httpx
|
||||||
|
|
||||||
|
BASE_URL = "https://qveris.ai/api/v1"
|
||||||
|
|
||||||
|
|
||||||
|
def get_api_key() -> str:
|
||||||
|
"""Get QVeris API key from environment."""
|
||||||
|
key = os.environ.get("QVERIS_API_KEY")
|
||||||
|
if not key:
|
||||||
|
print("Error: QVERIS_API_KEY environment variable not set", file=sys.stderr)
|
||||||
|
print("Get your API key at https://qveris.ai", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
return key
|
||||||
|
|
||||||
|
|
||||||
|
async def search_tools(query: str, limit: int = 5) -> dict:
|
||||||
|
"""Search for tools matching a capability description."""
|
||||||
|
api_key = get_api_key()
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(timeout=30) as client:
|
||||||
|
response = await client.post(
|
||||||
|
f"{BASE_URL}/search",
|
||||||
|
headers={
|
||||||
|
"Authorization": f"Bearer {api_key}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
json={"query": query, "limit": limit},
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
|
||||||
|
async def execute_tool(
|
||||||
|
tool_id: str,
|
||||||
|
search_id: str,
|
||||||
|
parameters: dict,
|
||||||
|
max_response_size: int = 20480,
|
||||||
|
) -> dict:
|
||||||
|
"""Execute a specific tool with parameters."""
|
||||||
|
api_key = get_api_key()
|
||||||
|
|
||||||
|
async with httpx.AsyncClient(timeout=60) as client:
|
||||||
|
response = await client.post(
|
||||||
|
f"{BASE_URL}/tools/execute",
|
||||||
|
params={"tool_id": tool_id},
|
||||||
|
headers={
|
||||||
|
"Authorization": f"Bearer {api_key}",
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
json={
|
||||||
|
"search_id": search_id,
|
||||||
|
"parameters": parameters,
|
||||||
|
"max_response_size": max_response_size,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
|
||||||
|
def display_search_results(result: dict) -> None:
|
||||||
|
"""Display search results in a formatted way."""
|
||||||
|
search_id = result.get("search_id", "N/A")
|
||||||
|
tools = result.get("results", [])
|
||||||
|
total = result.get("total", len(tools))
|
||||||
|
|
||||||
|
print(f"\nSearch ID: {search_id}")
|
||||||
|
print(f"Found {total} tools\n")
|
||||||
|
|
||||||
|
if not tools:
|
||||||
|
print("No tools found.")
|
||||||
|
return
|
||||||
|
|
||||||
|
for i, tool in enumerate(tools, 1):
|
||||||
|
tool_id = tool.get("tool_id", "N/A")
|
||||||
|
name = tool.get("name", "N/A")
|
||||||
|
desc = tool.get("description", "N/A")
|
||||||
|
|
||||||
|
# Stats
|
||||||
|
stats = tool.get("stats", {})
|
||||||
|
success_rate = stats.get("success_rate", "N/A")
|
||||||
|
avg_time = stats.get("avg_execution_time_ms", "N/A")
|
||||||
|
|
||||||
|
if isinstance(success_rate, (int, float)):
|
||||||
|
success_rate = f"{success_rate:.0%}"
|
||||||
|
if isinstance(avg_time, (int, float)):
|
||||||
|
avg_time = f"{avg_time:.1f}ms"
|
||||||
|
|
||||||
|
print(f"[{i}] {name}")
|
||||||
|
print(f" ID: {tool_id}")
|
||||||
|
print(f" {desc[:100]}{'...' if len(desc) > 100 else ''}")
|
||||||
|
print(f" Success: {success_rate} | Avg Time: {avg_time}")
|
||||||
|
|
||||||
|
# Show params
|
||||||
|
params = tool.get("params", [])
|
||||||
|
if params:
|
||||||
|
required = [p["name"] for p in params if p.get("required")]
|
||||||
|
optional = [p["name"] for p in params if not p.get("required")]
|
||||||
|
if required:
|
||||||
|
print(f" Required: {', '.join(required)}")
|
||||||
|
if optional:
|
||||||
|
print(f" Optional: {', '.join(optional[:5])}{'...' if len(optional) > 5 else ''}")
|
||||||
|
|
||||||
|
# Show example
|
||||||
|
examples = tool.get("examples", {})
|
||||||
|
sample = examples.get("sample_parameters")
|
||||||
|
if sample:
|
||||||
|
print(f" Example: {json.dumps(sample)}")
|
||||||
|
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
def display_execution_result(result: dict) -> None:
|
||||||
|
"""Display tool execution result."""
|
||||||
|
success = result.get("success", False)
|
||||||
|
exec_time = result.get("elapsed_time_ms", "N/A")
|
||||||
|
cost = result.get("cost", 0)
|
||||||
|
|
||||||
|
status = "Success" if success else "Failed"
|
||||||
|
print(f"\n{status}")
|
||||||
|
print(f"Time: {exec_time}ms | Cost: {cost}")
|
||||||
|
|
||||||
|
if not success:
|
||||||
|
error = result.get("error_message", "Unknown error")
|
||||||
|
print(f"Error: {error}")
|
||||||
|
|
||||||
|
data = result.get("result", {})
|
||||||
|
if data:
|
||||||
|
print("\nResult:")
|
||||||
|
print(json.dumps(data, indent=2, ensure_ascii=False))
|
||||||
|
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
parser = argparse.ArgumentParser(
|
||||||
|
description="QVeris Tool Search & Execution CLI",
|
||||||
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
|
epilog="""
|
||||||
|
Examples:
|
||||||
|
%(prog)s search "weather forecast API"
|
||||||
|
%(prog)s execute openweathermap_current_weather --search-id abc123 --params '{"city": "London"}'
|
||||||
|
""",
|
||||||
|
)
|
||||||
|
|
||||||
|
subparsers = parser.add_subparsers(dest="command", required=True)
|
||||||
|
|
||||||
|
# Search command
|
||||||
|
search_parser = subparsers.add_parser("search", help="Search for tools")
|
||||||
|
search_parser.add_argument("query", help="Capability description to search for")
|
||||||
|
search_parser.add_argument("--limit", type=int, default=5, help="Max results (default: 5)")
|
||||||
|
search_parser.add_argument("--json", action="store_true", help="Output raw JSON")
|
||||||
|
|
||||||
|
# Execute command
|
||||||
|
exec_parser = subparsers.add_parser("execute", help="Execute a tool")
|
||||||
|
exec_parser.add_argument("tool_id", help="Tool ID to execute")
|
||||||
|
exec_parser.add_argument("--search-id", required=True, help="Search ID from previous search")
|
||||||
|
exec_parser.add_argument("--params", default="{}", help="Tool parameters as JSON string")
|
||||||
|
exec_parser.add_argument("--max-size", type=int, default=20480, help="Max response size")
|
||||||
|
exec_parser.add_argument("--json", action="store_true", help="Output raw JSON")
|
||||||
|
|
||||||
|
args = parser.parse_args()
|
||||||
|
|
||||||
|
try:
|
||||||
|
if args.command == "search":
|
||||||
|
result = await search_tools(args.query, args.limit)
|
||||||
|
if args.json:
|
||||||
|
print(json.dumps(result, indent=2, ensure_ascii=False))
|
||||||
|
else:
|
||||||
|
display_search_results(result)
|
||||||
|
|
||||||
|
elif args.command == "execute":
|
||||||
|
params = json.loads(args.params)
|
||||||
|
result = await execute_tool(
|
||||||
|
args.tool_id,
|
||||||
|
args.search_id,
|
||||||
|
params,
|
||||||
|
args.max_size,
|
||||||
|
)
|
||||||
|
if args.json:
|
||||||
|
print(json.dumps(result, indent=2, ensure_ascii=False))
|
||||||
|
else:
|
||||||
|
display_execution_result(result)
|
||||||
|
|
||||||
|
except httpx.HTTPStatusError as e:
|
||||||
|
print(f"HTTP Error: {e.response.status_code}", file=sys.stderr)
|
||||||
|
print(e.response.text, file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
print(f"Invalid JSON in --params: {e}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error: {e}", file=sys.stderr)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
asyncio.run(main())
|
||||||
Reference in New Issue
Block a user