diff --git a/app/mcp/v1/tools/ch_reader.py b/app/mcp/v1/tools/ch_reader.py index 6ccf2de..9043fc7 100644 --- a/app/mcp/v1/tools/ch_reader.py +++ b/app/mcp/v1/tools/ch_reader.py @@ -36,7 +36,7 @@ def get_health_summary_ch() -> dict[str, Any]: try: return get_health_summary_from_ch() except Exception as e: - return {"error": str(e)} + return {"error": f"Failed to get health summary: {str(e)}"} @ch_reader_router.tool @@ -71,7 +71,7 @@ def search_health_records_ch(params: HealthRecordSearchParams) -> dict[str, Any] try: return search_health_records_from_ch(params) except Exception as e: - return {"error": str(e)} + return {"error": f"Failed to search health records: {str(e)}"} @ch_reader_router.tool @@ -142,9 +142,11 @@ def get_trend_data_ch( Returns: - record_type: The analyzed record type + - device: The device on which the data was recorded - interval: The time interval used - trend_data: List of time buckets with statistics for each period: * date: The time period (ISO string) + * value_sum: Sum of values for the period * avg_value: Average value for the period * min_value: Minimum value for the period * max_value: Maximum value for the period @@ -152,6 +154,14 @@ def get_trend_data_ch( Notes for LLMs: - Use this to analyze trends, patterns, and seasonal variations in health data + - Keep in mind that when there is data from multiple devices spanning the same + time period, there is a possibility of data being duplicated. Inform the user + of this possibility if you see multiple devices in the same time period. + - If a user asks you to sum up some values from their health records, DO NOT + search for records and write a script to sum them, instead, use this tool: + if they ask to sum data from a year, use this tool with date_from set as the + beginning of the year and date_to as the end of the year, with an interval + of 'year' - The function automatically handles date filtering if date_from/date_to are provided - IMPORTANT - interval must be one of: "day", "week", "month", or "year". Do not use other values. diff --git a/app/mcp/v1/tools/duckdb_reader.py b/app/mcp/v1/tools/duckdb_reader.py index f142ea9..b064cd1 100644 --- a/app/mcp/v1/tools/duckdb_reader.py +++ b/app/mcp/v1/tools/duckdb_reader.py @@ -36,7 +36,7 @@ def get_health_summary_duckdb() -> list[dict[str, Any]]: try: return get_health_summary_from_duckdb() except Exception as e: - return [{"error": str(e)}] + return [{"error": f"Failed to get health summary: {str(e)}"}] @duckdb_reader_router.tool @@ -71,7 +71,7 @@ def search_health_records_duckdb(params: HealthRecordSearchParams) -> list[dict[ try: return search_health_records_from_duckdb(params) except Exception as e: - return [{"error": str(e)}] + return [{"error": f"Failed to search health records: {str(e)}"}] @duckdb_reader_router.tool @@ -142,9 +142,11 @@ def get_trend_data_duckdb( Returns: - record_type: The analyzed record type + - device: The device on which the data was recorded - interval: The time interval used - trend_data: List of time buckets with statistics for each period: * date: The time period (ISO string) + * value_sum: Sum of values for the period * avg_value: Average value for the period * min_value: Minimum value for the period * max_value: Maximum value for the period @@ -152,6 +154,14 @@ def get_trend_data_duckdb( Notes for LLMs: - Use this to analyze trends, patterns, and seasonal variations in health data + - Keep in mind that when there is data from multiple devices spanning the same + time period, there is a possibility of data being duplicated. Inform the user + of this possibility if you see multiple devices in the same time period. + - If a user asks you to sum up some values from their health records, DO NOT + search for records and write a script to sum them, instead, use this tool: + if they ask to sum data from a year, use this tool with date_from set as the + beginning of the year and date_to as the end of the year, with an interval + of 'year' - The function automatically handles date filtering if date_from/date_to are provided - IMPORTANT - interval must be one of: "day", "week", "month", or "year". Do not use other values. @@ -207,4 +217,4 @@ def search_values_duckdb( try: return search_values_from_duckdb(record_type, value, date_from, date_to) except Exception as e: - return [{"error": f"Failed to get trend data: {str(e)}"}] + return [{"error": f"Failed to search for values: {str(e)}"}] diff --git a/app/mcp/v1/tools/es_reader.py b/app/mcp/v1/tools/es_reader.py index 2281819..6cbcccd 100644 --- a/app/mcp/v1/tools/es_reader.py +++ b/app/mcp/v1/tools/es_reader.py @@ -36,7 +36,7 @@ def get_health_summary_es() -> dict[str, Any]: try: return get_health_summary_from_es() except Exception as e: - return {"error": f"Failed to get health summary from ES: {str(e)}"} + return {"error": f"Failed to get health summary: {str(e)}"} @es_reader_router.tool @@ -142,9 +142,11 @@ def get_trend_data_es( Returns: - record_type: The analyzed record type + - device: The device on which the data was recorded - interval: The time interval used - trend_data: List of time buckets with statistics for each period: * date: The time period (ISO string) + * value_sum: Sum of values for the period * avg_value: Average value for the period * min_value: Minimum value for the period * max_value: Maximum value for the period @@ -152,6 +154,14 @@ def get_trend_data_es( Notes for LLMs: - Use this to analyze trends, patterns, and seasonal variations in health data + - Keep in mind that when there is data from multiple devices spanning the same + time period, there is a possibility of data being duplicated. Inform the user + of this possibility if you see multiple devices in the same time period. + - If a user asks you to sum up some values from their health records, DO NOT + search for records and write a script to sum them, instead, use this tool: + if they ask to sum data from a year, use this tool with date_from set as the + beginning of the year and date_to as the end of the year, with an interval + of 'year' - The function automatically handles date filtering if date_from/date_to are provided - IMPORTANT - interval must be one of: "day", "week", "month", or "year". Do not use other values. @@ -207,4 +217,4 @@ def search_values_es( try: return search_values_logic(record_type, value, date_from, date_to) except Exception as e: - return [{"error": f"Failed to get trend data: {str(e)}"}] + return [{"error": f"Failed to search for values: {str(e)}"}] diff --git a/app/services/health/clickhouse.py b/app/services/health/clickhouse.py index d80d87b..0a5bcd5 100644 --- a/app/services/health/clickhouse.py +++ b/app/services/health/clickhouse.py @@ -32,12 +32,13 @@ def get_trend_data_from_ch( date_to: str | None = None, ) -> dict[str, Any]: return ch.inquire(f""" - SELECT toStartOfInterval(startDate, INTERVAL 1 {interval}) AS interval, - AVG(value), MIN(value), MAX(value), COUNT(*) FROM {ch.db_name}.{ch.table_name} + SELECT device, toStartOfInterval(startDate, INTERVAL 1 {interval}) AS interval, + AVG(value) AS average, SUM(value) AS sum, MIN(value) AS min, + MAX(value) AS max, COUNT(*) AS count FROM {ch.db_name}.{ch.table_name} WHERE type = '{record_type}' {f"AND startDate >= '{date_from}'" if date_from else ""} {f"AND startDate <= '{date_to}'" if date_to else ""} - GROUP BY interval ORDER BY interval ASC + GROUP BY interval, device ORDER BY interval ASC """) diff --git a/app/services/health/duckdb_queries.py b/app/services/health/duckdb_queries.py index 6b90fae..72b8bcf 100644 --- a/app/services/health/duckdb_queries.py +++ b/app/services/health/duckdb_queries.py @@ -44,13 +44,14 @@ def get_trend_data_from_duckdb( date_to: str | None = None, ) -> list[dict[str, Any]]: result = duckdb.sql(f""" - SELECT time_bucket(INTERVAL '1 {interval}', startDate) AS interval, - AVG(value) AS average, MIN(value) AS min, MAX(value) AS max, COUNT(*) AS count + SELECT device, time_bucket(INTERVAL '1 {interval}', startDate) AS interval, + AVG(value) AS average, SUM(value) AS sum, + MIN(value) AS min, MAX(value) AS max, COUNT(*) AS count FROM read_parquet('{client.parquetpath}') WHERE type = '{record_type}' - {f"AND startDate >= '{date_from}'" if date_from else ""} - {f"AND startDate <= '{date_to}'" if date_to else ""} - GROUP BY interval ORDER BY interval ASC + {f"AND startDate >= '{date_from}'" if date_from else ""} + {f"AND startDate <= '{date_to}'" if date_to else ""} + GROUP BY interval, device ORDER BY interval ASC """) return client.format_response(result) diff --git a/app/services/health/elasticsearch.py b/app/services/health/elasticsearch.py index 9f0d76a..dca5fb1 100644 --- a/app/services/health/elasticsearch.py +++ b/app/services/health/elasticsearch.py @@ -106,6 +106,7 @@ def get_trend_data_logic( "avg_value": {"avg": {"field": "value"}}, "min_value": {"min": {"field": "value"}}, "max_value": {"max": {"field": "value"}}, + "value_sum": {"sum": {"field": "value"}}, "count": {"value_count": {"field": "value"}}, }, }, @@ -121,6 +122,7 @@ def get_trend_data_logic( "avg_value": bucket["avg_value"]["value"], "min_value": bucket["min_value"]["value"], "max_value": bucket["max_value"]["value"], + "value_sum": bucket["value_sum"]["value"], "count": bucket["count"]["value"], }, )