diff --git a/apps/api-service/src/middleware/promptEnhancement.ts b/apps/api-service/src/middleware/promptEnhancement.ts index 57895b2..793b190 100644 --- a/apps/api-service/src/middleware/promptEnhancement.ts +++ b/apps/api-service/src/middleware/promptEnhancement.ts @@ -50,12 +50,21 @@ export const autoEnhancePrompt = async ( promptEnhancementService = new PromptEnhancementService(apiKey); } + // Extract orgId and projectId from validated API key + const orgId = req.apiKey?.organizationSlug || "unknown"; + const projectId = req.apiKey?.projectSlug || "unknown"; + const result = await promptEnhancementService.enhancePrompt( prompt, { ...enhancementOptions, ...(req.body.meta?.tags && { tags: req.body.meta.tags }), }, + { + orgId, + projectId, + ...(req.body.meta && { meta: req.body.meta }), + }, ); if (result.success && result.enhancedPrompt) { diff --git a/apps/api-service/src/routes/enhance.ts b/apps/api-service/src/routes/enhance.ts index a55c89e..fc3c94a 100644 --- a/apps/api-service/src/routes/enhance.ts +++ b/apps/api-service/src/routes/enhance.ts @@ -133,9 +133,17 @@ enhanceRouter.post( console.log(`[${timestamp}] [${requestId}] Starting prompt enhancement`); try { + // Extract orgId and projectId from validated API key + const orgId = req.apiKey?.organizationSlug || "unknown"; + const projectId = req.apiKey?.projectSlug || "unknown"; + const result = await promptEnhancementService.enhancePrompt( prompt, options || {}, + { + orgId, + projectId, + }, ); console.log(`[${timestamp}] [${requestId}] Enhancement completed:`, { diff --git a/apps/api-service/src/services/EnhancementLogger.ts b/apps/api-service/src/services/EnhancementLogger.ts new file mode 100644 index 0000000..c323fb1 --- /dev/null +++ b/apps/api-service/src/services/EnhancementLogger.ts @@ -0,0 +1,136 @@ +import { writeFileSync, readFileSync, existsSync, mkdirSync } from "fs"; +import { dirname } from "path"; + +export interface EnhancementLogEntry { + timestamp: string; + orgId: string; + projectId: string; + originalPrompt: string; + enhancedPrompt: string; + meta?: { + tags?: string[]; + }; + template: string; + detectedLanguage?: string; + enhancements: string[]; + model: string; +} + +export class EnhancementLogger { + private static instance: EnhancementLogger | null = null; + private logFilePath: string | null = null; + private isEnabled: boolean = false; + + private constructor() { + const enhLogPath = process.env["ENH_LOG"]; + + if (enhLogPath) { + this.logFilePath = enhLogPath; + this.isEnabled = true; + this.initializeLogFile(); + } + } + + static getInstance(): EnhancementLogger { + if (!EnhancementLogger.instance) { + EnhancementLogger.instance = new EnhancementLogger(); + } + return EnhancementLogger.instance; + } + + private initializeLogFile(): void { + if (!this.logFilePath) return; + + try { + // Ensure directory exists + const dir = dirname(this.logFilePath); + if (!existsSync(dir)) { + mkdirSync(dir, { recursive: true }); + } + + // Reset/clear the log file on service start + writeFileSync(this.logFilePath, "# Prompt Enhancement Log\n\n", { + encoding: "utf-8", + }); + + console.log( + `[EnhancementLogger] Log file initialized: ${this.logFilePath}`, + ); + } catch (error) { + console.error( + `[EnhancementLogger] Failed to initialize log file:`, + error, + ); + this.isEnabled = false; + } + } + + log(entry: EnhancementLogEntry): void { + if (!this.isEnabled || !this.logFilePath) { + return; + } + + try { + const newLogEntry = this.formatLogEntry(entry); + + // Read existing content + const existingContent = existsSync(this.logFilePath) + ? readFileSync(this.logFilePath, "utf-8") + : "# Prompt Enhancement Log\n\n"; + + // Insert new entry AFTER header but BEFORE old entries + const headerEnd = existingContent.indexOf("\n\n") + 2; + const header = existingContent.slice(0, headerEnd); + const oldEntries = existingContent.slice(headerEnd); + + writeFileSync( + this.logFilePath, + header + newLogEntry + oldEntries, + "utf-8", + ); + } catch (error) { + console.error(`[EnhancementLogger] Failed to write log entry:`, error); + } + } + + private formatLogEntry(entry: EnhancementLogEntry): string { + const { + timestamp, + orgId, + projectId, + originalPrompt, + enhancedPrompt, + meta, + template, + detectedLanguage, + enhancements, + model, + } = entry; + + // Format date from ISO timestamp + const date = new Date(timestamp); + const formattedDate = date.toISOString().replace("T", " ").slice(0, 19); + + let logText = `## ${formattedDate}\n`; + logText += `${orgId}/${projectId}\n\n`; + logText += `**Original Prompt:** ${originalPrompt}\n\n`; + logText += `**Enhanced Prompt:** ${enhancedPrompt}\n\n`; + + // Add tags if present + if (meta?.tags && meta.tags.length > 0) { + logText += `**Tags:** ${meta.tags.join(", ")}\n\n`; + } + + logText += `**Template:** ${template}\n`; + if (detectedLanguage) { + logText += `**Language:** ${detectedLanguage}\n`; + } + if (enhancements.length > 0) { + logText += `**Enhancements:** ${enhancements.join(", ")}\n`; + } + logText += `**Model:** ${model}\n\n`; + logText += `---\n\n`; + + return logText; + } +} diff --git a/apps/api-service/src/services/PromptEnhancementService.ts b/apps/api-service/src/services/PromptEnhancementService.ts index b2b3703..6aa1966 100644 --- a/apps/api-service/src/services/PromptEnhancementService.ts +++ b/apps/api-service/src/services/PromptEnhancementService.ts @@ -1,4 +1,5 @@ import { GoogleGenAI } from "@google/genai"; +import { EnhancementLogger, EnhancementLogEntry } from "./EnhancementLogger"; export interface PromptEnhancementOptions { template?: @@ -12,6 +13,14 @@ export interface PromptEnhancementOptions { tags?: string[]; // Optional tags - accepted but not used yet } +export interface PromptEnhancementContext { + orgId: string; + projectId: string; + meta?: { + tags?: string[]; + }; +} + export interface PromptEnhancementResult { success: boolean; originalPrompt: string; @@ -40,6 +49,7 @@ export class PromptEnhancementService { async enhancePrompt( rawPrompt: string, options: PromptEnhancementOptions = {}, + context?: PromptEnhancementContext, ): Promise { const timestamp = new Date().toISOString(); @@ -105,6 +115,27 @@ export class PromptEnhancementService { enhancements: result.enhancements, }, }; + + // Log the enhancement if context is provided + if (context) { + const logEntry: EnhancementLogEntry = { + timestamp, + orgId: context.orgId, + projectId: context.projectId, + originalPrompt: rawPrompt, + enhancedPrompt: result.enhancedPrompt, + ...(context.meta && { meta: context.meta }), + template: finalOptions.template, + ...(result.detectedLanguage && { + detectedLanguage: result.detectedLanguage, + }), + enhancements: result.enhancements, + model: this.model, + }; + + EnhancementLogger.getInstance().log(logEntry); + } + return enhancementResult; }