| import json |
| import os |
| import pprint |
| import shutil |
| from functools import partial |
| from pathlib import Path |
|
|
| import gradio as gr |
|
|
| from dingo.config import InputArgs |
| from dingo.exec import Executor |
| from dingo.model import Model |
|
|
|
|
| def dingo_demo( |
| uploaded_file, |
| dataset_source, data_format, remove_output, input_path, max_workers, batch_size, |
| fields_data, |
| rule_list, llm_list, |
| |
| llm_config_data |
| ): |
| if not data_format: |
| raise gr.Error('ValueError: data_format can not be empty, please input.') |
|
|
| if not rule_list and not llm_list: |
| raise gr.Error('ValueError: rule_list and llm_list can not be empty at the same time.') |
|
|
| |
| if dataset_source == "hugging_face": |
| if not input_path: |
| raise gr.Error('ValueError: input_path can not be empty for hugging_face dataset, please input.') |
| final_input_path = input_path |
| else: |
| if not uploaded_file: |
| raise gr.Error('Please upload a file for local dataset.') |
|
|
| file_base_name = os.path.basename(uploaded_file.name) |
| if not str(file_base_name).endswith(('.jsonl', '.json', '.txt')): |
| raise gr.Error('File format must be \'.jsonl\', \'.json\' or \'.txt\'') |
|
|
| final_input_path = uploaded_file.name |
|
|
| if max_workers <= 0: |
| raise gr.Error('Please input value > 0 in max_workers.') |
| if batch_size <= 0: |
| raise gr.Error('Please input value > 0 in batch_size.') |
|
|
| try: |
| |
| fields = {} |
| if fields_data is not None and len(fields_data) > 0: |
| for row in fields_data.values.tolist(): |
| if len(row) >= 2 and row[0] and row[1]: |
| fields[row[0]] = row[1] |
|
|
| |
| rule_configs = {} |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| llm_configs = {} |
| if llm_config_data is not None and len(llm_config_data) > 0: |
| for row in llm_config_data.values.tolist(): |
| if len(row) >= 5 and row[0]: |
| llm_name = row[0] |
| config = {} |
|
|
| |
| if row[1] and str(row[1]).strip(): |
| config['model'] = str(row[1]) |
|
|
| |
| if row[2] and str(row[2]).strip(): |
| config['key'] = str(row[2]) |
|
|
| |
| if row[3] and str(row[3]).strip(): |
| config['api_url'] = str(row[3]) |
|
|
| |
| if row[4] and str(row[4]).strip(): |
| try: |
| config['parameters'] = json.loads(str(row[4])) |
| except json.JSONDecodeError as e: |
| raise gr.Error(f"Invalid JSON in 'parameters' for LLM '{llm_name}': {e}") |
|
|
| if config: |
| llm_configs[llm_name] = config |
|
|
| |
| evals = [] |
|
|
| |
| for rule in rule_list: |
| eval_item = {"name": rule} |
| if rule in rule_configs: |
| eval_item["config"] = rule_configs[rule] |
| evals.append(eval_item) |
|
|
| |
| for llm in llm_list: |
| eval_item = {"name": llm} |
| if llm in llm_configs: |
| eval_item["config"] = llm_configs[llm] |
| evals.append(eval_item) |
|
|
| input_data = { |
| "input_path": final_input_path, |
| "output_path": "" if dataset_source == 'hugging_face' else os.path.dirname(final_input_path), |
| "dataset": { |
| "source": dataset_source, |
| "format": data_format, |
| }, |
| "executor": { |
| "result_save": { |
| "bad": True, |
| |
| }, |
| "max_workers": max_workers, |
| "batch_size": batch_size, |
| }, |
| "evaluator": [ |
| { |
| "fields": fields, |
| "evals": evals |
| } |
| ] |
| } |
|
|
| |
| |
|
|
| input_args = InputArgs(**input_data) |
| executor = Executor.exec_map["local"](input_args) |
| summary = executor.execute().to_dict() |
| detail = executor.get_bad_info_list() |
| dingo_id_set = set() |
| new_detail = [] |
| for item in detail: |
| if item['dingo_id'] not in dingo_id_set: |
| dingo_id_set.add(item['dingo_id']) |
| new_detail.append(item) |
| if summary['output_path']: |
| if remove_output == "true": |
| shutil.rmtree(summary['output_path']) |
| summary['output_path'] = "" |
|
|
| |
| return json.dumps(summary, indent=4), new_detail |
| except Exception as e: |
| raise gr.Error(str(e)) |
|
|
|
|
| def update_input_components(dataset_source): |
| |
| if dataset_source == "hugging_face": |
| |
| return [ |
| gr.Textbox(visible=True), |
| gr.File(visible=False), |
| ] |
| else: |
| |
| return [ |
| gr.Textbox(visible=False), |
| gr.File(visible=True), |
| ] |
|
|
|
|
| def update_rule_list(rule_type_mapping, rule_type): |
| return gr.CheckboxGroup( |
| choices=rule_type_mapping.get(rule_type, []), |
| value=[], |
| label="rule_list", |
| elem_classes="limited-height-checkboxgroup" |
| ) |
|
|
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
|
|
| def generate_llm_config_dataframe(llm_list): |
| """Generate LLM configuration dataframe based on selected LLMs""" |
| if not llm_list: |
| return gr.update(value=[], visible=False) |
|
|
| |
| rows = [] |
| for llm in llm_list: |
| rows.append([llm, "deepseek-chat", "your-api-key", "https://api.deepseek.com/v1", ""]) |
|
|
| return gr.update(value=rows, visible=True) |
|
|
|
|
| def suggest_fields_dataframe(rule_list, llm_list): |
| """Suggest required field mappings based on selected evaluators""" |
| suggested_fields = set() |
|
|
| |
| rule_type_mapping = get_rule_type_mapping() |
| data_column_mapping = get_data_column_mapping() |
|
|
| for rule in rule_list: |
| |
| for rule_type, rules in rule_type_mapping.items(): |
| if rule in rules: |
| if rule_type in data_column_mapping: |
| suggested_fields.update(data_column_mapping[rule_type]) |
| break |
|
|
| |
| llm_column_mapping = get_llm_column_mapping() |
| for llm in llm_list: |
| if llm in llm_column_mapping: |
| suggested_fields.update(llm_column_mapping[llm]) |
|
|
| |
| rows = [] |
| for field in sorted(suggested_fields): |
| rows.append([field, field]) |
|
|
| return gr.update(value=rows if rows else [["content", "content"]]) |
|
|
|
|
| def get_rule_type_mapping(): |
| origin_map = Model.get_rule_metric_type_map() |
| process_map = {'Rule-Based TEXT Quality Metrics': []} |
| for k, v in origin_map.items(): |
| if k in ['QUALITY_BAD_COMPLETENESS', 'QUALITY_BAD_EFFECTIVENESS', 'QUALITY_BAD_FLUENCY', |
| 'QUALITY_BAD_RELEVANCE', |
| 'QUALITY_BAD_SIMILARITY', 'QUALITY_BAD_UNDERSTANDABILITY']: |
| k = 'Rule-Based TEXT Quality Metrics' |
| for r in v: |
| if k not in process_map: |
| process_map[k] = [] |
| process_map[k].append(r.__name__) |
| |
|
|
| return process_map |
|
|
|
|
| def get_llm_list(): |
| """Get LLM list from Model.llm_name_map""" |
| llm_name_map = Model.get_llm_name_map() |
| return list(llm_name_map.keys()) |
|
|
|
|
| def get_llm_column_mapping(): |
| """Get column mapping required by each LLM""" |
| |
| |
| llm_list = get_llm_list() |
| mapping = {} |
| for llm_name in llm_list: |
| |
| if 'VLM' in llm_name or 'Image' in llm_name: |
| mapping[llm_name] = ['content', 'image'] |
| elif 'Relevant' in llm_name: |
| mapping[llm_name] = ['prompt', 'content'] |
| else: |
| mapping[llm_name] = ['content'] |
| return mapping |
|
|
|
|
| def get_data_column_mapping(): |
| return { |
| |
| 'Rule-Based TEXT Quality Metrics': ['content'], |
| 'QUALITY_BAD_SECURITY': ['content'], |
| 'QUALITY_BAD_IMG_EFFECTIVENESS': ['image'], |
| 'QUALITY_BAD_IMG_RELEVANCE': ['content', 'image'], |
| 'QUALITY_BAD_IMG_SIMILARITY': ['content'], |
| } |
|
|
|
|
| if __name__ == '__main__': |
| rule_type_mapping = get_rule_type_mapping() |
| rule_type_options = list(rule_type_mapping.keys()) |
|
|
| llm_options = get_llm_list() |
|
|
| current_dir = Path(__file__).parent |
| with open(os.path.join(current_dir, 'header.html'), "r") as file: |
| header = file.read() |
| with gr.Blocks() as demo: |
| gr.HTML(header) |
| with gr.Row(): |
| with gr.Column(): |
| with gr.Column(): |
| dataset_source = gr.Dropdown( |
| choices=["hugging_face", "local"], |
| value="hugging_face", |
| label="dataset [source]" |
| ) |
| input_path = gr.Textbox( |
| value='chupei/format-jsonl', |
| placeholder="please input hugging_face dataset path", |
| label="input_path", |
| visible=True |
| ) |
| uploaded_file = gr.File( |
| label="upload file", |
| visible=False |
| ) |
|
|
| with gr.Row(): |
| data_format = gr.Dropdown( |
| ["jsonl", "json", "plaintext", "listjson","image"], |
| label="data_format" |
| ) |
| remove_output = gr.Dropdown( |
| ["true"], |
| value="true", |
| label="remove_output" |
| ) |
| with gr.Row(): |
| max_workers = gr.Number( |
| value=1, |
| |
| label="max_workers", |
| precision=0 |
| ) |
| batch_size = gr.Number( |
| value=1, |
| |
| label="batch_size", |
| precision=0 |
| ) |
|
|
| |
| rule_type = gr.Dropdown( |
| choices=rule_type_options, |
| value=rule_type_options[0], |
| label="Rule Type", |
| interactive=True |
| ) |
| rule_list = gr.CheckboxGroup( |
| choices=rule_type_mapping.get(rule_type_options[0], []), |
| label="Rule List", |
| elem_classes="limited-height-checkboxgroup" |
| ) |
| |
| llm_list = gr.CheckboxGroup( |
| choices=llm_options, |
| label="LLM List", |
| elem_classes="limited-height-checkboxgroup" |
| ) |
|
|
| gr.Markdown("### EvalPipline Configuration") |
| gr.Markdown("Configure field mappings and evaluator parameters based on selected evaluators ([Examples](https://github.com/MigoXLab/dingo/tree/main/examples))") |
|
|
| |
| gr.Markdown("**EvalPipline.fields** - Field Mapping") |
| fields_dataframe = gr.Dataframe( |
| value=[["content", "content"]], |
| headers=["Field Key", "Dataset Column"], |
| datatype=["str", "str"], |
| column_count=(2, "fixed"), |
| row_count=(1, "dynamic"), |
| label="Field Mappings (add/remove rows as needed)", |
| interactive=True |
| ) |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
|
| |
| gr.Markdown("**LLM Config** - EvalPiplineConfig.config for LLMs") |
| llm_config_dataframe = gr.Dataframe( |
| value=[], |
| headers=["LLM Name", "model", "key", "api_url", "parameters"], |
| datatype=["str", "str", "str", "str", "str"], |
| column_count=(5, "fixed"), |
| row_count=(0, "dynamic"), |
| label="LLM Configurations (auto-generated based on llm_list selection)", |
| interactive=True, |
| visible=False |
| ) |
|
|
| with gr.Row(): |
| submit_single = gr.Button(value="Submit", interactive=True, variant="primary") |
|
|
| with gr.Column(): |
| |
| with gr.Tabs(): |
| with gr.Tab("Result Summary"): |
| summary_output = gr.JSON(label="Summary", max_height=800) |
| with gr.Tab("Result Detail"): |
| detail_output = gr.JSON(label="Detail", max_height=800) |
|
|
| dataset_source.change( |
| fn=update_input_components, |
| inputs=dataset_source, |
| outputs=[input_path, uploaded_file] |
| ) |
|
|
| rule_type.change( |
| fn=partial(update_rule_list, rule_type_mapping), |
| inputs=rule_type, |
| outputs=rule_list |
| ) |
|
|
| |
| |
| |
| |
| |
| |
|
|
| |
| llm_list.change( |
| fn=generate_llm_config_dataframe, |
| inputs=llm_list, |
| outputs=llm_config_dataframe |
| ) |
|
|
| |
| for comp in [rule_list, llm_list]: |
| comp.change( |
| fn=suggest_fields_dataframe, |
| inputs=[rule_list, llm_list], |
| outputs=fields_dataframe |
| ) |
|
|
| submit_single.click( |
| fn=dingo_demo, |
| inputs=[ |
| uploaded_file, |
| dataset_source, data_format, remove_output, input_path, max_workers, batch_size, |
| fields_dataframe, |
| rule_list, llm_list, |
| |
| llm_config_dataframe |
| ], |
| outputs=[summary_output, detail_output] |
| ) |
|
|
| |
| demo.launch(share=False) |
|
|