马良AI写作初始化仓库

This commit is contained in:
邓滨杰
2025-09-10 00:07:52 +08:00
parent 3c06bb1a03
commit 39c0f8840f
1309 changed files with 318528 additions and 0 deletions

View File

@@ -0,0 +1,463 @@
import 'package:flutter/material.dart';
import 'package:flutter_svg/flutter_svg.dart';
/// 图标尺寸枚举
enum IconSize {
small, // 16px
medium, // 24px
large, // 32px
extraLarge, // 48px
}
/// AI模型提供商图标管理类
/// 提供统一的图标获取接口
class ProviderIcons {
// 私有构造函数,防止实例化
ProviderIcons._();
/// 提供商图标路径映射表
static const Map<String, String> _providerIconPaths = {
// OpenAI系列
'openai': 'assets/icons/openai.svg',
'chatgpt': 'assets/icons/openai.svg',
'gpt': 'assets/icons/openai.svg',
// Anthropic系列
'anthropic': 'assets/icons/anthropic.svg',
'claude': 'assets/icons/claude-color.svg',
// Google系列
'google': 'assets/icons/gemini-color.svg',
'gemini': 'assets/icons/gemini-color.svg',
'bard': 'assets/icons/gemini-color.svg',
// 微软系列
'microsoft': 'assets/icons/microsoft-color.svg',
'azure': 'assets/icons/microsoft-color.svg',
'copilot': 'assets/icons/microsoft-color.svg',
// Meta系列
'meta': 'assets/icons/meta-color.svg',
'llama': 'assets/icons/meta-color.svg',
'facebook': 'assets/icons/meta-color.svg',
// 字节跳动系列
'bytedance': 'assets/icons/bytedance-color.svg',
'doubao': 'assets/icons/doubao-color.svg',
'豆包': 'assets/icons/doubao-color.svg',
// 智谱AI系列
'zhipu': 'assets/icons/zhipu-color.svg',
'glm': 'assets/icons/zhipu-color.svg',
'智谱': 'assets/icons/zhipu-color.svg',
// 阿里系列
'qwen': 'assets/icons/qwen-color.svg',
'tongyi': 'assets/icons/qwen-color.svg',
'alibaba': 'assets/icons/qwen-color.svg',
'通义': 'assets/icons/qwen-color.svg',
// DeepSeek系列
'deepseek': 'assets/icons/deepseek-color.svg',
// Mistral系列
'mistral': 'assets/icons/mistral-color.svg',
// 硅基流动
'siliconcloud': 'assets/icons/siliconcloud-color.svg',
'siliconflow': 'assets/icons/siliconcloud-color.svg',
// Perplexity
'perplexity': 'assets/icons/perplexity-color.svg',
// HuggingFace
'huggingface': 'assets/icons/huggingface-color.svg',
'hf': 'assets/icons/huggingface-color.svg',
// Stability AI
'stability': 'assets/icons/stability-color.svg',
'stable-diffusion': 'assets/icons/stability-color.svg',
// OpenRouter
'openrouter': 'assets/icons/openrouter.svg',
// Ollama
'ollama': 'assets/icons/ollama.svg',
// xAI Grok
'xai': 'assets/icons/grok.svg',
'grok': 'assets/icons/grok.svg',
// xAI Grok
'x-ai': 'assets/icons/grok.svg',
'X-ai': 'assets/icons/grok.svg',
// Midjourney
'midjourney': 'assets/icons/midjourney.svg',
'mj': 'assets/icons/midjourney.svg',
// LM Studio
'lm-studio': 'assets/icons/ollama.svg',
'lmstudio': 'assets/icons/ollama.svg',
// LocalAI
'localai': 'assets/icons/ollama.svg',
'local': 'assets/icons/ollama.svg',
};
/// 提供商默认颜色映射
/// 颜色配置参考: https://lobehub.com/zh/icons
static const Map<String, Color> _providerColors = {
// OpenAI系列 - #000
'openai': Color(0xFF000000),
'chatgpt': Color(0xFF000000),
'gpt': Color(0xFF000000),
// Anthropic系列 - #F1F0E8 (浅色背景) / Claude: #D97757
'anthropic': Color(0xFFF1F0E8),
'claude': Color(0xFFD97757),
// Google系列 - #1C69FF (Gemini) / #FFF (Google)
'google': Color(0xFFFFFFFF),
'gemini': Color(0xFF1C69FF),
'bard': Color(0xFF1C69FF),
// 微软系列 - #00A4EF / Copilot: #FFF
'microsoft': Color(0xFF00A4EF),
'azure': Color(0xFF00A4EF),
'copilot': Color(0xFFFFFFFF),
// Meta系列 - #1D65C1
'meta': Color(0xFF1D65C1),
'llama': Color(0xFF1D65C1),
'facebook': Color(0xFF1D65C1),
// 字节跳动系列 - #325AB4 / Doubao: #FFF
'bytedance': Color(0xFF325AB4),
'doubao': Color(0xFFFFFFFF),
'豆包': Color(0xFFFFFFFF),
// 智谱AI系列 - #3859FF / ChatGLM: #4268FA
'zhipu': Color(0xFF3859FF),
'glm': Color(0xFF4268FA),
'智谱': Color(0xFF3859FF),
// 阿里系列 - #615CED
'qwen': Color(0xFF615CED),
'tongyi': Color(0xFF615CED),
'alibaba': Color(0xFF615CED),
'通义': Color(0xFF615CED),
// DeepSeek系列
'deepseek': Color(0xFF4D6BFE),
// Mistral系列 - #FA520F
'mistral': Color(0xFFFA520F),
// 硅基流动
'siliconcloud': Color(0xFF7C3AED),
'siliconflow': Color(0xFF7C3AED),
// Perplexity - #22B8CD
'perplexity': Color(0xFF22B8CD),
// HuggingFace - #FFF
'huggingface': Color(0xFFFFFFFF),
'hf': Color(0xFFFFFFFF),
// Stability AI - #330066
'stability': Color(0xFF330066),
'stable-diffusion': Color(0xFF330066),
// OpenRouter - #6566F1
'openrouter': Color(0xFF6566F1),
// Ollama - #FFF
'ollama': Color(0xFFFFFFFF),
// xAI Grok - #000
'xai': Color(0xFF000000),
'grok': Color(0xFF000000),
'x-ai': Color(0xFF000000),
'X-ai': Color(0xFF000000),
// Midjourney - #FFF
'midjourney': Color(0xFFFFFFFF),
'mj': Color(0xFFFFFFFF),
// Groq - #F55036
'groq': Color(0xFFF55036),
// together.ai - #0F6FFF
'together': Color(0xFF0F6FFF),
'together.ai': Color(0xFF0F6FFF),
// Fireworks - #5019C5
'fireworks': Color(0xFF5019C5),
// Cohere - #39594D
'cohere': Color(0xFF39594D),
// Replicate - #EA2805
'replicate': Color(0xFFEA2805),
// LM Studio / LocalAI
'lm-studio': Color(0xFFFFFFFF),
'lmstudio': Color(0xFFFFFFFF),
'localai': Color(0xFFFFFFFF),
'local': Color(0xFFFFFFFF),
};
/// 获取提供商图标(优化版本)
///
/// [provider] 提供商名称,大小写不敏感
/// [size] 图标大小默认为24提高默认尺寸提升清晰度
/// [color] 图标颜色,如果不指定则使用默认颜色
/// [useHighQuality] 是否使用高质量渲染默认为true
static Widget getProviderIcon(
String provider, {
double size = 24, // 提高默认尺寸
Color? color,
bool useHighQuality = true,
}) {
final normalizedProvider = provider.toLowerCase().trim();
final iconPath = _providerIconPaths[normalizedProvider];
if (iconPath != null) {
// 首先尝试加载 SVG 格式
if (iconPath.endsWith('.svg')) {
return SvgPicture.asset(
iconPath,
width: size,
height: size,
colorFilter: color != null
? ColorFilter.mode(color, BlendMode.srcIn)
: null,
placeholderBuilder: (context) => _getDefaultIcon(
provider,
size: size,
color: color,
),
);
} else {
// 优化的 PNG 加载配置
return Image.asset(
iconPath,
width: size,
height: size,
fit: BoxFit.contain,
color: color,
// 启用高质量过滤器,减少模糊
filterQuality: useHighQuality ? FilterQuality.high : FilterQuality.medium,
// 禁用抗锯齿可能导致的模糊
isAntiAlias: true,
errorBuilder: (context, error, stackTrace) {
return _getDefaultIcon(provider, size: size, color: color);
},
);
}
} else {
// 如果没有找到对应图标,使用默认图标
return _getDefaultIcon(provider, size: size, color: color);
}
}
/// 获取提供商图标(指定尺寸版本)
/// 对于不同使用场景提供不同的尺寸建议
static Widget getProviderIconForContext(
String provider, {
required IconSize iconSize,
Color? color,
}) {
double size;
switch (iconSize) {
case IconSize.small:
size = 16;
break;
case IconSize.medium:
size = 24;
break;
case IconSize.large:
size = 32;
break;
case IconSize.extraLarge:
size = 48;
break;
}
return getProviderIcon(
provider,
size: size,
color: color,
useHighQuality: true,
);
}
/// 获取提供商默认颜色
static Color getProviderColor(String provider) {
final normalizedProvider = provider.toLowerCase().trim();
return _providerColors[normalizedProvider] ?? Colors.grey;
}
/// 获取默认图标(当找不到对应图标时使用)
static Widget _getDefaultIcon(
String provider, {
required double size,
Color? color,
}) {
final normalizedProvider = provider.toLowerCase().trim();
IconData iconData;
Color iconColor = color ?? getProviderColor(provider);
// 根据提供商名称选择合适的Material Icon作为备用
if (normalizedProvider.contains('openai') ||
normalizedProvider.contains('gpt') ||
normalizedProvider.contains('chatgpt')) {
iconData = Icons.auto_awesome;
} else if (normalizedProvider.contains('anthropic') ||
normalizedProvider.contains('claude')) {
iconData = Icons.psychology;
} else if (normalizedProvider.contains('google') ||
normalizedProvider.contains('gemini') ||
normalizedProvider.contains('bard')) {
iconData = Icons.star;
} else if (normalizedProvider.contains('openrouter')) {
iconData = Icons.router;
} else if (normalizedProvider.contains('ollama') ||
normalizedProvider.contains('local')) {
iconData = Icons.computer;
} else if (normalizedProvider.contains('microsoft') ||
normalizedProvider.contains('azure') ||
normalizedProvider.contains('copilot')) {
iconData = Icons.science;
} else if (normalizedProvider.contains('meta') ||
normalizedProvider.contains('llama') ||
normalizedProvider.contains('facebook')) {
iconData = Icons.groups;
} else if (normalizedProvider.contains('bytedance') ||
normalizedProvider.contains('doubao')) {
iconData = Icons.smart_toy;
} else if (normalizedProvider.contains('zhipu') ||
normalizedProvider.contains('glm')) {
iconData = Icons.lightbulb;
} else if (normalizedProvider.contains('qwen') ||
normalizedProvider.contains('tongyi') ||
normalizedProvider.contains('alibaba')) {
iconData = Icons.cloud;
} else if (normalizedProvider.contains('deepseek')) {
iconData = Icons.search;
} else if (normalizedProvider.contains('mistral')) {
iconData = Icons.air;
} else if (normalizedProvider.contains('silicon')) {
iconData = Icons.memory;
} else if (normalizedProvider.contains('perplexity')) {
iconData = Icons.quiz;
} else if (normalizedProvider.contains('huggingface') ||
normalizedProvider.contains('hf')) {
iconData = Icons.emoji_emotions;
} else if (normalizedProvider.contains('stability') ||
normalizedProvider.contains('stable')) {
iconData = Icons.image;
} else if (normalizedProvider.contains('midjourney') ||
normalizedProvider.contains('mj')) {
iconData = Icons.palette;
} else if (normalizedProvider.contains('xai') ||
normalizedProvider.contains('grok')) {
iconData = Icons.explore;
} else if (normalizedProvider.contains('groq')) {
iconData = Icons.speed;
} else if (normalizedProvider.contains('together')) {
iconData = Icons.group_work;
} else if (normalizedProvider.contains('fireworks')) {
iconData = Icons.celebration;
} else if (normalizedProvider.contains('cohere')) {
iconData = Icons.link;
} else if (normalizedProvider.contains('replicate')) {
iconData = Icons.replay;
} else {
iconData = Icons.api;
}
return Icon(
iconData,
color: iconColor,
size: size,
);
}
/// 检查是否支持某个提供商
static bool isSupported(String provider) {
final normalizedProvider = provider.toLowerCase().trim();
return _providerIconPaths.containsKey(normalizedProvider);
}
/// 获取所有支持的提供商列表
static List<String> getSupportedProviders() {
return _providerIconPaths.keys.toList();
}
/// 获取提供商的显示名称
static String getProviderDisplayName(String provider) {
final normalizedProvider = provider.toLowerCase().trim();
const displayNames = {
'openai': 'OpenAI',
'chatgpt': 'ChatGPT',
'gpt': 'GPT',
'anthropic': 'Anthropic',
'claude': 'Claude',
'google': 'Google',
'gemini': 'Gemini',
'bard': 'Bard',
'microsoft': 'Microsoft',
'azure': 'Azure',
'copilot': 'Copilot',
'meta': 'Meta',
'llama': 'Llama',
'facebook': 'Facebook',
'bytedance': '字节跳动',
'doubao': '豆包',
'zhipu': '智谱AI',
'glm': 'GLM',
'qwen': '通义千问',
'tongyi': '通义千问',
'alibaba': '阿里巴巴',
'deepseek': 'DeepSeek',
'mistral': 'Mistral',
'siliconcloud': '硅基流动',
'siliconflow': '硅基流动',
'perplexity': 'Perplexity',
'huggingface': 'Hugging Face',
'hf': 'Hugging Face',
'stability': 'Stability AI',
'stable-diffusion': 'Stable Diffusion',
'openrouter': 'OpenRouter',
'ollama': 'Ollama',
'xai': 'xAI',
'grok': 'Grok',
'x-ai': 'xAI',
'X-ai': 'xAI',
'midjourney': 'Midjourney',
'mj': 'Midjourney',
'groq': 'Groq',
'together': 'Together AI',
'together.ai': 'Together AI',
'fireworks': 'Fireworks AI',
'cohere': 'Cohere',
'replicate': 'Replicate',
'lm-studio': 'LM Studio',
'lmstudio': 'LM Studio',
'localai': 'LocalAI',
'local': 'Local',
};
return displayNames[normalizedProvider] ?? _capitalizeFirst(provider);
}
/// 首字母大写
static String _capitalizeFirst(String text) {
if (text.isEmpty) return text;
return text[0].toUpperCase() + text.substring(1);
}
}