cnhkmcp 2.1.3__py3-none-any.whl → 2.1.4__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cnhkmcp/__init__.py +126 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/README.md +38 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/ace.log +0 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/config.json +6 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/get_knowledgeBase_tool/ace_lib.py +1514 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/get_knowledgeBase_tool/fetch_all_datasets.py +157 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/get_knowledgeBase_tool/fetch_all_documentation.py +132 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/get_knowledgeBase_tool/fetch_all_operators.py +99 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/get_knowledgeBase_tool/helpful_functions.py +180 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/icon.ico +0 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/icon.png +0 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/001_10_Steps_to_Start_on_BRAIN_documentation.json +14 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/001_Intermediate_Pack_-_Improve_your_Alpha_2_2_documentation.json +174 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/001_Intermediate_Pack_-_Understand_Results_1_2_documentation.json +167 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/001_Introduction_to_Alphas_documentation.json +145 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/001_Introduction_to_BRAIN_Expression_Language_documentation.json +107 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/001_WorldQuant_Challenge_documentation.json +56 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/001__Read_this_First_-_Starter_Pack_documentation.json +404 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/002_How_to_choose_the_Simulation_Settings_documentation.json +268 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/002_Simulate_your_first_Alpha_documentation.json +88 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/002__Alpha_Examples_for_Beginners_documentation.json +254 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/002__Alpha_Examples_for_Bronze_Users_documentation.json +114 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/002__Alpha_Examples_for_Silver_Users_documentation.json +79 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/002__How_BRAIN_works_documentation.json +184 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/003_Clear_these_tests_before_submitting_an_Alpha_documentation.json +388 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/003_Parameters_in_the_Simulation_results_documentation.json +243 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/004_Group_Data_Fields_documentation.json +69 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/004_How_to_use_the_Data_Explorer_documentation.json +142 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/004_Model77_dataset_documentation.json +14 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/004_Sentiment1_dataset_documentation.json +14 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/004_Understanding_Data_in_BRAIN_Key_Concepts_and_Tips_documentation.json +182 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/004_Vector_Data_Fields_documentation.json +30 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/005_Crowding_Risk-Neutralized_Alphas_documentation.json +64 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/005_D0_documentation.json +66 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/005_Double_Neutralization_documentation.json +53 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/005_Fast_D1_Documentation_documentation.json +304 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/005_Investability_Constrained_Metrics_documentation.json +129 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/005_Must-read_posts_How_to_improve_your_Alphas_documentation.json +14 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/005_Neutralization_documentation.json +29 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/005_RAM_Risk-Neutralized_Alphas_documentation.json +64 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/005_Risk_Neutralization_Default_setting_documentation.json +75 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/005_Risk_Neutralized_Alphas_documentation.json +171 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/005_Statistical_Risk-Neutralized_Alphas_documentation.json +51 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/006_EUR_TOP2500_Universe_documentation.json +35 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/006_GLB_TOPDIV3000_Universe_documentation.json +48 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/006_Getting_Started_China_Research_for_Consultants_Gold_documentation.json +142 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/006_Getting_started_on_Illiquid_Universes_Gold_documentation.json +46 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/006_Getting_started_with_USA_TOPSP500_universe_Gold_documentation.json +62 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/006_Global_Alphas_Gold_documentation.json +66 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/006_India_Alphas_documentation.json +35 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/007_Consultant_Dos_and_Don_ts_documentation.json +35 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/007_Consultant_Features_documentation.json +239 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/007_Consultant_Simulation_Features_documentation.json +149 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/007_Consultant_Submission_Tests_documentation.json +363 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/007_Finding_Consultant_Alphas_documentation.json +333 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/007_Power_Pool_Alphas_documentation.json +14 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/007_Research_Advisory_Program_documentation.json +35 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/007_Starting_Guide_for_Research_Consultants_documentation.json +14 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/007_Visualization_Tool_documentation.json +99 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/007_Your_Advisor_-_Kunqi_Jiang_documentation.json +53 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/007__Brain_Genius_documentation.json +288 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/007__Single_Dataset_Alphas_documentation.json +41 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/008_Advisory_Theme_Calendar_documentation.json +14 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/008_Multiplier_Rules_documentation.json +14 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/008_Overview_of_Themes_documentation.json +14 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/008_Theme_Calendar_documentation.json +14 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/009_Combo_Expression_documentation.json +272 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/009_Global_SuperAlphas_documentation.json +14 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/009_Helpful_Tips_documentation.json +58 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/009_Selection_Expression_documentation.json +1546 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/009_SuperAlpha_Operators_documentation.json +890 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/009_SuperAlpha_Results_documentation.json +83 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/009_What_is_a_SuperAlpha_documentation.json +261 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/010_BRAIN_API_documentation.json +515 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/010_Documentation_for_ACE_API_Library_Gold_documentation.json +27 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/010__Understanding_simulation_limits_documentation.json +210 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/arithmetic_operators.json +209 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/cross_sectional_operators.json +98 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/group_operators.json +121 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/logical_operators.json +145 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/reduce_operators.json +156 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/special_operators.json +35 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/test.txt +1 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/time_series_operators.json +386 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/transformational_operators.json +61 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/knowledge/vector_operators.json +38 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/main.py +576 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/process_knowledge_base.py +281 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/rag_engine.py +408 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/requirements.txt +7 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/run.bat +3 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/vector_db/_manifest.json +302 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/vector_db/_meta.json +1 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242/vector_db/chroma.sqlite3 +0 -0
- cnhkmcp/untracked/AI/321/206/320/261/320/234/321/211/320/255/320/262/321/206/320/237/320/242/321/204/342/225/227/342/225/242//321/211/320/266/320/246/321/206/320/274/320/261/321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/231/320/243/321/205/342/225/235/320/220/321/206/320/230/320/241.py +265 -0
- cnhkmcp/untracked/APP/.gitignore +32 -0
- cnhkmcp/untracked/APP/MODULAR_STRUCTURE.md +112 -0
- cnhkmcp/untracked/APP/README.md +309 -0
- cnhkmcp/untracked/APP/Tranformer/Transformer.py +4989 -0
- cnhkmcp/untracked/APP/Tranformer/ace.log +0 -0
- cnhkmcp/untracked/APP/Tranformer/ace_lib.py +1514 -0
- cnhkmcp/untracked/APP/Tranformer/helpful_functions.py +180 -0
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_candidates.json +7187 -0
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_candidates_/321/207/320/264/342/225/221/321/204/342/225/233/320/233.json +654 -0
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_error.json +1 -0
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_success.json +47312 -0
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_/321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/320/237/320/277/321/207/320/253/342/224/244/321/206/320/236/320/265/321/210/342/225/234/342/225/234/321/205/320/225/320/265Machine_lib.json +22 -0
- cnhkmcp/untracked/APP/Tranformer/parsetab.py +60 -0
- cnhkmcp/untracked/APP/Tranformer/template_summary.txt +3182 -0
- cnhkmcp/untracked/APP/Tranformer/transformer_config.json +7 -0
- cnhkmcp/untracked/APP/Tranformer/validator.py +889 -0
- cnhkmcp/untracked/APP/ace.log +69 -0
- cnhkmcp/untracked/APP/ace_lib.py +1514 -0
- cnhkmcp/untracked/APP/blueprints/__init__.py +6 -0
- cnhkmcp/untracked/APP/blueprints/feature_engineering.py +347 -0
- cnhkmcp/untracked/APP/blueprints/idea_house.py +221 -0
- cnhkmcp/untracked/APP/blueprints/inspiration_house.py +432 -0
- cnhkmcp/untracked/APP/blueprints/paper_analysis.py +570 -0
- cnhkmcp/untracked/APP/custom_templates/templates.json +1257 -0
- cnhkmcp/untracked/APP/give_me_idea/BRAIN_Alpha_Template_Expert_SystemPrompt.md +400 -0
- cnhkmcp/untracked/APP/give_me_idea/ace_lib.py +1514 -0
- cnhkmcp/untracked/APP/give_me_idea/alpha_data_specific_template_master.py +252 -0
- cnhkmcp/untracked/APP/give_me_idea/fetch_all_datasets.py +157 -0
- cnhkmcp/untracked/APP/give_me_idea/fetch_all_operators.py +99 -0
- cnhkmcp/untracked/APP/give_me_idea/helpful_functions.py +180 -0
- cnhkmcp/untracked/APP/give_me_idea/what_is_Alpha_template.md +11 -0
- cnhkmcp/untracked/APP/helpful_functions.py +180 -0
- cnhkmcp/untracked/APP/hkSimulator/ace_lib.py +1501 -0
- cnhkmcp/untracked/APP/hkSimulator/autosimulator.py +447 -0
- cnhkmcp/untracked/APP/hkSimulator/helpful_functions.py +180 -0
- cnhkmcp/untracked/APP/mirror_config.txt +20 -0
- cnhkmcp/untracked/APP/operaters.csv +129 -0
- cnhkmcp/untracked/APP/requirements.txt +53 -0
- cnhkmcp/untracked/APP/run_app.bat +28 -0
- cnhkmcp/untracked/APP/run_app.sh +34 -0
- cnhkmcp/untracked/APP/setup_tsinghua.bat +39 -0
- cnhkmcp/untracked/APP/setup_tsinghua.sh +43 -0
- cnhkmcp/untracked/APP/simulator/alpha_submitter.py +404 -0
- cnhkmcp/untracked/APP/simulator/simulator_wqb.py +618 -0
- cnhkmcp/untracked/APP/simulator/wqb20260107015647.log +57 -0
- cnhkmcp/untracked/APP/ssrn-3332513.pdf +109188 -19
- cnhkmcp/untracked/APP/static/brain.js +589 -0
- cnhkmcp/untracked/APP/static/decoder.js +1540 -0
- cnhkmcp/untracked/APP/static/feature_engineering.js +1729 -0
- cnhkmcp/untracked/APP/static/idea_house.js +937 -0
- cnhkmcp/untracked/APP/static/inspiration.js +465 -0
- cnhkmcp/untracked/APP/static/inspiration_house.js +868 -0
- cnhkmcp/untracked/APP/static/paper_analysis.js +390 -0
- cnhkmcp/untracked/APP/static/script.js +3082 -0
- cnhkmcp/untracked/APP/static/simulator.js +597 -0
- cnhkmcp/untracked/APP/static/styles.css +3127 -0
- cnhkmcp/untracked/APP/static/usage_widget.js +508 -0
- cnhkmcp/untracked/APP/templates/alpha_inspector.html +511 -0
- cnhkmcp/untracked/APP/templates/feature_engineering.html +960 -0
- cnhkmcp/untracked/APP/templates/idea_house.html +564 -0
- cnhkmcp/untracked/APP/templates/index.html +932 -0
- cnhkmcp/untracked/APP/templates/inspiration_house.html +861 -0
- cnhkmcp/untracked/APP/templates/paper_analysis.html +91 -0
- cnhkmcp/untracked/APP/templates/simulator.html +343 -0
- cnhkmcp/untracked/APP/templates/transformer_web.html +580 -0
- cnhkmcp/untracked/APP/usage.md +351 -0
- cnhkmcp/untracked/APP//321/207/342/225/235/320/250/321/205/320/230/320/226/321/204/342/225/225/320/220/321/211/320/221/320/243/321/206/320/261/320/265/ace_lib.py +1514 -0
- cnhkmcp/untracked/APP//321/207/342/225/235/320/250/321/205/320/230/320/226/321/204/342/225/225/320/220/321/211/320/221/320/243/321/206/320/261/320/265/brain_alpha_inspector.py +712 -0
- cnhkmcp/untracked/APP//321/207/342/225/235/320/250/321/205/320/230/320/226/321/204/342/225/225/320/220/321/211/320/221/320/243/321/206/320/261/320/265/helpful_functions.py +180 -0
- cnhkmcp/untracked/APP//321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/231/320/243/321/205/342/225/235/320/220/321/206/320/230/320/241.py +2460 -0
- cnhkmcp/untracked/__init__.py +0 -0
- cnhkmcp/untracked/arXiv_API_Tool_Manual.md +490 -0
- cnhkmcp/untracked/arxiv_api.py +229 -0
- cnhkmcp/untracked/forum_functions.py +998 -0
- cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272/forum_functions.py +407 -0
- cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272/platform_functions.py +2601 -0
- cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272/user_config.json +31 -0
- cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272//321/210/320/276/320/271AI/321/210/320/277/342/225/227/321/210/342/224/220/320/251/321/204/342/225/225/320/272/321/206/320/246/320/227/321/206/320/261/320/263/321/206/320/255/320/265/321/205/320/275/320/266/321/204/342/225/235/320/252/321/204/342/225/225/320/233/321/210/342/225/234/342/225/234/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270.md +101 -0
- cnhkmcp/untracked/mcp/321/206/320/246/320/227/321/204/342/225/227/342/225/242/321/210/320/276/342/225/221/321/205/320/255/320/253/321/207/320/231/320/2302_/321/205/320/266/320/222/321/206/320/256/320/254/321/205/320/236/320/257/321/207/320/231/320/230/321/205/320/240/320/277/321/205/320/232/320/270/321/204/342/225/225/320/235/321/204/342/225/221/320/226/321/206/342/225/241/320/237/321/210/320/267/320/230/321/205/320/251/320/270/321/205/342/226/221/342/226/222/321/210/320/277/320/245/321/210/342/224/220/320/251/321/204/342/225/225/320/272//321/211/320/225/320/235/321/207/342/225/234/320/276/321/205/320/231/320/235/321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/230/320/241_/321/205/320/276/320/231/321/210/320/263/320/225/321/205/342/224/220/320/225/321/210/320/266/320/221/321/204/342/225/233/320/255/321/210/342/225/241/320/246/321/205/320/234/320/225.py +190 -0
- cnhkmcp/untracked/platform_functions.py +2886 -0
- cnhkmcp/untracked/sample_mcp_config.json +11 -0
- cnhkmcp/untracked/user_config.json +31 -0
- cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/320/237/320/222/321/210/320/220/320/223/321/206/320/246/320/227/321/206/320/261/320/263_BRAIN_Alpha_Test_Requirements_and_Tips.md +202 -0
- cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/342/225/226/320/265/321/204/342/225/234/320/254/321/206/342/225/241/320/221_Alpha_explaination_workflow.md +56 -0
- cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/342/225/226/320/265/321/204/342/225/234/320/254/321/206/342/225/241/320/221_BRAIN_6_Tips_Datafield_Exploration_Guide.md +194 -0
- cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/342/225/226/320/265/321/204/342/225/234/320/254/321/206/342/225/241/320/221_BRAIN_Alpha_Improvement_Workflow.md +101 -0
- cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/342/225/226/320/265/321/204/342/225/234/320/254/321/206/342/225/241/320/221_Dataset_Exploration_Expert_Manual.md +436 -0
- cnhkmcp/untracked//321/207/320/264/342/225/221/321/204/342/225/233/320/233/321/205/342/225/226/320/265/321/204/342/225/234/320/254/321/206/342/225/241/320/221_daily_report_workflow.md +128 -0
- cnhkmcp/untracked//321/211/320/225/320/235/321/207/342/225/234/320/276/321/205/320/231/320/235/321/210/342/224/220/320/240/321/210/320/261/320/234/321/206/320/230/320/241_/321/205/320/276/320/231/321/210/320/263/320/225/321/205/342/224/220/320/225/321/210/320/266/320/221/321/204/342/225/233/320/255/321/210/342/225/241/320/246/321/205/320/234/320/225.py +190 -0
- {cnhkmcp-2.1.3.dist-info → cnhkmcp-2.1.4.dist-info}/METADATA +1 -1
- cnhkmcp-2.1.4.dist-info/RECORD +190 -0
- cnhkmcp-2.1.4.dist-info/top_level.txt +1 -0
- cnhkmcp-2.1.3.dist-info/RECORD +0 -6
- cnhkmcp-2.1.3.dist-info/top_level.txt +0 -1
- {cnhkmcp-2.1.3.dist-info → cnhkmcp-2.1.4.dist-info}/WHEEL +0 -0
- {cnhkmcp-2.1.3.dist-info → cnhkmcp-2.1.4.dist-info}/entry_points.txt +0 -0
- {cnhkmcp-2.1.3.dist-info → cnhkmcp-2.1.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,1729 @@
|
|
|
1
|
+
// Feature Engineering JavaScript
|
|
2
|
+
|
|
3
|
+
// Store API key and state in session storage
|
|
4
|
+
let apiKey = sessionStorage.getItem('deepseekApiKey');
|
|
5
|
+
let modelProvider = sessionStorage.getItem('featureEngProvider') || 'deepseek';
|
|
6
|
+
let modelName = sessionStorage.getItem('featureEngModelName') || 'deepseek-chat';
|
|
7
|
+
let currentStep = parseInt(sessionStorage.getItem('featureEngCurrentStep')) || 1;
|
|
8
|
+
let pipelineSteps = JSON.parse(sessionStorage.getItem('featureEngPipelineSteps')) || [];
|
|
9
|
+
let currentOptions = JSON.parse(sessionStorage.getItem('featureEngCurrentOptions')) || [];
|
|
10
|
+
let currentDataState = sessionStorage.getItem('featureEngCurrentDataState') || 'raw data';
|
|
11
|
+
let conversationHistory = JSON.parse(sessionStorage.getItem('featureEngConversationHistory')) || [];
|
|
12
|
+
let customSystemPrompt = sessionStorage.getItem('customSystemPrompt') || null;
|
|
13
|
+
|
|
14
|
+
// DOM Elements
|
|
15
|
+
const modelProviderSelect = document.getElementById('modelProvider');
|
|
16
|
+
const apiKeyInput = document.getElementById('apiKey');
|
|
17
|
+
const modelNameInput = document.getElementById('modelName');
|
|
18
|
+
const saveApiKeyBtn = document.getElementById('saveApiKey');
|
|
19
|
+
const apiConfigSection = document.getElementById('apiConfigSection');
|
|
20
|
+
const showApiConfigSection = document.getElementById('showApiConfigSection');
|
|
21
|
+
const showApiConfigBtn = document.getElementById('showApiConfig');
|
|
22
|
+
const loadQuestionTemplateBtn = document.getElementById('loadQuestionTemplate');
|
|
23
|
+
const editSystemPromptBtn = document.getElementById('editSystemPrompt');
|
|
24
|
+
const questionTemplateInput = document.getElementById('questionTemplate');
|
|
25
|
+
const startPipelineBtn = document.getElementById('startPipeline');
|
|
26
|
+
const systemPromptModal = document.getElementById('systemPromptModal');
|
|
27
|
+
const systemPromptTextarea = document.getElementById('systemPromptTextarea');
|
|
28
|
+
const loadDefaultPromptBtn = document.getElementById('loadDefaultPrompt');
|
|
29
|
+
const initialSetupSection = document.getElementById('initialSetup');
|
|
30
|
+
const optionsSection = document.getElementById('optionsSection');
|
|
31
|
+
const optionsContainer = document.getElementById('optionsContainer');
|
|
32
|
+
const clearOptionsBtn = document.getElementById('clearOptions');
|
|
33
|
+
const exportPipelineBtn = document.getElementById('exportPipeline');
|
|
34
|
+
const pipelineStatus = document.getElementById('pipelineStatus');
|
|
35
|
+
const pipelineStepsDiv = document.getElementById('pipelineSteps');
|
|
36
|
+
const modalOverlay = document.getElementById('modalOverlay');
|
|
37
|
+
const categoryPopup = document.getElementById('categoryPopup');
|
|
38
|
+
const categoryPopupTitle = document.getElementById('categoryPopupTitle');
|
|
39
|
+
const categoryPopupDescription = document.getElementById('categoryPopupDescription');
|
|
40
|
+
const categoryPopupOperators = document.getElementById('categoryPopupOperators');
|
|
41
|
+
const categoryPopupOperatorsTitle = document.getElementById('categoryPopupOperatorsTitle');
|
|
42
|
+
|
|
43
|
+
// Initialize API key if exists
|
|
44
|
+
if (apiKey) {
|
|
45
|
+
apiKeyInput.value = apiKey;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Initialize model provider and name
|
|
49
|
+
modelProviderSelect.value = modelProvider;
|
|
50
|
+
modelNameInput.value = modelName;
|
|
51
|
+
|
|
52
|
+
// Update model name placeholder based on provider
|
|
53
|
+
function updateModelNamePlaceholder() {
|
|
54
|
+
const provider = modelProviderSelect.value;
|
|
55
|
+
if (provider === 'kimi') {
|
|
56
|
+
modelNameInput.placeholder = 'e.g., kimi-k2-0711-preview';
|
|
57
|
+
if (modelNameInput.value === 'deepseek-chat') {
|
|
58
|
+
modelNameInput.value = 'kimi-k2-0711-preview';
|
|
59
|
+
}
|
|
60
|
+
} else {
|
|
61
|
+
modelNameInput.placeholder = 'e.g., deepseek-chat, deepseek-coder';
|
|
62
|
+
if (modelNameInput.value === 'kimi-k2-0711-preview') {
|
|
63
|
+
modelNameInput.value = 'deepseek-chat';
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Model provider change handler
|
|
69
|
+
modelProviderSelect.addEventListener('change', () => {
|
|
70
|
+
modelProvider = modelProviderSelect.value;
|
|
71
|
+
sessionStorage.setItem('featureEngProvider', modelProvider);
|
|
72
|
+
updateModelNamePlaceholder();
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Model name change handler
|
|
76
|
+
modelNameInput.addEventListener('input', () => {
|
|
77
|
+
modelName = modelNameInput.value;
|
|
78
|
+
sessionStorage.setItem('featureEngModelName', modelName);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Initialize placeholder on page load
|
|
82
|
+
updateModelNamePlaceholder();
|
|
83
|
+
|
|
84
|
+
// Check if API is already configured and hide config section if so
|
|
85
|
+
function checkApiConfigStatus() {
|
|
86
|
+
if (apiKey && modelProvider && modelName) {
|
|
87
|
+
apiConfigSection.style.display = 'none';
|
|
88
|
+
showApiConfigSection.style.display = 'block';
|
|
89
|
+
} else {
|
|
90
|
+
apiConfigSection.style.display = 'block';
|
|
91
|
+
showApiConfigSection.style.display = 'none';
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// Show API Config button event listener
|
|
96
|
+
showApiConfigBtn.addEventListener('click', () => {
|
|
97
|
+
apiConfigSection.style.display = 'block';
|
|
98
|
+
showApiConfigSection.style.display = 'none';
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
// Load existing conversation state on page load
|
|
102
|
+
window.addEventListener('DOMContentLoaded', () => {
|
|
103
|
+
console.log('Loading conversation state...');
|
|
104
|
+
console.log('Conversation history:', conversationHistory);
|
|
105
|
+
console.log('Current step:', currentStep);
|
|
106
|
+
console.log('Pipeline steps:', pipelineSteps);
|
|
107
|
+
console.log('Current options:', currentOptions);
|
|
108
|
+
|
|
109
|
+
// Check API config status
|
|
110
|
+
checkApiConfigStatus();
|
|
111
|
+
|
|
112
|
+
// If we have conversation history, display the current options
|
|
113
|
+
if (conversationHistory.length > 0 && currentOptions.length > 0) {
|
|
114
|
+
console.log('Restoring conversation state...');
|
|
115
|
+
initialSetupSection.style.display = 'none';
|
|
116
|
+
optionsSection.style.display = 'block';
|
|
117
|
+
displayOptions();
|
|
118
|
+
updatePipelineStatus();
|
|
119
|
+
} else {
|
|
120
|
+
// Ensure we start with a clean state
|
|
121
|
+
console.log('Starting with clean state...');
|
|
122
|
+
initialSetupSection.style.display = 'block';
|
|
123
|
+
optionsSection.style.display = 'none';
|
|
124
|
+
}
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
// Close modal when clicking overlay
|
|
128
|
+
modalOverlay.addEventListener('click', (e) => {
|
|
129
|
+
if (e.target === modalOverlay) {
|
|
130
|
+
modalOverlay.classList.remove('active');
|
|
131
|
+
// Find the editing card and cancel edit
|
|
132
|
+
const editingCard = document.querySelector('.option-card.editing');
|
|
133
|
+
if (editingCard) {
|
|
134
|
+
const index = parseInt(editingCard.dataset.optionIndex);
|
|
135
|
+
cancelEdit(index);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
// Save API Key and Test Connection
|
|
141
|
+
saveApiKeyBtn.addEventListener('click', async () => {
|
|
142
|
+
const newApiKey = apiKeyInput.value.trim();
|
|
143
|
+
const newProvider = modelProviderSelect.value;
|
|
144
|
+
const newModelName = modelNameInput.value.trim();
|
|
145
|
+
|
|
146
|
+
if (!newApiKey) {
|
|
147
|
+
showNotification('Please enter a valid API key', 'error');
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (!newModelName) {
|
|
152
|
+
showNotification('Please enter a model name', 'error');
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
try {
|
|
157
|
+
showLoading('Testing API connection...');
|
|
158
|
+
|
|
159
|
+
const response = await fetch('/feature-engineering/api/test-deepseek', {
|
|
160
|
+
method: 'POST',
|
|
161
|
+
headers: {
|
|
162
|
+
'X-API-Key': newApiKey,
|
|
163
|
+
'Content-Type': 'application/json'
|
|
164
|
+
},
|
|
165
|
+
body: JSON.stringify({
|
|
166
|
+
provider: newProvider,
|
|
167
|
+
model_name: newModelName
|
|
168
|
+
})
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
const data = await response.json();
|
|
172
|
+
|
|
173
|
+
if (response.ok && data.success) {
|
|
174
|
+
sessionStorage.setItem('deepseekApiKey', newApiKey);
|
|
175
|
+
sessionStorage.setItem('featureEngProvider', newProvider);
|
|
176
|
+
sessionStorage.setItem('featureEngModelName', newModelName);
|
|
177
|
+
apiKey = newApiKey;
|
|
178
|
+
modelProvider = newProvider;
|
|
179
|
+
modelName = newModelName;
|
|
180
|
+
showNotification(`${newProvider.charAt(0).toUpperCase() + newProvider.slice(1)} API connection successful`, 'success');
|
|
181
|
+
|
|
182
|
+
// Hide API config section after successful configuration
|
|
183
|
+
apiConfigSection.style.display = 'none';
|
|
184
|
+
showApiConfigSection.style.display = 'block';
|
|
185
|
+
} else {
|
|
186
|
+
showNotification(`API Error: ${data.error || 'Unknown error'}`, 'error');
|
|
187
|
+
console.error('API Error Details:', data);
|
|
188
|
+
}
|
|
189
|
+
} catch (error) {
|
|
190
|
+
showNotification('Error testing API connection: ' + error.message, 'error');
|
|
191
|
+
console.error('API Test Error:', error);
|
|
192
|
+
} finally {
|
|
193
|
+
hideLoading();
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
// Load Question Template
|
|
198
|
+
loadQuestionTemplateBtn.addEventListener('click', () => {
|
|
199
|
+
const template = `Current step: 0
|
|
200
|
+
Current datafield: modify_your_input
|
|
201
|
+
Current datafiled description: input_datafield_description
|
|
202
|
+
Initial EDA observation: input_datafield_eda_observation
|
|
203
|
+
Previous steps and categories used: None
|
|
204
|
+
Current data state: this is the first step raw data`;
|
|
205
|
+
|
|
206
|
+
questionTemplateInput.value = template;
|
|
207
|
+
showNotification('Question template loaded', 'success');
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
// Edit System Prompt
|
|
211
|
+
editSystemPromptBtn.addEventListener('click', () => {
|
|
212
|
+
// Load current system prompt or default
|
|
213
|
+
if (customSystemPrompt) {
|
|
214
|
+
systemPromptTextarea.value = customSystemPrompt;
|
|
215
|
+
} else {
|
|
216
|
+
loadDefaultSystemPrompt();
|
|
217
|
+
}
|
|
218
|
+
systemPromptModal.style.display = 'block';
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// Load Default System Prompt
|
|
222
|
+
loadDefaultPromptBtn.addEventListener('click', loadDefaultSystemPrompt);
|
|
223
|
+
|
|
224
|
+
// Hide category popup when clicking outside
|
|
225
|
+
document.addEventListener('click', (e) => {
|
|
226
|
+
if (!categoryPopup.contains(e.target) && !e.target.classList.contains('clickable-category')) {
|
|
227
|
+
hideCategoryPopup();
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
async function loadDefaultSystemPrompt() {
|
|
232
|
+
try {
|
|
233
|
+
showLoading('Loading default system prompt...');
|
|
234
|
+
|
|
235
|
+
const response = await fetch('/feature-engineering/api/get-default-system-prompt', {
|
|
236
|
+
method: 'GET',
|
|
237
|
+
headers: {
|
|
238
|
+
'Content-Type': 'application/json'
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
const data = await response.json();
|
|
243
|
+
|
|
244
|
+
if (response.ok && data.success) {
|
|
245
|
+
systemPromptTextarea.value = data.default_system_prompt;
|
|
246
|
+
showNotification('Default system prompt loaded from backend', 'success');
|
|
247
|
+
} else {
|
|
248
|
+
showNotification(`Error loading default prompt: ${data.error || 'Unknown error'}`, 'error');
|
|
249
|
+
console.error('Error loading default prompt:', data);
|
|
250
|
+
}
|
|
251
|
+
} catch (error) {
|
|
252
|
+
showNotification('Error loading default system prompt: ' + error.message, 'error');
|
|
253
|
+
console.error('Error loading default prompt:', error);
|
|
254
|
+
} finally {
|
|
255
|
+
hideLoading();
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// Close System Prompt Modal
|
|
260
|
+
function closeSystemPromptModal() {
|
|
261
|
+
systemPromptModal.style.display = 'none';
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
// Save System Prompt
|
|
265
|
+
function saveSystemPrompt() {
|
|
266
|
+
const prompt = systemPromptTextarea.value.trim();
|
|
267
|
+
if (!prompt) {
|
|
268
|
+
showNotification('System prompt cannot be empty', 'error');
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
customSystemPrompt = prompt;
|
|
273
|
+
sessionStorage.setItem('customSystemPrompt', prompt);
|
|
274
|
+
systemPromptModal.style.display = 'none';
|
|
275
|
+
showNotification('System prompt saved successfully', 'success');
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
// Start Feature Engineering Pipeline
|
|
279
|
+
startPipelineBtn.addEventListener('click', async () => {
|
|
280
|
+
if (!apiKey) {
|
|
281
|
+
showNotification('Please configure your Deepseek API key first', 'error');
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const questionTemplate = questionTemplateInput.value.trim();
|
|
286
|
+
|
|
287
|
+
if (!questionTemplate) {
|
|
288
|
+
showNotification('Please load or enter a question template', 'error');
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
try {
|
|
293
|
+
showLoading('Getting AI recommendations...');
|
|
294
|
+
|
|
295
|
+
console.log('=== STARTING NEW PIPELINE ===');
|
|
296
|
+
console.log('Current conversation history before start:', conversationHistory);
|
|
297
|
+
console.log('Conversation history length:', conversationHistory.length);
|
|
298
|
+
|
|
299
|
+
const response = await fetch('/feature-engineering/api/continue-conversation', {
|
|
300
|
+
method: 'POST',
|
|
301
|
+
headers: {
|
|
302
|
+
'X-API-Key': apiKey,
|
|
303
|
+
'Content-Type': 'application/json'
|
|
304
|
+
},
|
|
305
|
+
body: JSON.stringify({
|
|
306
|
+
conversation_history: [],
|
|
307
|
+
user_message: questionTemplate,
|
|
308
|
+
custom_system_prompt: customSystemPrompt,
|
|
309
|
+
provider: modelProvider,
|
|
310
|
+
model_name: modelName
|
|
311
|
+
})
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
const data = await response.json();
|
|
315
|
+
|
|
316
|
+
console.log('=== INITIAL PROMPT ===');
|
|
317
|
+
console.log('User message:', questionTemplate);
|
|
318
|
+
console.log('=== AI RESPONSE ===');
|
|
319
|
+
console.log('AI response:', data.response);
|
|
320
|
+
console.log('==================');
|
|
321
|
+
|
|
322
|
+
if (response.ok && data.success) {
|
|
323
|
+
// Clear conversation history and reset state for new pipeline
|
|
324
|
+
conversationHistory = [];
|
|
325
|
+
currentStep = 1;
|
|
326
|
+
pipelineSteps = [];
|
|
327
|
+
currentDataState = 'raw data';
|
|
328
|
+
|
|
329
|
+
// Add to conversation history
|
|
330
|
+
conversationHistory.push({
|
|
331
|
+
role: 'user',
|
|
332
|
+
content: questionTemplate
|
|
333
|
+
});
|
|
334
|
+
conversationHistory.push({
|
|
335
|
+
role: 'assistant',
|
|
336
|
+
content: data.response
|
|
337
|
+
});
|
|
338
|
+
|
|
339
|
+
console.log('Conversation history after initial:', conversationHistory);
|
|
340
|
+
console.log('Conversation history length:', conversationHistory.length);
|
|
341
|
+
|
|
342
|
+
// Parse the AI response to extract options
|
|
343
|
+
parseAIResponse(data.response);
|
|
344
|
+
|
|
345
|
+
// Save conversation state
|
|
346
|
+
saveConversationState();
|
|
347
|
+
|
|
348
|
+
// Show options section and hide initial setup
|
|
349
|
+
initialSetupSection.style.display = 'none';
|
|
350
|
+
optionsSection.style.display = 'block';
|
|
351
|
+
updatePipelineStatus();
|
|
352
|
+
|
|
353
|
+
showNotification('AI recommendations loaded successfully', 'success');
|
|
354
|
+
} else {
|
|
355
|
+
showNotification(`Error: ${data.error || 'Unknown error'}`, 'error');
|
|
356
|
+
console.error('API Error Details:', data);
|
|
357
|
+
}
|
|
358
|
+
} catch (error) {
|
|
359
|
+
showNotification('Error getting recommendations: ' + error.message, 'error');
|
|
360
|
+
console.error('Pipeline Start Error:', error);
|
|
361
|
+
} finally {
|
|
362
|
+
hideLoading();
|
|
363
|
+
}
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
// Parse AI Response to extract options
|
|
367
|
+
function parseAIResponse(response) {
|
|
368
|
+
console.log('=== PARSING AI RESPONSE ===');
|
|
369
|
+
console.log('Raw response:', response);
|
|
370
|
+
|
|
371
|
+
currentOptions = [];
|
|
372
|
+
|
|
373
|
+
// Dynamic content cleaning - remove various summary sections
|
|
374
|
+
let cleanResponse = response;
|
|
375
|
+
const summaryPatterns = [
|
|
376
|
+
/### \*\*Best Choice\?\*\*[\s\S]*$/i,
|
|
377
|
+
/### \*\*Recommended Next Step:\*\*[\s\S]*$/i,
|
|
378
|
+
/Most recommended choice:[\s\S]*$/i,
|
|
379
|
+
/Rationale:[\s\S]*$/i,
|
|
380
|
+
/This maintains[\s\S]*$/i,
|
|
381
|
+
/Would you like to proceed[\s\S]*$/i,
|
|
382
|
+
/\*Example features to create:\*[\s\S]*$/i
|
|
383
|
+
];
|
|
384
|
+
|
|
385
|
+
summaryPatterns.forEach(pattern => {
|
|
386
|
+
cleanResponse = cleanResponse.replace(pattern, '');
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
console.log('Cleaned response:', cleanResponse);
|
|
390
|
+
|
|
391
|
+
// Extract top-level context dynamically
|
|
392
|
+
let globalContext = null;
|
|
393
|
+
const contextPatterns = [
|
|
394
|
+
/\*\*Context:\*\*\s*([\s\S]*?)(?=###|####|\*\*Option|\*\*Choose|Option\s+\d+|$)/i,
|
|
395
|
+
/Context:\s*([\s\S]*?)(?=###|####|\*\*Option|\*\*Choose|Option\s+\d+|$)/i
|
|
396
|
+
];
|
|
397
|
+
|
|
398
|
+
for (const pattern of contextPatterns) {
|
|
399
|
+
const match = cleanResponse.match(pattern);
|
|
400
|
+
if (match) {
|
|
401
|
+
globalContext = match[1].trim();
|
|
402
|
+
console.log('Found global context:', globalContext);
|
|
403
|
+
break;
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// Dynamic option pattern matching
|
|
408
|
+
const optionPatterns = [
|
|
409
|
+
/(?:####\s*)?(?:\*\*)?Option\s+(\d+)\s+for\s+Step\s+(\d+):?\*?\*?\s*([\s\S]*?)(?=(?:####\s*)?(?:\*\*)?Option\s+\d+\s+for\s+Step\s+\d+:|Most recommended|Rationale:|This maintains|$)/gi,
|
|
410
|
+
/(?:####\s*)?(?:\*\*)?option\s+(\d+)\s+for\s+Step\s+(\d+):\s*([\s\S]*?)(?=(?:####\s*)?(?:\*\*)?option\s+\d+\s+for\s+Step\s+\d+:|Most recommended|Rationale:|This maintains|$)/gi
|
|
411
|
+
];
|
|
412
|
+
|
|
413
|
+
let optionsFound = false;
|
|
414
|
+
|
|
415
|
+
for (const optionPattern of optionPatterns) {
|
|
416
|
+
let match;
|
|
417
|
+
const tempOptions = [];
|
|
418
|
+
|
|
419
|
+
while ((match = optionPattern.exec(cleanResponse)) !== null) {
|
|
420
|
+
const optionNumber = match[1];
|
|
421
|
+
const stepNumber = match[2];
|
|
422
|
+
const content = match[3].trim();
|
|
423
|
+
|
|
424
|
+
console.log(`Found option ${optionNumber} for step ${stepNumber}:`, content);
|
|
425
|
+
|
|
426
|
+
const parsedOption = parseOptionContent(content, globalContext, parseInt(optionNumber), parseInt(stepNumber));
|
|
427
|
+
if (parsedOption) {
|
|
428
|
+
tempOptions.push(parsedOption);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
if (tempOptions.length > 0) {
|
|
433
|
+
currentOptions = tempOptions;
|
|
434
|
+
optionsFound = true;
|
|
435
|
+
break;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
// Reset regex lastIndex for next pattern
|
|
439
|
+
optionPattern.lastIndex = 0;
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
if (!optionsFound) {
|
|
443
|
+
console.log('No options found with standard patterns, trying fallback parsing...');
|
|
444
|
+
// Fallback: try to find any numbered options
|
|
445
|
+
const fallbackPattern = /(\d+)[.)]\s*([\s\S]*?)(?=\d+[.)]|$)/g;
|
|
446
|
+
let match;
|
|
447
|
+
while ((match = fallbackPattern.exec(cleanResponse)) !== null) {
|
|
448
|
+
const optionNumber = match[1];
|
|
449
|
+
const content = match[2].trim();
|
|
450
|
+
console.log(`Fallback found option ${optionNumber}:`, content);
|
|
451
|
+
|
|
452
|
+
const parsedOption = parseOptionContent(content, globalContext, parseInt(optionNumber), currentStep);
|
|
453
|
+
if (parsedOption) {
|
|
454
|
+
currentOptions.push(parsedOption);
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Ensure all options have the same context (copy from first if needed)
|
|
460
|
+
if (currentOptions.length > 0 && currentOptions[0].context) {
|
|
461
|
+
const sharedContext = currentOptions[0].context;
|
|
462
|
+
currentOptions.forEach(option => {
|
|
463
|
+
if (!option.context || option.context.includes('Same as above')) {
|
|
464
|
+
option.context = sharedContext;
|
|
465
|
+
}
|
|
466
|
+
});
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
console.log('Total options parsed:', currentOptions.length);
|
|
470
|
+
console.log('Current options:', currentOptions);
|
|
471
|
+
console.log('========================');
|
|
472
|
+
|
|
473
|
+
displayOptions();
|
|
474
|
+
|
|
475
|
+
// Save current options state
|
|
476
|
+
saveConversationState();
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
// Helper function to parse individual option content
|
|
480
|
+
function parseOptionContent(content, globalContext, optionNumber, stepNumber) {
|
|
481
|
+
console.log('=== PARSING OPTION CONTENT ===');
|
|
482
|
+
console.log('Raw content:', content);
|
|
483
|
+
|
|
484
|
+
// More precise patterns for the exact format
|
|
485
|
+
const contextPatterns = [
|
|
486
|
+
/Context:\s*([\s\S]*?)(?=\s+Choose next step:)/i,
|
|
487
|
+
/\*\*Context:\*\*\s*([\s\S]*?)(?=\s+\*\*Choose next step:\*\*)/i,
|
|
488
|
+
/Context:\s*([\s\S]*?)(?=\s+\*\*Choose next step:\*\*)/i
|
|
489
|
+
];
|
|
490
|
+
|
|
491
|
+
// Multiple patterns for next step extraction
|
|
492
|
+
const nextStepPatterns = [
|
|
493
|
+
/Choose next step:\s*([^\n\r]+?)(?=\s+Reason:)/i,
|
|
494
|
+
/\*\*Choose next step:\*\*\s*([^\n\r]+?)(?=\s+\*\*Reason:\*\*)/i,
|
|
495
|
+
/Choose next step:\s*([^\n\r]+?)(?=\s+\*\*Reason:\*\*)/i
|
|
496
|
+
];
|
|
497
|
+
|
|
498
|
+
// Multiple patterns for reason extraction
|
|
499
|
+
const reasonPatterns = [
|
|
500
|
+
/Reason:\s*([\s\S]*?)(?=Most recommended|Rationale:|This maintains|$)/i,
|
|
501
|
+
/\*\*Reason:\*\*\s*([\s\S]*?)(?=Most recommended|Rationale:|This maintains|$)/i
|
|
502
|
+
];
|
|
503
|
+
|
|
504
|
+
let contextMatch = null;
|
|
505
|
+
let nextStepMatch = null;
|
|
506
|
+
let reasonMatch = null;
|
|
507
|
+
|
|
508
|
+
// Try context patterns
|
|
509
|
+
for (const pattern of contextPatterns) {
|
|
510
|
+
contextMatch = content.match(pattern);
|
|
511
|
+
if (contextMatch) {
|
|
512
|
+
console.log('Context pattern matched:', pattern);
|
|
513
|
+
console.log('Context match:', contextMatch[1].trim());
|
|
514
|
+
break;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Try next step patterns
|
|
519
|
+
for (const pattern of nextStepPatterns) {
|
|
520
|
+
nextStepMatch = content.match(pattern);
|
|
521
|
+
if (nextStepMatch) {
|
|
522
|
+
console.log('Next step pattern matched:', pattern);
|
|
523
|
+
console.log('Next step match:', nextStepMatch[1].trim());
|
|
524
|
+
break;
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// Try reason patterns
|
|
529
|
+
for (const pattern of reasonPatterns) {
|
|
530
|
+
reasonMatch = content.match(pattern);
|
|
531
|
+
if (reasonMatch) {
|
|
532
|
+
console.log('Reason pattern matched:', pattern);
|
|
533
|
+
console.log('Reason match:', reasonMatch[1].trim());
|
|
534
|
+
break;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
console.log('Parsing results:', {
|
|
539
|
+
contextMatch: contextMatch ? contextMatch[1].trim() : null,
|
|
540
|
+
nextStepMatch: nextStepMatch ? nextStepMatch[1].trim() : null,
|
|
541
|
+
reasonMatch: reasonMatch ? reasonMatch[1].trim() : null,
|
|
542
|
+
globalContext: globalContext ? 'available' : 'not available'
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
// Determine context to use - prioritize individual option context over global context
|
|
546
|
+
let context = null;
|
|
547
|
+
if (contextMatch) {
|
|
548
|
+
context = contextMatch[1].trim().replace(/Same as above/gi, '').trim();
|
|
549
|
+
console.log('Using individual option context:', context);
|
|
550
|
+
} else if (globalContext) {
|
|
551
|
+
context = globalContext;
|
|
552
|
+
console.log('Using global context:', context);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
if ((context || contextMatch) && nextStepMatch && reasonMatch) {
|
|
556
|
+
const result = {
|
|
557
|
+
optionNumber: optionNumber,
|
|
558
|
+
stepNumber: stepNumber,
|
|
559
|
+
context: context,
|
|
560
|
+
nextStep: nextStepMatch[1].trim().replace(/\*\*/g, ''),
|
|
561
|
+
reason: reasonMatch[1].trim(),
|
|
562
|
+
originalContent: content
|
|
563
|
+
};
|
|
564
|
+
result.reason = "I used xxxxxxx operator" + " in this step, in order to \n" + result.reason;
|
|
565
|
+
console.log('Successfully parsed option:', result);
|
|
566
|
+
console.log('Final context being stored:', result.context);
|
|
567
|
+
console.log('===============================');
|
|
568
|
+
return result;
|
|
569
|
+
} else {
|
|
570
|
+
console.log('Failed to parse option content:', {
|
|
571
|
+
hasContext: !!(context || contextMatch),
|
|
572
|
+
hasNextStep: !!nextStepMatch,
|
|
573
|
+
hasReason: !!reasonMatch
|
|
574
|
+
});
|
|
575
|
+
console.log('===============================');
|
|
576
|
+
return null;
|
|
577
|
+
}
|
|
578
|
+
}
|
|
579
|
+
|
|
580
|
+
// Display options as cards
|
|
581
|
+
function displayOptions() {
|
|
582
|
+
optionsContainer.innerHTML = '';
|
|
583
|
+
|
|
584
|
+
currentOptions.forEach((option, index) => {
|
|
585
|
+
const card = createOptionCard(option, index);
|
|
586
|
+
optionsContainer.appendChild(card);
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// Create option card
|
|
591
|
+
function createOptionCard(option, index) {
|
|
592
|
+
console.log('=== CREATING OPTION CARD ===');
|
|
593
|
+
console.log('Option index:', index);
|
|
594
|
+
console.log('Option context being displayed:', option.context);
|
|
595
|
+
console.log('Option next step:', option.nextStep);
|
|
596
|
+
console.log('Option reason:', option.reason);
|
|
597
|
+
console.log('============================');
|
|
598
|
+
|
|
599
|
+
const card = document.createElement('div');
|
|
600
|
+
card.className = 'option-card';
|
|
601
|
+
card.dataset.optionIndex = index;
|
|
602
|
+
|
|
603
|
+
card.innerHTML = `
|
|
604
|
+
<div class="option-header">
|
|
605
|
+
<span class="option-number">Option ${option.optionNumber}</span>
|
|
606
|
+
<div class="option-actions">
|
|
607
|
+
<button class="select-btn" onclick="selectAndEdit(${index})">Select & Edit</button>
|
|
608
|
+
<button class="btn btn-secondary" style="background: #9b59b6; margin-left: 5px; padding: 5px 10px; font-size: 12px;" onclick="openOperatorSuggestions(${index})">🎯 Get Operators</button>
|
|
609
|
+
</div>
|
|
610
|
+
</div>
|
|
611
|
+
<div class="option-content">
|
|
612
|
+
<div class="option-field readonly">
|
|
613
|
+
<label>Context:</label>
|
|
614
|
+
<textarea readonly class="auto-resize-textarea">${option.context}</textarea>
|
|
615
|
+
</div>
|
|
616
|
+
<div class="option-field readonly">
|
|
617
|
+
<label>Next Step:</label>
|
|
618
|
+
<input type="text" readonly value="${option.nextStep}" style="display: none;">
|
|
619
|
+
<div class="readonly-display">
|
|
620
|
+
<span class="clickable-category" onclick="showCategoryPopup('${option.nextStep.replace(/'/g, "\\'")}', event)">${option.nextStep}</span>
|
|
621
|
+
</div>
|
|
622
|
+
</div>
|
|
623
|
+
<div class="option-field readonly">
|
|
624
|
+
<label>Reason:</label>
|
|
625
|
+
<textarea readonly class="auto-resize-textarea">${option.reason}</textarea>
|
|
626
|
+
</div>
|
|
627
|
+
</div>
|
|
628
|
+
`;
|
|
629
|
+
|
|
630
|
+
// Auto-resize textareas after creating the card
|
|
631
|
+
setTimeout(() => {
|
|
632
|
+
const textareas = card.querySelectorAll('.auto-resize-textarea');
|
|
633
|
+
textareas.forEach(autoResizeTextarea);
|
|
634
|
+
}, 0);
|
|
635
|
+
|
|
636
|
+
return card;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
// Auto-resize textarea function
|
|
640
|
+
function autoResizeTextarea(textarea) {
|
|
641
|
+
textarea.style.height = 'auto';
|
|
642
|
+
textarea.style.height = Math.max(textarea.scrollHeight, 60) + 'px';
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
// Select and edit option
|
|
646
|
+
function selectAndEdit(index) {
|
|
647
|
+
const card = document.querySelector(`[data-option-index="${index}"]`);
|
|
648
|
+
const fields = card.querySelectorAll('.option-field');
|
|
649
|
+
|
|
650
|
+
// Remove readonly class and make fields editable
|
|
651
|
+
fields.forEach(field => {
|
|
652
|
+
field.classList.remove('readonly');
|
|
653
|
+
const input = field.querySelector('input, textarea');
|
|
654
|
+
const readonlyDisplay = field.querySelector('.readonly-display');
|
|
655
|
+
|
|
656
|
+
if (input) {
|
|
657
|
+
input.removeAttribute('readonly');
|
|
658
|
+
// For Next Step field, show input and hide readonly display
|
|
659
|
+
if (readonlyDisplay) {
|
|
660
|
+
input.style.display = 'block';
|
|
661
|
+
readonlyDisplay.style.display = 'none';
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
|
|
665
|
+
// Add auto-resize functionality to textareas
|
|
666
|
+
if (input && input.tagName === 'TEXTAREA') {
|
|
667
|
+
input.addEventListener('input', () => autoResizeTextarea(input));
|
|
668
|
+
autoResizeTextarea(input); // Initial resize
|
|
669
|
+
}
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
// Update card state and show modal overlay
|
|
673
|
+
card.classList.add('editing');
|
|
674
|
+
modalOverlay.classList.add('active');
|
|
675
|
+
|
|
676
|
+
// Update action buttons
|
|
677
|
+
const actionsDiv = card.querySelector('.option-actions');
|
|
678
|
+
actionsDiv.innerHTML = `
|
|
679
|
+
<button class="save-btn" onclick="saveOption(${index})">Save Changes</button>
|
|
680
|
+
<button class="cancel-btn" onclick="cancelEdit(${index})">Cancel</button>
|
|
681
|
+
<button class="send-continue-btn" onclick="sendAndContinue(${index})">Send & Continue</button>
|
|
682
|
+
`;
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
// Save option
|
|
686
|
+
function saveOption(index) {
|
|
687
|
+
const card = document.querySelector(`[data-option-index="${index}"]`);
|
|
688
|
+
const contextTextarea = card.querySelector('.option-field:nth-child(1) textarea');
|
|
689
|
+
const nextStepInput = card.querySelector('.option-field:nth-child(2) input');
|
|
690
|
+
const reasonTextarea = card.querySelector('.option-field:nth-child(3) textarea');
|
|
691
|
+
|
|
692
|
+
// Update the option data
|
|
693
|
+
currentOptions[index].context = contextTextarea.value;
|
|
694
|
+
currentOptions[index].nextStep = nextStepInput.value;
|
|
695
|
+
currentOptions[index].reason = reasonTextarea.value;
|
|
696
|
+
|
|
697
|
+
// Save updated options state
|
|
698
|
+
saveConversationState();
|
|
699
|
+
|
|
700
|
+
// Make fields readonly again
|
|
701
|
+
const fields = card.querySelectorAll('.option-field');
|
|
702
|
+
fields.forEach(field => {
|
|
703
|
+
field.classList.add('readonly');
|
|
704
|
+
const input = field.querySelector('input, textarea');
|
|
705
|
+
const readonlyDisplay = field.querySelector('.readonly-display');
|
|
706
|
+
|
|
707
|
+
if (input) {
|
|
708
|
+
input.setAttribute('readonly', 'readonly');
|
|
709
|
+
// For Next Step field, hide input and show readonly display
|
|
710
|
+
if (readonlyDisplay) {
|
|
711
|
+
input.style.display = 'none';
|
|
712
|
+
readonlyDisplay.style.display = 'block';
|
|
713
|
+
// Update the clickable category text
|
|
714
|
+
const categorySpan = readonlyDisplay.querySelector('.clickable-category');
|
|
715
|
+
if (categorySpan) {
|
|
716
|
+
categorySpan.textContent = input.value;
|
|
717
|
+
categorySpan.setAttribute('onclick', `showCategoryPopup('${input.value.replace(/'/g, "\\'")}', event)`);
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
// Update card state and hide modal overlay
|
|
724
|
+
card.classList.remove('editing');
|
|
725
|
+
modalOverlay.classList.remove('active');
|
|
726
|
+
|
|
727
|
+
// Update action buttons
|
|
728
|
+
const actionsDiv = card.querySelector('.option-actions');
|
|
729
|
+
actionsDiv.innerHTML = `
|
|
730
|
+
<button class="select-btn" onclick="selectAndEdit(${index})">Select & Edit</button>
|
|
731
|
+
`;
|
|
732
|
+
|
|
733
|
+
showNotification('Option saved successfully', 'success');
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
// Cancel edit
|
|
737
|
+
function cancelEdit(index) {
|
|
738
|
+
// Hide modal overlay
|
|
739
|
+
modalOverlay.classList.remove('active');
|
|
740
|
+
|
|
741
|
+
// Refresh the card with original data
|
|
742
|
+
const card = createOptionCard(currentOptions[index], index);
|
|
743
|
+
const oldCard = document.querySelector(`[data-option-index="${index}"]`);
|
|
744
|
+
oldCard.parentNode.replaceChild(card, oldCard);
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
|
|
748
|
+
|
|
749
|
+
// Get data state from category
|
|
750
|
+
function getDataStateFromCategory(category) {
|
|
751
|
+
const stateMap = {
|
|
752
|
+
'Basic Arithmetic & Mathematical Operations': 'mathematically transformed',
|
|
753
|
+
'Logical & Conditional Operations': 'conditionally filtered',
|
|
754
|
+
'Time Series: Change Detection & Value Comparison': 'change-analyzed',
|
|
755
|
+
'Time Series: Statistical Feature Engineering': 'statistically engineered',
|
|
756
|
+
'Time Series: Ranking, Scaling, and Normalization': 'ranked and normalized',
|
|
757
|
+
'Time Series: Decay, Smoothing, and Turnover Control': 'smoothed and controlled',
|
|
758
|
+
'Time Series: Extremes & Position Identification': 'extreme-identified',
|
|
759
|
+
'Cross-Sectional: Ranking, Scaling, and Normalization': 'cross-sectionally normalized',
|
|
760
|
+
'Cross-Sectional: Regression & Neutralization': 'neutralized',
|
|
761
|
+
'Cross-Sectional: Distributional Transformation & Truncation': 'distributionally transformed',
|
|
762
|
+
'Transformational & Filtering Operations': 'transformed and filtered',
|
|
763
|
+
'Group Aggregation & Statistical Summary': 'aggregated',
|
|
764
|
+
'Group Ranking, Scaling, and Normalization': 'group-normalized',
|
|
765
|
+
'Group Regression & Neutralization': 'group-neutralized',
|
|
766
|
+
'Group Imputation & Backfilling': 'imputed and backfilled'
|
|
767
|
+
};
|
|
768
|
+
|
|
769
|
+
return stateMap[category] || 'processed';
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
// Clear Options and Start Over
|
|
773
|
+
clearOptionsBtn.addEventListener('click', () => {
|
|
774
|
+
if (confirm('Are you sure you want to clear all progress and start over?')) {
|
|
775
|
+
// Clear all state
|
|
776
|
+
conversationHistory = [];
|
|
777
|
+
currentStep = 1;
|
|
778
|
+
pipelineSteps = [];
|
|
779
|
+
currentOptions = [];
|
|
780
|
+
currentDataState = 'raw data';
|
|
781
|
+
|
|
782
|
+
// Clear session storage
|
|
783
|
+
sessionStorage.removeItem('featureEngConversationHistory');
|
|
784
|
+
sessionStorage.removeItem('featureEngCurrentStep');
|
|
785
|
+
sessionStorage.removeItem('featureEngPipelineSteps');
|
|
786
|
+
sessionStorage.removeItem('featureEngCurrentOptions');
|
|
787
|
+
sessionStorage.removeItem('featureEngCurrentDataState');
|
|
788
|
+
|
|
789
|
+
// Reset UI
|
|
790
|
+
optionsSection.style.display = 'none';
|
|
791
|
+
initialSetupSection.style.display = 'block';
|
|
792
|
+
questionTemplateInput.value = '';
|
|
793
|
+
|
|
794
|
+
// Update pipeline status to reflect cleared state
|
|
795
|
+
updatePipelineStatus();
|
|
796
|
+
|
|
797
|
+
showNotification('Pipeline cleared. You can start a new conversation.', 'success');
|
|
798
|
+
}
|
|
799
|
+
});
|
|
800
|
+
|
|
801
|
+
// Export pipeline
|
|
802
|
+
exportPipelineBtn.addEventListener('click', () => {
|
|
803
|
+
const exportData = {
|
|
804
|
+
timestamp: new Date().toISOString(),
|
|
805
|
+
currentStep: currentStep,
|
|
806
|
+
pipelineSteps: pipelineSteps,
|
|
807
|
+
currentOptions: currentOptions,
|
|
808
|
+
conversationHistory: conversationHistory
|
|
809
|
+
};
|
|
810
|
+
|
|
811
|
+
const blob = new Blob([JSON.stringify(exportData, null, 2)], { type: 'application/json' });
|
|
812
|
+
const url = URL.createObjectURL(blob);
|
|
813
|
+
const a = document.createElement('a');
|
|
814
|
+
a.href = url;
|
|
815
|
+
a.download = `feature_engineering_pipeline_${new Date().toISOString().split('T')[0]}.json`;
|
|
816
|
+
document.body.appendChild(a);
|
|
817
|
+
a.click();
|
|
818
|
+
document.body.removeChild(a);
|
|
819
|
+
URL.revokeObjectURL(url);
|
|
820
|
+
|
|
821
|
+
showNotification('Pipeline exported successfully', 'success');
|
|
822
|
+
});
|
|
823
|
+
|
|
824
|
+
// Send edited option and continue
|
|
825
|
+
function sendAndContinue(index) {
|
|
826
|
+
const card = document.querySelector(`[data-option-index="${index}"]`);
|
|
827
|
+
const contextTextarea = card.querySelector('.option-field:nth-child(1) textarea');
|
|
828
|
+
const nextStepInput = card.querySelector('.option-field:nth-child(2) input');
|
|
829
|
+
const reasonTextarea = card.querySelector('.option-field:nth-child(3) textarea');
|
|
830
|
+
|
|
831
|
+
// Get the edited values
|
|
832
|
+
const context = contextTextarea.value;
|
|
833
|
+
const chosenStep = nextStepInput.value;
|
|
834
|
+
const reason = reasonTextarea.value;
|
|
835
|
+
|
|
836
|
+
console.log('=== SEND AND CONTINUE DEBUG ===');
|
|
837
|
+
console.log('Selected option index:', index);
|
|
838
|
+
console.log('Current option:', currentOptions[index]);
|
|
839
|
+
console.log('Context:', context);
|
|
840
|
+
console.log('Chosen step:', chosenStep);
|
|
841
|
+
console.log('Reason:', reason);
|
|
842
|
+
console.log('Current step before update:', currentStep);
|
|
843
|
+
console.log('Pipeline steps before update:', pipelineSteps);
|
|
844
|
+
|
|
845
|
+
// Hide modal overlay
|
|
846
|
+
modalOverlay.classList.remove('active');
|
|
847
|
+
|
|
848
|
+
// Add to pipeline steps - Fix: Use currentStep instead of stepNumber from option
|
|
849
|
+
pipelineSteps.push(`Step ${currentStep}: ${chosenStep}`);
|
|
850
|
+
currentStep = currentStep + 1; // Increment from current step
|
|
851
|
+
currentDataState = getDataStateFromCategory(chosenStep);
|
|
852
|
+
|
|
853
|
+
console.log('Current step after update:', currentStep);
|
|
854
|
+
console.log('Pipeline steps after update:', pipelineSteps);
|
|
855
|
+
console.log('Current data state:', currentDataState);
|
|
856
|
+
|
|
857
|
+
// Update pipeline status
|
|
858
|
+
updatePipelineStatus();
|
|
859
|
+
|
|
860
|
+
// Save pipeline state
|
|
861
|
+
saveConversationState();
|
|
862
|
+
|
|
863
|
+
// Prepare message in the proper format for the AI system prompt
|
|
864
|
+
|
|
865
|
+
// Build the previous steps list
|
|
866
|
+
const previousStepsText = pipelineSteps.length > 0 ? pipelineSteps.join(', ') : 'None';
|
|
867
|
+
|
|
868
|
+
// Get the category description for the chosen step
|
|
869
|
+
const categoryData = operatorsData.find(cat => cat.name === chosenStep);
|
|
870
|
+
const stepDescription = categoryData ? categoryData.description : 'No description available';
|
|
871
|
+
|
|
872
|
+
const userMessage = `
|
|
873
|
+
|
|
874
|
+
I Chosen next step: ${chosenStep}
|
|
875
|
+
The step description: ${stepDescription}
|
|
876
|
+
Reason for choice: ${reason}
|
|
877
|
+
based on my choice and info, please recommend me some further options`;
|
|
878
|
+
|
|
879
|
+
console.log('=== CONSTRUCTED MESSAGE FOR AI ===');
|
|
880
|
+
console.log('User message being sent:', userMessage);
|
|
881
|
+
console.log('Current step:', currentStep);
|
|
882
|
+
console.log('Previous steps:', previousStepsText);
|
|
883
|
+
console.log('Current data state:', currentDataState);
|
|
884
|
+
console.log('Step description:', stepDescription);
|
|
885
|
+
console.log('Chosen next step:', chosenStep);
|
|
886
|
+
console.log('Reason for choice:', reason);
|
|
887
|
+
console.log('=================================');
|
|
888
|
+
|
|
889
|
+
// Get next recommendations
|
|
890
|
+
showLoading('Getting next recommendations...');
|
|
891
|
+
|
|
892
|
+
fetch('/feature-engineering/api/continue-conversation', {
|
|
893
|
+
method: 'POST',
|
|
894
|
+
headers: {
|
|
895
|
+
'X-API-Key': apiKey,
|
|
896
|
+
'Content-Type': 'application/json'
|
|
897
|
+
},
|
|
898
|
+
body: JSON.stringify({
|
|
899
|
+
conversation_history: conversationHistory,
|
|
900
|
+
user_message: userMessage,
|
|
901
|
+
custom_system_prompt: customSystemPrompt,
|
|
902
|
+
provider: modelProvider,
|
|
903
|
+
model_name: modelName
|
|
904
|
+
})
|
|
905
|
+
})
|
|
906
|
+
.then(response => response.json())
|
|
907
|
+
.then(data => {
|
|
908
|
+
console.log('=== SEND & CONTINUE PROMPT ===');
|
|
909
|
+
console.log('User message:', userMessage);
|
|
910
|
+
console.log('Current step before:', currentStep);
|
|
911
|
+
console.log('Pipeline steps before:', pipelineSteps);
|
|
912
|
+
console.log('Conversation history sent:', conversationHistory);
|
|
913
|
+
console.log('=== AI RESPONSE ===');
|
|
914
|
+
console.log('AI response:', data.response);
|
|
915
|
+
console.log('==================');
|
|
916
|
+
|
|
917
|
+
if (data.success) {
|
|
918
|
+
// Add to conversation history
|
|
919
|
+
conversationHistory.push({
|
|
920
|
+
role: 'user',
|
|
921
|
+
content: userMessage
|
|
922
|
+
});
|
|
923
|
+
conversationHistory.push({
|
|
924
|
+
role: 'assistant',
|
|
925
|
+
content: data.response
|
|
926
|
+
});
|
|
927
|
+
|
|
928
|
+
console.log('Updated conversation history:', conversationHistory);
|
|
929
|
+
|
|
930
|
+
// Parse the new AI response
|
|
931
|
+
parseAIResponse(data.response);
|
|
932
|
+
|
|
933
|
+
// Save conversation state
|
|
934
|
+
saveConversationState();
|
|
935
|
+
|
|
936
|
+
showNotification(`Edited option sent successfully. Next step recommendations loaded.`, 'success');
|
|
937
|
+
} else {
|
|
938
|
+
showNotification(`Error: ${data.error || 'Unknown error'}`, 'error');
|
|
939
|
+
console.error('API Error Details:', data);
|
|
940
|
+
}
|
|
941
|
+
})
|
|
942
|
+
.catch(error => {
|
|
943
|
+
showNotification('Error getting next recommendations: ' + error.message, 'error');
|
|
944
|
+
console.error('Next Step Error:', error);
|
|
945
|
+
})
|
|
946
|
+
.finally(() => {
|
|
947
|
+
hideLoading();
|
|
948
|
+
});
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
// Make functions global for onclick handlers
|
|
952
|
+
window.selectAndEdit = selectAndEdit;
|
|
953
|
+
window.saveOption = saveOption;
|
|
954
|
+
window.cancelEdit = cancelEdit;
|
|
955
|
+
window.sendAndContinue = sendAndContinue;
|
|
956
|
+
window.closeSystemPromptModal = closeSystemPromptModal;
|
|
957
|
+
window.saveSystemPrompt = saveSystemPrompt;
|
|
958
|
+
|
|
959
|
+
// Update pipeline status
|
|
960
|
+
function updatePipelineStatus() {
|
|
961
|
+
console.log('=== UPDATE PIPELINE STATUS ===');
|
|
962
|
+
console.log('Pipeline steps:', pipelineSteps);
|
|
963
|
+
console.log('Current step:', currentStep);
|
|
964
|
+
console.log('Current data state:', currentDataState);
|
|
965
|
+
|
|
966
|
+
if (pipelineSteps.length === 0) {
|
|
967
|
+
pipelineStatus.style.display = 'none';
|
|
968
|
+
return;
|
|
969
|
+
}
|
|
970
|
+
|
|
971
|
+
pipelineStatus.style.display = 'block';
|
|
972
|
+
pipelineStepsDiv.innerHTML = pipelineSteps.map(step =>
|
|
973
|
+
`<div class="pipeline-step"><strong>${step}</strong></div>`
|
|
974
|
+
).join('');
|
|
975
|
+
|
|
976
|
+
// Add current status
|
|
977
|
+
const statusDiv = document.createElement('div');
|
|
978
|
+
statusDiv.className = 'pipeline-step';
|
|
979
|
+
statusDiv.style.backgroundColor = '#e8f5e8';
|
|
980
|
+
statusDiv.innerHTML = `<strong>Current Step:</strong> ${currentStep} | <strong>Data State:</strong> ${currentDataState}`;
|
|
981
|
+
pipelineStepsDiv.appendChild(statusDiv);
|
|
982
|
+
|
|
983
|
+
console.log('Pipeline status updated');
|
|
984
|
+
console.log('==============================');
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
// Utility Functions
|
|
988
|
+
function showNotification(message, type) {
|
|
989
|
+
const notification = document.createElement('div');
|
|
990
|
+
notification.className = `notification ${type}`;
|
|
991
|
+
notification.textContent = message;
|
|
992
|
+
document.body.appendChild(notification);
|
|
993
|
+
|
|
994
|
+
setTimeout(() => {
|
|
995
|
+
notification.remove();
|
|
996
|
+
}, 8000);
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
let loadingElement = null;
|
|
1000
|
+
|
|
1001
|
+
function showLoading(message) {
|
|
1002
|
+
loadingElement = document.createElement('div');
|
|
1003
|
+
loadingElement.className = 'loading-overlay';
|
|
1004
|
+
loadingElement.innerHTML = `
|
|
1005
|
+
<div class="loading-spinner"></div>
|
|
1006
|
+
<div class="loading-message">${message}</div>
|
|
1007
|
+
`;
|
|
1008
|
+
document.body.appendChild(loadingElement);
|
|
1009
|
+
}
|
|
1010
|
+
|
|
1011
|
+
function hideLoading() {
|
|
1012
|
+
if (loadingElement) {
|
|
1013
|
+
loadingElement.remove();
|
|
1014
|
+
loadingElement = null;
|
|
1015
|
+
}
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
// Operators Reference Data
|
|
1019
|
+
const operatorsData = [
|
|
1020
|
+
{
|
|
1021
|
+
id: 1,
|
|
1022
|
+
name: "Basic Arithmetic & Mathematical Operations",
|
|
1023
|
+
description: "Core mathematical and elementwise operations (e.g., add, subtract, multiply, log, exp, abs, power, etc.)",
|
|
1024
|
+
operators: ["add", "subtract", "multiply", "divide", "exp", "log", "abs", "power", "sqrt", "round", "round_down", "floor", "ceiling", "inverse", "negate", "signed_power", "sign", "arc_sin", "arc_cos", "arc_tan", "tanh", "sigmoid", "s_log_1p", "fraction", "max", "min", "densify", "pasteurize", "purify", "to_nan", "nan_out", "replace", "reverse"]
|
|
1025
|
+
},
|
|
1026
|
+
{
|
|
1027
|
+
id: 2,
|
|
1028
|
+
name: "Logical & Conditional Operations",
|
|
1029
|
+
description: "Boolean logic, comparisons, and conditional branching (e.g., and, or, not, if_else, equal, greater, less, etc.)",
|
|
1030
|
+
operators: ["and", "or", "not", "if_else", "equal", "not_equal", "less", "less_equal", "greater", "greater_equal", "is_nan", "is_not_nan", "is_finite", "is_not_finite", "nan_mask"]
|
|
1031
|
+
},
|
|
1032
|
+
{
|
|
1033
|
+
id: 3,
|
|
1034
|
+
name: "Time Series: Change Detection & Value Comparison",
|
|
1035
|
+
description: "Compare values over time, compute differences, detect changes, or count days since change (e.g., ts_delta, ts_returns, days_from_last_change, last_diff_value, etc.)",
|
|
1036
|
+
operators: ["ts_delta", "ts_returns", "days_from_last_change", "last_diff_value", "ts_delta_limit", "ts_backfill"]
|
|
1037
|
+
},
|
|
1038
|
+
{
|
|
1039
|
+
id: 4,
|
|
1040
|
+
name: "Time Series: Statistical Feature Engineering",
|
|
1041
|
+
description: "Calculate rolling statistical properties over time (e.g., ts_mean, ts_std_dev, ts_skewness, ts_kurtosis, ts_entropy, ts_moment, ts_covariance, ts_corr, ts_co_skewness, ts_co_kurtosis, etc.)",
|
|
1042
|
+
operators: ["ts_mean", "ts_std_dev", "ts_skewness", "ts_kurtosis", "ts_entropy", "ts_moment", "ts_covariance", "ts_corr", "ts_partial_corr", "ts_triple_corr", "ts_ir", "ts_sum", "ts_product", "ts_median", "ts_count_nans", "ts_av_diff", "ts_regression", "ts_poly_regression", "ts_vector_neut", "ts_vector_proj", "ts_co_skewness", "ts_co_kurtosis", "ts_theilsen", "ts_zscore", "ts_rank_gmean_amean_diff", "ts_step", "ts_delay", "inst_tvr", "generate_stats"]
|
|
1043
|
+
},
|
|
1044
|
+
{
|
|
1045
|
+
id: 5,
|
|
1046
|
+
name: "Time Series: Ranking, Scaling, and Normalization",
|
|
1047
|
+
description: "Rank, scale, or normalize time series data within a rolling window (e.g., ts_rank, ts_scale, ts_percentage, ts_quantile, etc.)",
|
|
1048
|
+
operators: ["ts_rank", "ts_scale", "ts_percentage", "ts_quantile", "ts_rank_gmean_amean_diff", "ts_zscore"]
|
|
1049
|
+
},
|
|
1050
|
+
{
|
|
1051
|
+
id: 6,
|
|
1052
|
+
name: "Time Series: Decay, Smoothing, and Turnover Control",
|
|
1053
|
+
description: "Apply decay (linear, exponential, weighted), smoothing, or control turnover in time series (e.g., ts_decay_exp_window, ts_decay_linear, ts_weighted_decay, ts_target_tvr_decay, hump, jump_decay, etc.)",
|
|
1054
|
+
operators: ["ts_decay_exp_window", "ts_decay_linear", "ts_weighted_decay", "ts_target_tvr_decay", "hump", "jump_decay", "ts_target_tvr_delta_limit", "ts_target_tvr_hump", "hump_decay"]
|
|
1055
|
+
},
|
|
1056
|
+
{
|
|
1057
|
+
id: 7,
|
|
1058
|
+
name: "Time Series: Extremes & Position Identification",
|
|
1059
|
+
description: "Identify min/max values, their differences, or the position (index) of extremes within a window (e.g., ts_min, ts_max, ts_min_diff, ts_max_diff, ts_arg_min, ts_arg_max, ts_min_max_diff, etc.)",
|
|
1060
|
+
operators: ["ts_min", "ts_max", "ts_min_diff", "ts_max_diff", "ts_arg_min", "ts_arg_max", "ts_min_max_diff", "ts_min_max_cps", "kth_element"]
|
|
1061
|
+
},
|
|
1062
|
+
{
|
|
1063
|
+
id: 8,
|
|
1064
|
+
name: "Cross-Sectional: Ranking, Scaling, and Normalization",
|
|
1065
|
+
description: "Rank, scale, normalize, or standardize data across instruments at a single time point (e.g., rank, zscore, scale_down, normalize, rank_by_side, etc.)",
|
|
1066
|
+
operators: ["rank", "zscore", "scale_down", "scale", "normalize", "rank_by_side", "generalized_rank", "one_side", "rank_gmean_amean_diff"]
|
|
1067
|
+
},
|
|
1068
|
+
{
|
|
1069
|
+
id: 9,
|
|
1070
|
+
name: "Cross-Sectional: Regression & Neutralization",
|
|
1071
|
+
description: "Remove effects of other variables, perform cross-sectional regression, or orthogonalize one vector with respect to another (e.g., regression_neut, vector_neut, regression_proj, vector_proj, multi_regression, etc.)",
|
|
1072
|
+
operators: ["regression_neut", "vector_neut", "regression_proj", "vector_proj", "multi_regression"]
|
|
1073
|
+
},
|
|
1074
|
+
{
|
|
1075
|
+
id: 10,
|
|
1076
|
+
name: "Cross-Sectional: Distributional Transformation & Truncation",
|
|
1077
|
+
description: "Transform distributions or truncate outliers across instruments (e.g., quantile, winsorize, truncate, bucket, generalized_rank, etc.)",
|
|
1078
|
+
operators: ["quantile", "winsorize", "truncate", "bucket", "right_tail", "left_tail", "tail"]
|
|
1079
|
+
},
|
|
1080
|
+
{
|
|
1081
|
+
id: 11,
|
|
1082
|
+
name: "Transformational & Filtering Operations",
|
|
1083
|
+
description: "General data transformation, filtering, clamping, masking, or conditional value assignment (e.g., filter, clamp, keep, tail, left_tail, right_tail, trade_when, etc.)",
|
|
1084
|
+
operators: ["filter", "clamp", "keep", "tail", "left_tail", "right_tail", "trade_when"]
|
|
1085
|
+
},
|
|
1086
|
+
{
|
|
1087
|
+
id: 12,
|
|
1088
|
+
name: "Group Aggregation & Statistical Summary",
|
|
1089
|
+
description: "Aggregate or summarize (e.g., mean, sum, std, min, max, median) within each group (such as industry, sector, country). Each stock receives the group-level value based on its group membership.",
|
|
1090
|
+
operators: ["group_mean", "group_sum", "group_std_dev", "group_min", "group_max", "group_median", "group_count", "group_percentage", "group_extra"]
|
|
1091
|
+
},
|
|
1092
|
+
{
|
|
1093
|
+
id: 13,
|
|
1094
|
+
name: "Group Ranking, Scaling, and Normalization",
|
|
1095
|
+
description: "Rank, scale, or normalize within each group (e.g., industry rank for each stock, scale values within sector). Each stock is ranked or scaled among its group peers.",
|
|
1096
|
+
operators: ["group_rank", "group_scale", "group_zscore", "group_normalize"]
|
|
1097
|
+
},
|
|
1098
|
+
{
|
|
1099
|
+
id: 14,
|
|
1100
|
+
name: "Group Regression & Neutralization",
|
|
1101
|
+
description: "Remove group-level effects, perform regression, or orthogonalize within each group (e.g., industry-neutralization, group-wise regression). Each group is treated independently.",
|
|
1102
|
+
operators: ["group_vector_neut", "group_vector_proj", "group_neutralize", "group_multi_regression"]
|
|
1103
|
+
},
|
|
1104
|
+
{
|
|
1105
|
+
id: 15,
|
|
1106
|
+
name: "Group Imputation & Backfilling",
|
|
1107
|
+
description: "Impute missing values or backfill using data from other stocks in the same group (e.g., fill NaN with group mean or median, group_backfill).",
|
|
1108
|
+
operators: ["group_backfill"]
|
|
1109
|
+
}
|
|
1110
|
+
];
|
|
1111
|
+
|
|
1112
|
+
// Show category popup
|
|
1113
|
+
function showCategoryPopup(categoryName, event) {
|
|
1114
|
+
event.stopPropagation();
|
|
1115
|
+
|
|
1116
|
+
// Find the category data
|
|
1117
|
+
const categoryData = operatorsData.find(cat => cat.name === categoryName);
|
|
1118
|
+
|
|
1119
|
+
if (!categoryData) {
|
|
1120
|
+
console.log('Category not found:', categoryName);
|
|
1121
|
+
return;
|
|
1122
|
+
}
|
|
1123
|
+
|
|
1124
|
+
// Populate popup content
|
|
1125
|
+
categoryPopupTitle.textContent = categoryData.name;
|
|
1126
|
+
categoryPopupDescription.textContent = categoryData.description;
|
|
1127
|
+
categoryPopupOperatorsTitle.textContent = `Available Operators (${categoryData.operators.length}):`;
|
|
1128
|
+
|
|
1129
|
+
const operatorsHtml = categoryData.operators.map(op =>
|
|
1130
|
+
`<span class="popup-operator-tag">${op}</span>`
|
|
1131
|
+
).join('');
|
|
1132
|
+
categoryPopupOperators.innerHTML = operatorsHtml;
|
|
1133
|
+
|
|
1134
|
+
// Position the popup near the clicked element
|
|
1135
|
+
const rect = event.target.getBoundingClientRect();
|
|
1136
|
+
const popup = categoryPopup;
|
|
1137
|
+
|
|
1138
|
+
popup.style.display = 'block';
|
|
1139
|
+
|
|
1140
|
+
// Calculate position
|
|
1141
|
+
let left = rect.left + window.scrollX;
|
|
1142
|
+
let top = rect.bottom + window.scrollY + 5;
|
|
1143
|
+
|
|
1144
|
+
// Adjust if popup would go off-screen
|
|
1145
|
+
const popupRect = popup.getBoundingClientRect();
|
|
1146
|
+
if (left + popupRect.width > window.innerWidth) {
|
|
1147
|
+
left = window.innerWidth - popupRect.width - 20;
|
|
1148
|
+
}
|
|
1149
|
+
if (top + popupRect.height > window.innerHeight + window.scrollY) {
|
|
1150
|
+
top = rect.top + window.scrollY - popupRect.height - 5;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
popup.style.left = left + 'px';
|
|
1154
|
+
popup.style.top = top + 'px';
|
|
1155
|
+
}
|
|
1156
|
+
|
|
1157
|
+
// Hide category popup
|
|
1158
|
+
function hideCategoryPopup() {
|
|
1159
|
+
categoryPopup.style.display = 'none';
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
// Make functions global for onclick handlers
|
|
1163
|
+
window.showCategoryPopup = showCategoryPopup;
|
|
1164
|
+
window.hideCategoryPopup = hideCategoryPopup;
|
|
1165
|
+
|
|
1166
|
+
// Function to save conversation state
|
|
1167
|
+
function saveConversationState() {
|
|
1168
|
+
sessionStorage.setItem('featureEngConversationHistory', JSON.stringify(conversationHistory));
|
|
1169
|
+
sessionStorage.setItem('featureEngCurrentStep', currentStep.toString());
|
|
1170
|
+
sessionStorage.setItem('featureEngPipelineSteps', JSON.stringify(pipelineSteps));
|
|
1171
|
+
sessionStorage.setItem('featureEngCurrentOptions', JSON.stringify(currentOptions));
|
|
1172
|
+
sessionStorage.setItem('featureEngCurrentDataState', currentDataState);
|
|
1173
|
+
console.log('Conversation state saved to sessionStorage');
|
|
1174
|
+
}
|
|
1175
|
+
|
|
1176
|
+
// Operator Suggestions Modal Functions
|
|
1177
|
+
let currentOperatorModalIndex = -1;
|
|
1178
|
+
let modalEvaluationResults = [];
|
|
1179
|
+
|
|
1180
|
+
// Open operator suggestions modal
|
|
1181
|
+
function openOperatorSuggestions(index) {
|
|
1182
|
+
currentOperatorModalIndex = index;
|
|
1183
|
+
const option = currentOptions[index];
|
|
1184
|
+
|
|
1185
|
+
// Set the target text from the option's reason instead of context
|
|
1186
|
+
let targetText = option.reason || 'No target specified';
|
|
1187
|
+
|
|
1188
|
+
// Replace "I used xxxxxxx operator in this step, in order to " with "I want to"
|
|
1189
|
+
targetText = targetText.replace(/I used .*? operator in this step, in order to /gi, 'I want to ');
|
|
1190
|
+
|
|
1191
|
+
document.getElementById('modalTargetText').textContent = targetText;
|
|
1192
|
+
|
|
1193
|
+
// Clear previous results
|
|
1194
|
+
document.getElementById('modalCurrentExpression').value = '';
|
|
1195
|
+
document.getElementById('modalEvaluationSection').style.display = 'none';
|
|
1196
|
+
document.getElementById('modalProgressSection').style.display = 'none';
|
|
1197
|
+
document.getElementById('modalExportResults').style.display = 'none';
|
|
1198
|
+
|
|
1199
|
+
// Check BRAIN connection status
|
|
1200
|
+
const sessionId = localStorage.getItem('brain_session_id');
|
|
1201
|
+
const storedOperators = sessionStorage.getItem('brainOperators');
|
|
1202
|
+
|
|
1203
|
+
if (!sessionId) {
|
|
1204
|
+
// No BRAIN session, show connection notice
|
|
1205
|
+
document.getElementById('modalBrainNotice').style.display = 'block';
|
|
1206
|
+
} else if (!storedOperators) {
|
|
1207
|
+
// Has session but no operators, try to load them
|
|
1208
|
+
loadOperatorsFromBRAIN().then(operators => {
|
|
1209
|
+
if (operators.length > 0) {
|
|
1210
|
+
document.getElementById('modalBrainNotice').style.display = 'none';
|
|
1211
|
+
} else {
|
|
1212
|
+
document.getElementById('modalBrainNotice').style.display = 'block';
|
|
1213
|
+
}
|
|
1214
|
+
});
|
|
1215
|
+
} else {
|
|
1216
|
+
// Has operators, hide notice
|
|
1217
|
+
document.getElementById('modalBrainNotice').style.display = 'none';
|
|
1218
|
+
}
|
|
1219
|
+
|
|
1220
|
+
// Show the modal
|
|
1221
|
+
document.getElementById('operatorSuggestionsModal').style.display = 'block';
|
|
1222
|
+
|
|
1223
|
+
// Add event listeners for modal controls
|
|
1224
|
+
setupModalEventListeners();
|
|
1225
|
+
|
|
1226
|
+
// Add click-outside-to-close functionality
|
|
1227
|
+
const modal = document.getElementById('operatorSuggestionsModal');
|
|
1228
|
+
modal.addEventListener('click', (e) => {
|
|
1229
|
+
if (e.target === modal) {
|
|
1230
|
+
closeOperatorSuggestionsModal();
|
|
1231
|
+
}
|
|
1232
|
+
});
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
// Setup modal event listeners
|
|
1236
|
+
function setupModalEventListeners() {
|
|
1237
|
+
// Remove existing listeners to prevent duplicates
|
|
1238
|
+
const startBtn = document.getElementById('modalStartEvaluation');
|
|
1239
|
+
const clearBtn = document.getElementById('modalClearExpression');
|
|
1240
|
+
const minScoreFilter = document.getElementById('modalMinScoreFilter');
|
|
1241
|
+
const showHighScores = document.getElementById('modalShowHighScores');
|
|
1242
|
+
const showMediumScores = document.getElementById('modalShowMediumScores');
|
|
1243
|
+
const showLowScores = document.getElementById('modalShowLowScores');
|
|
1244
|
+
const exportBtn = document.getElementById('modalExportResults');
|
|
1245
|
+
const editTargetBtn = document.getElementById('modalEditTarget');
|
|
1246
|
+
const saveTargetBtn = document.getElementById('modalSaveTarget');
|
|
1247
|
+
const cancelTargetBtn = document.getElementById('modalCancelTarget');
|
|
1248
|
+
|
|
1249
|
+
// Clone elements to remove old listeners
|
|
1250
|
+
startBtn.replaceWith(startBtn.cloneNode(true));
|
|
1251
|
+
clearBtn.replaceWith(clearBtn.cloneNode(true));
|
|
1252
|
+
minScoreFilter.replaceWith(minScoreFilter.cloneNode(true));
|
|
1253
|
+
showHighScores.replaceWith(showHighScores.cloneNode(true));
|
|
1254
|
+
showMediumScores.replaceWith(showMediumScores.cloneNode(true));
|
|
1255
|
+
showLowScores.replaceWith(showLowScores.cloneNode(true));
|
|
1256
|
+
exportBtn.replaceWith(exportBtn.cloneNode(true));
|
|
1257
|
+
editTargetBtn.replaceWith(editTargetBtn.cloneNode(true));
|
|
1258
|
+
saveTargetBtn.replaceWith(saveTargetBtn.cloneNode(true));
|
|
1259
|
+
cancelTargetBtn.replaceWith(cancelTargetBtn.cloneNode(true));
|
|
1260
|
+
|
|
1261
|
+
// Get fresh references
|
|
1262
|
+
const newStartBtn = document.getElementById('modalStartEvaluation');
|
|
1263
|
+
const newClearBtn = document.getElementById('modalClearExpression');
|
|
1264
|
+
const newMinScoreFilter = document.getElementById('modalMinScoreFilter');
|
|
1265
|
+
const newShowHighScores = document.getElementById('modalShowHighScores');
|
|
1266
|
+
const newShowMediumScores = document.getElementById('modalShowMediumScores');
|
|
1267
|
+
const newShowLowScores = document.getElementById('modalShowLowScores');
|
|
1268
|
+
const newExportBtn = document.getElementById('modalExportResults');
|
|
1269
|
+
const newEditTargetBtn = document.getElementById('modalEditTarget');
|
|
1270
|
+
const newSaveTargetBtn = document.getElementById('modalSaveTarget');
|
|
1271
|
+
const newCancelTargetBtn = document.getElementById('modalCancelTarget');
|
|
1272
|
+
|
|
1273
|
+
// Add new listeners
|
|
1274
|
+
newStartBtn.addEventListener('click', startModalEvaluation);
|
|
1275
|
+
|
|
1276
|
+
newClearBtn.addEventListener('click', () => {
|
|
1277
|
+
document.getElementById('modalCurrentExpression').value = '';
|
|
1278
|
+
});
|
|
1279
|
+
|
|
1280
|
+
newMinScoreFilter.addEventListener('input', (e) => {
|
|
1281
|
+
document.getElementById('modalMinScoreValue').textContent = e.target.value;
|
|
1282
|
+
filterModalResults();
|
|
1283
|
+
});
|
|
1284
|
+
|
|
1285
|
+
newShowHighScores.addEventListener('change', filterModalResults);
|
|
1286
|
+
newShowMediumScores.addEventListener('change', filterModalResults);
|
|
1287
|
+
newShowLowScores.addEventListener('change', filterModalResults);
|
|
1288
|
+
|
|
1289
|
+
newExportBtn.addEventListener('click', exportModalResults);
|
|
1290
|
+
|
|
1291
|
+
// Target editing listeners
|
|
1292
|
+
newEditTargetBtn.addEventListener('click', () => {
|
|
1293
|
+
const targetText = document.getElementById('modalTargetText').textContent;
|
|
1294
|
+
document.getElementById('modalTargetInput').value = targetText;
|
|
1295
|
+
document.getElementById('modalTargetDisplay').style.display = 'none';
|
|
1296
|
+
document.getElementById('modalTargetInputGroup').style.display = 'block';
|
|
1297
|
+
newEditTargetBtn.style.display = 'none';
|
|
1298
|
+
});
|
|
1299
|
+
|
|
1300
|
+
newSaveTargetBtn.addEventListener('click', () => {
|
|
1301
|
+
const newTarget = document.getElementById('modalTargetInput').value.trim();
|
|
1302
|
+
if (newTarget) {
|
|
1303
|
+
document.getElementById('modalTargetText').textContent = newTarget;
|
|
1304
|
+
document.getElementById('modalTargetDisplay').style.display = 'block';
|
|
1305
|
+
document.getElementById('modalTargetInputGroup').style.display = 'none';
|
|
1306
|
+
newEditTargetBtn.style.display = 'inline-block';
|
|
1307
|
+
showNotification('Target updated successfully', 'success');
|
|
1308
|
+
} else {
|
|
1309
|
+
showNotification('Please enter a target description', 'error');
|
|
1310
|
+
}
|
|
1311
|
+
});
|
|
1312
|
+
|
|
1313
|
+
newCancelTargetBtn.addEventListener('click', () => {
|
|
1314
|
+
document.getElementById('modalTargetDisplay').style.display = 'block';
|
|
1315
|
+
document.getElementById('modalTargetInputGroup').style.display = 'none';
|
|
1316
|
+
newEditTargetBtn.style.display = 'inline-block';
|
|
1317
|
+
});
|
|
1318
|
+
}
|
|
1319
|
+
|
|
1320
|
+
// Start operator evaluation in modal
|
|
1321
|
+
async function startModalEvaluation() {
|
|
1322
|
+
const expression = document.getElementById('modalCurrentExpression').value.trim();
|
|
1323
|
+
const target = document.getElementById('modalTargetText').textContent;
|
|
1324
|
+
|
|
1325
|
+
if (!expression) {
|
|
1326
|
+
showNotification('Please enter an expression to evaluate', 'error');
|
|
1327
|
+
return;
|
|
1328
|
+
}
|
|
1329
|
+
|
|
1330
|
+
if (!apiKey) {
|
|
1331
|
+
showNotification('Please configure your API key first', 'error');
|
|
1332
|
+
return;
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
// Get operators list
|
|
1336
|
+
let operators = [];
|
|
1337
|
+
const storedOperators = sessionStorage.getItem('brainOperators');
|
|
1338
|
+
|
|
1339
|
+
if (storedOperators) {
|
|
1340
|
+
try {
|
|
1341
|
+
operators = JSON.parse(storedOperators);
|
|
1342
|
+
} catch (error) {
|
|
1343
|
+
console.error('Error parsing stored operators:', error);
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
// If no operators from BRAIN, ask user for choice
|
|
1348
|
+
if (operators.length === 0) {
|
|
1349
|
+
const userChoice = confirm(
|
|
1350
|
+
'No BRAIN operators available. Would you like to:\n\n' +
|
|
1351
|
+
'• Click "OK" to connect to BRAIN and get 400+ operators\n' +
|
|
1352
|
+
'• Click "Cancel" to use fallback operators (40 operators)'
|
|
1353
|
+
);
|
|
1354
|
+
|
|
1355
|
+
if (userChoice) {
|
|
1356
|
+
// User wants to connect to BRAIN
|
|
1357
|
+
closeOperatorSuggestionsModal();
|
|
1358
|
+
openBrainLoginModal();
|
|
1359
|
+
return;
|
|
1360
|
+
} else {
|
|
1361
|
+
// User chooses fallback operators
|
|
1362
|
+
operators = getFallbackOperators();
|
|
1363
|
+
showNotification('Using fallback operator list (40 operators).', 'info');
|
|
1364
|
+
document.getElementById('modalBrainNotice').style.display = 'block';
|
|
1365
|
+
}
|
|
1366
|
+
} else {
|
|
1367
|
+
// Hide BRAIN connection notice if operators are available
|
|
1368
|
+
document.getElementById('modalBrainNotice').style.display = 'none';
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
try {
|
|
1372
|
+
// Show progress section
|
|
1373
|
+
document.getElementById('modalProgressSection').style.display = 'block';
|
|
1374
|
+
document.getElementById('modalEvaluationSection').style.display = 'none';
|
|
1375
|
+
|
|
1376
|
+
// Get operators from inspiration house API
|
|
1377
|
+
const response = await fetch('/inspiration-house/api/batch-evaluate', {
|
|
1378
|
+
method: 'POST',
|
|
1379
|
+
headers: {
|
|
1380
|
+
'X-API-Key': apiKey,
|
|
1381
|
+
'Content-Type': 'application/json'
|
|
1382
|
+
},
|
|
1383
|
+
body: JSON.stringify({
|
|
1384
|
+
operators: operators,
|
|
1385
|
+
research_target: target,
|
|
1386
|
+
current_expression: expression,
|
|
1387
|
+
expression_context: `Feature engineering step ${currentStep}: ${currentOptions[currentOperatorModalIndex].nextStep}`,
|
|
1388
|
+
provider: modelProvider,
|
|
1389
|
+
model_name: modelName,
|
|
1390
|
+
batch_size: 100
|
|
1391
|
+
})
|
|
1392
|
+
});
|
|
1393
|
+
|
|
1394
|
+
const data = await response.json();
|
|
1395
|
+
|
|
1396
|
+
if (response.ok && data.success) {
|
|
1397
|
+
modalEvaluationResults = data.results || [];
|
|
1398
|
+
displayModalResults();
|
|
1399
|
+
showNotification(`Evaluated ${modalEvaluationResults.length} operators`, 'success');
|
|
1400
|
+
} else {
|
|
1401
|
+
showNotification(`Evaluation failed: ${data.error || 'Unknown error'}`, 'error');
|
|
1402
|
+
}
|
|
1403
|
+
} catch (error) {
|
|
1404
|
+
showNotification('Error evaluating operators: ' + error.message, 'error');
|
|
1405
|
+
console.error('Modal evaluation error:', error);
|
|
1406
|
+
} finally {
|
|
1407
|
+
document.getElementById('modalProgressSection').style.display = 'none';
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
|
|
1411
|
+
// Display modal results
|
|
1412
|
+
function displayModalResults() {
|
|
1413
|
+
const tableBody = document.getElementById('modalEvaluationTableBody');
|
|
1414
|
+
const summaryStats = document.getElementById('modalSummaryStats');
|
|
1415
|
+
|
|
1416
|
+
if (modalEvaluationResults.length === 0) {
|
|
1417
|
+
tableBody.innerHTML = `
|
|
1418
|
+
<tr>
|
|
1419
|
+
<td colspan="3" style="text-align: center; color: #7f8c8d; font-style: italic; padding: 20px;">
|
|
1420
|
+
No operators found. Try a different expression.
|
|
1421
|
+
</td>
|
|
1422
|
+
</tr>
|
|
1423
|
+
`;
|
|
1424
|
+
summaryStats.style.display = 'none';
|
|
1425
|
+
return;
|
|
1426
|
+
}
|
|
1427
|
+
|
|
1428
|
+
// Calculate summary stats
|
|
1429
|
+
const highScores = modalEvaluationResults.filter(r => (r.score || 0) >= 8).length;
|
|
1430
|
+
const mediumScores = modalEvaluationResults.filter(r => (r.score || 0) >= 4 && (r.score || 0) < 8).length;
|
|
1431
|
+
const lowScores = modalEvaluationResults.filter(r => (r.score || 0) < 4).length;
|
|
1432
|
+
|
|
1433
|
+
document.getElementById('modalHighScoreCount').textContent = highScores;
|
|
1434
|
+
document.getElementById('modalMediumScoreCount').textContent = mediumScores;
|
|
1435
|
+
document.getElementById('modalLowScoreCount').textContent = lowScores;
|
|
1436
|
+
summaryStats.style.display = 'grid';
|
|
1437
|
+
|
|
1438
|
+
// Display results
|
|
1439
|
+
filterModalResults();
|
|
1440
|
+
|
|
1441
|
+
// Show action buttons
|
|
1442
|
+
document.getElementById('modalExportResults').style.display = 'inline-block';
|
|
1443
|
+
|
|
1444
|
+
// Show evaluation section
|
|
1445
|
+
document.getElementById('modalEvaluationSection').style.display = 'block';
|
|
1446
|
+
}
|
|
1447
|
+
|
|
1448
|
+
// Filter modal results based on score and checkboxes
|
|
1449
|
+
function filterModalResults() {
|
|
1450
|
+
const minScore = parseInt(document.getElementById('modalMinScoreFilter').value);
|
|
1451
|
+
const showHigh = document.getElementById('modalShowHighScores').checked;
|
|
1452
|
+
const showMedium = document.getElementById('modalShowMediumScores').checked;
|
|
1453
|
+
const showLow = document.getElementById('modalShowLowScores').checked;
|
|
1454
|
+
|
|
1455
|
+
const filteredResults = modalEvaluationResults.filter(result => {
|
|
1456
|
+
const score = result.score || 0;
|
|
1457
|
+
if (score < minScore) return false;
|
|
1458
|
+
|
|
1459
|
+
if (score >= 8 && !showHigh) return false;
|
|
1460
|
+
if (score >= 4 && score < 8 && !showMedium) return false;
|
|
1461
|
+
if (score < 4 && !showLow) return false;
|
|
1462
|
+
|
|
1463
|
+
return true;
|
|
1464
|
+
});
|
|
1465
|
+
|
|
1466
|
+
const tableBody = document.getElementById('modalEvaluationTableBody');
|
|
1467
|
+
|
|
1468
|
+
if (filteredResults.length === 0) {
|
|
1469
|
+
tableBody.innerHTML = `
|
|
1470
|
+
<tr>
|
|
1471
|
+
<td colspan="3" style="text-align: center; color: #7f8c8d; font-style: italic; padding: 20px;">
|
|
1472
|
+
No operators match the current filters.
|
|
1473
|
+
</td>
|
|
1474
|
+
</tr>
|
|
1475
|
+
`;
|
|
1476
|
+
return;
|
|
1477
|
+
}
|
|
1478
|
+
|
|
1479
|
+
// Get operators list from sessionStorage (like inspiration_house.js does)
|
|
1480
|
+
let operatorsList = [];
|
|
1481
|
+
const storedOperators = sessionStorage.getItem('brainOperators');
|
|
1482
|
+
if (storedOperators) {
|
|
1483
|
+
try {
|
|
1484
|
+
operatorsList = JSON.parse(storedOperators);
|
|
1485
|
+
} catch (error) {
|
|
1486
|
+
console.error('Error parsing stored operators:', error);
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
tableBody.innerHTML = filteredResults.map(result => {
|
|
1491
|
+
const operatorName = result.operator_name || result.operator || 'Unknown';
|
|
1492
|
+
const category = result.category || 'Unknown';
|
|
1493
|
+
const reason = result.reason || '';
|
|
1494
|
+
const score = result.score || 0;
|
|
1495
|
+
|
|
1496
|
+
// Find the operator details from the operators list (like inspiration_house.js)
|
|
1497
|
+
const operatorDetails = operatorsList.find(op => op.name === operatorName);
|
|
1498
|
+
const description = operatorDetails ? operatorDetails.description || '' : '';
|
|
1499
|
+
const definition = operatorDetails ? operatorDetails.definition || '' : '';
|
|
1500
|
+
|
|
1501
|
+
return `
|
|
1502
|
+
<tr>
|
|
1503
|
+
<td style="border: 1px solid #dee2e6; padding: 8px; vertical-align: top;">
|
|
1504
|
+
<div class="operator-name">${operatorName}</div>
|
|
1505
|
+
<div class="operator-category">${category}</div>
|
|
1506
|
+
${description ? `<div class="operator-description">${convertMarkdownToHTML(description)}</div>` : ''}
|
|
1507
|
+
${definition ? `<div class="operator-definition"><strong>Definition:</strong> ${convertMarkdownToHTML(definition)}</div>` : ''}
|
|
1508
|
+
</td>
|
|
1509
|
+
<td class="reason-text" style="border: 1px solid #dee2e6; padding: 8px; vertical-align: top;">${convertMarkdownToHTML(reason)}</td>
|
|
1510
|
+
<td class="score-cell score-${score >= 8 ? 'high' : score >= 4 ? 'medium' : 'low'}" style="border: 1px solid #dee2e6; padding: 8px; text-align: center; vertical-align: top;">${score}</td>
|
|
1511
|
+
</tr>
|
|
1512
|
+
`;
|
|
1513
|
+
}).join('');
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
// Copy operator to clipboard
|
|
1517
|
+
function copyOperatorToClipboard(operatorName) {
|
|
1518
|
+
navigator.clipboard.writeText(operatorName).then(() => {
|
|
1519
|
+
showNotification(`Copied "${operatorName}" to clipboard`, 'success');
|
|
1520
|
+
}).catch(() => {
|
|
1521
|
+
showNotification('Failed to copy to clipboard', 'error');
|
|
1522
|
+
});
|
|
1523
|
+
}
|
|
1524
|
+
|
|
1525
|
+
// Export modal results
|
|
1526
|
+
function exportModalResults() {
|
|
1527
|
+
const data = modalEvaluationResults.map(result => ({
|
|
1528
|
+
operator: result.operator_name,
|
|
1529
|
+
category: result.category,
|
|
1530
|
+
score: result.score,
|
|
1531
|
+
reason: result.reason,
|
|
1532
|
+
description: result.description
|
|
1533
|
+
}));
|
|
1534
|
+
|
|
1535
|
+
const blob = new Blob([JSON.stringify(data, null, 2)], { type: 'application/json' });
|
|
1536
|
+
const url = URL.createObjectURL(blob);
|
|
1537
|
+
const a = document.createElement('a');
|
|
1538
|
+
a.href = url;
|
|
1539
|
+
a.download = `operator_suggestions_step_${currentStep}.json`;
|
|
1540
|
+
a.click();
|
|
1541
|
+
URL.revokeObjectURL(url);
|
|
1542
|
+
|
|
1543
|
+
showNotification('Results exported successfully', 'success');
|
|
1544
|
+
}
|
|
1545
|
+
|
|
1546
|
+
|
|
1547
|
+
|
|
1548
|
+
// Close operator suggestions modal
|
|
1549
|
+
function closeOperatorSuggestionsModal() {
|
|
1550
|
+
document.getElementById('operatorSuggestionsModal').style.display = 'none';
|
|
1551
|
+
currentOperatorModalIndex = -1;
|
|
1552
|
+
modalEvaluationResults = [];
|
|
1553
|
+
}
|
|
1554
|
+
|
|
1555
|
+
// Convert markdown to HTML for better display (like inspiration_house.js)
|
|
1556
|
+
function convertMarkdownToHTML(text) {
|
|
1557
|
+
if (!text) return '';
|
|
1558
|
+
|
|
1559
|
+
return text
|
|
1560
|
+
// Bold text: **text** -> <strong>text</strong>
|
|
1561
|
+
.replace(/\*\*(.*?)\*\*/g, '<strong>$1</strong>')
|
|
1562
|
+
// Italic text: *text* -> <em>text</em>
|
|
1563
|
+
.replace(/\*(.*?)\*/g, '<em>$1</em>')
|
|
1564
|
+
// Code: `text` -> <code>text</code>
|
|
1565
|
+
.replace(/`(.*?)`/g, '<code>$1</code>')
|
|
1566
|
+
// Headers: ### text -> <h4>text</h4>
|
|
1567
|
+
.replace(/^### (.+)$/gm, '<h4>$1</h4>')
|
|
1568
|
+
.replace(/^## (.+)$/gm, '<h3>$1</h3>')
|
|
1569
|
+
.replace(/^# (.+)$/gm, '<h2>$1</h2>')
|
|
1570
|
+
// Lists: - item -> <li>item</li>
|
|
1571
|
+
.replace(/^- (.+)$/gm, '<li>$1</li>')
|
|
1572
|
+
// Numbered lists: 1. item -> <li>item</li>
|
|
1573
|
+
.replace(/^(\d+)\. (.+)$/gm, '<li>$2</li>')
|
|
1574
|
+
// Line breaks: \n -> <br>
|
|
1575
|
+
.replace(/\n/g, '<br>')
|
|
1576
|
+
// Escape HTML characters
|
|
1577
|
+
.replace(/&/g, '&')
|
|
1578
|
+
.replace(/</g, '<')
|
|
1579
|
+
.replace(/>/g, '>')
|
|
1580
|
+
// Restore our HTML tags
|
|
1581
|
+
.replace(/<strong>/g, '<strong>')
|
|
1582
|
+
.replace(/<\/strong>/g, '</strong>')
|
|
1583
|
+
.replace(/<em>/g, '<em>')
|
|
1584
|
+
.replace(/<\/em>/g, '</em>')
|
|
1585
|
+
.replace(/<code>/g, '<code>')
|
|
1586
|
+
.replace(/<\/code>/g, '</code>')
|
|
1587
|
+
.replace(/<br>/g, '<br>')
|
|
1588
|
+
.replace(/<h[234]>/g, '<$1>')
|
|
1589
|
+
.replace(/<\/h[234]>/g, '</$1>')
|
|
1590
|
+
.replace(/<li>/g, '<li>')
|
|
1591
|
+
.replace(/<\/li>/g, '</li>');
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1594
|
+
// Get fallback operators list (when BRAIN is not connected)
|
|
1595
|
+
function getFallbackOperators() {
|
|
1596
|
+
return [
|
|
1597
|
+
// Basic Arithmetic & Mathematical Operations
|
|
1598
|
+
{ name: 'add', category: 'Basic Arithmetic & Mathematical Operations', description: 'Add two values' },
|
|
1599
|
+
{ name: 'subtract', category: 'Basic Arithmetic & Mathematical Operations', description: 'Subtract two values' },
|
|
1600
|
+
{ name: 'multiply', category: 'Basic Arithmetic & Mathematical Operations', description: 'Multiply two values' },
|
|
1601
|
+
{ name: 'divide', category: 'Basic Arithmetic & Mathematical Operations', description: 'Divide two values' },
|
|
1602
|
+
{ name: 'exp', category: 'Basic Arithmetic & Mathematical Operations', description: 'Exponential function' },
|
|
1603
|
+
{ name: 'log', category: 'Basic Arithmetic & Mathematical Operations', description: 'Natural logarithm' },
|
|
1604
|
+
{ name: 'abs', category: 'Basic Arithmetic & Mathematical Operations', description: 'Absolute value' },
|
|
1605
|
+
{ name: 'power', category: 'Basic Arithmetic & Mathematical Operations', description: 'Raise to power' },
|
|
1606
|
+
{ name: 'sqrt', category: 'Basic Arithmetic & Mathematical Operations', description: 'Square root' },
|
|
1607
|
+
|
|
1608
|
+
// Time Series Operations
|
|
1609
|
+
{ name: 'ts_mean', category: 'Time Series: Statistical Feature Engineering', description: 'Rolling mean over time' },
|
|
1610
|
+
{ name: 'ts_std_dev', category: 'Time Series: Statistical Feature Engineering', description: 'Rolling standard deviation' },
|
|
1611
|
+
{ name: 'ts_rank', category: 'Time Series: Ranking, Scaling, and Normalization', description: 'Rolling rank over time' },
|
|
1612
|
+
{ name: 'ts_scale', category: 'Time Series: Ranking, Scaling, and Normalization', description: 'Rolling scaling over time' },
|
|
1613
|
+
{ name: 'ts_delta', category: 'Time Series: Change Detection & Value Comparison', description: 'Time series difference' },
|
|
1614
|
+
{ name: 'ts_returns', category: 'Time Series: Change Detection & Value Comparison', description: 'Time series returns' },
|
|
1615
|
+
{ name: 'ts_min', category: 'Time Series: Extremes & Position Identification', description: 'Rolling minimum' },
|
|
1616
|
+
{ name: 'ts_max', category: 'Time Series: Extremes & Position Identification', description: 'Rolling maximum' },
|
|
1617
|
+
{ name: 'ts_decay_exp_window', category: 'Time Series: Decay, Smoothing, and Turnover Control', description: 'Exponential decay' },
|
|
1618
|
+
|
|
1619
|
+
// Cross-Sectional Operations
|
|
1620
|
+
{ name: 'rank', category: 'Cross-Sectional: Ranking, Scaling, and Normalization', description: 'Cross-sectional rank' },
|
|
1621
|
+
{ name: 'zscore', category: 'Cross-Sectional: Ranking, Scaling, and Normalization', description: 'Cross-sectional z-score' },
|
|
1622
|
+
{ name: 'scale', category: 'Cross-Sectional: Ranking, Scaling, and Normalization', description: 'Cross-sectional scaling' },
|
|
1623
|
+
{ name: 'normalize', category: 'Cross-Sectional: Ranking, Scaling, and Normalization', description: 'Cross-sectional normalization' },
|
|
1624
|
+
{ name: 'regression_neut', category: 'Cross-Sectional: Regression & Neutralization', description: 'Regression neutralization' },
|
|
1625
|
+
{ name: 'vector_neut', category: 'Cross-Sectional: Regression & Neutralization', description: 'Vector neutralization' },
|
|
1626
|
+
{ name: 'quantile', category: 'Cross-Sectional: Distributional Transformation & Truncation', description: 'Quantile transformation' },
|
|
1627
|
+
{ name: 'winsorize', category: 'Cross-Sectional: Distributional Transformation & Truncation', description: 'Winsorize outliers' },
|
|
1628
|
+
|
|
1629
|
+
// Logical & Conditional Operations
|
|
1630
|
+
{ name: 'if_else', category: 'Logical & Conditional Operations', description: 'Conditional value assignment' },
|
|
1631
|
+
{ name: 'equal', category: 'Logical & Conditional Operations', description: 'Equality comparison' },
|
|
1632
|
+
{ name: 'greater', category: 'Logical & Conditional Operations', description: 'Greater than comparison' },
|
|
1633
|
+
{ name: 'less', category: 'Logical & Conditional Operations', description: 'Less than comparison' },
|
|
1634
|
+
|
|
1635
|
+
// Group Operations
|
|
1636
|
+
{ name: 'group_mean', category: 'Group Aggregation & Statistical Summary', description: 'Group mean aggregation' },
|
|
1637
|
+
{ name: 'group_rank', category: 'Group Ranking, Scaling, and Normalization', description: 'Group ranking' },
|
|
1638
|
+
{ name: 'group_scale', category: 'Group Ranking, Scaling, and Normalization', description: 'Group scaling' },
|
|
1639
|
+
{ name: 'group_vector_neut', category: 'Group Regression & Neutralization', description: 'Group vector neutralization' },
|
|
1640
|
+
|
|
1641
|
+
// Transformational & Filtering Operations
|
|
1642
|
+
{ name: 'filter', category: 'Transformational & Filtering Operations', description: 'Filter data' },
|
|
1643
|
+
{ name: 'clamp', category: 'Transformational & Filtering Operations', description: 'Clamp values to range' },
|
|
1644
|
+
{ name: 'keep', category: 'Transformational & Filtering Operations', description: 'Keep specific values' }
|
|
1645
|
+
];
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1648
|
+
// Function to refresh operators after BRAIN connection
|
|
1649
|
+
function refreshOperatorsAfterBrainLogin() {
|
|
1650
|
+
const storedOperators = sessionStorage.getItem('brainOperators');
|
|
1651
|
+
if (storedOperators) {
|
|
1652
|
+
try {
|
|
1653
|
+
const operators = JSON.parse(storedOperators);
|
|
1654
|
+
if (operators.length > 0) {
|
|
1655
|
+
// Hide BRAIN connection notice
|
|
1656
|
+
document.getElementById('modalBrainNotice').style.display = 'none';
|
|
1657
|
+
showNotification(`Successfully loaded ${operators.length} operators from BRAIN`, 'success');
|
|
1658
|
+
|
|
1659
|
+
// Reopen the operator suggestions modal with BRAIN operators
|
|
1660
|
+
setTimeout(() => {
|
|
1661
|
+
openOperatorSuggestions(currentOperatorModalIndex);
|
|
1662
|
+
}, 1000);
|
|
1663
|
+
}
|
|
1664
|
+
} catch (error) {
|
|
1665
|
+
console.error('Error parsing stored operators:', error);
|
|
1666
|
+
}
|
|
1667
|
+
}
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
// Override the original authenticateBrain function to refresh operators
|
|
1671
|
+
const originalAuthenticateBrain = window.authenticateBrain;
|
|
1672
|
+
window.authenticateBrain = async function() {
|
|
1673
|
+
if (originalAuthenticateBrain) {
|
|
1674
|
+
await originalAuthenticateBrain();
|
|
1675
|
+
// Load operators after successful authentication
|
|
1676
|
+
setTimeout(async () => {
|
|
1677
|
+
const operators = await loadOperatorsFromBRAIN();
|
|
1678
|
+
if (operators.length > 0) {
|
|
1679
|
+
refreshOperatorsAfterBrainLogin();
|
|
1680
|
+
}
|
|
1681
|
+
}, 2000);
|
|
1682
|
+
}
|
|
1683
|
+
};
|
|
1684
|
+
|
|
1685
|
+
// Function to load operators from BRAIN (similar to inspiration_house.js)
|
|
1686
|
+
async function loadOperatorsFromBRAIN() {
|
|
1687
|
+
try {
|
|
1688
|
+
// Get session ID from localStorage
|
|
1689
|
+
const sessionId = localStorage.getItem('brain_session_id');
|
|
1690
|
+
if (!sessionId) {
|
|
1691
|
+
showNotification('Please connect to BRAIN first to load operators', 'warning');
|
|
1692
|
+
return [];
|
|
1693
|
+
}
|
|
1694
|
+
|
|
1695
|
+
const response = await fetch('/api/operators', {
|
|
1696
|
+
headers: {
|
|
1697
|
+
'Session-ID': sessionId
|
|
1698
|
+
}
|
|
1699
|
+
});
|
|
1700
|
+
const data = await response.json();
|
|
1701
|
+
|
|
1702
|
+
if (response.ok && Array.isArray(data)) {
|
|
1703
|
+
const operators = data;
|
|
1704
|
+
sessionStorage.setItem('brainOperators', JSON.stringify(operators));
|
|
1705
|
+
console.log(`Loaded ${operators.length} operators from BRAIN`);
|
|
1706
|
+
showNotification(`Loaded ${operators.length} operators from BRAIN`, 'success');
|
|
1707
|
+
return operators;
|
|
1708
|
+
} else {
|
|
1709
|
+
console.error('Failed to load operators:', data.error);
|
|
1710
|
+
if (data.error && data.error.includes('Invalid or expired session')) {
|
|
1711
|
+
showNotification('Please connect to BRAIN first to load operators', 'warning');
|
|
1712
|
+
} else {
|
|
1713
|
+
showNotification('Failed to load operators from BRAIN', 'error');
|
|
1714
|
+
}
|
|
1715
|
+
return [];
|
|
1716
|
+
}
|
|
1717
|
+
} catch (error) {
|
|
1718
|
+
console.error('Error loading operators:', error);
|
|
1719
|
+
showNotification('Error connecting to BRAIN API', 'error');
|
|
1720
|
+
return [];
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
|
|
1724
|
+
// Make functions global for onclick handlers
|
|
1725
|
+
window.openOperatorSuggestions = openOperatorSuggestions;
|
|
1726
|
+
window.closeOperatorSuggestionsModal = closeOperatorSuggestionsModal;
|
|
1727
|
+
window.copyOperatorToClipboard = copyOperatorToClipboard;
|
|
1728
|
+
window.openBrainLoginModal = openBrainLoginModal;
|
|
1729
|
+
window.closeBrainLoginModal = closeBrainLoginModal;
|