import argparse import os import json from logging import getLogger logger = getLogger(__name__) from typing import Union, Dict from modules.datafact_generator.util import DataFact from modules.datafact_generator.value_fact import ValueFact, ValueFactGenerator from modules.datafact_generator.trend_fact import TrendFact, TrendFactGenerator from modules.datafact_generator.proportion_fact import ProportionFact, ProportionFactGenerator from modules.datafact_generator.difference_fact import DifferenceFact, DifferenceFactGenerator from .util import DataFact from .value_fact import ValueFact, ValueFactGenerator from .trend_fact import TrendFact, TrendFactGenerator from .proportion_fact import ProportionFact, ProportionFactGenerator from .difference_fact import DifferenceFact, DifferenceFactGenerator from .correlation_fact import CorrelationFact, CorrelationFactGenerator class DatafactGenerator: def __init__(self, data: dict, topk: int=5): self.data = data self.topk = topk self.value_facts: list[ValueFact] = [] self.trend_facts: list[TrendFact] = [] self.proportion_facts: list[ProportionFact] = [] self.difference_facts: list[DifferenceFact] = [] self.correlation_facts: list[CorrelationFact] = [] self.datafacts: list[DataFact] = [] def generate_datafacts(self, topk=5): """ 生成 datafacts """ try: value_fact_generator = ValueFactGenerator(self.data) self.value_facts = value_fact_generator.extract_value_facts() except Exception as e: logger.error(f"生成value facts失败: {str(e)}") self.value_facts = [] try: trend_fact_generator = TrendFactGenerator(self.data) self.trend_facts = trend_fact_generator.extract_trend_facts() except Exception as e: logger.error(f"生成trend facts失败: {str(e)}") self.trend_facts = [] try: proportion_fact_generator = ProportionFactGenerator(self.data, self.value_facts) self.proportion_facts = proportion_fact_generator.extract_proportion_facts() except Exception as e: logger.error(f"生成proportion facts失败: {str(e)}") self.proportion_facts = [] try: difference_fact_generator = DifferenceFactGenerator(self.data, self.value_facts) self.difference_facts = difference_fact_generator.extract_difference_facts() except Exception as e: logger.error(f"生成difference facts失败: {str(e)}") self.difference_facts = [] try: correlation_fact_generator = CorrelationFactGenerator(self.data) self.correlation_facts = correlation_fact_generator.extract_correlation_facts() except Exception as e: logger.error(f"生成correlation facts失败: {str(e)}") self.correlation_facts = [] self.datafacts = self.value_facts + self.trend_facts + self.proportion_facts + \ self.difference_facts + self.correlation_facts self.datafacts = sorted(self.datafacts, key=lambda x: x.score, reverse=True)[:min(topk, len(self.datafacts))] return self.datafacts def process(input: str, output: str) -> None: """ Pipeline入口函数,处理单个文件的数据洞察生成 Args: input (str): 输入JSON文件路径 output (str): 输出JSON文件路径 """ try: # 读取输入文件 with open(input, "r", encoding="utf-8") as f: data = json.load(f) # 预处理数据,确保类型正确 processed_data = preprocess_data(data) # 调用原有的处理逻辑 result = generate_datafacts(input_data=processed_data, input_path=None) if result: # 确保有结果才写入 # 保存结果 with open(output, "w", encoding="utf-8") as f: json.dump(result, f, indent=2, ensure_ascii=False) else: logger.warning(f"跳过文件 {input}: 无有效结果") except Exception as e: logger.error(f"数据洞察生成失败: {str(e)}") raise def preprocess_data(data): """ 预处理数据,处理类型转换问题 """ try: # 深拷贝避免修改原始数据 processed = data.copy() # 确保data字段存在且格式正确 if "data" in processed and isinstance(processed["data"], dict): # 处理数据部分 if "data" in processed["data"]: rows = processed["data"]["data"] if isinstance(rows, list): # 处理每一行数据 for i, row in enumerate(rows): if isinstance(row, dict): # 尝试将数值字符串转换为数值类型 for key, value in row.items(): if isinstance(value, str): try: # 尝试转换为数值 if '.' in value: row[key] = float(value) else: row[key] = int(value) except (ValueError, TypeError): # 如果转换失败,保持原始值 pass elif value is None: # 将None替换为0或其他适当的默认值 row[key] = 0 return processed except Exception as e: logger.error(f"数据预处理失败: {str(e)}") raise def generate_datafacts(input_data=None, input_path=None): """ 原有的数据洞察生成逻辑 Args: input_data: 直接传入的数据对象 input_path: 输入文件路径 """ try: if input_data is not None: data = input_data assert(input_path is None) else: assert(input_path and os.path.exists(input_path)) try: with open(input_path, "r", encoding="utf-8") as f: data = json.load(f) except Exception as e: logger.error(f"Failed to read input file: {e}") return None datafact_generator = DatafactGenerator(data) datafacts = datafact_generator.generate_datafacts() data["datafacts"] = [datafact.get_json() for datafact in datafacts if datafact.score > 0] return data except Exception as e: logger.error(f"生成数据洞察失败: {str(e)}") return None def main(): parser = argparse.ArgumentParser(description="Datafact Generator") parser.add_argument("--input", type=str, required=True, help="Input JSON file path") parser.add_argument("--output", type=str, required=True, help="Output JSON file path") parser.add_argument("--topk", type=int, default=5, help="Max number of facts to include") args = parser.parse_args() success = process(input_path=args.input, output_path=args.output, topk=args.topk) if success: print("Processing json successed.") else: print("Processing json successed.") if __name__ == "__main__": main()