Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 114 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,13 +1,126 @@
# Dependencies
/node_modules
package-lock.json

# AI Models and Large Files
/models/
/vendor/

# Video Resources (large files)
/视频资源/
/Bellaicon/

# Build and Distribution
/dist/
/build/
*.tgz
*.tar.gz

# Environment and Configuration
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
config.json
secrets.json

# Logs
logs/
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

# Runtime data
pids/
*.pid
*.seed
*.pid.lock

# Coverage directory used by tools like istanbul
coverage/
*.lcov

# nyc test coverage
.nyc_output

# Dependency directories
jspm_packages/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Microbundle cache
.rpt2_cache/
.rts2_cache_cjs/
.rts2_cache_es/
.rts2_cache_umd/

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# parcel-bundler cache (https://parceljs.org/)
.cache
.parcel-cache

# Next.js build output
.next

# Nuxt.js build / generate output
.nuxt
dist

# Gatsby files
.cache/
public

# Storybook build outputs
.out
.storybook-out

# Temporary folders
tmp/
temp/

# IDEs and editors
.idea/
.vscode/
*.swp
*.swo
*~

# OS-generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
.Trashes
ehthumbs.db
Thumbs.db

# Deployment
.vercel/
.netlify/

# AI and ML specific
*.onnx
*.bin
*.safetensors
*.h5
*.pb
*.tflite

# Local development
.trae/
.kiro/
152 changes: 146 additions & 6 deletions chatInterface.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ class ChatInterface {
<option value="assistant">智能助手</option>
<option value="creative">创意伙伴</option>
</select>
<div class="bella-mode-description">
<small id="modeDescription">选择不同的聊天模式来改变贝拉的回应风格</small>
</div>
</div>
<div class="bella-setting-group">
<button class="bella-clear-history">清除聊天记录</button>
Expand Down Expand Up @@ -205,6 +208,26 @@ class ChatInterface {
}
});

// 模式选择
const modeSelect = this.settingsPanel.querySelector('.bella-mode-select');
const modeDescription = this.settingsPanel.querySelector('#modeDescription');

modeSelect.addEventListener('change', (e) => {
const mode = e.target.value;

// 更新模式描述
const descriptions = {
casual: '轻松聊天模式:贝拉会以温暖、友好的方式与你对话',
assistant: '智能助手模式:贝拉会提供专业、准确的信息和建议',
creative: '创意伙伴模式:贝拉会发挥想象力,提供独特的创意观点'
};
modeDescription.textContent = descriptions[mode] || descriptions.casual;

// 触发模式切换事件
this.onModeChange?.(mode);
this.showNotification(`已切换到${modeSelect.options[modeSelect.selectedIndex].text}模式`, 'success');
});

// 清除聊天记录
this.settingsPanel.querySelector('.bella-clear-history').addEventListener('click', () => {
this.clearMessages();
Expand Down Expand Up @@ -351,7 +374,7 @@ class ChatInterface {
}

// 显示打字指示器
showTypingIndicator() {
showTypingIndicator(message = '贝拉正在思考...') {
const existingIndicator = this.messageContainer.querySelector('.bella-typing-indicator');
if (existingIndicator) return;

Expand All @@ -360,10 +383,16 @@ class ChatInterface {
typingElement.innerHTML = `
<div class="bella-message-avatar">💝</div>
<div class="bella-message-content">
<div class="bella-typing-dots">
<span class="bella-typing-dot"></span>
<span class="bella-typing-dot"></span>
<span class="bella-typing-dot"></span>
<div class="bella-thinking-status">
<span class="bella-thinking-text">${message}</span>
<div class="bella-typing-dots">
<span class="bella-typing-dot"></span>
<span class="bella-typing-dot"></span>
<span class="bella-typing-dot"></span>
</div>
</div>
<div class="bella-thinking-progress">
<div class="bella-progress-bar"></div>
</div>
</div>
`;
Expand All @@ -375,13 +404,65 @@ class ChatInterface {
setTimeout(() => {
typingElement.classList.add('bella-typing-show');
}, 10);

// 启动进度条动画
this.startProgressAnimation(typingElement);
}

// 启动进度条动画
startProgressAnimation(typingElement) {
const progressBar = typingElement.querySelector('.bella-progress-bar');
if (!progressBar) return;

let progress = 0;
const interval = setInterval(() => {
progress += Math.random() * 15;
if (progress > 90) progress = 90; // 不要到100%,等实际完成

progressBar.style.width = `${progress}%`;

// 如果元素被移除了,清除定时器
if (!document.body.contains(typingElement)) {
clearInterval(interval);
}
}, 200);

// 存储定时器引用以便清理
typingElement._progressInterval = interval;
}

// 更新思考状态
updateThinkingStatus(message) {
const indicator = this.messageContainer.querySelector('.bella-typing-indicator');
if (indicator) {
const textElement = indicator.querySelector('.bella-thinking-text');
if (textElement) {
textElement.textContent = message;
}
}
}

// 隐藏打字指示器
hideTypingIndicator() {
const indicator = this.messageContainer.querySelector('.bella-typing-indicator');
if (indicator) {
this.messageContainer.removeChild(indicator);
// 清理进度条定时器
if (indicator._progressInterval) {
clearInterval(indicator._progressInterval);
}

// 完成进度条动画
const progressBar = indicator.querySelector('.bella-progress-bar');
if (progressBar) {
progressBar.style.width = '100%';
}

// 延迟移除以显示完成状态
setTimeout(() => {
if (indicator.parentNode) {
this.messageContainer.removeChild(indicator);
}
}, 300);
}
}

Expand Down Expand Up @@ -430,11 +511,70 @@ class ChatInterface {
return this.isVisible;
}

// 显示错误状态
showErrorState(errorMessage, canRetry = true) {
const errorElement = document.createElement('div');
errorElement.className = 'bella-message bella-message-error';

const timestamp = new Date().toLocaleTimeString('zh-CN', {
hour: '2-digit',
minute: '2-digit'
});

errorElement.innerHTML = `
<div class="bella-message-avatar">⚠️</div>
<div class="bella-message-content">
<div class="bella-error-content">
<div class="bella-error-message">${errorMessage}</div>
${canRetry ? '<button class="bella-retry-button">重试</button>' : ''}
</div>
<div class="bella-message-time">${timestamp}</div>
</div>
`;

// 添加重试功能
if (canRetry) {
const retryButton = errorElement.querySelector('.bella-retry-button');
retryButton.addEventListener('click', () => {
this.onRetryLastMessage?.();
this.messageContainer.removeChild(errorElement);
});
}

this.messageContainer.appendChild(errorElement);
this.scrollToBottom();

// 添加动画效果
setTimeout(() => {
errorElement.classList.add('bella-message-appear');
}, 10);
}

// 获取当前聊天模式
getCurrentMode() {
const modeSelect = this.settingsPanel.querySelector('.bella-mode-select');
return modeSelect ? modeSelect.value : 'casual';
}

// 设置聊天模式
setMode(mode) {
const modeSelect = this.settingsPanel.querySelector('.bella-mode-select');
if (modeSelect && ['casual', 'assistant', 'creative'].includes(mode)) {
modeSelect.value = mode;

// 触发change事件以更新描述
const event = new Event('change');
modeSelect.dispatchEvent(event);
}
}

// 设置回调函数
onMessageSend = null;
onProviderChange = null;
onAPIKeySave = null;
onClearHistory = null;
onModeChange = null;
onRetryLastMessage = null;
}

// ES6模块导出
Expand Down
Loading