cnhkmcp 2.1.2__py3-none-any.whl → 2.1.3__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.
Files changed (113) hide show
  1. {cnhkmcp-2.1.2.dist-info → cnhkmcp-2.1.3.dist-info}/METADATA +1 -1
  2. cnhkmcp-2.1.3.dist-info/RECORD +6 -0
  3. cnhkmcp-2.1.3.dist-info/top_level.txt +1 -0
  4. cnhkmcp/__init__.py +0 -125
  5. 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 +0 -38
  6. 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
  7. 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 +0 -6
  8. 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 +0 -1510
  9. 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 +0 -157
  10. 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 +0 -132
  11. 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 +0 -99
  12. 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 +0 -180
  13. 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
  14. 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
  15. 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 +0 -1
  16. 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 +0 -576
  17. 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 +0 -281
  18. 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 +0 -408
  19. 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 +0 -7
  20. 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 +0 -3
  21. 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 +0 -265
  22. cnhkmcp/untracked/APP/.gitignore +0 -32
  23. cnhkmcp/untracked/APP/MODULAR_STRUCTURE.md +0 -112
  24. cnhkmcp/untracked/APP/README.md +0 -309
  25. cnhkmcp/untracked/APP/Tranformer/Transformer.py +0 -4985
  26. cnhkmcp/untracked/APP/Tranformer/ace.log +0 -0
  27. cnhkmcp/untracked/APP/Tranformer/ace_lib.py +0 -1510
  28. cnhkmcp/untracked/APP/Tranformer/helpful_functions.py +0 -180
  29. cnhkmcp/untracked/APP/Tranformer/output/Alpha_candidates.json +0 -2421
  30. cnhkmcp/untracked/APP/Tranformer/output/Alpha_candidates_/321/207/320/264/342/225/221/321/204/342/225/233/320/233.json +0 -654
  31. cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_error.json +0 -1034
  32. cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_success.json +0 -444
  33. 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 +0 -22
  34. cnhkmcp/untracked/APP/Tranformer/parsetab.py +0 -60
  35. cnhkmcp/untracked/APP/Tranformer/template_summary.txt +0 -3182
  36. cnhkmcp/untracked/APP/Tranformer/transformer_config.json +0 -7
  37. cnhkmcp/untracked/APP/Tranformer/validator.py +0 -889
  38. cnhkmcp/untracked/APP/ace.log +0 -69
  39. cnhkmcp/untracked/APP/ace_lib.py +0 -1510
  40. cnhkmcp/untracked/APP/blueprints/__init__.py +0 -6
  41. cnhkmcp/untracked/APP/blueprints/feature_engineering.py +0 -347
  42. cnhkmcp/untracked/APP/blueprints/idea_house.py +0 -221
  43. cnhkmcp/untracked/APP/blueprints/inspiration_house.py +0 -432
  44. cnhkmcp/untracked/APP/blueprints/paper_analysis.py +0 -570
  45. cnhkmcp/untracked/APP/custom_templates/templates.json +0 -1257
  46. cnhkmcp/untracked/APP/give_me_idea/BRAIN_Alpha_Template_Expert_SystemPrompt.md +0 -400
  47. cnhkmcp/untracked/APP/give_me_idea/ace_lib.py +0 -1510
  48. cnhkmcp/untracked/APP/give_me_idea/alpha_data_specific_template_master.py +0 -252
  49. cnhkmcp/untracked/APP/give_me_idea/fetch_all_datasets.py +0 -157
  50. cnhkmcp/untracked/APP/give_me_idea/fetch_all_operators.py +0 -99
  51. cnhkmcp/untracked/APP/give_me_idea/helpful_functions.py +0 -180
  52. cnhkmcp/untracked/APP/give_me_idea/what_is_Alpha_template.md +0 -11
  53. cnhkmcp/untracked/APP/helpful_functions.py +0 -180
  54. cnhkmcp/untracked/APP/hkSimulator/ace_lib.py +0 -1497
  55. cnhkmcp/untracked/APP/hkSimulator/autosimulator.py +0 -447
  56. cnhkmcp/untracked/APP/hkSimulator/helpful_functions.py +0 -180
  57. cnhkmcp/untracked/APP/mirror_config.txt +0 -20
  58. cnhkmcp/untracked/APP/operaters.csv +0 -129
  59. cnhkmcp/untracked/APP/requirements.txt +0 -53
  60. cnhkmcp/untracked/APP/run_app.bat +0 -28
  61. cnhkmcp/untracked/APP/run_app.sh +0 -34
  62. cnhkmcp/untracked/APP/setup_tsinghua.bat +0 -39
  63. cnhkmcp/untracked/APP/setup_tsinghua.sh +0 -43
  64. cnhkmcp/untracked/APP/simulator/alpha_submitter.py +0 -404
  65. cnhkmcp/untracked/APP/simulator/simulator_wqb.py +0 -618
  66. cnhkmcp/untracked/APP/ssrn-3332513.pdf +6 -109201
  67. cnhkmcp/untracked/APP/static/brain.js +0 -589
  68. cnhkmcp/untracked/APP/static/decoder.js +0 -1540
  69. cnhkmcp/untracked/APP/static/feature_engineering.js +0 -1729
  70. cnhkmcp/untracked/APP/static/idea_house.js +0 -937
  71. cnhkmcp/untracked/APP/static/inspiration.js +0 -465
  72. cnhkmcp/untracked/APP/static/inspiration_house.js +0 -868
  73. cnhkmcp/untracked/APP/static/paper_analysis.js +0 -390
  74. cnhkmcp/untracked/APP/static/script.js +0 -3082
  75. cnhkmcp/untracked/APP/static/simulator.js +0 -597
  76. cnhkmcp/untracked/APP/static/styles.css +0 -3127
  77. cnhkmcp/untracked/APP/static/usage_widget.js +0 -508
  78. cnhkmcp/untracked/APP/templates/alpha_inspector.html +0 -511
  79. cnhkmcp/untracked/APP/templates/feature_engineering.html +0 -960
  80. cnhkmcp/untracked/APP/templates/idea_house.html +0 -564
  81. cnhkmcp/untracked/APP/templates/index.html +0 -932
  82. cnhkmcp/untracked/APP/templates/inspiration_house.html +0 -861
  83. cnhkmcp/untracked/APP/templates/paper_analysis.html +0 -91
  84. cnhkmcp/untracked/APP/templates/simulator.html +0 -343
  85. cnhkmcp/untracked/APP/templates/transformer_web.html +0 -580
  86. cnhkmcp/untracked/APP/usage.md +0 -351
  87. 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 +0 -1510
  88. 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 +0 -712
  89. 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 +0 -180
  90. 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 +0 -2456
  91. cnhkmcp/untracked/arXiv_API_Tool_Manual.md +0 -490
  92. cnhkmcp/untracked/arxiv_api.py +0 -229
  93. cnhkmcp/untracked/forum_functions.py +0 -998
  94. 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 +0 -407
  95. 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 +0 -2415
  96. 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 +0 -31
  97. 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 +0 -101
  98. 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 +0 -190
  99. cnhkmcp/untracked/platform_functions.py +0 -2886
  100. cnhkmcp/untracked/sample_mcp_config.json +0 -11
  101. cnhkmcp/untracked/user_config.json +0 -31
  102. 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 +0 -202
  103. 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 +0 -56
  104. 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 +0 -194
  105. 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 +0 -101
  106. 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 +0 -436
  107. 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 +0 -128
  108. 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 +0 -190
  109. cnhkmcp-2.1.2.dist-info/RECORD +0 -111
  110. cnhkmcp-2.1.2.dist-info/top_level.txt +0 -1
  111. {cnhkmcp-2.1.2.dist-info → cnhkmcp-2.1.3.dist-info}/WHEEL +0 -0
  112. {cnhkmcp-2.1.2.dist-info → cnhkmcp-2.1.3.dist-info}/entry_points.txt +0 -0
  113. {cnhkmcp-2.1.2.dist-info → cnhkmcp-2.1.3.dist-info}/licenses/LICENSE +0 -0
@@ -1,589 +0,0 @@
1
- /**
2
- * BRAIN API Integration Module
3
- * Handles authentication, operators, and data fields from WorldQuant BRAIN
4
- * Now uses a local Python proxy server to bypass CORS restrictions
5
- */
6
-
7
- // BRAIN session and data storage
8
- let brainSession = null;
9
- let brainOperators = null;
10
- let brainDataFields = null;
11
- let brainSessionId = localStorage.getItem('brain_session_id');
12
-
13
- // Flask app API endpoints
14
- const PROXY_BASE = '';
15
-
16
- async function readJsonOrText(response) {
17
- const contentType = (response.headers && response.headers.get('content-type')) || '';
18
- const rawText = await response.text();
19
- const looksJson = contentType.includes('application/json') || rawText.trim().startsWith('{') || rawText.trim().startsWith('[');
20
-
21
- if (looksJson) {
22
- try {
23
- return { ok: true, data: JSON.parse(rawText), rawText };
24
- } catch (e) {
25
- return { ok: false, data: null, rawText };
26
- }
27
- }
28
-
29
- return { ok: false, data: null, rawText };
30
- }
31
-
32
- // Open BRAIN login modal
33
- function openBrainLoginModal() {
34
- const modal = document.getElementById('brainLoginModal');
35
- const statusDiv = document.getElementById('brainLoginStatus');
36
- statusDiv.innerHTML = '';
37
- statusDiv.className = 'login-status';
38
-
39
- // Clear previous inputs
40
- document.getElementById('brainUsername').value = '';
41
- document.getElementById('brainPassword').value = '';
42
-
43
- modal.style.display = 'block';
44
- document.getElementById('brainUsername').focus();
45
- }
46
-
47
- // Close BRAIN login modal
48
- function closeBrainLoginModal() {
49
- const modal = document.getElementById('brainLoginModal');
50
- const loginBtn = document.getElementById('loginBtn');
51
-
52
- // Don't allow closing if login is in progress
53
- if (loginBtn.disabled) {
54
- return;
55
- }
56
-
57
- // Clean up any biometric authentication buttons
58
- const statusDiv = document.getElementById('brainLoginStatus');
59
- const completeBtn = statusDiv.querySelector('button');
60
- if (completeBtn) {
61
- completeBtn.remove();
62
- }
63
-
64
- modal.style.display = 'none';
65
- }
66
-
67
- // Authenticate with BRAIN via proxy server
68
- async function authenticateBrain() {
69
- const username = document.getElementById('brainUsername').value.trim();
70
- const password = document.getElementById('brainPassword').value;
71
- const statusDiv = document.getElementById('brainLoginStatus');
72
- const loginBtn = document.getElementById('loginBtn');
73
- const spinner = document.getElementById('loginSpinner');
74
- const modal = document.getElementById('brainLoginModal');
75
-
76
- if (!username || !password) {
77
- showLoginStatus('Please enter both username and password.', 'error');
78
- return;
79
- }
80
-
81
- // Disable all inputs and buttons
82
- document.getElementById('brainUsername').disabled = true;
83
- document.getElementById('brainPassword').disabled = true;
84
- document.getElementById('cancelBtn').disabled = true;
85
- loginBtn.disabled = true;
86
- loginBtn.textContent = 'Connecting...';
87
-
88
- // Show spinner
89
- spinner.style.display = 'block';
90
-
91
- // Disable modal closing
92
- modal.querySelector('.close').style.display = 'none';
93
-
94
- // Show loading state
95
- showLoginStatus('Connecting to proxy server...', 'loading');
96
-
97
- try {
98
- showLoginStatus('Authenticating with BRAIN...', 'loading');
99
-
100
- // Authenticate via proxy server
101
- const authResponse = await fetch(`${PROXY_BASE}/api/authenticate`, {
102
- method: 'POST',
103
- headers: {
104
- 'Content-Type': 'application/json'
105
- },
106
- body: JSON.stringify({
107
- username: username,
108
- password: password
109
- })
110
- });
111
-
112
- const parsed = await readJsonOrText(authResponse);
113
- const authData = parsed.data || {};
114
-
115
- // If backend returned HTML (or otherwise non-JSON), show a helpful message
116
- if (!parsed.ok) {
117
- const status = authResponse.status;
118
- if (status === 404) {
119
- throw new Error('登录接口不存在(/api/authenticate 404)。请确认后端服务正在运行且页面没有被反向代理到别处。');
120
- }
121
- if (status === 401) {
122
- throw new Error('用户名或密码错误(401)。');
123
- }
124
- // Common symptom: Flask 500 HTML error page
125
- throw new Error(`登录失败(HTTP ${status})。后端返回了非JSON内容,通常表示后端异常或被重定向到HTML页面。请查看后端控制台日志。`);
126
- }
127
-
128
- // Check if biometric authentication is required
129
- if (authData.requires_biometric) {
130
- showLoginStatus('Biometric authentication required. Opening BRAIN website...', 'loading');
131
-
132
- // Open biometric URL in new tab
133
- window.open(authData.biometric_url, '_blank');
134
-
135
- // Store the session ID for biometric completion
136
- brainSessionId = authData.session_id;
137
- localStorage.setItem('brain_session_id', brainSessionId);
138
-
139
- showLoginStatus('Please complete biometric authentication in the new tab, then click "Complete Authentication" below.', 'info');
140
-
141
- // Show complete authentication button
142
- const completeBtn = document.createElement('button');
143
- completeBtn.textContent = 'Complete Authentication';
144
- completeBtn.className = 'btn btn-secondary';
145
- completeBtn.style.marginTop = '10px';
146
- completeBtn.onclick = completeBiometricAuth;
147
-
148
- const statusDiv = document.getElementById('brainLoginStatus');
149
- statusDiv.appendChild(completeBtn);
150
-
151
- return;
152
- }
153
-
154
- if (!authResponse.ok) {
155
- // Provide clearer message on credential errors
156
- if (authResponse.status === 401) {
157
- throw new Error(authData.error || '用户名或密码错误(401)。');
158
- }
159
- throw new Error(authData.error || 'Authentication failed');
160
- }
161
-
162
- brainSessionId = authData.session_id;
163
- brainSession = { authenticated: true, username: username };
164
-
165
- // Store simulation options if available
166
- if (authData.options && typeof simulationOptions !== 'undefined') {
167
- simulationOptions = authData.options;
168
- console.log("Loaded simulation options:", simulationOptions);
169
- }
170
-
171
- // Store session ID in localStorage for other pages
172
- localStorage.setItem('brain_session_id', brainSessionId);
173
-
174
- // Fetch operators immediately for "Op" button functionality
175
- showLoginStatus('Loading operators...', 'loading');
176
- brainOperators = await getUserOperators();
177
-
178
- // Store operators in sessionStorage for other pages (like Inspiration House)
179
- sessionStorage.setItem('brainOperators', JSON.stringify(brainOperators));
180
-
181
- // Update UI to show connected state
182
- updateConnectedState();
183
- showLoginStatus(`Successfully connected! Loaded ${brainOperators.length} operators.`, 'success');
184
-
185
- // Update Inspiration Button State
186
- if (window.updateInspirationButtonState) {
187
- window.updateInspirationButtonState();
188
- }
189
-
190
- // Disable buttons to prevent further clicks
191
- loginBtn.disabled = true;
192
- document.getElementById('brainUsername').disabled = true;
193
- document.getElementById('brainPassword').disabled = true;
194
-
195
- // Close modal after a short delay
196
- setTimeout(() => {
197
- // Re-enable everything before closing
198
- document.getElementById('brainUsername').disabled = false;
199
- document.getElementById('brainPassword').disabled = false;
200
- document.getElementById('cancelBtn').disabled = false;
201
- loginBtn.disabled = false;
202
- loginBtn.textContent = 'Connect';
203
- spinner.style.display = 'none';
204
- modal.querySelector('.close').style.display = 'block';
205
-
206
- closeBrainLoginModal();
207
- }, 1500);
208
-
209
- } catch (error) {
210
- console.error('BRAIN authentication failed:', error);
211
- showLoginStatus(`Connection failed: ${error.message}`, 'error');
212
- brainSession = null;
213
- brainSessionId = null;
214
- } finally {
215
- // Re-enable everything
216
- document.getElementById('brainUsername').disabled = false;
217
- document.getElementById('brainPassword').disabled = false;
218
- document.getElementById('cancelBtn').disabled = false;
219
- loginBtn.disabled = false;
220
- loginBtn.textContent = 'Connect';
221
- spinner.style.display = 'none';
222
- modal.querySelector('.close').style.display = 'block';
223
- }
224
- }
225
-
226
- // Complete biometric authentication
227
- async function completeBiometricAuth() {
228
- const statusDiv = document.getElementById('brainLoginStatus');
229
-
230
- try {
231
- showLoginStatus('Verifying biometric authentication...', 'loading');
232
-
233
- const response = await fetch(`${PROXY_BASE}/api/complete-biometric`, {
234
- method: 'POST',
235
- headers: {
236
- 'Session-ID': brainSessionId
237
- }
238
- });
239
-
240
- const data = await response.json();
241
-
242
- if (data.success) {
243
- brainSessionId = data.session_id;
244
- brainSession = { authenticated: true };
245
- localStorage.setItem('brain_session_id', brainSessionId);
246
-
247
- // Fetch operators
248
- showLoginStatus('Loading operators...', 'loading');
249
- brainOperators = await getUserOperators();
250
-
251
- // Store operators in sessionStorage for other pages (like Inspiration House)
252
- sessionStorage.setItem('brainOperators', JSON.stringify(brainOperators));
253
-
254
- // Update UI
255
- updateConnectedState();
256
- showLoginStatus(`Successfully connected! Loaded ${brainOperators.length} operators.`, 'success');
257
-
258
- // Close modal after delay
259
- setTimeout(() => {
260
- closeBrainLoginModal();
261
- }, 1500);
262
- } else {
263
- showLoginStatus(`Biometric verification failed: ${data.error}`, 'error');
264
- }
265
-
266
- } catch (error) {
267
- console.error('Biometric completion failed:', error);
268
- showLoginStatus(`Biometric verification failed: ${error.message}`, 'error');
269
- }
270
- }
271
-
272
- // Get user operators via proxy server
273
- async function getUserOperators() {
274
- if (!brainSession || !brainSessionId) {
275
- throw new Error('Not authenticated with BRAIN');
276
- }
277
-
278
- try {
279
- const response = await fetch(`${PROXY_BASE}/api/operators`, {
280
- method: 'GET',
281
- headers: {
282
- 'Session-ID': brainSessionId
283
- }
284
- });
285
-
286
- if (!response.ok) {
287
- const errorData = await response.json();
288
- throw new Error(errorData.error || 'Failed to fetch operators');
289
- }
290
-
291
- const operators = await response.json();
292
- console.log(`Received ${operators.length} operators from BRAIN API`);
293
-
294
- // Log the categories to verify we have all operator types
295
- const categories = [...new Set(operators.map(op => op.category))].sort();
296
- console.log(`Operator categories: ${categories.join(', ')}`);
297
-
298
- return operators;
299
-
300
- } catch (error) {
301
- console.error('Failed to fetch operators:', error);
302
- throw error;
303
- }
304
- }
305
-
306
- // Get data fields via proxy server
307
- async function getDatasets(region = 'USA', delay = 1, universe = 'TOP3000') {
308
- if (!brainSession || !brainSessionId) {
309
- throw new Error('Not authenticated with BRAIN');
310
- }
311
-
312
- try {
313
- const params = new URLSearchParams({
314
- region: region,
315
- delay: delay.toString(),
316
- universe: universe
317
- });
318
-
319
- const response = await fetch(`${PROXY_BASE}/api/datasets?${params}`, {
320
- method: 'GET',
321
- headers: {
322
- 'Session-ID': brainSessionId
323
- }
324
- });
325
-
326
- if (!response.ok) {
327
- const errorData = await response.json();
328
- throw new Error(errorData.error || 'Failed to fetch datasets');
329
- }
330
-
331
- const data = await response.json();
332
- return data.results || [];
333
-
334
- } catch (error) {
335
- console.error('Failed to fetch datasets:', error);
336
- throw error;
337
- }
338
- }
339
-
340
- async function getSimulationOptions() {
341
- if (!brainSession || !brainSessionId) {
342
- throw new Error('Not authenticated with BRAIN');
343
- }
344
-
345
- try {
346
- const response = await fetch(`${PROXY_BASE}/api/simulation-options`, {
347
- method: 'GET',
348
- headers: {
349
- 'Session-ID': brainSessionId
350
- }
351
- });
352
-
353
- if (!response.ok) {
354
- const errorData = await response.json();
355
- throw new Error(errorData.error || 'Failed to fetch simulation options');
356
- }
357
-
358
- return await response.json();
359
-
360
- } catch (error) {
361
- console.error('Failed to fetch simulation options:', error);
362
- throw error;
363
- }
364
- }
365
-
366
- async function getDataFields(region = 'USA', delay = 1, universe = 'TOP3000', datasetId = 'fundamental6') {
367
- if (!brainSession || !brainSessionId) {
368
- throw new Error('Not authenticated with BRAIN');
369
- }
370
-
371
- try {
372
- const params = new URLSearchParams({
373
- region: region,
374
- delay: delay.toString(),
375
- universe: universe,
376
- dataset_id: datasetId
377
- });
378
-
379
- const response = await fetch(`${PROXY_BASE}/api/datafields?${params}`, {
380
- method: 'GET',
381
- headers: {
382
- 'Session-ID': brainSessionId
383
- }
384
- });
385
-
386
- if (!response.ok) {
387
- const errorData = await response.json();
388
- throw new Error(errorData.error || 'Failed to fetch data fields');
389
- }
390
-
391
- return await response.json();
392
-
393
- } catch (error) {
394
- console.error('Failed to fetch data fields:', error);
395
- throw error;
396
- }
397
- }
398
-
399
- // Update UI to show connected state
400
- function updateConnectedState() {
401
- // Update connect button if it exists (main page)
402
- const connectBtn = document.getElementById('connectToBrain');
403
- if (connectBtn) {
404
- connectBtn.textContent = 'Connected to BRAIN';
405
- connectBtn.className = 'btn btn-brain connected';
406
- }
407
-
408
- // Show connection info in the grammar errors area if it exists (main page)
409
- const errorsDiv = document.getElementById('grammarErrors');
410
- if (errorsDiv) {
411
- errorsDiv.innerHTML = `<div class="success-message">
412
- ✓ Successfully connected to WorldQuant BRAIN<br>
413
- <strong>Username:</strong> ${brainSession.username}<br>
414
- <strong>Operators loaded:</strong> ${brainOperators ? brainOperators.length : 0}<br>
415
- <em>Data fields will be loaded when needed.</em>
416
- </div>`;
417
-
418
- // Auto-hide the message after 5 seconds
419
- setTimeout(() => {
420
- if (errorsDiv.innerHTML.includes('Successfully connected')) {
421
- errorsDiv.innerHTML = '';
422
- }
423
- }, 5000);
424
- }
425
- }
426
-
427
- // Show login status message
428
- function showLoginStatus(message, type) {
429
- const statusDiv = document.getElementById('brainLoginStatus');
430
- statusDiv.textContent = message;
431
- statusDiv.className = `login-status ${type}`;
432
- }
433
-
434
- // Check if connected to BRAIN
435
- function isConnectedToBrain() {
436
- return brainSession !== null && brainSessionId !== null;
437
- }
438
-
439
- // Get all available operators (fetch on-demand)
440
- async function getAllOperators() {
441
- if (!brainOperators && isConnectedToBrain()) {
442
- try {
443
- brainOperators = await getUserOperators();
444
- // Store operators in sessionStorage for other pages (like Inspiration House)
445
- sessionStorage.setItem('brainOperators', JSON.stringify(brainOperators));
446
- } catch (error) {
447
- console.error('Failed to fetch operators on-demand:', error);
448
- return [];
449
- }
450
- }
451
- return brainOperators || [];
452
- }
453
-
454
- // Get loaded operators synchronously (for UI components)
455
- function getLoadedOperators() {
456
- return brainOperators || [];
457
- }
458
-
459
- // Get all available data fields (fetch on-demand)
460
- async function getAllDataFields() {
461
- if (!brainDataFields && isConnectedToBrain()) {
462
- try {
463
- brainDataFields = await getDataFields();
464
- } catch (error) {
465
- console.error('Failed to fetch data fields on-demand:', error);
466
- return [];
467
- }
468
- }
469
- return brainDataFields || [];
470
- }
471
-
472
- // Get operators by category (with on-demand loading)
473
- async function getOperatorsByCategory(category) {
474
- const operators = await getAllOperators();
475
- return operators.filter(op => op.category === category);
476
- }
477
-
478
- // Search operators (with on-demand loading)
479
- async function searchOperators(searchTerm) {
480
- const operators = await getAllOperators();
481
- const term = searchTerm.toLowerCase();
482
- return operators.filter(op =>
483
- op.name.toLowerCase().includes(term) ||
484
- op.category.toLowerCase().includes(term)
485
- );
486
- }
487
-
488
- // Search data fields (with on-demand loading)
489
- async function searchDataFields(searchTerm) {
490
- const dataFields = await getAllDataFields();
491
- const term = searchTerm.toLowerCase();
492
- return dataFields.filter(field =>
493
- field.id.toLowerCase().includes(term) ||
494
- field.description.toLowerCase().includes(term)
495
- );
496
- }
497
-
498
- // Logout from BRAIN
499
- async function logoutFromBrain() {
500
- if (brainSessionId) {
501
- try {
502
- await fetch(`${PROXY_BASE}/api/logout`, {
503
- method: 'POST',
504
- headers: {
505
- 'Session-ID': brainSessionId
506
- }
507
- });
508
- } catch (error) {
509
- console.warn('Failed to logout from proxy server:', error);
510
- }
511
- }
512
-
513
- // Clear local session data
514
- brainSession = null;
515
- brainSessionId = null;
516
- brainOperators = null;
517
- brainDataFields = null;
518
-
519
- // Clear localStorage and sessionStorage
520
- localStorage.removeItem('brain_session_id');
521
- sessionStorage.removeItem('brainOperators');
522
-
523
- // Update UI
524
- const connectBtn = document.getElementById('connectToBrain');
525
- if (connectBtn) {
526
- connectBtn.textContent = 'Connect to BRAIN';
527
- connectBtn.className = 'btn btn-brain';
528
- }
529
- }
530
-
531
- // Check session validity on page load; optionally prompt to login immediately
532
- async function checkSessionValidity({ promptOnMissing = false } = {}) {
533
- if (brainSessionId) {
534
- try {
535
- const response = await fetch(`${PROXY_BASE}/api/status`, {
536
- method: 'GET',
537
- headers: {
538
- 'Session-ID': brainSessionId
539
- }
540
- });
541
-
542
- if (response.ok) {
543
- const data = await response.json();
544
- if (data.valid) {
545
- brainSession = { authenticated: true, username: data.username };
546
- // Update UI to show connected state
547
- updateConnectedState();
548
- } else {
549
- // Session expired, clear it
550
- localStorage.removeItem('brain_session_id');
551
- brainSessionId = null;
552
- }
553
- }
554
- } catch (error) {
555
- console.warn('Failed to check session validity:', error);
556
- }
557
- }
558
-
559
- // If requested, prompt the login modal when no valid session is present
560
- if (promptOnMissing && !isConnectedToBrain()) {
561
- openBrainLoginModal();
562
- }
563
- }
564
-
565
- // Initialize on page load
566
- document.addEventListener('DOMContentLoaded', () => checkSessionValidity({ promptOnMissing: true }));
567
-
568
- // Export functions for use in other modules
569
- window.brainAPI = {
570
- openBrainLoginModal,
571
- closeBrainLoginModal,
572
- authenticateBrain,
573
- isConnectedToBrain,
574
- getAllOperators,
575
- getAllDataFields,
576
- getDatasets,
577
- getSimulationOptions,
578
- getDataFields,
579
- getOperatorsByCategory,
580
- searchOperators,
581
- searchDataFields,
582
- logoutFromBrain,
583
- getLoadedOperators
584
- };
585
-
586
- // Also make key functions globally available for HTML onclick handlers
587
- window.openBrainLoginModal = openBrainLoginModal;
588
- window.closeBrainLoginModal = closeBrainLoginModal;
589
- window.authenticateBrain = authenticateBrain;