diff --git a/pyproject.toml b/pyproject.toml index c42db1a9e..3a5b25455 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,7 +10,7 @@ description = "ValidMind Library" license = "Commercial License" name = "validmind" readme = "README.pypi.md" -version = "2.8.9" +version = "2.8.10" [tool.poetry.dependencies] python = ">=3.8.1,<3.12" diff --git a/validmind/__version__.py b/validmind/__version__.py index e71de367e..71322b8ca 100644 --- a/validmind/__version__.py +++ b/validmind/__version__.py @@ -1 +1 @@ -__version__ = "2.8.9" +__version__ = "2.8.10" diff --git a/validmind/ai/test_descriptions.py b/validmind/ai/test_descriptions.py index b52bc3820..48747627a 100644 --- a/validmind/ai/test_descriptions.py +++ b/validmind/ai/test_descriptions.py @@ -7,6 +7,8 @@ from concurrent.futures import ThreadPoolExecutor from typing import List, Optional, Union +import tiktoken + from ..client_config import client_config from ..logging import get_logger from ..utils import NumpyEncoder, md_to_html, test_id_to_name @@ -35,6 +37,29 @@ def _get_llm_global_context(): return context if context_enabled and context else None +def _truncate_summary(summary: str, test_id: str, max_tokens: int = 100_000): + if len(summary) < max_tokens: + # since string itself is less than max_tokens, definitely small enough + return summary + + # TODO: better context length handling + encoding = tiktoken.encoding_for_model("gpt-4o") + summary_tokens = encoding.encode(summary) + + if len(summary_tokens) > max_tokens: + logger.warning( + f"Truncating {test_id} due to context length restrictions..." + " Generated description may be innacurate" + ) + summary = ( + encoding.decode(summary_tokens[:max_tokens]) + + "...[truncated]" + + encoding.decode(summary_tokens[-100:]) + ) + + return summary + + def generate_description( test_id: str, test_description: str, @@ -79,7 +104,7 @@ def generate_description( "test_name": test_name, "test_description": test_description, "title": title, - "summary": summary, + "summary": _truncate_summary(summary, test_id), "figures": [ figure._get_b64_url() for figure in ([] if tables else figures) ], @@ -107,7 +132,13 @@ def wrapped(): title=title, ) except Exception as e: - logger.error(f"Failed to generate description: {e}") + if "maximum context length" in str(e): + logger.warning( + f"Test result {test_id} is too large to generate a description" + ) + else: + logger.warning(f"Failed to generate description for {test_id}: {e}") + logger.warning(f"Using default description for {test_id}") return test_description