bolt.diy/app/routes/api.enhancer.ts

138 lines
4.5 KiB
TypeScript
Raw Permalink Normal View History

2024-07-10 16:44:39 +00:00
import { type ActionFunctionArgs } from '@remix-run/cloudflare';
import { streamText } from '~/lib/.server/llm/stream-text';
import { stripIndents } from '~/utils/stripIndent';
import type { ProviderInfo } from '~/types/model';
import { getApiKeysFromCookie, getProviderSettingsFromCookie } from '~/lib/api/cookies';
import { createScopedLogger } from '~/utils/logger';
2024-07-10 16:44:39 +00:00
2024-07-29 18:31:45 +00:00
export async function action(args: ActionFunctionArgs) {
2024-09-26 16:45:41 +00:00
return enhancerAction(args);
2024-07-29 18:31:45 +00:00
}
const logger = createScopedLogger('api.enhancher');
2024-07-29 18:31:45 +00:00
async function enhancerAction({ context, request }: ActionFunctionArgs) {
2024-12-11 08:32:21 +00:00
const { message, model, provider } = await request.json<{
2024-11-12 00:10:54 +00:00
message: string;
model: string;
provider: ProviderInfo;
2024-11-12 00:10:54 +00:00
apiKeys?: Record<string, string>;
}>();
const { name: providerName } = provider;
// validate 'model' and 'provider' fields
2024-11-12 00:10:54 +00:00
if (!model || typeof model !== 'string') {
throw new Response('Invalid or missing model', {
status: 400,
statusText: 'Bad Request',
2024-11-12 00:10:54 +00:00
});
}
if (!providerName || typeof providerName !== 'string') {
2024-11-12 00:10:54 +00:00
throw new Response('Invalid or missing provider', {
status: 400,
statusText: 'Bad Request',
2024-11-12 00:10:54 +00:00
});
}
2024-07-10 16:44:39 +00:00
2024-12-11 08:32:21 +00:00
const cookieHeader = request.headers.get('Cookie');
const apiKeys = getApiKeysFromCookie(cookieHeader);
const providerSettings = getProviderSettingsFromCookie(cookieHeader);
2024-12-11 08:32:21 +00:00
2024-07-10 16:44:39 +00:00
try {
2024-12-11 08:32:21 +00:00
const result = await streamText({
messages: [
2024-07-10 16:44:39 +00:00
{
role: 'user',
content:
`[Model: ${model}]\n\n[Provider: ${providerName}]\n\n` +
stripIndents`
You are a professional prompt engineer specializing in crafting precise, effective prompts.
Your task is to enhance prompts by making them more specific, actionable, and effective.
I want you to improve the user prompt that is wrapped in \`<original_prompt>\` tags.
For valid prompts:
- Make instructions explicit and unambiguous
- Add relevant context and constraints
- Remove redundant information
- Maintain the core intent
- Ensure the prompt is self-contained
- Use professional language
For invalid or unclear prompts:
- Respond with clear, professional guidance
- Keep responses concise and actionable
- Maintain a helpful, constructive tone
- Focus on what the user should provide
- Use a standard template for consistency
IMPORTANT: Your response must ONLY contain the enhanced prompt text.
Do not include any explanations, metadata, or wrapper tags.
<original_prompt>
${message}
</original_prompt>
`,
2024-07-10 16:44:39 +00:00
},
],
env: context.cloudflare?.env as any,
apiKeys,
2024-12-11 08:32:21 +00:00
providerSettings,
options: {
system:
'You are a senior software principal architect, you should help the user analyse the user query and enrich it with the necessary context and constraints to make it more specific, actionable, and effective. You should also ensure that the prompt is self-contained and uses professional language. Your response should ONLY contain the enhanced prompt text. Do not include any explanations, metadata, or wrapper tags.',
/*
* onError: (event) => {
* throw new Response(null, {
* status: 500,
* statusText: 'Internal Server Error',
* });
* }
*/
},
2024-12-11 08:32:21 +00:00
});
2024-07-10 16:44:39 +00:00
// Handle streaming errors in a non-blocking way
(async () => {
try {
for await (const part of result.fullStream) {
if (part.type === 'error') {
const error: any = part.error;
logger.error('Streaming error:', error);
break;
}
}
} catch (error) {
logger.error('Error processing stream:', error);
}
})();
// Return the text stream directly since it's already text data
2024-12-17 20:50:14 +00:00
return new Response(result.textStream, {
status: 200,
headers: {
'Content-Type': 'text/event-stream',
Connection: 'keep-alive',
'Cache-Control': 'no-cache',
},
});
2024-11-12 00:10:54 +00:00
} catch (error: unknown) {
2024-07-10 16:44:39 +00:00
console.log(error);
2024-11-12 00:10:54 +00:00
if (error instanceof Error && error.message?.includes('API key')) {
throw new Response('Invalid or missing API key', {
status: 401,
statusText: 'Unauthorized',
2024-11-12 00:10:54 +00:00
});
}
2024-07-10 16:44:39 +00:00
throw new Response(null, {
status: 500,
statusText: 'Internal Server Error',
});
}
}