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.
- {cnhkmcp-2.1.2.dist-info → cnhkmcp-2.1.3.dist-info}/METADATA +1 -1
- cnhkmcp-2.1.3.dist-info/RECORD +6 -0
- cnhkmcp-2.1.3.dist-info/top_level.txt +1 -0
- cnhkmcp/__init__.py +0 -125
- 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
- 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 +0 -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/get_knowledgeBase_tool/ace_lib.py +0 -1510
- 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
- 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
- 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
- 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
- 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/test.txt +0 -1
- 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
- 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
- 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
- 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
- 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
- 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
- cnhkmcp/untracked/APP/.gitignore +0 -32
- cnhkmcp/untracked/APP/MODULAR_STRUCTURE.md +0 -112
- cnhkmcp/untracked/APP/README.md +0 -309
- cnhkmcp/untracked/APP/Tranformer/Transformer.py +0 -4985
- cnhkmcp/untracked/APP/Tranformer/ace.log +0 -0
- cnhkmcp/untracked/APP/Tranformer/ace_lib.py +0 -1510
- cnhkmcp/untracked/APP/Tranformer/helpful_functions.py +0 -180
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_candidates.json +0 -2421
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_candidates_/321/207/320/264/342/225/221/321/204/342/225/233/320/233.json +0 -654
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_error.json +0 -1034
- cnhkmcp/untracked/APP/Tranformer/output/Alpha_generated_expressions_success.json +0 -444
- 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
- cnhkmcp/untracked/APP/Tranformer/parsetab.py +0 -60
- cnhkmcp/untracked/APP/Tranformer/template_summary.txt +0 -3182
- cnhkmcp/untracked/APP/Tranformer/transformer_config.json +0 -7
- cnhkmcp/untracked/APP/Tranformer/validator.py +0 -889
- cnhkmcp/untracked/APP/ace.log +0 -69
- cnhkmcp/untracked/APP/ace_lib.py +0 -1510
- cnhkmcp/untracked/APP/blueprints/__init__.py +0 -6
- cnhkmcp/untracked/APP/blueprints/feature_engineering.py +0 -347
- cnhkmcp/untracked/APP/blueprints/idea_house.py +0 -221
- cnhkmcp/untracked/APP/blueprints/inspiration_house.py +0 -432
- cnhkmcp/untracked/APP/blueprints/paper_analysis.py +0 -570
- cnhkmcp/untracked/APP/custom_templates/templates.json +0 -1257
- cnhkmcp/untracked/APP/give_me_idea/BRAIN_Alpha_Template_Expert_SystemPrompt.md +0 -400
- cnhkmcp/untracked/APP/give_me_idea/ace_lib.py +0 -1510
- cnhkmcp/untracked/APP/give_me_idea/alpha_data_specific_template_master.py +0 -252
- cnhkmcp/untracked/APP/give_me_idea/fetch_all_datasets.py +0 -157
- cnhkmcp/untracked/APP/give_me_idea/fetch_all_operators.py +0 -99
- cnhkmcp/untracked/APP/give_me_idea/helpful_functions.py +0 -180
- cnhkmcp/untracked/APP/give_me_idea/what_is_Alpha_template.md +0 -11
- cnhkmcp/untracked/APP/helpful_functions.py +0 -180
- cnhkmcp/untracked/APP/hkSimulator/ace_lib.py +0 -1497
- cnhkmcp/untracked/APP/hkSimulator/autosimulator.py +0 -447
- cnhkmcp/untracked/APP/hkSimulator/helpful_functions.py +0 -180
- cnhkmcp/untracked/APP/mirror_config.txt +0 -20
- cnhkmcp/untracked/APP/operaters.csv +0 -129
- cnhkmcp/untracked/APP/requirements.txt +0 -53
- cnhkmcp/untracked/APP/run_app.bat +0 -28
- cnhkmcp/untracked/APP/run_app.sh +0 -34
- cnhkmcp/untracked/APP/setup_tsinghua.bat +0 -39
- cnhkmcp/untracked/APP/setup_tsinghua.sh +0 -43
- cnhkmcp/untracked/APP/simulator/alpha_submitter.py +0 -404
- cnhkmcp/untracked/APP/simulator/simulator_wqb.py +0 -618
- cnhkmcp/untracked/APP/ssrn-3332513.pdf +6 -109201
- cnhkmcp/untracked/APP/static/brain.js +0 -589
- cnhkmcp/untracked/APP/static/decoder.js +0 -1540
- cnhkmcp/untracked/APP/static/feature_engineering.js +0 -1729
- cnhkmcp/untracked/APP/static/idea_house.js +0 -937
- cnhkmcp/untracked/APP/static/inspiration.js +0 -465
- cnhkmcp/untracked/APP/static/inspiration_house.js +0 -868
- cnhkmcp/untracked/APP/static/paper_analysis.js +0 -390
- cnhkmcp/untracked/APP/static/script.js +0 -3082
- cnhkmcp/untracked/APP/static/simulator.js +0 -597
- cnhkmcp/untracked/APP/static/styles.css +0 -3127
- cnhkmcp/untracked/APP/static/usage_widget.js +0 -508
- cnhkmcp/untracked/APP/templates/alpha_inspector.html +0 -511
- cnhkmcp/untracked/APP/templates/feature_engineering.html +0 -960
- cnhkmcp/untracked/APP/templates/idea_house.html +0 -564
- cnhkmcp/untracked/APP/templates/index.html +0 -932
- cnhkmcp/untracked/APP/templates/inspiration_house.html +0 -861
- cnhkmcp/untracked/APP/templates/paper_analysis.html +0 -91
- cnhkmcp/untracked/APP/templates/simulator.html +0 -343
- cnhkmcp/untracked/APP/templates/transformer_web.html +0 -580
- cnhkmcp/untracked/APP/usage.md +0 -351
- 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
- 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
- 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
- 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
- cnhkmcp/untracked/arXiv_API_Tool_Manual.md +0 -490
- cnhkmcp/untracked/arxiv_api.py +0 -229
- cnhkmcp/untracked/forum_functions.py +0 -998
- 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
- 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
- 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
- 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
- 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
- cnhkmcp/untracked/platform_functions.py +0 -2886
- cnhkmcp/untracked/sample_mcp_config.json +0 -11
- cnhkmcp/untracked/user_config.json +0 -31
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- cnhkmcp-2.1.2.dist-info/RECORD +0 -111
- cnhkmcp-2.1.2.dist-info/top_level.txt +0 -1
- {cnhkmcp-2.1.2.dist-info → cnhkmcp-2.1.3.dist-info}/WHEEL +0 -0
- {cnhkmcp-2.1.2.dist-info → cnhkmcp-2.1.3.dist-info}/entry_points.txt +0 -0
- {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;
|