Files
Bella/core.js
T

286 lines
11 KiB
JavaScript

// core.js - Bella's Brain (v3)
// Bella's core AI logic, supporting a hybrid architecture of local models and cloud APIs
import { pipeline, env, AutoTokenizer, AutoModelForSpeechSeq2Seq } from './vendor/transformers.js';
import CloudAPIService from './cloudAPI.js';
// Local model configuration
env.allowLocalModels = true;
env.useBrowserCache = false;
env.allowRemoteModels = false;
env.backends.onnx.logLevel = 'verbose';
env.localModelPath = './models/';
class BellaAI {
static instance = null;
static async getInstance() {
if (this.instance === null) {
this.instance = new BellaAI();
await this.instance.init();
}
return this.instance;
}
constructor() {
this.cloudAPI = new CloudAPIService();
this.useCloudAPI = false; // Default to using local model
this.currentMode = 'casual'; // Chat modes: casual, assistant, creative
}
async init() {
console.log('Initializing Bella\'s core AI...');
// Priority loading of LLM model (chat functionality)
try {
console.log('Loading LLM model...');
this.llm = await pipeline('text2text-generation', 'Xenova/LaMini-Flan-T5-77M');
console.log('LLM model loaded successfully.');
} catch (error) {
console.error('Failed to load LLM model:', error);
// LLM loading failure doesn't block initialization
}
// Attempt to load ASR model (voice recognition)
try {
console.log('Loading ASR model...');
const modelPath = 'Xenova/whisper-asr';
const tokenizer = await AutoTokenizer.from_pretrained(modelPath);
const model = await AutoModelForSpeechSeq2Seq.from_pretrained(modelPath);
this.asr = await pipeline('automatic-speech-recognition', model, { tokenizer });
console.log('ASR model loaded successfully.');
} catch (error) {
console.warn('ASR model failed to load, voice recognition will be disabled:', error);
// ASR loading failure doesn't affect chat functionality
this.asr = null;
}
// TTS model temporarily disabled
// try {
// console.log('Loading TTS model...');
// this.tts = await pipeline('text-to-speech', 'Xenova/speecht5_tts', { quantized: false });
// console.log('TTS model loaded successfully.');
// } catch (error) {
// console.warn('TTS model failed to load, voice synthesis will be disabled:', error);
// this.tts = null;
// }
console.log('Bella\'s core AI initialized successfully.');
}
async think(prompt) {
try {
// If cloud API is enabled and configured, use it as priority
if (this.useCloudAPI && this.cloudAPI.isConfigured()) {
return await this.thinkWithCloudAPI(prompt);
}
// Otherwise use local model
return await this.thinkWithLocalModel(prompt);
} catch (error) {
console.error('Error during thinking process:', error);
// If cloud API fails, try falling back to local model
if (this.useCloudAPI) {
console.log('Cloud API failed, falling back to local model...');
try {
return await this.thinkWithLocalModel(prompt);
} catch (localError) {
console.error('Local model also failed:', localError);
}
}
return this.getErrorResponse();
}
}
// Think using cloud API
async thinkWithCloudAPI(prompt) {
const enhancedPrompt = this.enhancePromptForMode(prompt);
return await this.cloudAPI.chat(enhancedPrompt);
}
// Think using local model with optimized LLM parameters and processing
async thinkWithLocalModel(prompt) {
if (!this.llm) {
return "I'm still learning how to think. Please wait a moment...";
}
const bellaPrompt = this.enhancePromptForMode(prompt, true);
// Optimized LLM parameters for better responses
const result = await this.llm(bellaPrompt, {
max_new_tokens: 180, // Increased token count for more complete responses
temperature: 0.7, // Slightly lowered temperature for better consistency
top_k: 50, // Increased top_k for more diverse vocabulary
top_p: 0.92, // Added top_p parameter to optimize sampling
do_sample: true, // Maintained sampling for creativity
repetition_penalty: 1.2, // Added repetition penalty to avoid repetitive content
});
// Enhanced text cleaning and processing
let response = result[0].generated_text;
// Remove prompt part
if (response.includes(bellaPrompt)) {
response = response.replace(bellaPrompt, '').trim();
}
// Remove possible "Bella's response:" prefixes
response = response.replace(/^(Bella's response:|Bella's professional response:|Bella's creative response:|Bella:)/i, '').trim();
// If response is empty, provide backup responses
if (!response || response.length < 2) {
const backupResponses = [
"That's an interesting question. Let me think about it for a moment...",
"Good question! I need to organize my thoughts...",
"I have some ideas, but let me put them together more coherently...",
"This topic is fascinating. Let me consider how to respond...",
"I'm thinking about different angles to this question. Just a moment..."
];
return backupResponses[Math.floor(Math.random() * backupResponses.length)];
}
return response;
}
// Enhance prompts based on mode, using advanced LLM prompt engineering
enhancePromptForMode(prompt, isLocal = false) {
const modePrompts = {
casual: isLocal ?
`As Bella, a friendly AI assistant similar to Siri, respond to the user in a warm, conversational tone. Your response should:
1. Be concise and helpful, like Siri's responses
2. Use natural, flowing language with a touch of personality
3. Be friendly but not overly emotional
4. Maintain a helpful, slightly witty tone
5. Sound intelligent and knowledgeable while remaining accessible
User message: ${prompt}
Bella's response:` :
`You are Bella, an AI assistant similar to Siri. Respond in a helpful, concise manner with a touch of personality. Keep your responses clear and direct, while maintaining a friendly tone. Avoid overly technical language unless necessary, and focus on providing value to the user.
User message: ${prompt}
Bella's response:`,
assistant: isLocal ?
`As Bella, an intelligent AI assistant like Siri, provide accurate and helpful information. Your response should:
1. Deliver clear, factual information and useful advice
2. Organize content for easy understanding and application
3. Maintain a professional yet approachable tone
4. Use simple language when possible, technical terms only when necessary
5. Demonstrate expertise while remaining accessible
User question: ${prompt}
Bella's professional response:` :
`You are Bella, a Siri-like AI assistant. Provide accurate, useful information and advice with a professional yet approachable tone. Organize your response clearly, avoid unnecessary technical language, and focus on being helpful and informative.
User question: ${prompt}
Bella's professional response:`,
creative: isLocal ?
`As Bella, a creative AI assistant with Siri-like qualities, use your imagination to respond. Your response should:
1. Present unique perspectives and creative thinking
2. Use vivid, descriptive language
3. Offer unexpected but interesting ideas
4. Inspire the user's imagination
5. Maintain a light, engaging tone
User prompt: ${prompt}
Bella's creative response:` :
`You are Bella, a creative AI assistant with Siri-like qualities. Provide interesting, unique responses using vivid language and creative thinking. Offer unexpected perspectives that inspire imagination while maintaining an engaging, helpful tone.
User prompt: ${prompt}
Bella's creative response:`
};
return modePrompts[this.currentMode] || modePrompts.casual;
}
// Get error response
getErrorResponse() {
const errorResponses = [
"I'm sorry, I'm having trouble processing that right now. Let me try to reorganize my thoughts...",
"Hmm... I need to think about this a bit more. Please wait a moment.",
"I seem to be having a bit of trouble with that. Give me a second to sort things out.",
"Let me rephrase my thoughts. Just a moment please.",
"I didn't quite catch that. Could you try asking in a different way?"
];
return errorResponses[Math.floor(Math.random() * errorResponses.length)];
}
// Set chat mode
setChatMode(mode) {
if (['casual', 'assistant', 'creative'].includes(mode)) {
this.currentMode = mode;
return true;
}
return false;
}
// Switch AI service provider
switchProvider(provider) {
if (provider === 'local') {
this.useCloudAPI = false;
return true;
} else {
const success = this.cloudAPI.switchProvider(provider);
if (success) {
this.useCloudAPI = true;
}
return success;
}
}
// Set API key
setAPIKey(provider, apiKey) {
return this.cloudAPI.setAPIKey(provider, apiKey);
}
// Clear conversation history
clearHistory() {
this.cloudAPI.clearHistory();
}
// Get current configuration
getCurrentConfig() {
return {
useCloudAPI: this.useCloudAPI,
provider: this.useCloudAPI ? this.cloudAPI.getCurrentProvider() : { name: 'local', model: 'LaMini-Flan-T5-77M' },
mode: this.currentMode,
isConfigured: this.useCloudAPI ? this.cloudAPI.isConfigured() : true
};
}
// Process audio input
async listen(audioData) {
if (!this.asr) {
throw new Error('Speech recognition model not initialized');
}
const result = await this.asr(audioData);
return result.text;
}
// Generate speech from text
async speak(text) {
if (!this.tts) {
throw new Error('Speech synthesis model not initialized');
}
// We need speaker embeddings for SpeechT5
const speaker_embeddings = 'models/Xenova/speecht5_tts/speaker_embeddings.bin';
const result = await this.tts(text, {
speaker_embeddings,
});
return result.audio;
}
// Get cloud API service instance (for external access)
getCloudAPIService() {
return this.cloudAPI;
}
}
// ES6 module export
export { BellaAI };