Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Add telemetry #965

Draft
wants to merge 5 commits into
base: develop
Choose a base branch
from
Draft
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
6 changes: 4 additions & 2 deletions .env.example
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

# Decide host and port for your Cat. Default will be localhost:1865
# CCAT_CORE_HOST=localhost
# CCAT_CORE_PORT=1865
Expand Down Expand Up @@ -37,4 +36,7 @@
# CCAT_METADATA_FILE="cat/data/metadata.json"

# Set container timezone
# CCAT_TIMEZONE=Europe/Rome
# CCAT_TIMEZONE=Europe/Rome

# Telemetry
CCAT_TELEMETRY=true
4 changes: 2 additions & 2 deletions compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ services:
context: ./core
container_name: cheshire_cat_core
# Uncomment the two lines below to use your .env (see .env.example)
#env_file:
# - .env
env_file:
- .env
ports:
- ${CCAT_CORE_PORT:-1865}:80
- 5678:5678 # only for development purposes (take away in production)
Expand Down
1 change: 1 addition & 0 deletions core/cat/env.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ def get_supported_env_variables():
"CCAT_JWT_EXPIRE_MINUTES": str(60 * 24), # JWT expires after 1 day
"CCAT_HTTPS_PROXY_MODE": False,
"CCAT_CORS_FORWARDED_ALLOW_IPS": "*",
"CCAT_TELEMETRY": True,
}


Expand Down
14 changes: 13 additions & 1 deletion core/cat/looking_glass/cheshire_cat.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from typing_extensions import Protocol


from cat.looking_glass.telemetry import TelemetryHandler
from langchain.base_language import BaseLanguageModel
from langchain_core.messages import SystemMessage
from langchain_core.runnables import RunnableLambda
Expand All @@ -29,6 +30,7 @@
from cat.utils import singleton
from cat import utils


class Procedure(Protocol):
name: str
procedure_type: str # "tool" or "form"
Expand Down Expand Up @@ -67,7 +69,10 @@ def __init__(self):

# Start scheduling system
self.white_rabbit = WhiteRabbit()


# Telemetry
self.telemetry = TelemetryHandler()

# instantiate MadHatter (loads all plugins' hooks and tools)
self.mad_hatter = MadHatter()

Expand Down Expand Up @@ -143,6 +148,7 @@ def load_language_model(self) -> BaseLanguageModel:
selected_llm_config = crud.get_setting_by_name(name=selected_llm_class)
try:
llm = FactoryClass.get_llm_from_config(selected_llm_config["value"])
self.telemetry.set_llm_model(selected_llm_class)
except Exception:
import traceback

Expand Down Expand Up @@ -186,6 +192,7 @@ def load_language_embedder(self) -> embedders.EmbedderSettings:
embedder = FactoryClass.get_embedder_from_config(
selected_embedder_config["value"]
)
self.telemetry.set_embedder_model(selected_embedder_class)
except AttributeError:
import traceback

Expand Down Expand Up @@ -426,3 +433,8 @@ def llm(self, prompt, *args, **kwargs) -> str:
)

return output

@property
def telemetryHandler(self):
if self.telemtry is None:
None
73 changes: 73 additions & 0 deletions core/cat/looking_glass/telemetry.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
from uuid import UUID
from pydantic import BaseModel, Field
from typing import Optional
import psutil
from cat.looking_glass.white_rabbit import WhiteRabbit
import httpx
from cat.log import log
from cat.env import get_env
from cat.utils import get_cat_version
from cat.db import crud, models


class SystemData(BaseModel):
ram_gb: float = Field(
frozen=True, default=round(psutil.virtual_memory().total / (1024.0**3), 2)
)
cpu_count: int = Field(frozen=True, default=psutil.cpu_count())


class TelemetryData(BaseModel):
telemetry_id: UUID
country: Optional[str] = None
version: str = get_cat_version()
llm_model: Optional[str] = None
embedder_model: Optional[str] = None
system: SystemData


class TelemetryHandler:
def __init__(self):
self.enable: bool = get_env("CCAT_TELEMETRY") == "true"
if self.enable:
log.info("Load Telemetry")

telemetry_settings = crud.get_setting_by_name("Telemetry")
if telemetry_settings:
# we use the setting_id as telemetry id
telemetry_id = telemetry_settings["setting_id"]
else:
setting = crud.create_setting(
models.Setting(name="Telemetry", category="telemetry", value={})
)
telemetry_id = setting["setting_id"]

system = SystemData()
self.data = TelemetryData(telemetry_id=telemetry_id, system=system)
WhiteRabbit().schedule_interval_job(self.send_telemetry, seconds=6)
else:
log.info("Telemetry is disable")

def set_country(self, country: str):
if not self.enable:
return
# should be ISO3166
self.data.country = country

def set_llm_model(self, llm_model: str):
if not self.enable:
return
self.data.llm_model = llm_model

def set_embedder_model(self, embedder_model: str):
if not self.enable:
return
self.data.embedder_model = embedder_model

def send_telemetry(self):
try:
log.info(f"Sending this chunk of data:{self.data}")
# res = httpx.post("http://telemetry.cheshirecat.ai", data=self.data)
# res.raise_for_status()
except httpx.HTTPStatusError as e:
log.error(f"Error when sending telemetry {e.response.status_code}")
8 changes: 3 additions & 5 deletions core/cat/routes/base.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from fastapi import APIRouter, Depends, Body
from fastapi.concurrency import run_in_threadpool
from typing import Dict
import tomli

from cat.auth.permissions import AuthPermission, AuthResource
from cat.auth.connection import HTTPAuth

from cat.convo.messages import CatMessage
from cat.utils import get_cat_version

router = APIRouter()

Expand All @@ -16,10 +17,7 @@ async def status(
stray=Depends(HTTPAuth(AuthResource.STATUS, AuthPermission.READ)),
) -> Dict:
"""Server status"""
with open("pyproject.toml", "rb") as f:
project_toml = tomli.load(f)["project"]

return {"status": "We're all mad here, dear!", "version": project_toml["version"]}
return {"status": "We're all mad here, dear!", "version": get_cat_version()}


@router.post("/message", response_model=CatMessage)
Expand Down
6 changes: 6 additions & 0 deletions core/cat/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from langchain_core.output_parsers import JsonOutputParser
from langchain_core.prompts import PromptTemplate
from langchain_core.utils import get_colored_text
import tomli

from cat.log import log
from cat.env import get_env
Expand Down Expand Up @@ -243,6 +244,11 @@ def langchain_log_output(langchain_output, title):
return langchain_output


def get_cat_version() -> str:
with open("pyproject.toml", "rb") as f:
project_toml = tomli.load(f)["project"]
return project_toml["version"]

# This is our masterwork during tea time
class singleton:
instances = {}
Expand Down
1 change: 1 addition & 0 deletions core/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ dependencies = [
"APScheduler==3.10.4",
"ruff==0.4.7",
"aiofiles==24.1.0",
"psutil==6.1.0",
]

[tool.coverage.run]
Expand Down
Loading