metrics.py 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667
  1. import time
  2. from pydantic import BaseModel, Field
  3. class Cost(BaseModel):
  4. model: str
  5. cost: float
  6. timestamp: float = Field(default_factory=time.time)
  7. class Metrics:
  8. """Metrics class can record various metrics during running and evaluation.
  9. Currently, we define the following metrics:
  10. accumulated_cost: the total cost (USD $) of the current LLM.
  11. """
  12. def __init__(self, model_name: str = 'default') -> None:
  13. self._accumulated_cost: float = 0.0
  14. self._costs: list[Cost] = []
  15. self.model_name = model_name
  16. @property
  17. def accumulated_cost(self) -> float:
  18. return self._accumulated_cost
  19. @accumulated_cost.setter
  20. def accumulated_cost(self, value: float) -> None:
  21. if value < 0:
  22. raise ValueError('Total cost cannot be negative.')
  23. self._accumulated_cost = value
  24. @property
  25. def costs(self) -> list[Cost]:
  26. return self._costs
  27. def add_cost(self, value: float) -> None:
  28. if value < 0:
  29. raise ValueError('Added cost cannot be negative.')
  30. self._accumulated_cost += value
  31. self._costs.append(Cost(cost=value, model=self.model_name))
  32. def merge(self, other: 'Metrics') -> None:
  33. self._accumulated_cost += other.accumulated_cost
  34. self._costs += other._costs
  35. def get(self) -> dict:
  36. """Return the metrics in a dictionary."""
  37. return {
  38. 'accumulated_cost': self._accumulated_cost,
  39. 'costs': [cost.model_dump() for cost in self._costs],
  40. }
  41. def reset(self):
  42. self._accumulated_cost = 0.0
  43. self._costs = []
  44. def log(self):
  45. """Log the metrics."""
  46. metrics = self.get()
  47. logs = ''
  48. for key, value in metrics.items():
  49. logs += f'{key}: {value}\n'
  50. return logs
  51. def __repr__(self):
  52. return f'Metrics({self.get()}'