File size: 5,050 Bytes
e636070
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
// api-panel.js
class APIPanel {
    constructor() {
        // 初始化时从服务器获取配置
        this.init();
    }

    async init() {
        this.providerSelect = document.getElementById('api-provider');
        this.modelSelect = document.getElementById('api-model');
        this.keysContainer = document.querySelector('.api-keys-container');
        
        // 从服务器获取配置
        await this.fetchAPIConfigs();
        
        this.providerSelect.addEventListener('change', () => this.updateProviderUI());
        this.initAPIForm();
        this.updateProviderUI(); // 初始化UI
    }

    async fetchAPIConfigs() {
        try {
            // 发送WebSocket消息请求配置
            if (window.ws && window.ws.readyState === WebSocket.OPEN) {
                window.ws.send(JSON.stringify({
                    type: 'request_api_configs'
                }));
            }

            // 添加一次性事件监听器来接收配置
            await new Promise((resolve) => {
                const configHandler = (event) => {
                    const message = JSON.parse(event.data);
                    if (message.type === 'api_configs') {
                        this.modelConfigs = message.data;
                        window.removeEventListener('message', configHandler);
                        resolve();
                    }
                };
                window.ws.addEventListener('message', configHandler);
            });

            // 初始化提供商选择器
            this.initProviderSelect();
        } catch (error) {
            console.error('获取API配置失败:', error);
            // 使用默认配置作为后备
            this.modelConfigs = this.getDefaultConfigs();
            this.initProviderSelect();
        }
    }

    getDefaultConfigs() {
        // 默认配置作为后备
        return {
            openai: {
                label: 'OpenAI API Key',
                models: ['gpt-3.5-turbo', 'gpt-4'],
                envKey: 'OPENAI_API_KEY'
            },
            anthropic: {
                label: 'Claude API Key',
                models: ['claude-3-opus', 'claude-3-sonnet'],
                envKey: 'ANTHROPIC_API_KEY'
            }
        };
    }

    initProviderSelect() {
        this.providerSelect.innerHTML = Object.entries(this.modelConfigs)
            .map(([key, config]) => `
                <option value="${key}">${config.label.split(' API Key')[0]}</option>
            `)
            .join('');
    }

    updateProviderUI() {
        const provider = this.providerSelect.value;
        
        // 更新API密钥输入区域
        this.keysContainer.innerHTML = this.createKeyInput(
            this.modelConfigs[provider].label,
            this.modelConfigs[provider].envKey
        );

        // 更新模型选择器
        this.modelSelect.innerHTML = this.modelConfigs[provider].models
            .map(model => `<option value="${model}">${model}</option>`)
            .join('');
            
        // 为密码可见性切换添加事件监听
        const toggles = document.querySelectorAll('.toggle-visibility');
        toggles.forEach(toggle => {
            toggle.addEventListener('click', (e) => {
                const input = e.target.previousElementSibling;
                const type = input.type === 'password' ? 'text' : 'password';
                input.type = type;
                e.target.innerHTML = type === 'password' ? '👁️' : '👁️‍🗨️';
            });
        });
    }

    createKeyInput(label, envKey) {
        return `
            <div class="api-key-input">
                <label>${label}</label>
                <div style="position: relative;">
                    <input type="password" 
                           data-env-key="${envKey}" 
                           placeholder="Enter API Key">
                    <span class="toggle-visibility">👁️</span>
                </div>
            </div>
        `;
    }

    initAPIForm() {
        const submitBtn = document.querySelector('.api-submit-btn');
        if (submitBtn) {
            submitBtn.addEventListener('click', () => {
                const provider = this.providerSelect.value;
                const model = this.modelSelect.value;
                const apiKey = document.querySelector(`[data-env-key="${this.modelConfigs[provider].envKey}"]`).value;

                if (window.ws && window.ws.readyState === WebSocket.OPEN) {
                    window.ws.send(JSON.stringify({
                        type: 'api_settings',
                        data: {
                            provider: provider,
                            model: model,
                            apiKey: apiKey,
                            envKey: this.modelConfigs[provider].envKey
                        }
                    }));
                }
            });
        }
    }
}

// 初始化API面板
document.addEventListener('DOMContentLoaded', () => {
    new APIPanel();
});