This commit is contained in:
momar3632 2025-05-27 13:12:49 +01:00 committed by GitHub
commit b0b786abb4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 294 additions and 8 deletions

View File

@ -1,5 +1,14 @@
# bolt.diy
> ## 📢 Add A free API from [Pollinations.ai] in the Bolt DIY!
> **A free API from [Pollinations.ai](https://pollinations.ai) has been added to the project.**
> This API provides access to several models that can be used to enhance and expand the functionalities of the project.
>
> 🔗 **API Link**: [Pollinations.ai](https://pollinations.ai)
> You can now access a variety of models to integrate into your project.
>
> 💬 *If you have any feedback or questions, feel free to reach out!*
[![bolt.diy: AI-Powered Full-Stack Web Development in the Browser](./public/social_preview_index.jpg)](https://bolt.diy)
Welcome to bolt.diy, the official open source version of Bolt.new, which allows you to choose the LLM that you use for each prompt! Currently, you can use OpenAI, Anthropic, Ollama, OpenRouter, Gemini, LMStudio, Mistral, xAI, HuggingFace, DeepSeek, or Groq models - and it is easily extended to use any other model supported by the Vercel AI SDK! See the instructions below for running this locally and extending it to include more models.

View File

@ -12,7 +12,7 @@ import { SiAmazon, SiGoogle, SiHuggingface, SiPerplexity, SiOpenai } from 'react
import { BsRobot, BsCloud } from 'react-icons/bs';
import { TbBrain, TbCloudComputing } from 'react-icons/tb';
import { BiCodeBlock, BiChip } from 'react-icons/bi';
import { FaCloud, FaBrain } from 'react-icons/fa';
import { FaCloud, FaBrain, FaRegLemon } from 'react-icons/fa';
import type { IconType } from 'react-icons';
// Add type for provider names to ensure type safety
@ -29,6 +29,7 @@ type ProviderName =
| 'OpenAI'
| 'OpenRouter'
| 'Perplexity'
| 'Pollinations'
| 'Together'
| 'XAI';
@ -46,6 +47,7 @@ const PROVIDER_ICONS: Record<ProviderName, IconType> = {
OpenAI: SiOpenai,
OpenRouter: FaCloud,
Perplexity: SiPerplexity,
Pollinations: FaRegLemon,
Together: BsCloud,
XAI: BsRobot,
};

View File

@ -14,15 +14,17 @@ import { providerBaseUrlEnvKeys } from '~/utils/constants';
import { useToast } from '~/components/ui/use-toast';
import { Progress } from '~/components/ui/Progress';
import OllamaModelInstaller from './OllamaModelInstaller';
import { FaRegLemon } from 'react-icons/fa';
// Add type for provider names to ensure type safety
type ProviderName = 'Ollama' | 'LMStudio' | 'OpenAILike';
type ProviderName = 'Ollama' | 'LMStudio' | 'OpenAILike' | 'Pollinations';
// Update the PROVIDER_ICONS type to use the ProviderName type
const PROVIDER_ICONS: Record<ProviderName, IconType> = {
Ollama: BsRobot,
LMStudio: BsRobot,
OpenAILike: TbBrandOpenai,
Pollinations: FaRegLemon,
};
// Update PROVIDER_DESCRIPTIONS to use the same type
@ -30,6 +32,7 @@ const PROVIDER_DESCRIPTIONS: Record<ProviderName, string> = {
Ollama: 'Run open-source models locally on your machine',
LMStudio: 'Local model inference with LM Studio',
OpenAILike: 'Connect to OpenAI-compatible API endpoints',
Pollinations: 'Free public AI API with no authentication required',
};
// Add a constant for the Ollama API base URL

View File

@ -11,6 +11,7 @@ import { HyperbolicStatusChecker } from './providers/hyperbolic';
import { MistralStatusChecker } from './providers/mistral';
import { OpenRouterStatusChecker } from './providers/openrouter';
import { PerplexityStatusChecker } from './providers/perplexity';
import { PollinationsStatusChecker } from './providers/pollinations';
import { TogetherStatusChecker } from './providers/together';
import { XAIStatusChecker } from './providers/xai';
@ -76,6 +77,12 @@ export class ProviderStatusCheckerFactory {
headers: {},
testModel: 'pplx-7b-chat',
},
Pollinations: {
statusUrl: 'https://pollinations.ai/',
apiUrl: 'https://www.pollinations.ai/api/v1/models',
headers: {},
testModel: 'haiku',
},
Together: {
statusUrl: 'https://status.together.ai/',
apiUrl: 'https://api.together.xyz/v1/models',
@ -118,6 +125,8 @@ export class ProviderStatusCheckerFactory {
return new OpenRouterStatusChecker(config);
case 'Perplexity':
return new PerplexityStatusChecker(config);
case 'Pollinations':
return new PollinationsStatusChecker(config);
case 'Together':
return new TogetherStatusChecker(config);
case 'XAI':

View File

@ -0,0 +1,31 @@
import { BaseProviderChecker } from '~/components/@settings/tabs/providers/service-status/base-provider';
import type { StatusCheckResult } from '~/components/@settings/tabs/providers/service-status/types';
export class PollinationsStatusChecker extends BaseProviderChecker {
async checkStatus(): Promise<StatusCheckResult> {
try {
// Check the main pollinations website
const endpointStatus = await this.checkEndpoint(this.config.statusUrl);
// Check the API endpoint
const apiStatus = await this.checkEndpoint(this.config.apiUrl);
// Determine overall status based on both checks
const status = endpointStatus === 'reachable' && apiStatus === 'reachable' ? 'operational' : 'degraded';
return {
status,
message: `Status page: ${endpointStatus}, API: ${apiStatus}`,
incidents: ['Note: Limited status information due to CORS restrictions'],
};
} catch (error) {
console.error('Error checking Pollinations status:', error);
return {
status: 'degraded',
message: 'Error checking service status',
incidents: ['Error occurred while checking service status'],
};
}
}
}

View File

@ -11,6 +11,7 @@ export type ProviderName =
| 'Mistral'
| 'OpenRouter'
| 'Perplexity'
| 'Pollinations'
| 'Together'
| 'XAI';

View File

@ -7,7 +7,7 @@ import { SiAmazon, SiGoogle, SiHuggingface, SiPerplexity, SiOpenai } from 'react
import { BsRobot, BsCloud } from 'react-icons/bs';
import { TbBrain } from 'react-icons/tb';
import { BiChip, BiCodeBlock } from 'react-icons/bi';
import { FaCloud, FaBrain } from 'react-icons/fa';
import { FaCloud, FaBrain, FaRegLemon } from 'react-icons/fa';
import type { IconType } from 'react-icons';
import { useSettings } from '~/lib/hooks/useSettings';
import { useToast } from '~/components/ui/use-toast';
@ -25,6 +25,7 @@ type ProviderName =
| 'OpenAI'
| 'OpenRouter'
| 'Perplexity'
| 'Pollinations'
| 'Together'
| 'XAI';
@ -170,6 +171,12 @@ const PROVIDER_STATUS_URLS: Record<ProviderName, ProviderConfig> = {
},
testModel: 'deepseek-chat',
},
Pollinations: {
statusUrl: 'https://pollinations.ai/',
apiUrl: 'https://text.pollinations.ai/openai/v1/models',
headers: {},
testModel: 'haiku',
},
};
const PROVIDER_ICONS: Record<ProviderName, IconType> = {
@ -186,6 +193,7 @@ const PROVIDER_ICONS: Record<ProviderName, IconType> = {
Together: BsCloud,
XAI: BsRobot,
Deepseek: BiCodeBlock,
Pollinations: FaRegLemon,
};
const ServiceStatusTab = () => {
@ -220,6 +228,7 @@ const ServiceStatusTab = () => {
OpenRouter: 'OPEN_ROUTER_API_KEY',
XAI: 'XAI_API_KEY',
Deepseek: 'DEEPSEEK_API_KEY',
Pollinations: 'POLLINATIONS_API_BASE_URL',
};
const envKey = envKeyMap[provider];

View File

@ -460,7 +460,8 @@ export const BaseChat = React.forwardRef<HTMLDivElement, BaseChatProps>(
/>
{(providerList || []).length > 0 &&
provider &&
(!LOCAL_PROVIDERS.includes(provider.name) || 'OpenAILike') && (
(!LOCAL_PROVIDERS.includes(provider.name) || provider.name === 'OpenAILike') &&
provider.name !== 'Pollinations' && (
<APIKeyManager
provider={provider}
apiKey={apiKeys[provider.name] || ''}

View File

@ -0,0 +1,219 @@
import { BaseProvider } from '~/lib/modules/llm/base-provider';
import type { ModelInfo } from '~/lib/modules/llm/types';
import type { IProviderSetting } from '~/types/model';
import type { LanguageModelV1 } from 'ai';
import { createOpenAI } from '@ai-sdk/openai';
import { createScopedLogger } from '~/utils/logger';
const logger = createScopedLogger('PollinationsProvider');
// Define response type for the Pollinations API
interface PollinationsModelResponse {
data: Array<{
id: string;
object: string;
created: number;
owned_by: string;
context_length?: number;
}>;
object: string;
}
export default class PollinationsProvider extends BaseProvider {
name = 'Pollinations';
getApiKeyLink = 'https://pollinations.ai/';
labelForGetApiKey = 'Visit Pollinations.ai';
icon = 'i-ph:flower-fill';
config = {
baseUrlKey: 'POLLINATIONS_API_BASE_URL',
};
constructor() {
super();
logger.info('Initializing Pollinations Provider');
}
staticModels: ModelInfo[] = [
{
name: 'haiku',
label: 'Haiku',
provider: 'Pollinations',
maxTokenAllowed: 4096,
},
{
name: 'mistral-medium',
label: 'Mistral Medium',
provider: 'Pollinations',
maxTokenAllowed: 8000,
},
{
name: 'llama3-8b',
label: 'Llama 3 8B',
provider: 'Pollinations',
maxTokenAllowed: 4096,
},
{
name: 'llama3-70b',
label: 'Llama 3 70B',
provider: 'Pollinations',
maxTokenAllowed: 8000,
},
{
name: 'phi-3-mini',
label: 'Phi-3 Mini',
provider: 'Pollinations',
maxTokenAllowed: 4096,
},
{
name: 'phi-3-medium',
label: 'Phi-3 Medium',
provider: 'Pollinations',
maxTokenAllowed: 4096,
},
{
name: 'gemma-7b',
label: 'Gemma 7B',
provider: 'Pollinations',
maxTokenAllowed: 4096,
},
{
name: 'mistral-small',
label: 'Mistral Small',
provider: 'Pollinations',
maxTokenAllowed: 4096,
},
{
name: 'mistral-large',
label: 'Mistral Large',
provider: 'Pollinations',
maxTokenAllowed: 8192,
},
{
name: 'gpt-4o',
label: 'GPT-4o',
provider: 'Pollinations',
maxTokenAllowed: 8192,
},
{
name: 'claude-3-haiku',
label: 'Claude 3 Haiku',
provider: 'Pollinations',
maxTokenAllowed: 4096,
},
{
name: 'claude-3-sonnet',
label: 'Claude 3 Sonnet',
provider: 'Pollinations',
maxTokenAllowed: 8192,
},
{
name: 'claude-3-opus',
label: 'Claude 3 Opus',
provider: 'Pollinations',
maxTokenAllowed: 32768,
},
{
name: 'deepseek-coder',
label: 'DeepSeek Coder',
provider: 'Pollinations',
maxTokenAllowed: 8192,
},
{
name: 'qwen-72b',
label: 'Qwen 72B',
provider: 'Pollinations',
maxTokenAllowed: 8192,
},
];
// You can also add a dynamic models function if needed
async getDynamicModels(
apiKeys?: Record<string, string>,
settings?: IProviderSetting,
serverEnv: Record<string, string> = {},
): Promise<ModelInfo[]> {
logger.info('Getting dynamic models for Pollinations');
let { baseUrl } = this.getProviderBaseUrlAndKey({
apiKeys,
providerSettings: settings,
serverEnv,
defaultBaseUrlKey: 'POLLINATIONS_API_BASE_URL',
defaultApiTokenKey: '',
});
// Default base URL if not provided
baseUrl = baseUrl || 'https://text.pollinations.ai/openai';
try {
// Fetch models from Pollinations API
const response = await fetch(`${baseUrl}/v1/models`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
},
});
if (!response.ok) {
logger.warn(`Failed to fetch models from Pollinations API: ${response.status}`);
return this.staticModels;
}
const data = (await response.json()) as PollinationsModelResponse;
if (data && Array.isArray(data.data)) {
const models = data.data.map((model) => ({
name: model.id,
label: model.id.split('/').pop() || model.id,
provider: this.name,
maxTokenAllowed: model.context_length || 4096,
}));
logger.info(`Retrieved ${models.length} models from Pollinations API`);
return models;
}
logger.warn('Invalid response format from Pollinations API, falling back to static models');
return this.staticModels;
} catch (error) {
logger.error('Error getting dynamic models for Pollinations:', error);
return this.staticModels;
}
}
getModelInstance(options: {
model: string;
serverEnv?: Env;
apiKeys?: Record<string, string>;
providerSettings?: Record<string, IProviderSetting>;
}): LanguageModelV1 {
const { model, serverEnv, providerSettings } = options;
let { baseUrl } = this.getProviderBaseUrlAndKey({
providerSettings: providerSettings?.[this.name],
serverEnv: serverEnv as any,
defaultBaseUrlKey: 'POLLINATIONS_API_BASE_URL',
defaultApiTokenKey: '',
});
// Default base URL if not provided
baseUrl = baseUrl || 'https://text.pollinations.ai/openai';
logger.info(`Creating OpenAI instance for Pollinations with model: ${model} at ${baseUrl}`);
try {
const openai = createOpenAI({
baseURL: baseUrl,
apiKey: 'not-needed', // No real API key required for Pollinations.ai
});
return openai(model);
} catch (error) {
logger.error(`Error creating Pollinations model instance: ${error}`);
throw new Error(`Failed to initialize Pollinations provider: ${error}`);
}
}
}

View File

@ -11,6 +11,7 @@ import OpenRouterProvider from './providers/open-router';
import OpenAILikeProvider from './providers/openai-like';
import OpenAIProvider from './providers/openai';
import PerplexityProvider from './providers/perplexity';
import PollinationsProvider from './providers/pollinations';
import TogetherProvider from './providers/together';
import XAIProvider from './providers/xai';
import HyperbolicProvider from './providers/hyperbolic';
@ -31,6 +32,7 @@ export {
OpenRouterProvider,
OpenAILikeProvider,
PerplexityProvider,
PollinationsProvider,
XAIProvider,
TogetherProvider,
LMStudioProvider,

View File

@ -29,8 +29,8 @@ export interface Shortcuts {
toggleTerminal: Shortcut;
}
export const URL_CONFIGURABLE_PROVIDERS = ['Ollama', 'LMStudio', 'OpenAILike'];
export const LOCAL_PROVIDERS = ['OpenAILike', 'LMStudio', 'Ollama'];
export const URL_CONFIGURABLE_PROVIDERS = ['Ollama', 'LMStudio', 'OpenAILike', 'Pollinations'];
export const LOCAL_PROVIDERS = ['OpenAILike', 'LMStudio', 'Ollama', 'Pollinations'];
export type ProviderSetting = Record<string, IProviderConfig>;
@ -71,8 +71,8 @@ const getInitialProviderSettings = (): ProviderSetting => {
initialSettings[provider.name] = {
...provider,
settings: {
// Local providers should be disabled by default
enabled: !LOCAL_PROVIDERS.includes(provider.name),
// Local providers should be disabled by default, except Pollinations
enabled: !LOCAL_PROVIDERS.includes(provider.name) || provider.name === 'Pollinations',
},
};
});