用AI生成动作时,“获取选中的文件”应复用quicker相关模块功能

V2版本讨论 · 435 次浏览
浅沧 创建于 1天5小时前

用AI生成动作时,默认只支持explorer,不支持directory opus中的文件,需要明确要求才会兼容DO,浪费token。

quicker的“获取选中文件”模块是支持多种文件管理器的,应让ai复用该模块功能,而不是自己写。


回复内容
CL 1天5小时前
#1
详细说一下,怎么给AI描述的,AI写的什么样的动作。目前的描述比较抽象,无法判断。
浅沧 回复 CL 1天2小时前 :


浅沧 回复 CL 1天2小时前 :


CL 回复 浅沧 22小时1分钟前 :

看起来没有什么明显的问题, 复制后获取文件列表是获取选中文件的常规做法,而且更通用,适合各种资源管理器程序以及everything之类软件。

DO里不能ctrl+c获取选中文件么?

CL 最后更新于 22小时0分钟前
浅沧 回复 CL 21小时54分钟前 :

DO里可以通过ctrl+c获取选中文件,但是AI笫一次生成动作的时候只考虑资源管理器,不是用ctrl+c的方式。

CL 回复 浅沧 21小时53分钟前 :

用的什么方式?

浅沧 回复 CL 21小时45分钟前 :

using System.IO;
using System.IO.Compression;

void Main()
{
    var files = qk.Selection.GetFiles();
    if (files == null || files.Length == 0)
    {
        qk.Ui.Notify("请先在资源管理器中选中要打包的文件或文件夹", "warn", "打包选中文件");
        return;
    }

    var items = new List<string>();
    foreach (var f in files)
    {
        if (string.IsNullOrWhiteSpace(f)) continue;
        var p = f.TrimEnd('\\', '/');
        if (p.Length == 0) continue;
        if (!File.Exists(p) && !Directory.Exists(p)) continue;
        if (!items.Any(x => string.Equals(x, p, StringComparison.OrdinalIgnoreCase))) items.Add(p);
    }

    if (items.Count == 0)
    {
        qk.Ui.Notify("选中的项目不可用(驱动器根目录无法打包)", "warn", "打包选中文件");
        return;
    }

    // 去掉被已选中文件夹包含的子项,避免重复打包
    var roots = new List<string>();
    foreach (var p in items)
    {
        var nested = false;
        foreach (var r in items)
        {
            if (string.Equals(p, r, StringComparison.OrdinalIgnoreCase)) continue;
            var prefix = r + "\\";
            if (p.StartsWith(prefix, StringComparison.OrdinalIgnoreCase)) { nested = true; break; }
        }
        if (!nested) roots.Add(p);
    }

    var baseDir = Path.GetDirectoryName(roots[0]);
    if (string.IsNullOrEmpty(baseDir) || !Directory.Exists(baseDir))
    {
        qk.Ui.Notify("无法确定输出目录", "error", "打包选中文件");
        return;
    }

    string baseName;
    if (roots.Count == 1)
    {
        baseName = Directory.Exists(roots[0])
            ? Path.GetFileName(roots[0])
            : Path.GetFileNameWithoutExtension(roots[0]);
    }
    else
    {
        baseName = new DirectoryInfo(baseDir).Name;
    }
    if (string.IsNullOrWhiteSpace(baseName)) baseName = "打包";

    var zipPath = UniquePath(Path.Combine(baseDir, baseName + ".zip"));

    var tempZip = Path.Combine(qk.Files.GetRunTempDirectory(), "archive.tmp");
    var count = 0;
    var bytes = 0L;

    void AddFile(ZipArchive zip, string path, string entryName)
    {
        var name = entryName.Replace('\\', '/');
        var entry = zip.CreateEntry(name, CompressionLevel.Optimal);
        entry.LastWriteTime = File.GetLastWriteTime(path);
        using (var src = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite))
        using (var dst = entry.Open())
        {
            src.CopyTo(dst);
        }
        count++;
        bytes += new FileInfo(path).Length;
    }

    void AddDir(ZipArchive zip, string dir, string prefix)
    {
        var children = Directory.GetFileSystemEntries(dir);
        if (children.Length == 0)
        {
            var marker = zip.CreateEntry(prefix.Replace('\\', '/') + "/", CompressionLevel.NoCompression);
            marker.LastWriteTime = Directory.GetLastWriteTime(dir);
            return;
        }
        foreach (var child in children)
        {
            var entryName = prefix + "/" + Path.GetFileName(child);
            if (Directory.Exists(child)) AddDir(zip, child, entryName);
            else AddFile(zip, child, entryName);
        }
    }

    try
    {
        using (var fs = new FileStream(tempZip, FileMode.Create, FileAccess.ReadWrite))
        using (var zip = new ZipArchive(fs, ZipArchiveMode.Create))
        {
            foreach (var root in roots)
            {
                if (Directory.Exists(root)) AddDir(zip, root, Path.GetFileName(root));
                else AddFile(zip, root, Path.GetFileName(root));
            }
        }

        File.Move(tempZip, zipPath);

        var sizeText = bytes >= 1048576L
            ? (bytes / 1048576.0).ToString("0.##") + " MB"
            : (bytes / 1024.0).ToString("0.#") + " KB";
        qk.Ui.Notify(string.Format("已打包 {0} 个文件({1})\n{2}", count, sizeText, zipPath), "success", "打包选中文件", 5000);
    }
    catch (Exception ex)
    {
        qk.Ui.Notify("打包失败:" + ex.Message, "error", "打包选中文件", -1);
    }
}

string UniquePath(string path)
{
    if (!File.Exists(path) && !Directory.Exists(path)) return path;
    var dir = Path.GetDirectoryName(path) ?? "";
    var name = Path.GetFileNameWithoutExtension(path);
    var ext = Path.GetExtension(path);
    for (var i = 2; i < 1000; i++)
    {
        var candidate = Path.Combine(dir, name + " (" + i + ")" + ext);
        if (!File.Exists(candidate) && !Directory.Exists(candidate)) return candidate;
    }
    return path;
}

CL 回复 浅沧 21小时41分钟前 :

这段代码可以确认原因了:qk.Selection.GetFiles() 读取的是 Windows 资源管理器或桌面的选中项,不会模拟 Ctrl+C,也不会自动回退到 Directory Opus。当前已发布的 2.3.29 中也是这个实现。Quicker 的“获取选中的文件”模块另有 Ctrl+C 回退,两者目前并不等价。可以让 AI 将这里改为调用该模块,以兼容 DO;这次生成动作没有选用这种通用取文件方式,与你前面反馈的情况一致。☆

CL 回复 浅沧 21小时38分钟前 :

这个我等改下代码,让这个方法和组合动作模块一致。

浅沧 回复 CL 21小时38分钟前 :

应该让ai默认调用兼容性更高的方式

CL 回复 浅沧 21小时7分钟前 :

AI不知道那么多信息,提供的信息太详细就会浪费token

CL 回复 浅沧 9小时24分钟前 :

补充版本信息:刚发布的 2.3.30 已让 qk.Selection.GetFiles() 复用“获取选中的文件”模块的逻辑,默认兼容 Directory Opus、OneCommander 等文件管理器。必要时会模拟 Ctrl+C,并保留复制后的剪贴板内容。请升级后用原来的脚本再试一下。☆

回复主贴