Project Icon

CliWrap

简化.NET命令行进程交互

CliWrap是一个专为.NET设计的命令行交互库,提供启动进程、重定向流、异步执行和取消操作等功能。它支持流畅的配置接口和灵活的管道操作,在多个平台上经过测试。CliWrap采用不可变设计,有效防止死锁,适用于多个.NET版本。这个库简化了外部命令行工具的集成过程,提高了开发效率。

CliWrap

状态 乌克兰制造 构建 覆盖率 版本 下载量 Discord 去他妈的俄罗斯

该项目的开发完全由社区资助。考虑捐赠以支持!

图标

CliWrap是一个用于与外部命令行界面交互的库。它提供了一个便捷的模型,用于启动进程、重定向输入和输出流、等待完成、处理取消等。

使用条款[?]

通过使用本项目或其源代码,无论出于何种目的和以何种形式,您默认同意以下所有声明:

  • 谴责俄罗斯及其对乌克兰的军事侵略
  • 认识到俄罗斯是非法入侵主权国家的占领者
  • 支持乌克兰的领土完整,包括其对克里米亚和顿巴斯临时被占领土的主张
  • 拒绝俄罗斯国家宣传perpetuated的虚假叙事

要了解更多关于战争的信息以及如何提供帮助,请点击这里。荣耀属于乌克兰!🇺🇦

安装

  • 📦 NuGet: dotnet add package CliWrap

特性

  • System.Diagnostics.Process的严密抽象
  • 流畅的配置接口
  • 灵活支持管道
  • 完全异步和支持取消的API
  • 使用中断信号进行优雅取消
  • 设计时考虑了严格的不可变性
  • 提供对典型死锁场景的安全保护
  • 在Windows、Linux和macOS上测试通过
  • 目标框架为.NET Standard 2.0+、.NET Core 3.0+、.NET Framework 4.6.2+
  • 无外部依赖

用法

视频指南

您可以观看以下视频之一来了解如何使用该库:

CliWrap简介

停止在.NET中使用Process类进行CLI交互

快速概览

与shell类似,CliWrap的基本工作单元是命令—一个封装了运行进程指令的对象。要构建一个命令,首先调用Cli.Wrap(...)并传入可执行文件路径,然后使用提供的流畅接口来配置参数、工作目录或其他选项。一旦命令配置完成,您可以通过调用ExecuteAsync()来运行它:

using CliWrap;

var result = await Cli.Wrap("path/to/exe")
    .WithArguments(["--foo", "bar"])
    .WithWorkingDirectory("work/dir/path")
    .ExecuteAsync();

// 结果包含:
// -- result.IsSuccess       (bool)
// -- result.ExitCode        (int)
// -- result.StartTime       (DateTimeOffset)
// -- result.ExitTime        (DateTimeOffset)
// -- result.RunTime         (TimeSpan)

上面的代码使用配置的命令行参数和工作目录启动一个子进程,然后异步等待它退出。任务完成后,它会解析为一个CommandResult对象,其中包含进程退出代码和其他相关信息。

警告: 如果底层进程返回非零退出代码,CliWrap将抛出异常,因为这通常表示发生了错误。 您可以通过使用WithValidation(CommandResultValidation.None)禁用结果验证来覆盖此行为

默认情况下,进程的标准输入、输出和错误流被路由到CliWrap等效的空设备,它表示一个空源和一个丢弃所有数据的目标。 您可以通过调用WithStandardInputPipe(...)WithStandardOutputPipe(...)WithStandardErrorPipe(...)来为相应的流配置管道,从而更改此行为:

using CliWrap;

var stdOutBuffer = new StringBuilder();
var stdErrBuffer = new StringBuilder();

var result = await Cli.Wrap("path/to/exe")
    .WithArguments(["--foo", "bar"])
    .WithWorkingDirectory("work/dir/path")
    // 这可以通过`ExecuteBufferedAsync()`简化
    .WithStandardOutputPipe(PipeTarget.ToStringBuilder(stdOutBuffer))
    .WithStandardErrorPipe(PipeTarget.ToStringBuilder(stdErrBuffer))
    .ExecuteAsync();

// 以字符串形式访问内存中缓冲的stdout和stderr
var stdOut = stdOutBuffer.ToString();
var stdErr = stdErrBuffer.ToString();

这个示例命令被配置为将写入标准输出和错误流的数据解码为文本,并将其附加到相应的StringBuilder缓冲区。执行完成后,可以检查这些缓冲区以查看进程在控制台上打印的内容。

处理命令输出是一个非常常见的用例,因此CliWrap提供了一些高级执行模型来简化这些场景。特别是,上面显示的相同内容也可以使用ExecuteBufferedAsync()扩展方法更简洁地实现:

using CliWrap;
using CliWrap.Buffered;

// 调用`ExecuteBufferedAsync()`而不是`ExecuteAsync()`
// 隐式配置将写入内存缓冲区的管道。
var result = await Cli.Wrap("path/to/exe")
    .WithArguments(["--foo", "bar"])
    .WithWorkingDirectory("work/dir/path")
    .ExecuteBufferedAsync();

// 结果包含:
// -- result.IsSuccess       (bool)
// -- result.StandardOutput  (string)
// -- result.StandardError   (string)
// -- result.ExitCode        (int)
// -- result.StartTime       (DateTimeOffset)
// -- result.ExitTime        (DateTimeOffset)
// -- result.RunTime         (TimeSpan)

警告: 使用ExecuteBufferedAsync()时要谨慎。 程序可以向输出和错误流写入任意数据(包括二进制数据),将其存储在内存中可能不切实际。 对于更高级的场景,CliWrap还提供了其他管道选项,这些在管道部分中有介绍。

命令配置

命令对象提供的流畅接口允许您配置其执行的各个方面。本节涵盖了所有可用的配置方法及其用法。

注意Command是一个不可变对象 — 这里列出的所有配置方法都会创建一个新实例,而不是修改现有实例。

WithArguments(...)

设置传递给子进程的命令行参数。

默认值:空。

示例

  • 使用数组设置参数:
var cmd = Cli.Wrap("git")
    // 每个元素被格式化为单独的参数。
    // 等效于:`git commit -m "my commit"`
    .WithArguments(["commit", "-m", "my commit"]);
  • 使用构建器设置参数:
var cmd = Cli.Wrap("git")
    // 每个 Add(...) 调用会自动处理格式化。
    // 等同于: `git clone https://github.com/Tyrrrz/CliWrap --depth 20`
    .WithArguments(args => args
        .Add("clone")
        .Add("https://github.com/Tyrrrz/CliWrap")
        .Add("--depth")
        .Add(20)
    );
var forcePush = true;

var cmd = Cli.Wrap("git")
    // 参数也可以以命令式方式构造。
    // 等同于: `git push --force`
    .WithArguments(args => 
    {
        args.Add("push");

        if (forcePush)
            args.Add("--force");
    });

注意: 构建器重载允许您定义自定义扩展方法以实现可重用的参数模式。 了解更多

  • 直接设置参数:
var cmd = Cli.Wrap("git")
    // 除非必要,否则避免使用此重载。
    // 等同于: `git commit -m "my commit"`
    .WithArguments("commit -m \"my commit\"");

警告: 除非绝对必要,否则避免直接从字符串设置命令行参数。 此方法要求所有参数都提前正确转义和格式化 — 自己做这件事可能会很麻烦。 格式化错误可能导致意外的错误和安全漏洞。

WithWorkingDirectory(...)

设置子进程的工作目录。

默认值: 当前工作目录,即 Directory.GetCurrentDirectory()

示例:

var cmd = Cli.Wrap("git")
    .WithWorkingDirectory("c:/projects/my project/");

WithEnvironmentVariables(...)

设置暴露给子进程的额外环境变量。

默认值: 空。

示例:

  • 使用构建器设置环境变量:
var cmd = Cli.Wrap("git")
    .WithEnvironmentVariables(env => env
        .Set("GIT_AUTHOR_NAME", "John")
        .Set("GIT_AUTHOR_EMAIL", "john@email.com")
    );
  • 直接设置环境变量:
var cmd = Cli.Wrap("git")
    .WithEnvironmentVariables(new Dictionary<string, string?>
    {
        ["GIT_AUTHOR_NAME"] = "John",
        ["GIT_AUTHOR_EMAIL"] = "john@email.com"
    });

注意: 使用 WithEnvironmentVariables(...) 配置的环境变量是在从父进程继承的环境变量之上应用的。 如果需要删除继承的变量,请将相应的值设置为 null

WithCredentials(...)

设置应该以其身份启动子进程的用户的域、名称和密码。

默认值: 无凭据。

示例:

  • 使用构建器设置凭据:
var cmd = Cli.Wrap("git")
    .WithCredentials(creds => creds
       .SetDomain("some_workspace")
       .SetUserName("johndoe")
       .SetPassword("securepassword123")
       .LoadUserProfile()
    );
  • 直接设置凭据:
var cmd = Cli.Wrap("git")
    .WithCredentials(new Credentials(
        domain: "some_workspace",
        userName: "johndoe",
        password: "securepassword123",
        loadUserProfile: true
    ));

警告: 在不同用户名下运行进程在所有平台上都得到支持,但其他选项仅在 Windows 上可用。

WithValidation(...)

设置验证执行结果的策略。

接受的值:

  • CommandResultValidation.None — 不验证
  • CommandResultValidation.ZeroExitCode — 确保进程退出时退出代码为零

默认值: CommandResultValidation.ZeroExitCode

示例:

  • 启用验证:
var cmd = Cli.Wrap("git")
    .WithValidation(CommandResultValidation.ZeroExitCode);
  • 禁用验证:
var cmd = Cli.Wrap("git")
    .WithValidation(CommandResultValidation.None);

如果您想在进程以非零退出代码退出时抛出自定义异常,请不要禁用结果验证,而是捕获默认的 CommandExecutionException 并在您自己的异常中重新抛出它。 这样您可以保留原始异常提供的信息,同时用额外的上下文扩展它:

try
{
    await Cli.Wrap("git").ExecuteAsync();
}
catch (CommandExecutionException ex)
{
    // 重新抛出原始异常以保留有关失败命令的附加信息
    // (退出代码、参数等)。
    throw new MyException("无法运行 git 命令行工具。", ex);
}

WithStandardInputPipe(...)

设置将用于进程标准输入流的管道源。

默认值: PipeSource.Null

管道部分中阅读有关此方法的更多信息。

WithStandardOutputPipe(...)

设置将用于进程标准输出流的管道目标。

默认值: PipeTarget.Null

管道部分中阅读有关此方法的更多信息。

WithStandardErrorPipe(...)

设置将用于进程标准错误流的管道目标。

默认值: PipeTarget.Null

管道部分中阅读有关此方法的更多信息。

管道

CliWrap 提供了一个非常强大和灵活的管道模型,允许您重定向进程的流、转换输入和输出数据,甚至以最小的努力将多个命令链接在一起。 它的核心基于两个抽象:为标准输入流提供数据的 PipeSource 和读取来自标准输出流或标准错误流的数据的 PipeTarget

默认情况下,命令的输入管道设置为 PipeSource.Null,输出和错误管道设置为 PipeTarget.Null。 这些对象有效地代表无操作存根,分别提供空输入和丢弃所有输出。

您可以通过在命令上调用相应的配置方法来指定自己的 PipeSourcePipeTarget 实例:

await using var input = File.OpenRead("input.txt");
await using var output = File.Create("output.txt");

await Cli.Wrap("foo")
    .WithStandardInputPipe(PipeSource.FromStream(input))
    .WithStandardOutputPipe(PipeTarget.ToStream(output))
    .ExecuteAsync();

或者,也可以使用管道运算符以稍微简洁的方式配置管道:

await using var input = File.OpenRead("input.txt");
await using var output = File.Create("output.txt");

await (input | Cli.Wrap("foo") | output).ExecuteAsync();

PipeSourcePipeTarget 都有许多工厂方法,可以让您为不同的场景创建管道实现:

  • PipeSource:
    • PipeSource.Null — 代表一个空的管道源
    • PipeSource.FromStream(...) — 从任何可读流中管道数据
    • PipeSource.FromFile(...) — 从文件中管道数据
    • PipeSource.FromBytes(...) — 从字节数组中管道数据
    • PipeSource.FromString(...) — 从文本字符串中管道数据
    • PipeSource.FromCommand(...) — 从另一个命令的标准输出中管道数据
  • PipeTarget:
    • PipeTarget.Null — 代表丢弃所有数据的管道目标
    • PipeTarget.ToStream(...) — 将数据管道到任何可写流
    • PipeTarget.ToFile(...) — 将数据管道到文件
    • PipeTarget.ToStringBuilder(...) — 将数据作为文本管道到 StringBuilder
    • PipeTarget.ToDelegate(...) — 将数据作为文本,逐行管道到 Action<string>Func<string, Task>Func<string, CancellationToken, Task> 委托
    • PipeTarget.Merge(...) — 通过将相同的数据复制到所有管道来合并多个出站管道

警告: 使用 PipeTarget.Null 会导致底层进程根本不打开相应的流(stdout 或 stderr)。 在绝大多数情况下,这种行为在功能上应该等同于管道到空流,但没有消耗和丢弃不需要的数据的性能开销。 在某些情况下这可能是不希望的 — 在这种情况下,建议使用 PipeTarget.ToStream(Stream.Null) 显式地管道到空流。

以下是一些使用 CliWrap 的管道功能可以实现的示例:

  • 将字符串管道到 stdin:
var cmd = "Hello world" | Cli.Wrap("foo");
await cmd.ExecuteAsync();
  • 将 stdout 作为文本管道到 StringBuilder:
var stdOutBuffer = new StringBuilder();

var cmd = Cli.Wrap("foo") | stdOutBuffer;
await cmd.ExecuteAsync();
  • 将二进制 HTTP 流管道到 stdin:
using var httpClient = new HttpClient();
await using var input = await httpClient.GetStreamAsync("https://example.com/image.png");

var cmd = input | Cli.Wrap("foo");
await cmd.ExecuteAsync();
  • 将一个命令的 stdout 管道到另一个命令的 stdin:
var cmd = Cli.Wrap("foo") | Cli.Wrap("bar") | Cli.Wrap("baz");
await cmd.ExecuteAsync();
  • 将 stdout 和 stderr 管道到父进程的 stdout 和 stderr:
await using var stdOut = Console.OpenStandardOutput();
await using var stdErr = Console.OpenStandardError();

var cmd = Cli.Wrap("foo") | (stdOut, stdErr);
await cmd.ExecuteAsync();
  • 将 stdout 管道到委托:
var cmd = Cli.Wrap("foo") | Debug.WriteLine;
await cmd.ExecuteAsync();
  • 将 stdout 管道到文件,将 stderr 管道到 StringBuilder:
var buffer = new StringBuilder();

var cmd = Cli.Wrap("foo") |
    (PipeTarget.ToFile("output.txt"), PipeTarget.ToStringBuilder(buffer));

await cmd.ExecuteAsync();
  • 同时将 stdout 管道到多个文件:
var target = PipeTarget.Merge(
    PipeTarget.ToFile("file1.txt"),
    PipeTarget.ToFile("file2.txt"),
    PipeTarget.ToFile("file3.txt")
);

var cmd = Cli.Wrap("foo") | target;
await cmd.ExecuteAsync();
  • 将字符串管道输入到一个命令的标准输入,将该命令的标准输出管道输入到另一个命令的标准输入,然后将最后一个命令的标准输出和标准错误管道输入到父进程的标准输出和标准错误:
var cmd =
    "Hello world" |
    Cli.Wrap("foo").WithArguments(["aaa"]) |
    Cli.Wrap("bar").WithArguments(["bbb"]) |
    (Console.WriteLine, Console.Error.WriteLine);

await cmd.ExecuteAsync();

执行模型

CliWrap提供了几种高级执行模型,为命令提供了替代的思考方式。 这些本质上只是利用前面展示的管道功能的扩展方法。

缓冲执行

这种执行模型允许你运行一个进程,同时将其标准输出和错误流作为文本缓冲在内存中。 缓冲的数据可以在命令执行完成后访问。

要使用缓冲执行命令,调用ExecuteBufferedAsync()扩展方法:

using CliWrap;
using CliWrap.Buffered;

var result = await Cli.Wrap("foo")
    .WithArguments(["bar"])
    .ExecuteBufferedAsync();

var exitCode = result.ExitCode;
var stdOut = result.StandardOutput;
var stdErr = result.StandardError;

默认情况下,ExecuteBufferedAsync()假设底层进程使用默认编码(Console.OutputEncoding)将文本写入控制台。 要覆盖此设置,请使用可用的重载方法之一明确指定编码:

// 将stdout和stderr都视为UTF8编码的文本流
var result = await Cli.Wrap("foo")
    .WithArguments(["bar"])
    .ExecuteBufferedAsync(Encoding.UTF8);

// 将stdout视为ASCII编码,stderr视为UTF8编码
var result = await Cli.Wrap("foo")
    .WithArguments(["bar"])
    .ExecuteBufferedAsync(Encoding.ASCII, Encoding.UTF8);

注意: 如果底层进程返回非零退出代码,ExecuteBufferedAsync()将抛出异常,类似于ExecuteAsync(),但异常消息还将包含标准错误数据。

基于拉取的事件流

除了将命令作为任务执行外,CliWrap还支持另一种模型,其中执行表示为事件流。 这让你可以启动一个进程并实时响应它产生的事件。

这些事件包括:

  • StartedCommandEvent — 仅在命令开始执行时接收一次(包含进程ID)
  • StandardOutputCommandEvent — 每当底层进程向输出流写入新行时接收(包含文本字符串)
  • StandardErrorCommandEvent — 每当底层进程向错误流写入新行时接收(包含文本字符串)
  • ExitedCommandEvent — 仅在命令完成执行时接收一次(包含退出代码)

要将命令作为_基于拉取_的事件流执行,请使用ListenAsync()扩展方法:

using CliWrap;
using CliWrap.EventStream;

var cmd = Cli.Wrap("foo").WithArguments(["bar"]);

await foreach (var cmdEvent in cmd.ListenAsync())
{
    switch (cmdEvent)
    {
        case StartedCommandEvent started:
            _output.WriteLine($"进程已启动; ID: {started.ProcessId}");
            break;
        case StandardOutputCommandEvent stdOut:
            _output.WriteLine($"输出> {stdOut.Text}");
            break;
        case StandardErrorCommandEvent stdErr:
            _output.WriteLine($"错误> {stdErr.Text}");
            break;
        case ExitedCommandEvent exited:
            _output.WriteLine($"进程已退出; 代码: {exited.ExitCode}");
            break;
    }
}

ListenAsync()方法启动命令并返回IAsyncEnumerable<CommandEvent>类型的对象,你可以使用C# 8中引入的await foreach构造进行迭代。 使用此执行模型时,通过在每次循环迭代之间锁定管道来实现反压,防止不必要的数据在内存中缓冲。

注意: 就像ExecuteBufferedAsync()一样,你可以使用ListenAsync()的重载之一为其指定自定义编码。

基于推送的事件流

与基于拉取的流类似,你也可以将命令作为_基于推送_的事件流执行:

using System.Reactive;
using CliWrap;
using CliWrap.EventStream;

var cmd = Cli.Wrap("foo").WithArguments(["bar"]);

await cmd.Observe().ForEachAsync(cmdEvent =>
{
    switch (cmdEvent)
    {
        case StartedCommandEvent started:
            _output.WriteLine($"进程已启动; ID: {started.ProcessId}");
            break;
        case StandardOutputCommandEvent stdOut:
            _output.WriteLine($"输出> {stdOut.Text}");
            break;
        case StandardErrorCommandEvent stdErr:
            _output.WriteLine($"错误> {stdErr.Text}");
            break;
        case ExitedCommandEvent exited:
            _output.WriteLine($"进程已退出; 代码: {exited.ExitCode}");
            break;
    }
});

在这种情况下,Observe()返回一个冷IObservable<CommandEvent>,表示命令事件的可观察流。 你可以使用Rx.NET提供的一系列扩展来转换、过滤、限制或以其他方式操作这个流。

与基于拉取的事件流不同,此执行模型不涉及任何反压,这意味着数据以可用的速率推送给观察者。

注意: 与ExecuteBufferedAsync()类似,你可以使用Observe()的重载之一为其指定自定义编码。

将执行模型与自定义管道结合

上面显示的不同执行模型基于管道模型,但这两个概念并不互斥。 使用内置执行模型之一运行命令时,现有的管道配置会被保留并使用PipeTarget.Merge(...)进行扩展。

这意味着你可以,例如,将命令管道输出到文件,同时将其作为事件流执行:

var cmd =
    PipeSource.FromFile("input.txt") |
    Cli.Wrap("foo") |
    PipeTarget.ToFile("output.txt");

// 作为事件流迭代并同时管道输出到文件
// (执行模型保留配置的管道)
await foreach (var cmdEvent in cmd.ListenAsync())
{
    // ...
}

超时和取消

命令执行本质上是异步的,因为它涉及一个完全独立的进程。 在许多情况下,实现一个中止机制来在执行完成之前停止执行可能很有用,无论是通过手动触发还是超时。

要做到这一点,发出相应的CancellationToken并在调用ExecuteAsync()时包含它:

using System.Threading;
using CliWrap;

using var cts = new CancellationTokenSource();

// 10秒后取消
cts.CancelAfter(TimeSpan.FromSeconds(10));

var result = await Cli.Wrap("foo").ExecuteAsync(cts.Token);

在取消请求的情况下,底层进程将被终止,ExecuteAsync()将抛出OperationCanceledException类型的异常(或其派生类TaskCanceledException)。 你需要在代码中捕获这个异常以从取消中恢复:

try
{
    await Cli.Wrap("foo").ExecuteAsync(cts.Token);
}
catch (OperationCanceledException)
{
    // 命令被取消
}

除了直接终止进程外,你还可以通过发送中断信号来以更优雅的方式请求取消。 要做到这一点,向ExecuteAsync()传递一个额外的取消令牌,该令牌对应于该请求:

using var forcefulCts = new CancellationTokenSource();
using var gracefulCts = new CancellationTokenSource();

// 10秒后强制取消。
// 这作为优雅取消耗时过长时的后备方案。
forcefulCts.CancelAfter(TimeSpan.FromSeconds(10));

// 7秒后优雅取消。
// 如果进程响应优雅取消的时间过长,
// 它将在3秒后被强制取消终止(如上面配置)。
gracefulCts.CancelAfter(TimeSpan.FromSeconds(7));

var result = await Cli.Wrap("foo").ExecuteAsync(forcefulCts.Token, gracefulCts.Token);

CliWrap中请求优雅取消在功能上等同于在控制台窗口中按Ctrl+C。 底层进程可以处理这个信号,在最后执行一些关键工作,然后按自己的方式退出。

优雅取消本质上是合作性的,所以进程可能需要太长时间来满足请求或选择完全忽略它。 在上面的例子中,通过额外安排延迟的强制取消来缓解这种风险,防止命令挂起。

如果你在方法内执行命令,并且不想向调用者暴露这些实现细节,你可以依赖以下模式,使用提供的令牌进行优雅取消,并用强制回退扩展它:

public async Task GitPushAsync(CancellationToken cancellationToken = default)
{
    using var forcefulCts = new CancellationTokenSource();

    // 当取消令牌被触发时,
    // 安排强制取消作为后备。
    await using var link = cancellationToken.Register(() =>
        forcefulCts.CancelAfter(TimeSpan.FromSeconds(3))
    );

    await Cli.Wrap("git")
        .WithArguments(["push"])
        .ExecuteAsync(forcefulCts.Token, cancellationToken);
}

注意: 与ExecuteAsync()类似,ExecuteBufferedAsync()ListenAsync()Observe()也支持取消。

检索进程相关信息

ExecuteAsync()ExecuteBufferedAsync()返回的任务实际上不是普通的Task<T>,而是CommandTask<T>的实例。 这是一个专门的可等待对象,包含与执行命令相关联的进程的额外信息:

var task = Cli.Wrap("foo")
    .WithArguments(["bar"])
    .ExecuteAsync();

// 获取进程ID
var processId = task.ProcessId;

// 等待任务完成
await task;
项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

豆包 MarsCode 是一款革命性的编程助手,通过AI技术提供代码补全、单测生成、代码解释和智能问答等功能,支持100+编程语言,与主流编辑器无缝集成,显著提升开发效率和代码质量。

Project Cover

AI写歌

Suno AI是一个革命性的AI音乐创作平台,能在短短30秒内帮助用户创作出一首完整的歌曲。无论是寻找创作灵感还是需要快速制作音乐,Suno AI都是音乐爱好者和专业人士的理想选择。

Project Cover

白日梦AI

白日梦AI提供专注于AI视频生成的多样化功能,包括文生视频、动态画面和形象生成等,帮助用户快速上手,创造专业级内容。

Project Cover

有言AI

有言平台提供一站式AIGC视频创作解决方案,通过智能技术简化视频制作流程。无论是企业宣传还是个人分享,有言都能帮助用户快速、轻松地制作出专业级别的视频内容。

Project Cover

Kimi

Kimi AI助手提供多语言对话支持,能够阅读和理解用户上传的文件内容,解析网页信息,并结合搜索结果为用户提供详尽的答案。无论是日常咨询还是专业问题,Kimi都能以友好、专业的方式提供帮助。

Project Cover

讯飞绘镜

讯飞绘镜是一个支持从创意到完整视频创作的智能平台,用户可以快速生成视频素材并创作独特的音乐视频和故事。平台提供多样化的主题和精选作品,帮助用户探索创意灵感。

Project Cover

讯飞文书

讯飞文书依托讯飞星火大模型,为文书写作者提供从素材筹备到稿件撰写及审稿的全程支持。通过录音智记和以稿写稿等功能,满足事务性工作的高频需求,帮助撰稿人节省精力,提高效率,优化工作与生活。

Project Cover

阿里绘蛙

绘蛙是阿里巴巴集团推出的革命性AI电商营销平台。利用尖端人工智能技术,为商家提供一键生成商品图和营销文案的服务,显著提升内容创作效率和营销效果。适用于淘宝、天猫等电商平台,让商品第一时间被种草。

Project Cover

AIWritePaper论文写作

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

投诉举报邮箱: service@vectorlightyear.com
@2024 懂AI·鲁ICP备2024100362号-6·鲁公网安备37021002001498号