Add image preview support: Krea-tag parsing with modal, file-explorer preview, skill output endpoint, increase execute timeout to 180s
- SkillEndpoint: GET /api/skills/{slug}/output/{filename} for skill output files
- WorkspaceEndpoint: GET /api/workspace/raw for raw file serving (images)
- File-Explorer: Image preview for png/jpg/gif/webp/svg/bmp/ico
- Chat UI: Parse [Krea: filename] tags into clickable chips with image modal
- ToolService: Increase execute timeout from 30s to 180s for long-running skills
This commit is contained in:
1 parent
cf6caea2dc
commit
9e4ed6dada
7 files changed
+253
-3
No files matched your search
@@ -43,6 +43,7 @@ public static class WorkspaceEndpoint
|
||||
app.MapGet("/api/workspace/agent/tree", HandleAgentTree);
|
||||
app.MapGet("/api/workspace/agent/file", HandleAgentFile);
|
||||
app.MapPut("/api/workspace/agent/file", HandleAgentFileSave);
|
||||
app.MapGet("/api/workspace/raw", HandleRawFile);
|
||||
}
|
||||
|
||||
private static async Task HandleTree(HttpContext ctx)
|
||||
@@ -421,4 +422,56 @@ public static class WorkspaceEndpoint
|
||||
lineCount
|
||||
});
|
||||
}
|
||||
|
||||
private static readonly Dictionary<string, string> MimeTypes = new(StringComparer.OrdinalIgnoreCase)
|
||||
{
|
||||
{ ".png", "image/png" }, { ".jpg", "image/jpeg" }, { ".jpeg", "image/jpeg" },
|
||||
{ ".gif", "image/gif" }, { ".webp", "image/webp" }, { ".svg", "image/svg+xml" },
|
||||
{ ".bmp", "image/bmp" }, { ".ico", "image/x-icon" },
|
||||
{ ".pdf", "application/pdf" },
|
||||
{ ".mp4", "video/mp4" }, { ".webm", "video/webm" },
|
||||
{ ".mp3", "audio/mpeg" }, { ".wav", "audio/wav" }, { ".ogg", "audio/ogg" },
|
||||
};
|
||||
|
||||
private static async Task HandleRawFile(HttpContext ctx)
|
||||
{
|
||||
var sessionId = ctx.Request.Query["sessionId"].FirstOrDefault();
|
||||
var filePath = ctx.Request.Query["path"].FirstOrDefault();
|
||||
|
||||
if (string.IsNullOrEmpty(filePath))
|
||||
{
|
||||
ctx.Response.StatusCode = 400;
|
||||
return;
|
||||
}
|
||||
|
||||
var db = ctx.RequestServices.GetRequiredService<Gott.Services.DatabaseService>();
|
||||
var session = await db.GetSession(sessionId ?? "");
|
||||
if (session == null || string.IsNullOrEmpty(session.Workspace))
|
||||
{
|
||||
ctx.Response.StatusCode = 400;
|
||||
return;
|
||||
}
|
||||
|
||||
var basePath = Path.GetFullPath(session.Workspace);
|
||||
var targetPath = Path.GetFullPath(Path.Combine(basePath, filePath));
|
||||
|
||||
if (!targetPath.StartsWith(basePath))
|
||||
{
|
||||
ctx.Response.StatusCode = 403;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!File.Exists(targetPath))
|
||||
{
|
||||
ctx.Response.StatusCode = 404;
|
||||
return;
|
||||
}
|
||||
|
||||
var ext = Path.GetExtension(targetPath);
|
||||
var contentType = MimeTypes.GetValueOrDefault(ext, "application/octet-stream");
|
||||
|
||||
ctx.Response.ContentType = contentType;
|
||||
ctx.Response.Headers["Cache-Control"] = "private, max-age=3600";
|
||||
await ctx.Response.SendFileAsync(targetPath);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user