fix: fixing the prompt in one
This commit is contained in:
@ -6,10 +6,9 @@ const { savePrompt, saveError } = require("../controller/generate");
|
|||||||
/**
|
/**
|
||||||
* Injects file contents into message content when file tags are present
|
* Injects file contents into message content when file tags are present
|
||||||
* @param {string} content - The message content to process
|
* @param {string} content - The message content to process
|
||||||
* @returns {string} The processed content with file contents injected
|
* @returns {Promise<string>} The processed content with file contents injected
|
||||||
*/
|
*/
|
||||||
|
async function injectFileContent(content) {
|
||||||
function injectFileContent(content) {
|
|
||||||
let processedContent = content;
|
let processedContent = content;
|
||||||
|
|
||||||
// First, handle <selected_files> block
|
// First, handle <selected_files> block
|
||||||
@ -19,7 +18,7 @@ function injectFileContent(content) {
|
|||||||
if (selectedFilesMatch) {
|
if (selectedFilesMatch) {
|
||||||
const fileListBlock = selectedFilesMatch[1];
|
const fileListBlock = selectedFilesMatch[1];
|
||||||
|
|
||||||
// Skip injection if it already contains <file> blocks
|
// Skip injection if it already contains <file> tags
|
||||||
const containsFileTags = fileListBlock.includes("<file path=");
|
const containsFileTags = fileListBlock.includes("<file path=");
|
||||||
if (!containsFileTags) {
|
if (!containsFileTags) {
|
||||||
const filePaths = fileListBlock
|
const filePaths = fileListBlock
|
||||||
@ -28,8 +27,8 @@ function injectFileContent(content) {
|
|||||||
.filter((line) => line && line.startsWith("- "))
|
.filter((line) => line && line.startsWith("- "))
|
||||||
.map((line) => line.replace(/^- /, ""));
|
.map((line) => line.replace(/^- /, ""));
|
||||||
|
|
||||||
const fileBlocks = filePaths
|
const fileBlocks = await Promise.all(
|
||||||
.map(async (filePath) => {
|
filePaths.map(async (filePath) => {
|
||||||
try {
|
try {
|
||||||
const resolvedPath = path.resolve(process.cwd(), filePath);
|
const resolvedPath = path.resolve(process.cwd(), filePath);
|
||||||
const fileContent = fs.readFileSync(resolvedPath, "utf-8");
|
const fileContent = fs.readFileSync(resolvedPath, "utf-8");
|
||||||
@ -39,26 +38,24 @@ function injectFileContent(content) {
|
|||||||
console.warn(
|
console.warn(
|
||||||
`⚠️ Failed to read file: ${filePath} → ${error.message}`,
|
`⚠️ Failed to read file: ${filePath} → ${error.message}`,
|
||||||
);
|
);
|
||||||
const errorDetails = {
|
|
||||||
message: error.message,
|
|
||||||
request: null,
|
|
||||||
response: error.response?.data,
|
|
||||||
stack: error.stack,
|
|
||||||
};
|
|
||||||
|
|
||||||
await saveError({
|
await saveError({
|
||||||
error_message: error.message,
|
error_message: error.message,
|
||||||
details: errorDetails,
|
details: {
|
||||||
|
message: error.message,
|
||||||
|
request: null,
|
||||||
|
response: error.response?.data,
|
||||||
|
stack: error.stack,
|
||||||
|
},
|
||||||
});
|
});
|
||||||
return `<file path="${filePath}" language="text">\n[Error: File not found or unreadable]\n</file>`;
|
return `<file path="${filePath}" language="text">\n[Error: File not found or unreadable]\n</file>`;
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
.join("\n\n");
|
);
|
||||||
|
|
||||||
// Replace the original <selected_files> block with injected file tags
|
// Replace the <selected_files> block with the injected file tags
|
||||||
processedContent = processedContent.replace(
|
processedContent = processedContent.replace(
|
||||||
selectedFilesMatch[0],
|
selectedFilesMatch[0],
|
||||||
fileBlocks,
|
fileBlocks.join("\n\n"),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
console.log(
|
console.log(
|
||||||
@ -67,34 +64,34 @@ function injectFileContent(content) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Then, safely resolve and inject content into any <file path="..."> tags (without inner content)
|
// Inject content into empty <file> tags
|
||||||
const fileTagRegex = /<file path="(.+?)"(?: language="(.+?)")?>\s*<\/file>/g;
|
const fileTagRegex = /<file path="(.+?)"(?: language="(.+?)")?>\s*<\/file>/g;
|
||||||
processedContent = processedContent.replace(
|
const matches = [...processedContent.matchAll(fileTagRegex)];
|
||||||
fileTagRegex,
|
|
||||||
async (_, filePath, lang) => {
|
for (const match of matches) {
|
||||||
try {
|
const [fullTag, filePath, lang] = match;
|
||||||
const resolvedPath = path.resolve(process.cwd(), filePath);
|
try {
|
||||||
const fileContent = fs.readFileSync(resolvedPath, "utf-8");
|
const resolvedPath = path.resolve(process.cwd(), filePath);
|
||||||
return `<file path="${filePath}" language="${lang || "text"}">\n${fileContent}\n</file>`;
|
const fileContent = fs.readFileSync(resolvedPath, "utf-8");
|
||||||
} catch (error) {
|
const replacement = `<file path="${filePath}" language="${lang || "text"}">\n${fileContent}\n</file>`;
|
||||||
console.warn(
|
processedContent = processedContent.replace(fullTag, replacement);
|
||||||
`⚠️ Failed to inject <file> tag for ${filePath}: ${error.message}`,
|
} catch (error) {
|
||||||
);
|
console.warn(
|
||||||
const errorDetails = {
|
`⚠️ Failed to inject <file> tag for ${filePath}: ${error.message}`,
|
||||||
|
);
|
||||||
|
await saveError({
|
||||||
|
error_message: error.message,
|
||||||
|
details: {
|
||||||
message: error.message,
|
message: error.message,
|
||||||
request: null,
|
request: null,
|
||||||
response: error.response?.data,
|
response: error.response?.data,
|
||||||
stack: error.stack,
|
stack: error.stack,
|
||||||
};
|
},
|
||||||
|
});
|
||||||
await saveError({
|
const replacement = `<file path="${filePath}" language="${lang || "text"}">\n[Error: File not found or unreadable]\n</file>`;
|
||||||
error_message: error.message,
|
processedContent = processedContent.replace(fullTag, replacement);
|
||||||
details: errorDetails,
|
}
|
||||||
});
|
}
|
||||||
return `<file path="${filePath}" language="${lang || "text"}">\n[Error: File not found or unreadable]\n</file>`;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
return processedContent;
|
return processedContent;
|
||||||
}
|
}
|
||||||
@ -104,7 +101,6 @@ function injectFileContent(content) {
|
|||||||
* Handles both chat-style and prompt-style requests to Ollama
|
* Handles both chat-style and prompt-style requests to Ollama
|
||||||
*/
|
*/
|
||||||
async function handleGenerate(req, res) {
|
async function handleGenerate(req, res) {
|
||||||
// Log the complete request for debugging
|
|
||||||
try {
|
try {
|
||||||
const requestData = {
|
const requestData = {
|
||||||
method: req.method,
|
method: req.method,
|
||||||
@ -119,9 +115,7 @@ async function handleGenerate(req, res) {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
// Validate request body
|
|
||||||
if (!requestData.body) {
|
if (!requestData.body) {
|
||||||
// Save request data even if body is empty
|
|
||||||
await savePrompt({
|
await savePrompt({
|
||||||
model: requestData.body?.model || "codellama:7b",
|
model: requestData.body?.model || "codellama:7b",
|
||||||
prompt: null,
|
prompt: null,
|
||||||
@ -131,9 +125,9 @@ async function handleGenerate(req, res) {
|
|||||||
throw new Error("Request body is required");
|
throw new Error("Request body is required");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Determine request type and validate required fields
|
|
||||||
const isChatRequest =
|
const isChatRequest =
|
||||||
requestData.body.messages && Array.isArray(requestData.body.messages);
|
requestData.body.messages && Array.isArray(requestData.body.messages);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isChatRequest &&
|
isChatRequest &&
|
||||||
(!requestData.body.messages.length ||
|
(!requestData.body.messages.length ||
|
||||||
@ -147,45 +141,42 @@ async function handleGenerate(req, res) {
|
|||||||
throw new Error("Prompt request must include a prompt field");
|
throw new Error("Prompt request must include a prompt field");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set defaults and validate model
|
|
||||||
const model = requestData.body.model || "codellama:7b";
|
const model = requestData.body.model || "codellama:7b";
|
||||||
const stream =
|
const stream =
|
||||||
requestData.body.stream !== undefined ? requestData.body.stream : true;
|
requestData.body.stream !== undefined ? requestData.body.stream : true;
|
||||||
|
|
||||||
// Clean and prepare the prompt/messages
|
|
||||||
const cleanedRequest = {
|
const cleanedRequest = {
|
||||||
model,
|
model,
|
||||||
stream,
|
stream,
|
||||||
...(isChatRequest
|
...(isChatRequest
|
||||||
? {
|
? {
|
||||||
messages: requestData.body.messages.map((msg) => ({
|
messages: await Promise.all(
|
||||||
role: msg.role || "user",
|
requestData.body.messages.map(async (msg) => ({
|
||||||
content:
|
role: msg.role || "user",
|
||||||
msg.role === "user" && typeof msg.content === "string"
|
content:
|
||||||
? injectFileContent(msg.content.trim())
|
msg.role === "user" && typeof msg.content === "string"
|
||||||
: msg.content.trim(),
|
? await injectFileContent(msg.content.trim())
|
||||||
})),
|
: msg.content.trim(),
|
||||||
|
})),
|
||||||
|
),
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
prompt: injectFileContent(requestData.body.prompt.trim()),
|
prompt: await injectFileContent(requestData.body.prompt.trim()),
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Save the complete request data to database
|
|
||||||
await savePrompt({
|
await savePrompt({
|
||||||
model,
|
model,
|
||||||
prompt: isChatRequest ? null : cleanedRequest.prompt,
|
prompt: isChatRequest ? null : cleanedRequest.prompt,
|
||||||
messages: isChatRequest ? cleanedRequest.messages : null,
|
messages: isChatRequest ? cleanedRequest.messages : null,
|
||||||
request_data: requestData, // Save all request data for debugging/tracking
|
request_data: requestData,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Prepare Ollama endpoint and payload
|
|
||||||
const ollamaUrl = isChatRequest
|
const ollamaUrl = isChatRequest
|
||||||
? "http://localhost:11434/api/chat"
|
? "http://localhost:11434/api/chat"
|
||||||
: "http://localhost:11434/api/generate";
|
: "http://localhost:11434/api/generate";
|
||||||
|
|
||||||
if (stream) {
|
if (stream) {
|
||||||
// Handle streaming response
|
|
||||||
const ollamaResponse = await axios.post(ollamaUrl, cleanedRequest, {
|
const ollamaResponse = await axios.post(ollamaUrl, cleanedRequest, {
|
||||||
responseType: "stream",
|
responseType: "stream",
|
||||||
headers: {
|
headers: {
|
||||||
@ -197,11 +188,9 @@ async function handleGenerate(req, res) {
|
|||||||
res.setHeader("Content-Type", "application/x-ndjson");
|
res.setHeader("Content-Type", "application/x-ndjson");
|
||||||
res.setHeader("Transfer-Encoding", "chunked");
|
res.setHeader("Transfer-Encoding", "chunked");
|
||||||
|
|
||||||
let responseContent = "";
|
|
||||||
ollamaResponse.data.on("data", (chunk) => {
|
ollamaResponse.data.on("data", (chunk) => {
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(chunk.toString());
|
const data = JSON.parse(chunk.toString());
|
||||||
responseContent += data.response || "";
|
|
||||||
res.write(JSON.stringify(data) + "\n");
|
res.write(JSON.stringify(data) + "\n");
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error("Error parsing chunk:", err);
|
console.error("Error parsing chunk:", err);
|
||||||
@ -233,12 +222,10 @@ async function handleGenerate(req, res) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// Handle non-streaming response
|
|
||||||
const ollamaResponse = await axios.post(ollamaUrl, cleanedRequest);
|
const ollamaResponse = await axios.post(ollamaUrl, cleanedRequest);
|
||||||
res.status(ollamaResponse.status).json(ollamaResponse.data);
|
res.status(ollamaResponse.status).json(ollamaResponse.data);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Enhanced error handling
|
|
||||||
const errorDetails = {
|
const errorDetails = {
|
||||||
message: error.message,
|
message: error.message,
|
||||||
request: requestData,
|
request: requestData,
|
||||||
|
Reference in New Issue
Block a user