MagicPot / js /textToImage.js
zhanglei
fix voice
ab5909a
Raw
History Blame Contribute Delete
11.8 kB
// 文生图API接口类
class TextToImageAPI {
constructor() {
this.apiEndpoint = 'https://api.openai.com/v1/images/generations'; // 示例API
this.apiKey = null; // 需要用户配置
this.cache = new Map(); // 图片缓存
this.isEnabled = false;
// 备用图片数据(Base64编码的小图标)
this.fallbackImages = this.initFallbackImages();
this.init();
}
init() {
// 检查是否有API密钥配置
this.apiKey = localStorage.getItem('textToImageApiKey');
this.isEnabled = !!this.apiKey;
if (!this.isEnabled) {
console.log('文生图API未配置,将使用备用图片');
}
}
async generateFood(foodName) {
try {
// 首先检查缓存
const cacheKey = `food_${foodName}`;
if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey);
}
let imageData;
if (this.isEnabled) {
// 使用真实API生成图片
imageData = await this.callAPI(`cartoon style ${foodName} food, cute, colorful, simple background`);
} else {
// 使用备用图片
imageData = this.getFallbackFoodImage(foodName);
}
// 缓存结果
this.cache.set(cacheKey, imageData);
return imageData;
} catch (error) {
console.error('生成食物图片失败:', error);
return this.getFallbackFoodImage(foodName);
}
}
async generateAnimal(foodName) {
try {
const cacheKey = `animal_${foodName}`;
if (this.cache.has(cacheKey)) {
return this.cache.get(cacheKey);
}
const animalType = this.getAnimalForFood(foodName);
let imageData;
if (this.isEnabled) {
imageData = await this.callAPI(`cartoon style cute ${animalType} animal, friendly, colorful, simple background`);
} else {
imageData = this.getFallbackAnimalImage(animalType);
}
this.cache.set(cacheKey, imageData);
return imageData;
} catch (error) {
console.error('生成动物图片失败:', error);
return this.getFallbackAnimalImage(this.getAnimalForFood(foodName));
}
}
async callAPI(prompt) {
if (!this.isEnabled) {
throw new Error('API未启用');
}
const response = await fetch(this.apiEndpoint, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${this.apiKey}`
},
body: JSON.stringify({
prompt: prompt,
n: 1,
size: '256x256',
style: 'cartoon'
})
});
if (!response.ok) {
throw new Error(`API请求失败: ${response.status}`);
}
const data = await response.json();
if (data.data && data.data.length > 0) {
// 下载图片并转换为本地数据
return await this.downloadImage(data.data[0].url);
} else {
throw new Error('API返回数据格式错误');
}
}
async downloadImage(url) {
const response = await fetch(url);
const blob = await response.blob();
return new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onload = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(blob);
});
}
getFallbackFoodImage(foodName) {
// 返回备用的食物图片数据
const fallbackFood = this.fallbackImages.food[foodName] || this.fallbackImages.food.default;
return this.createSimpleImage(fallbackFood.emoji, fallbackFood.color);
}
getFallbackAnimalImage(animalType) {
// 返回备用的动物图片数据
const fallbackAnimal = this.fallbackImages.animals[animalType] || this.fallbackImages.animals.default;
return this.createSimpleImage(fallbackAnimal.emoji, fallbackAnimal.color);
}
createSimpleImage(emoji, backgroundColor = '#FFFFFF') {
// 创建一个简单的Canvas图片
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = 64;
canvas.height = 64;
// 背景
ctx.fillStyle = backgroundColor;
ctx.fillRect(0, 0, 64, 64);
// 表情符号
ctx.font = '40px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(emoji, 32, 32);
return canvas.toDataURL();
}
initFallbackImages() {
return {
food: {
'apple': { emoji: '🍎', color: '#FFE4E1' },
'banana': { emoji: '🍌', color: '#FFFACD' },
'orange': { emoji: '🍊', color: '#FFE4B5' },
'strawberry': { emoji: '🍓', color: '#FFB6C1' },
'watermelon': { emoji: '🍉', color: '#F0FFF0' },
'grape': { emoji: '🍇', color: '#E6E6FA' },
'pizza': { emoji: '🍕', color: '#FFEFD5' },
'burger': { emoji: '🍔', color: '#F5DEB3' },
'cake': { emoji: '🍰', color: '#FFF8DC' },
'cookie': { emoji: '🍪', color: '#DEB887' },
'bread': { emoji: '🍞', color: '#F5DEB3' },
'cheese': { emoji: '🧀', color: '#FFFACD' },
'fish': { emoji: '🐟', color: '#E0FFFF' },
'chicken': { emoji: '🍗', color: '#FFEFD5' },
'rice': { emoji: '🍚', color: '#F8F8FF' },
'noodles': { emoji: '🍜', color: '#FFF8DC' },
'default': { emoji: '🍽️', color: '#F0F8FF' }
},
animals: {
'rabbit': { emoji: '🐰', color: '#F5F5DC' },
'monkey': { emoji: '🐵', color: '#DEB887' },
'bird': { emoji: '🐦', color: '#E0F6FF' },
'bear': { emoji: '🐻', color: '#D2B48C' },
'elephant': { emoji: '🐘', color: '#DCDCDC' },
'fox': { emoji: '🦊', color: '#FFE4B5' },
'cat': { emoji: '🐱', color: '#FFB6C1' },
'dog': { emoji: '🐶', color: '#DEB887' },
'mouse': { emoji: '🐭', color: '#D3D3D3' },
'squirrel': { emoji: '🐿️', color: '#D2691E' },
'duck': { emoji: '🦆', color: '#FFFACD' },
'rat': { emoji: '🐀', color: '#A9A9A9' },
'panda': { emoji: '🐼', color: '#F0F8FF' },
'chicken': { emoji: '🐔', color: '#FFFACD' },
'default': { emoji: '🐱', color: '#FFB6C1' }
}
};
}
getAnimalForFood(foodName) {
const animalMap = {
'apple': 'rabbit',
'banana': 'monkey',
'orange': 'bird',
'strawberry': 'bear',
'watermelon': 'elephant',
'grape': 'fox',
'pizza': 'cat',
'burger': 'dog',
'cake': 'mouse',
'cookie': 'squirrel',
'bread': 'duck',
'cheese': 'rat',
'fish': 'cat',
'chicken': 'dog',
'rice': 'bird',
'noodles': 'panda',
'carrot': 'rabbit',
'corn': 'chicken'
};
return animalMap[foodName] || 'cat';
}
// 配置API密钥
setApiKey(apiKey) {
this.apiKey = apiKey;
this.isEnabled = !!apiKey;
if (apiKey) {
localStorage.setItem('textToImageApiKey', apiKey);
} else {
localStorage.removeItem('textToImageApiKey');
}
}
// 清除缓存
clearCache() {
this.cache.clear();
}
// 获取缓存大小
getCacheSize() {
return this.cache.size;
}
// 预加载常用图片
async preloadCommonImages() {
const commonFoods = ['apple', 'banana', 'orange', 'strawberry', 'watermelon'];
const promises = [];
for (const food of commonFoods) {
promises.push(this.generateFood(food));
promises.push(this.generateAnimal(food));
}
try {
await Promise.all(promises);
console.log('常用图片预加载完成');
} catch (error) {
console.error('预加载图片失败:', error);
}
}
// 创建配置UI
createConfigUI() {
const configDiv = document.createElement('div');
configDiv.id = 'textToImageConfig';
configDiv.style.cssText = `
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: white;
padding: 20px;
border-radius: 10px;
box-shadow: 0 4px 20px rgba(0,0,0,0.3);
z-index: 10000;
display: none;
`;
configDiv.innerHTML = `
<h3>文生图API配置</h3>
<p>输入您的API密钥以启用AI图片生成功能:</p>
<input type="text" id="apiKeyInput" placeholder="输入API密钥" style="width: 300px; padding: 8px; margin: 10px 0;">
<br>
<button id="saveApiKey" style="padding: 8px 16px; margin-right: 10px;">保存</button>
<button id="cancelConfig" style="padding: 8px 16px;">取消</button>
<p style="font-size: 12px; color: #666; margin-top: 10px;">
如果不配置API密钥,将使用备用的表情符号图片
</p>
`;
document.body.appendChild(configDiv);
// 事件监听
document.getElementById('saveApiKey').onclick = () => {
const apiKey = document.getElementById('apiKeyInput').value.trim();
this.setApiKey(apiKey);
configDiv.style.display = 'none';
if (apiKey) {
alert('API密钥已保存,现在将使用AI生成图片');
} else {
alert('API密钥已清除,将使用备用图片');
}
};
document.getElementById('cancelConfig').onclick = () => {
configDiv.style.display = 'none';
};
return configDiv;
}
// 显示配置界面
showConfig() {
let configDiv = document.getElementById('textToImageConfig');
if (!configDiv) {
configDiv = this.createConfigUI();
}
document.getElementById('apiKeyInput').value = this.apiKey || '';
configDiv.style.display = 'block';
}
// 测试API连接
async testAPI() {
if (!this.isEnabled) {
return { success: false, message: 'API未配置' };
}
try {
await this.callAPI('test image');
return { success: true, message: 'API连接正常' };
} catch (error) {
return { success: false, message: error.message };
}
}
}
// 添加全局快捷键来配置API
document.addEventListener('keydown', (e) => {
if (e.ctrlKey && e.shiftKey && e.key === 'I') {
if (window.game && window.game.textToImage) {
window.game.textToImage.showConfig();
}
}
});