diff --git a/.gitignore b/.gitignore index 41dbbf2d8..4501eb521 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,8 @@ data/ # Workspace workspace/ +config/ + ### Python ### # Byte-compiled / optimized / DLL files __pycache__/ diff --git a/.vscode/settings.json b/.vscode/settings.json index d3aa302bb..511290989 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -16,5 +16,6 @@ }, "files.insertFinalNewline": true, "files.trimTrailingWhitespace": true, - "editor.formatOnSave": true + "editor.formatOnSave": true, + "liveServer.settings.port": 5501 } diff --git a/app/agent/data_analysis.py b/app/agent/data_analysis.py index 79b9c2967..f564f3ecd 100644 --- a/app/agent/data_analysis.py +++ b/app/agent/data_analysis.py @@ -4,9 +4,23 @@ from app.config import config from app.prompt.visualization import NEXT_STEP_PROMPT, SYSTEM_PROMPT from app.tool import Terminate, ToolCollection +from app.tool.chart_visualization.python_execute import NormalPythonExecute +# from app.tool.chart_visualization.chart_prepare import VisualizationPrepare +# from app.tool.chart_visualization.data_visualization import DataVisualization +# from app.tool.chart_visualization.initial_report_generation import GenerateInitialReport +# from app.tool.chart_visualization.final_report_generation import GenerateFinalReport +# from app.tool.chart_visualization.search_report_template import SearchReportTemplate +# from app.tool.chart_visualization.report_template_generation import ReportTemplateGeneration +# from app.tool.chart_visualization.initial_information_collection import InitialInformationCollection from app.tool.chart_visualization.chart_prepare import VisualizationPrepare +from app.tool.chart_visualization.select_insights import SelectInsights +from app.tool.chart_visualization.add_insights import AddInsights from app.tool.chart_visualization.data_visualization import DataVisualization -from app.tool.chart_visualization.python_execute import NormalPythonExecute +from app.tool.chart_visualization.v2.search_html_library import SearchHtmlLibrary +from app.tool.chart_visualization.v2.initial_report_generation import GenerateInitialReport +from app.tool.chart_visualization.v2.report_template_generation import ReportTemplateGeneration +from app.tool.chart_visualization.v2.final_report_generation import GenerateFinalReport +from app.tool.chart_visualization.v2.report_beautify import ReportBeautify class DataAnalysis(ToolCallAgent): @@ -18,7 +32,34 @@ class DataAnalysis(ToolCallAgent): """ name: str = "Data_Analysis" - description: str = "An analytical agent that utilizes python and data visualization tools to solve diverse data analysis tasks" + description: str = """ + A data science agent specializing in Python-based analytics and advanced visualization techniques + for solving complex data analysis challenges. + + Standard Report Generation Workflow: + 1. Template Preparation: + - SearchHtmlLibrary: Identify suitable visualization templates + - ReportTemplateGeneration & GenerateInitialReport: Create initial report structure + + 2. Visualization Pipeline: + - VisualizationPrepare: Configure data for visualization + - DataVisualization: Generate interactive charts and graphs + + 3. Insight Enhancement: + - SelectInsights: Extract key findings from visualizations + - AddInsights: Annotate charts with analytical insights + + 4. Report Finalization: + - GenerateFinalReport: Replace the placeholders with charts + - ReportBeautify: Apply professional styling and formatting + + Operational Protocol: + - First determine optimal visualization types based on dataset characteristics + - Utilize HTML template library to establish report framework + - Execute visualization pipeline to create data representations + - Enhance each chart with key insights you selected + - Assemble final report by embedding enriched visualizations + """ system_prompt: str = SYSTEM_PROMPT.format(directory=config.workspace_root) next_step_prompt: str = NEXT_STEP_PROMPT @@ -30,8 +71,15 @@ class DataAnalysis(ToolCallAgent): available_tools: ToolCollection = Field( default_factory=lambda: ToolCollection( NormalPythonExecute(), + SearchHtmlLibrary(), + ReportTemplateGeneration(), + GenerateInitialReport(), + GenerateFinalReport(), + ReportBeautify(), + AddInsights(), VisualizationPrepare(), DataVisualization(), + SelectInsights(), Terminate(), ) ) diff --git a/app/prompt/visualization.py b/app/prompt/visualization.py index 8e4fecc53..e5f4bdac6 100644 --- a/app/prompt/visualization.py +++ b/app/prompt/visualization.py @@ -1,7 +1,33 @@ SYSTEM_PROMPT = """You are an AI agent designed to data analysis / visualization task. You have various tools at your disposal that you can call upon to efficiently complete complex requests. # Note: 1. The workspace directory is: {directory}; Read / write file in workspace -2. Generate analysis conclusion report in the end""" +2. Generate analysis conclusion report in the end + +Standard Report Generation Workflow: +1. Template Preparation: + - SearchHtmlLibrary: Identify suitable visualization templates + - ReportTemplateGeneration & GenerateInitialReport: Create initial report structure + +2. Visualization Pipeline: + - VisualizationPrepare: Configure data for visualization + - DataVisualization: Generate interactive charts and graphs + +3. Insight Enhancement: + - SelectInsights: Extract key findings from visualizations + - AddInsights: Annotate charts with analytical insights + +4. Report Finalization: + - GenerateFinalReport: Replace the placeholders with charts + - ReportBeautify: Apply professional styling and formatting + +Operational Protocol: +- First determine optimal visualization types based on dataset characteristics +- Utilize HTML template library to establish report framework +- Execute visualization pipeline to create data representations +- Enhance each chart with key insights you selected +- Assemble final report by embedding enriched visualizations + +""" NEXT_STEP_PROMPT = """Based on user needs, break down the problem and use different tools step by step to solve it. # Note diff --git a/app/tool/chart_visualization/__init__.py b/app/tool/chart_visualization/__init__.py index ea7d51a39..eda63d1ba 100644 --- a/app/tool/chart_visualization/__init__.py +++ b/app/tool/chart_visualization/__init__.py @@ -1,6 +1,3 @@ from app.tool.chart_visualization.chart_prepare import VisualizationPrepare from app.tool.chart_visualization.data_visualization import DataVisualization from app.tool.chart_visualization.python_execute import NormalPythonExecute - - -__all__ = ["DataVisualization", "VisualizationPrepare", "NormalPythonExecute"] diff --git a/app/tool/chart_visualization/add_insights.py b/app/tool/chart_visualization/add_insights.py new file mode 100644 index 000000000..d61b3642e --- /dev/null +++ b/app/tool/chart_visualization/add_insights.py @@ -0,0 +1,228 @@ +import sys +import asyncio +import json +import os +print(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))) +sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))))) + +from typing import Any, Hashable + +import pandas as pd +from pydantic import Field, model_validator + +from app.config import config +from app.llm import LLM +from app.logger import logger +from app.tool.base import BaseTool + + +class AddInsights(BaseTool): + name: str = "add_insights" + description: str = ( + "Enhances charts by adding insights markers and annotations " + "using JSON data generated by the insights_selection tool. " + "This creates the final annotated visualization output." + ) + + parameters: dict = { + "type": "object", + "properties": { + "json_path": { + "type": "string", + "description": """Path to the JSON file generated by insights_selection tool. +Contains chart insights data in format: +{ + "chartPath": string, + "insights_id": number[] +}""", + }, + "output_type": { + "type": "string", + "description": "Visualization output format selection", + "default": "html", + "enum": [ + "png", # Static image format + "html" # Interactive web format (recommended) + ], + }, + }, + "required": ["json_path"], + } + llm: LLM = Field(default_factory=LLM, description="Language model instance") + + @model_validator(mode="after") + def initialize_llm(self): + """Initialize llm with default settings if not provided.""" + if self.llm is None or not isinstance(self.llm, LLM): + self.llm = LLM(config_name=self.name.lower()) + return self + + def load_chart_with_css(self, chart_path): + # 读取 HTML 文件 + with open(chart_path, 'r', encoding='utf-8') as f: + html_content = f.read() + html_content = html_content.replace('`', "'") + + # 在
里插入 CSS + css = """ + + """ + + # 如果原文件没有 ,直接插入到最前面 + if "" in html_content: + html_content = html_content.replace("", "" + css) + else: + html_content = css + html_content + + with open(chart_path, 'w', encoding='utf-8') as f: + f.write(html_content) + + def get_file_path( + self, + json_info: list[dict[str, str]], + path_str: str, + directory: str = None, + ) -> list[str]: + res = [] + for item in json_info: + if os.path.exists(item[path_str]): + res.append(item[path_str]) + elif os.path.exists( + os.path.join(f"{directory or config.workspace_root}", item[path_str]) + ): + res.append( + os.path.join( + f"{directory or config.workspace_root}", item[path_str] + ) + ) + else: + raise Exception(f"No such file or directory: {item[path_str]}") + return res + + async def add_insights( + self, json_info: list[dict[str, str]], output_type: str + ) -> str: + data_list = [] + chart_file_path = self.get_file_path( + json_info, "chartPath", os.path.join(config.workspace_root, "visualization") + ) + for index, item in enumerate(json_info): + if "insights_id" in item: + data_list.append( + { + "file_name": os.path.basename(chart_file_path[index]).replace( + f".{output_type}", "" + ), + "insights_id": item["insights_id"], + } + ) + tasks = [ + self.invoke_vmind( + insights_id=item["insights_id"], + file_name=item["file_name"], + output_type=output_type, + task_type="insight", + ) + for item in data_list + ] + results = await asyncio.gather(*tasks) + error_list = [] + success_list = [] + for index, result in enumerate(results): + chart_path = chart_file_path[index] + if "error" in result and "chart_path" not in result: + error_list.append(f"Error in {chart_path}: {result['error']}") + else: + success_list.append(chart_path) + self.load_chart_with_css(chart_path) + + success_template = ( + f"# Charts Update with Insights\n{','.join(success_list)}" + if len(success_list) > 0 + else "" + ) + if len(error_list) > 0: + return { + "observation": f"# Error in chart insights:{'\n'.join(error_list)}\n{success_template}", + "success": False, + } + else: + return {"observation": f"{success_template}"} + + async def execute( + self, + json_path: str, + output_type: str | None = "html", + tool_type: str | None = "visualization", + language: str | None = "en", + ) -> str: + try: + logger.info(f"📈 data_visualization with {json_path} in: {tool_type} ") + with open(json_path, "r", encoding="utf-8") as file: + json_info = json.load(file) + return await self.add_insights(json_info, output_type) + except Exception as e: + return { + "observation": f"Error: {e}", + "success": False, + } + + async def invoke_vmind( + self, + file_name: str, + output_type: str, + task_type: str, + insights_id: list[str] = None, + dict_data: list[dict[Hashable, Any]] = None, + chart_description: str = None, + language: str = "en", + ): + llm_config = { + "base_url": self.llm.base_url, + "model": self.llm.model, + "api_key": self.llm.api_key, + } + vmind_params = { + "llm_config": llm_config, + "user_prompt": chart_description, + "dataset": dict_data, + "file_name": file_name, + "output_type": output_type, + "insights_id": insights_id, + "task_type": task_type, + "directory": str(config.workspace_root), + "language": language, + } + + process = await asyncio.create_subprocess_exec( + "npx", + "ts-node", + "src/chartVisualize.ts", + stdin=asyncio.subprocess.PIPE, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + cwd=os.path.dirname(__file__), + ) + input_json = json.dumps(vmind_params, ensure_ascii=False).encode("utf-8") + try: + stdout, stderr = await process.communicate(input_json) + stdout_str = stdout.decode("utf-8") + stderr_str = stderr.decode("utf-8") + if process.returncode == 0: + return json.loads(stdout_str) + else: + return {"error": f"Node.js Error: {stderr_str}"} + except Exception as e: + return {"error": f"Subprocess Error: {str(e)}"} + diff --git a/app/tool/chart_visualization/chart_prepare.py b/app/tool/chart_visualization/chart_prepare.py index 1eed35e4d..d9898d709 100644 --- a/app/tool/chart_visualization/chart_prepare.py +++ b/app/tool/chart_visualization/chart_prepare.py @@ -1,36 +1,36 @@ from app.tool.chart_visualization.python_execute import NormalPythonExecute - - class VisualizationPrepare(NormalPythonExecute): """A tool for Chart Generation Preparation""" name: str = "visualization_preparation" - description: str = "Using Python code to generates metadata of data_visualization tool. Outputs: 1) JSON Information. 2) Cleaned CSV data files (Optional)." + description: str = """ + You need some charts to replace initial report's placeholders. So you need to use this tool first to prepare metadata for data_visualization tool. + Using Python code to generates metadata of data_visualization tool. Outputs: 1) JSON Information. 2) Cleaned CSV data files (Optional). + """ parameters: dict = { "type": "object", "properties": { "code_type": { - "description": "code type, visualization: csv -> chart; insight: choose insight into chart", + "description": "code type, visualization: csv -> chart", "type": "string", - "default": "visualization", - "enum": ["visualization", "insight"], + "default": "visualization" }, "code": { "type": "string", "description": """Python code for data_visualization prepare. -## Visualization Type + +## Visualization Type (Initial Step) 1. Data loading logic 2. Csv Data and chart description generate -2.1 Csv data (The data you want to visulazation, cleaning / transform from origin data, saved in .csv) -2.2 Chart description of csv data (The chart title or description should be concise and clear. Examples: 'Product sales distribution', 'Monthly revenue trend'.) + 2.1 Csv data (The data you want to visulazation, cleaning / transform from origin data, saved in .csv) + 2.2 Chart description of csv data (The chart title or description should be concise and clear. Examples: 'Product sales distribution', 'Monthly revenue trend'.) 3. Save information in json file.( format: {"csvFilePath": string, "chartTitle": string}[]) -## Insight Type -1. Select the insights from the data_visualization results that you want to add to the chart. -2. Save information in json file.( format: {"chartPath": string, "insights_id": number[]}[]) -# Note -1. You can generate one or multiple csv data with different visualization needs. -2. Make each chart data esay, clean and different. -3. Json file saving in utf-8 with path print: print(json_path) + + +# Best Practices +1. Generate one or multiple csv data with different visualization needs based on the initial report +2. Make each chart data simple, clean and distinct +4. Json file saving in utf-8 with path print: print(json_path) """, }, }, diff --git a/app/tool/chart_visualization/data_visualization.py b/app/tool/chart_visualization/data_visualization.py index 26dfaa985..a75b62aa0 100644 --- a/app/tool/chart_visualization/data_visualization.py +++ b/app/tool/chart_visualization/data_visualization.py @@ -14,12 +14,8 @@ class DataVisualization(BaseTool): name: str = "data_visualization" - description: str = """Visualize statistical chart or Add insights in chart with JSON info from visualization_preparation tool. You can do steps as follows: -1. Visualize statistical chart -2. Choose insights into chart based on step 1 (Optional) -Outputs: -1. Charts (png/html) -2. Charts Insights (.md)(Optional)""" + description: str = """Visualize statistical chart with JSON info from visualization_preparation tool. +Outputs: Charts (png/html)""" parameters: dict = { "type": "object", "properties": { @@ -34,10 +30,9 @@ class DataVisualization(BaseTool): "enum": ["png", "html"], }, "tool_type": { - "description": "visualize chart or add insights", + "description": "visualize", "type": "string", "default": "visualization", - "enum": ["visualization", "insight"], }, "language": { "description": "english(en) / chinese(zh)", @@ -79,11 +74,43 @@ def get_file_path( raise Exception(f"No such file or directory: {item[path_str]}") return res + def load_chart_with_css(self, chart_path): + # 读取 HTML 文件 + with open(chart_path, 'r', encoding='utf-8') as f: + html_content = f.read() + + # 在 里插入 CSS + css = """ + + """ + + # 如果原文件没有 ,直接插入到最前面 + if "" in html_content: + html_content = html_content.replace("", "" + css) + else: + html_content = css + html_content + + with open(chart_path, 'w', encoding='utf-8') as f: + f.write(html_content) + def success_output_template(self, result: list[dict[str, str]]) -> str: content = "" if len(result) == 0: return "Is EMPTY!" for item in result: + chart_path=item['chart_path'] + self.load_chart_with_css(chart_path) content += f"""## {item['title']}\nChart saved in: {item['chart_path']}""" if "insight_path" in item and item["insight_path"] and "insight_md" in item: content += "\n" + item["insight_md"] @@ -145,7 +172,7 @@ async def data_visualization( else: return {"observation": f"{self.success_output_template(success_list)}"} - async def add_insighs( + async def add_insights( self, json_info: list[dict[str, str]], output_type: str ) -> str: data_list = [] @@ -207,7 +234,7 @@ async def execute( if tool_type == "visualization": return await self.data_visualization(json_info, output_type, language) else: - return await self.add_insighs(json_info, output_type) + return await self.add_insights(json_info, output_type) except Exception as e: return { "observation": f"Error: {e}", diff --git a/app/tool/chart_visualization/package-lock.json b/app/tool/chart_visualization/package-lock.json index 19dae01ea..7365da31e 100644 --- a/app/tool/chart_visualization/package-lock.json +++ b/app/tool/chart_visualization/package-lock.json @@ -10,7 +10,7 @@ "license": "ISC", "dependencies": { "@visactor/vchart": "^1.13.7", - "@visactor/vmind": "2.0.5", + "@visactor/vmind": "2.0.6-alpha.2", "get-stdin": "^9.0.0", "puppeteer": "^24.9.0" }, @@ -6319,9 +6319,9 @@ } }, "node_modules/@visactor/calculator": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@visactor/calculator/-/calculator-2.0.5.tgz", - "integrity": "sha512-/NBDB/wBQLeQuSspDBuiEAbbyfJS/xPX6mubVsLGhfy65UwUBojAQgmX25FcRJnUsRXooK5heshni19DBBf8xA==", + "version": "2.0.6-alpha.2", + "resolved": "https://registry.npmjs.org/@visactor/calculator/-/calculator-2.0.6-alpha.2.tgz", + "integrity": "sha512-eSihYc5cTOeH3gFIW5lBBSWk1PDPDrO/dhaz3G6ZfRRx/wLNf5K1W1jCUaKeNcfcLyydB+6JH7u1k8vm2oIznw==", "dependencies": { "@visactor/vutils": "~0.19.3", "node-sql-parser": "~4.17.0", @@ -6329,13 +6329,26 @@ } }, "node_modules/@visactor/chart-advisor": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@visactor/chart-advisor/-/chart-advisor-2.0.5.tgz", - "integrity": "sha512-pvHceRlworB7kDSmbWXUtherLLXh5nMj0aEGuxtzKQyHmeO0sjuu9gGXBFIgscGliSZM4tmeNrFU9eBLGJ8dxw==", + "version": "2.0.6-alpha.2", + "resolved": "https://registry.npmjs.org/@visactor/chart-advisor/-/chart-advisor-2.0.6-alpha.2.tgz", + "integrity": "sha512-QlhM5s3o48QtUDn0VmJB6xwYwBPgUh2SfxYosGKrbmajRFUb8e6I6LDKTNOda2dQ3/e0a04+zZIiDTpViMxkCw==", + "license": "MIT", "dependencies": { "@visactor/vutils": "~0.19.3" } }, + "node_modules/@visactor/generate-vchart": { + "version": "2.0.6-alpha.2", + "resolved": "https://registry.npmjs.org/@visactor/generate-vchart/-/generate-vchart-2.0.6-alpha.2.tgz", + "integrity": "sha512-Md62wBLtAwIZ/a04xRyCfgeFDy0sgwUiBei6vD6FoE+vgEkpp9+Vf0jpMXK1sTuxFa3nxi8GxcUsDmiNwEZJ9w==", + "dependencies": { + "@visactor/vchart-theme": "~1.12.2", + "@visactor/vutils": "~0.19.3", + "dayjs": "~1.11.10", + "node-sql-parser": "~4.17.0", + "ts-pattern": "~4.1.4" + } + }, "node_modules/@visactor/vchart": { "version": "1.13.8", "resolved": "https://registry.npmjs.org/@visactor/vchart/-/vchart-1.13.8.tgz", @@ -6496,14 +6509,16 @@ } }, "node_modules/@visactor/vmind": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@visactor/vmind/-/vmind-2.0.5.tgz", - "integrity": "sha512-QztQaeSkdeRZYOUlB4qaBpx3/swyO3JzFH8eYvSgvptS/rf8aQDZiufAUasafDLkcME5N6RpBGkcGYIDkmt74Q==", + "version": "2.0.6-alpha.2", + "resolved": "https://registry.npmjs.org/@visactor/vmind/-/vmind-2.0.6-alpha.2.tgz", + "integrity": "sha512-bPuZ4U7dIxHbYnu1oSuddJc5HvRN194Yair9kYqlx4fBqNukHAqWAUEyCdir9YzyJVDvSdEJ7xqmvXecW5W3WQ==", + "license": "MIT", "dependencies": { "@stdlib/stats-base-dists-t-quantile": "0.2.1", - "@visactor/calculator": "2.0.5", - "@visactor/chart-advisor": "2.0.5", - "@visactor/vchart-theme": "^1.11.2", + "@visactor/calculator": "2.0.6-alpha.2", + "@visactor/chart-advisor": "2.0.6-alpha.2", + "@visactor/generate-vchart": "2.0.6-alpha.2", + "@visactor/vchart-theme": "~1.12.2", "@visactor/vdataset": "~0.19.3", "@visactor/vutils": "~0.19.3", "alasql": "~4.3.2", diff --git a/app/tool/chart_visualization/package.json b/app/tool/chart_visualization/package.json index 1e9189dcb..4de31476e 100644 --- a/app/tool/chart_visualization/package.json +++ b/app/tool/chart_visualization/package.json @@ -9,7 +9,7 @@ }, "dependencies": { "@visactor/vchart": "^1.13.7", - "@visactor/vmind": "2.0.5", + "@visactor/vmind": "2.0.6-alpha.2", "get-stdin": "^9.0.0", "puppeteer": "^24.9.0" }, diff --git a/app/tool/chart_visualization/select_insights.py b/app/tool/chart_visualization/select_insights.py new file mode 100644 index 000000000..fb56a305b --- /dev/null +++ b/app/tool/chart_visualization/select_insights.py @@ -0,0 +1,54 @@ +from app.tool.chart_visualization.python_execute import NormalPythonExecute +class SelectInsights(NormalPythonExecute): + name: str = "insights_selection" + description: str = ( + "This tool analyzes data_visualization tool's outputs and identifies key data insights for each chart." + "based on their importance ranking. Insights are prioritized in three tiers:\n" + "1 **Critical Insights**: 'abnormal_trend', 'abnormal_band', 'turning_point', 'overall_trend'\n" + "2 **Important Insights**: 'outlier', 'extreme_value', 'majority_value', 'avg'\n" + "3 **Basic Insights**: 'min', 'max'\n\n" + "**!Must be called immediately after data_visualization completes!**" + "**!All insights_id must come from the data_visualization analysis results!**" + + ) + parameters: dict = { + "type": "object", + "properties": { + "code": { + "type": "string", + "description": """Python code to analyze visualized charts and extract insights. + +# PRIORITY REQUIREMENTS +Insights must be selected and ranked according to these importance tiers: +1. **First Priority**: Always include 'abnormal_trend', 'abnormal_band', 'turning_point', 'overall_trend' when present +2. **Second Priority**: Include 'outlier', 'extreme_value', 'majority_value', 'avg' if no first-tier insights exist +3. **Third Priority**: Fall back to 'min', 'max' only when no higher-priority insights are available + +# EXECUTION REQUIREMENTS +1. **Timing**: MUST be called immediately after data_visualization completes +2. **Dependency**: MUST use insights from data_visualization output as the only source for insights_id + + +# CODE REQUIREMENTS +Your Python code must: +1. Analyze the data_visualization results to identify significant insights for each chart. +2. Save the findings in JSON format: + ```json + [ + { + "chartPath": "string", // Path to the generated chart + "insights_id": number[] // Array of key insight IDs FROM DATA_VISUALIZATION RESULTS + }, + { + "chartPath": "string", // Path to the generated chart + "insights_id": number[] // Array of key insight IDs FROM DATA_VISUALIZATION RESULTS + }, + ... + ] + ``` +Json file saving in utf-8 with path print: print(json_path) +""", + }, + }, + "required": ["code"], + } diff --git a/app/tool/chart_visualization/src/chartVisualize.ts b/app/tool/chart_visualization/src/chartVisualize.ts index c5091a373..784b6cba2 100644 --- a/app/tool/chart_visualization/src/chartVisualize.ts +++ b/app/tool/chart_visualization/src/chartVisualize.ts @@ -1,7 +1,8 @@ import path from "path"; import fs from "fs"; import puppeteer from "puppeteer"; -import VMind, { ChartType, DataTable } from "@visactor/vmind"; +import VMind, { ChartType } from "@visactor/vmind"; +import type { DataTable } from '@visactor/generate-vchart'; import { isString } from "@visactor/vutils"; enum AlgorithmType { @@ -63,8 +64,7 @@ function getHtmlVChart(spec: any, width?: number, height?: number) { -