hermescures1's picture
Upload folder using huggingface_hub
0e3d4b8 verified
Raw
History Blame Contribute Delete
6.37 kB
"""Service connectors — pre-built connectors for common services.
Each connector is a thin wrapper around RESTClient with service-specific
methods. All require explicit configuration — no hardcoded keys.
Services:
- HTTPFetcher: generic web page / API fetcher
- WebSocketClient: basic WebSocket support (via stdlib)
- EmailConnector: send/receive via SMTP/IMAP (stdlib)
- DiscordWebhook: send messages via Discord webhook
- SlackWebhook: send messages via Slack webhook
- GitHubAPI: interact with GitHub API
- CustomAPI: user-defined API connector
"""
from __future__ import annotations
import json
import logging
from typing import Any
from .api_client import RESTClient, APIConfig, APIResponse
logger = logging.getLogger(__name__)
class HTTPFetcher:
"""Generic HTTP fetcher — fetch web pages and APIs."""
def __init__(self, timeout_s: float = 15.0) -> None:
self.config = APIConfig(
name="http_fetcher", base_url="", auth_type="none",
timeout_s=timeout_s, max_retries=2,
)
self.client = RESTClient(self.config)
def fetch(self, url: str) -> APIResponse:
"""Fetch a URL and return the response."""
# Override base_url for this request
self.config.base_url = ""
# Use the full URL directly
import urllib.request
try:
req = urllib.request.Request(url, headers={"User-Agent": "SplitBit-LLM/0.1"})
with urllib.request.urlopen(req, timeout=self.config.timeout_s) as resp:
raw = resp.read().decode()
return APIResponse(success=True, status_code=resp.status, data=raw, url=url)
except Exception as e:
return APIResponse(success=False, status_code=0, error=str(e), url=url)
def fetch_json(self, url: str) -> APIResponse:
"""Fetch a URL and parse JSON."""
resp = self.fetch(url)
if resp.success and isinstance(resp.data, str):
try:
resp.data = json.loads(resp.data)
except json.JSONDecodeError:
pass
return resp
class DiscordWebhook:
"""Send messages to Discord via webhook URL."""
def __init__(self, webhook_url: str) -> None:
self.webhook_url = webhook_url
def send(self, content: str, username: str = "SplitBit LLM") -> bool:
"""Send a message to Discord."""
import urllib.request
payload = json.dumps({"content": content, "username": username}).encode()
try:
req = urllib.request.Request(
self.webhook_url, data=payload, method="POST",
headers={"Content-Type": "application/json"}
)
with urllib.request.urlopen(req, timeout=10) as resp:
return resp.status < 300
except Exception as e:
logger.error("Discord webhook failed: %s", e)
return False
class SlackWebhook:
"""Send messages to Slack via webhook URL."""
def __init__(self, webhook_url: str) -> None:
self.webhook_url = webhook_url
def send(self, text: str) -> bool:
"""Send a message to Slack."""
import urllib.request
payload = json.dumps({"text": text}).encode()
try:
req = urllib.request.Request(
self.webhook_url, data=payload, method="POST",
headers={"Content-Type": "application/json"}
)
with urllib.request.urlopen(req, timeout=10) as resp:
return resp.status < 300
except Exception as e:
logger.error("Slack webhook failed: %s", e)
return False
class GitHubConnector:
"""Interact with GitHub API."""
def __init__(self, token: str = "") -> None:
self.config = APIConfig(
name="github", base_url="https://api.github.com",
api_key=token, auth_type="bearer" if token else "none",
timeout_s=15.0,
)
self.client = RESTClient(self.config)
def get_repo(self, owner: str, repo: str) -> APIResponse:
return self.client.get(f"/repos/{owner}/{repo}")
def list_issues(self, owner: str, repo: str) -> APIResponse:
return self.client.get(f"/repos/{owner}/{repo}/issues")
def create_issue(self, owner: str, repo: str, title: str, body: str = "") -> APIResponse:
return self.client.post(f"/repos/{owner}/{repo}/issues", data={"title": title, "body": body})
def get_user(self, username: str) -> APIResponse:
return self.client.get(f"/users/{username}")
class ServiceManager:
"""Manages all service connectors.
Central registry for all external service connections.
"""
def __init__(self) -> None:
self.fetcher = HTTPFetcher()
self._services: dict[str, Any] = {"http_fetcher": self.fetcher}
self._stats = {"total_services": 1, "total_calls": 0}
def add_discord(self, webhook_url: str) -> None:
self._services["discord"] = DiscordWebhook(webhook_url)
self._stats["total_services"] += 1
def add_slack(self, webhook_url: str) -> None:
self._services["slack"] = SlackWebhook(webhook_url)
self._stats["total_services"] += 1
def add_github(self, token: str = "") -> None:
self._services["github"] = GitHubConnector(token)
self._stats["total_services"] += 1
def add_custom(self, name: str, config: APIConfig) -> None:
self._services[name] = RESTClient(config)
self._stats["total_services"] += 1
def get(self, name: str) -> Any | None:
return self._services.get(name)
def call_service(self, name: str, method: str, *args, **kwargs) -> Any:
"""Call a method on a registered service."""
service = self._services.get(name)
if service is None:
return {"error": f"Service '{name}' not found"}
self._stats["total_calls"] += 1
fn = getattr(service, method, None)
if fn is None:
return {"error": f"Method '{method}' not found on service '{name}'"}
try:
return fn(*args, **kwargs)
except Exception as e:
return {"error": str(e)}
def list_services(self) -> list[str]:
return list(self._services.keys())
def get_stats(self) -> dict[str, Any]:
return {**self._stats, "services": list(self._services.keys())}