Merge pull request #123 from AutoMaker-Org/enhance-feature-with-ai

feat: add AI enhancement feature to settings and board views
This commit is contained in:
Web Dev Cody
2025-12-16 02:01:30 -05:00
committed by GitHub
15 changed files with 1211 additions and 8 deletions

View File

@@ -0,0 +1,22 @@
/**
* Enhance prompt routes - HTTP API for AI-powered text enhancement
*
* Provides endpoints for enhancing user input text using Claude AI
* with different enhancement modes (improve, expand, simplify, etc.)
*/
import { Router } from "express";
import { createEnhanceHandler } from "./routes/enhance.js";
/**
* Create the enhance-prompt router
*
* @returns Express router with enhance-prompt endpoints
*/
export function createEnhancePromptRoutes(): Router {
const router = Router();
router.post("/", createEnhanceHandler());
return router;
}

View File

@@ -0,0 +1,195 @@
/**
* POST /enhance-prompt endpoint - Enhance user input text
*
* Uses Claude AI to enhance text based on the specified enhancement mode.
* Supports modes: improve, technical, simplify, acceptance
*/
import type { Request, Response } from "express";
import { query } from "@anthropic-ai/claude-agent-sdk";
import { createLogger } from "../../../lib/logger.js";
import {
getSystemPrompt,
buildUserPrompt,
isValidEnhancementMode,
type EnhancementMode,
} from "../../../lib/enhancement-prompts.js";
import { resolveModelString, CLAUDE_MODEL_MAP } from "../../../lib/model-resolver.js";
const logger = createLogger("EnhancePrompt");
/**
* Request body for the enhance endpoint
*/
interface EnhanceRequestBody {
/** The original text to enhance */
originalText: string;
/** The enhancement mode to apply */
enhancementMode: string;
/** Optional model override */
model?: string;
}
/**
* Success response from the enhance endpoint
*/
interface EnhanceSuccessResponse {
success: true;
enhancedText: string;
}
/**
* Error response from the enhance endpoint
*/
interface EnhanceErrorResponse {
success: false;
error: string;
}
/**
* Extract text content from Claude SDK response messages
*
* @param stream - The async iterable from the query function
* @returns The extracted text content
*/
async function extractTextFromStream(
stream: AsyncIterable<{
type: string;
subtype?: string;
result?: string;
message?: {
content?: Array<{ type: string; text?: string }>;
};
}>
): Promise<string> {
let responseText = "";
for await (const msg of stream) {
if (msg.type === "assistant" && msg.message?.content) {
for (const block of msg.message.content) {
if (block.type === "text" && block.text) {
responseText += block.text;
}
}
} else if (msg.type === "result" && msg.subtype === "success") {
responseText = msg.result || responseText;
}
}
return responseText;
}
/**
* Create the enhance request handler
*
* @returns Express request handler for text enhancement
*/
export function createEnhanceHandler(): (
req: Request,
res: Response
) => Promise<void> {
return async (req: Request, res: Response): Promise<void> => {
try {
const { originalText, enhancementMode, model } =
req.body as EnhanceRequestBody;
// Validate required fields
if (!originalText || typeof originalText !== "string") {
const response: EnhanceErrorResponse = {
success: false,
error: "originalText is required and must be a string",
};
res.status(400).json(response);
return;
}
if (!enhancementMode || typeof enhancementMode !== "string") {
const response: EnhanceErrorResponse = {
success: false,
error: "enhancementMode is required and must be a string",
};
res.status(400).json(response);
return;
}
// Validate text is not empty
const trimmedText = originalText.trim();
if (trimmedText.length === 0) {
const response: EnhanceErrorResponse = {
success: false,
error: "originalText cannot be empty",
};
res.status(400).json(response);
return;
}
// Validate and normalize enhancement mode
const normalizedMode = enhancementMode.toLowerCase();
const validMode: EnhancementMode = isValidEnhancementMode(normalizedMode)
? normalizedMode
: "improve";
logger.info(
`Enhancing text with mode: ${validMode}, length: ${trimmedText.length} chars`
);
// Get the system prompt for this mode
const systemPrompt = getSystemPrompt(validMode);
// Build the user prompt with few-shot examples
// This helps the model understand this is text transformation, not a coding task
const userPrompt = buildUserPrompt(validMode, trimmedText, true);
// Resolve the model - use the passed model, default to sonnet for quality
const resolvedModel = resolveModelString(model, CLAUDE_MODEL_MAP.sonnet);
logger.debug(`Using model: ${resolvedModel}`);
// Call Claude SDK with minimal configuration for text transformation
// Key: no tools, just text completion
const stream = query({
prompt: userPrompt,
options: {
model: resolvedModel,
systemPrompt,
maxTurns: 1,
allowedTools: [],
permissionMode: "acceptEdits",
},
});
// Extract the enhanced text from the response
const enhancedText = await extractTextFromStream(stream);
if (!enhancedText || enhancedText.trim().length === 0) {
logger.warn("Received empty response from Claude");
const response: EnhanceErrorResponse = {
success: false,
error: "Failed to generate enhanced text - empty response",
};
res.status(500).json(response);
return;
}
logger.info(
`Enhancement complete, output length: ${enhancedText.length} chars`
);
const response: EnhanceSuccessResponse = {
success: true,
enhancedText: enhancedText.trim(),
};
res.json(response);
} catch (error) {
const errorMessage =
error instanceof Error ? error.message : "Unknown error occurred";
logger.error("Enhancement failed:", errorMessage);
const response: EnhanceErrorResponse = {
success: false,
error: errorMessage,
};
res.status(500).json(response);
}
};
}