Project Icon

zerolog

Go语言高性能结构化JSON日志库

zerolog是一个为Go语言设计的高性能JSON日志库。它采用零内存分配策略和链式API,高效输出结构化日志。除了卓越性能外,zerolog还提供分级日志、采样、钩子和上下文字段等功能,适用于各种规模的Go项目。其简洁API和优异表现使其成为Go生态系统中备受欢迎的日志解决方案。

零分配 JSON 日志记录器

godoc license Build Status Go Coverage

zerolog 包提供了一个快速简单的专用于 JSON 输出的日志记录器。

Zerolog 的 API 旨在提供出色的开发者体验和惊人的性能。其独特的链式 API 使 zerolog 能够通过避免分配和反射来编写 JSON(或 CBOR)日志事件。

Uber 的 zap 库首创了这种方法。Zerolog 在此基础上更进一步,提供了更简单易用的 API 和更好的性能。

为了保持代码库和 API 的简洁,zerolog 只专注于高效的结构化日志记录。通过提供的(但效率较低的)zerolog.ConsoleWriter可以实现控制台上的美化日志输出。

美化日志输出图片

谁在使用 zerolog

了解谁在使用 zerolog并将你的公司/项目添加到列表中。

特性

安装

go get -u github.com/rs/zerolog/log

入门

简单日志记录示例

对于简单的日志记录,导入全局日志记录包 github.com/rs/zerolog/log

package main

import (
    "github.com/rs/zerolog"
    "github.com/rs/zerolog/log"
)

func main() {
    // UNIX 时间比大多数时间戳更快且更小
    zerolog.TimeFieldFormat = zerolog.TimeFormatUnix

    log.Print("hello world")
}

// 输出: {"time":1516134303,"level":"debug","message":"hello world"}

注意:默认情况下,日志写入 os.Stderr 注意:log.Print 的默认日志级别是 trace

上下文日志记录

zerolog 允许以键值对的形式向日志消息添加数据。添加到消息中的数据为日志事件提供了"上下文",这对调试以及众多其他用途至关重要。以下是一个示例:

package main

import (
    "github.com/rs/zerolog"
    "github.com/rs/zerolog/log"
)

func main() {
    zerolog.TimeFieldFormat = zerolog.TimeFormatUnix

    log.Debug().
        Str("Scale", "833 cents").
        Float64("Interval", 833.09).
        Msg("Fibonacci is everywhere")
    
    log.Debug().
        Str("Name", "Tom").
        Send()
}

// 输出: {"level":"debug","Scale":"833 cents","Interval":833.09,"time":1562212768,"message":"Fibonacci is everywhere"}
// 输出: {"level":"debug","Name":"Tom","time":1562212768}

你会注意到在上面的示例中,添加上下文字段时,字段是强类型的。你可以在这里找到支持的字段的完整列表

分级日志记录

简单分级日志记录示例

package main

import (
    "github.com/rs/zerolog"
    "github.com/rs/zerolog/log"
)

func main() {
    zerolog.TimeFieldFormat = zerolog.TimeFormatUnix

    log.Info().Msg("hello world")
}

// 输出: {"time":1516134303,"level":"info","message":"hello world"}

非常重要的是要注意,当使用 zerolog 链式 API 时,如上所示(log.Info().Msg("hello world")),链必须包含 MsgMsgf 方法调用。如果你忘记添加这两个方法中的任何一个,日志将不会记录,并且没有编译时错误来提醒你这一点。

zerolog 允许在以下级别(从高到低)进行日志记录:

  • panic (zerolog.PanicLevel, 5)
  • fatal (zerolog.FatalLevel, 4)
  • error (zerolog.ErrorLevel, 3)
  • warn (zerolog.WarnLevel, 2)
  • info (zerolog.InfoLevel, 1)
  • debug (zerolog.DebugLevel, 0)
  • trace (zerolog.TraceLevel, -1)

你可以使用 zerolog 包中的 SetGlobalLevel 函数将全局日志级别设置为上述任何选项,传入给定的常量之一,例如 zerolog.InfoLevel 将是"info"级别。无论选择哪个级别,所有级别大于或等于该级别的日志都将被记录。要完全关闭日志记录,请传递 zerolog.Disabled 常量。

设置全局日志级别

这个示例使用命令行标志来演示根据所选日志级别的不同输出。

package main

import (
    "flag"

    "github.com/rs/zerolog"
    "github.com/rs/zerolog/log"
)

func main() {
    zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
    debug := flag.Bool("debug", false, "sets log level to debug")

    flag.Parse()

    // 本示例的默认级别为 info,除非存在 debug 标志
    zerolog.SetGlobalLevel(zerolog.InfoLevel)
    if *debug {
        zerolog.SetGlobalLevel(zerolog.DebugLevel)
    }

    log.Debug().Msg("This message appears only when log level set to Debug")
    log.Info().Msg("This message appears when log level set to Debug or Info")

    if e := log.Debug(); e.Enabled() {
        // 仅在启用时计算日志输出。
        value := "bar"
        e.Str("foo", value).Msg("some debug message")
    }
}

Info 输出(无标志)

$ ./logLevelExample
{"time":1516387492,"level":"info","message":"This message appears when log level set to Debug or Info"}

Debug 输出(设置 debug 标志)

$ ./logLevelExample -debug
{"time":1516387573,"level":"debug","message":"This message appears only when log level set to Debug"}
{"time":1516387573,"level":"info","message":"This message appears when log level set to Debug or Info"}
{"time":1516387573,"level":"debug","foo":"bar","message":"some debug message"}

不带级别或消息的日志记录

你可以选择使用Log方法进行无特定级别的日志记录。你也可以通过在Msg方法的msg string参数中设置空字符串来不写入消息。以下示例演示了这两种方式。

package main

import (
    "github.com/rs/zerolog"
    "github.com/rs/zerolog/log"
)

func main() {
    zerolog.TimeFieldFormat = zerolog.TimeFormatUnix

    log.Log().
        Str("foo", "bar").
        Msg("")
}

// 输出: {"time":1494567715,"foo":"bar"}

错误日志记录

你可以使用Err方法记录错误

package main

import (
	"errors"

	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
)

func main() {
	zerolog.TimeFieldFormat = zerolog.TimeFormatUnix

	err := errors.New("似乎这里有个错误")
	log.Error().Err(err).Msg("")
}

// 输出: {"level":"error","error":"似乎这里有个错误","time":1609085256}

错误的默认字段名是error,你可以通过设置zerolog.ErrorFieldName来满足你的需求。

带堆栈跟踪的错误日志记录

使用github.com/pkg/errors,你可以为错误添加格式化的堆栈跟踪。

package main

import (
	"github.com/pkg/errors"
	"github.com/rs/zerolog/pkgerrors"

	"github.com/rs/zerolog"
	"github.com/rs/zerolog/log"
)

func main() {
	zerolog.TimeFieldFormat = zerolog.TimeFormatUnix
	zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack

	err := outer()
	log.Error().Stack().Err(err).Msg("")
}

func inner() error {
	return errors.New("似乎这里有个错误")
}

func middle() error {
	err := inner()
	if err != nil {
		return err
	}
	return nil
}

func outer() error {
	err := middle()
	if err != nil {
		return err
	}
	return nil
}

// 输出: {"level":"error","stack":[{"func":"inner","line":"20","source":"errors.go"},{"func":"middle","line":"24","source":"errors.go"},{"func":"outer","line":"32","source":"errors.go"},{"func":"main","line":"15","source":"errors.go"},{"func":"main","line":"204","source":"proc.go"},{"func":"goexit","line":"1374","source":"asm_amd64.s"}],"error":"似乎这里有个错误","time":1609086683}

必须设置zerolog.ErrorStackMarshaler才能输出堆栈信息。

记录致命错误消息

package main

import (
    "errors"

    "github.com/rs/zerolog"
    "github.com/rs/zerolog/log"
)

func main() {
    err := errors.New("收债人的一生都在应对紧张局势")
    service := "myservice"

    zerolog.TimeFieldFormat = zerolog.TimeFormatUnix

    log.Fatal().
        Err(err).
        Str("service", service).
        Msgf("无法启动%s", service)
}

// 输出: {"time":1516133263,"level":"fatal","error":"收债人的一生都在应对紧张局势","service":"myservice","message":"无法启动myservice"}
//         exit status 1

注意:即使日志记录器被禁用,使用Msgf也会产生一次内存分配。

创建日志记录器实例以管理不同的输出

logger := zerolog.New(os.Stderr).With().Timestamp().Logger()

logger.Info().Str("foo", "bar").Msg("你好,世界")

// 输出: {"level":"info","time":1494567715,"message":"你好,世界","foo":"bar"}

子日志记录器让你可以链式添加额外上下文

sublogger := log.With().
                 Str("component", "foo").
                 Logger()
sublogger.Info().Msg("你好,世界")

// 输出: {"level":"info","time":1494567715,"message":"你好,世界","component":"foo"}

美化日志输出

要输出人类友好的、带颜色的日志,使用zerolog.ConsoleWriter

log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})

log.Info().Str("foo", "bar").Msg("你好,世界")

// 输出: 3:04PM INF 你好,世界 foo=bar

自定义配置和格式化:

output := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC3339}
output.FormatLevel = func(i interface{}) string {
    return strings.ToUpper(fmt.Sprintf("| %-6s|", i))
}
output.FormatMessage = func(i interface{}) string {
    return fmt.Sprintf("***%s****", i)
}
output.FormatFieldName = func(i interface{}) string {
    return fmt.Sprintf("%s:", i)
}
output.FormatFieldValue = func(i interface{}) string {
    return strings.ToUpper(fmt.Sprintf("%s", i))
}

log := zerolog.New(output).With().Timestamp().Logger()

log.Info().Str("foo", "bar").Msg("你好,世界")

// 输出: 2006-01-02T15:04:05Z07:00 | INFO  | ***你好,世界**** foo:BAR

子字典

log.Info().
    Str("foo", "bar").
    Dict("dict", zerolog.Dict().
        Str("bar", "baz").
        Int("n", 1),
    ).Msg("你好,世界")

// 输出: {"level":"info","time":1494567715,"foo":"bar","dict":{"bar":"baz","n":1},"message":"你好,世界"}

自定义自动字段名

zerolog.TimestampFieldName = "t"
zerolog.LevelFieldName = "l"
zerolog.MessageFieldName = "m"

log.Info().Msg("你好,世界")

// 输出: {"l":"info","t":1494567715,"m":"你好,世界"}

为全局日志记录器添加上下文字段

log.Logger = log.With().Str("foo", "bar").Logger()

在日志中添加文件和行号

等同于Llongfile

log.Logger = log.With().Caller().Logger()
log.Info().Msg("你好,世界")

// 输出: {"level": "info", "message": "你好,世界", "caller": "/go/src/your_project/some_file:21"}

等同于Lshortfile

zerolog.CallerMarshalFunc = func(pc uintptr, file string, line int) string {
    return filepath.Base(file) + ":" + strconv.Itoa(line)
}
log.Logger = log.With().Caller().Logger()
log.Info().Msg("你好,世界")

// 输出: {"level": "info", "message": "你好,世界", "caller": "some_file:21"}

线程安全、无锁、非阻塞的写入器

如果你的写入器可能很慢或不是线程安全的,而你需要确保日志生产者永远不会被慢速写入器拖慢,你可以使用diode.Writer,如下所示:

wr := diode.NewWriter(os.Stdout, 1000, 10*time.Millisecond, func(missed int) {
		fmt.Printf("日志记录器丢弃了 %d 条消息", missed)
	})
log := zerolog.New(wr)
log.Print("测试")

要使用此功能,你需要安装code.cloudfoundry.org/go-diodes

日志采样

sampled := log.Sample(&zerolog.BasicSampler{N: 10})
sampled.Info().Msg("每10条消息记录一次")

// 输出: {"time":1494567715,"level":"info","message":"每10条消息记录一次"}

更高级的采样:

// 每1秒期间允许5条debug消息。
// 超过5条debug消息后,每100条debug消息记录1条。
// 其他级别不进行采样。
sampled := log.Sample(zerolog.LevelSampler{
    DebugSampler: &zerolog.BurstSampler{
        Burst: 5,
        Period: 1*time.Second,
        NextSampler: &zerolog.BasicSampler{N: 100},
    },
})
sampled.Debug().Msg("你好,世界")

// 输出: {"time":1494567715,"level":"debug","message":"hello world"}


### 钩子

```go
type SeverityHook struct{}

func (h SeverityHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {
    if level != zerolog.NoLevel {
        e.Str("severity", level.String())
    }
}

hooked := log.Hook(SeverityHook{})
hooked.Warn().Msg("")

// 输出: {"level":"warn","severity":"warn"}

通过上下文传递子日志记录器

ctx := log.With().Str("component", "module").Logger().WithContext(ctx)

log.Ctx(ctx).Info().Msg("hello world")

// 输出: {"component":"module","level":"info","message":"hello world"}

设置为标准日志输出

log := zerolog.New(os.Stdout).With().
    Str("foo", "bar").
    Logger()

stdlog.SetFlags(0)
stdlog.SetOutput(log)

stdlog.Print("hello world")

// 输出: {"foo":"bar","message":"hello world"}

context.Context 集成

Go 上下文通常在整个 Go 代码中传递,这可以帮助你将 Logger 传递到可能难以注入的地方。可以使用 Logger.WithContext(ctx)Logger 实例附加到 Go 上下文(context.Context)中,并使用 zerolog.Ctx(ctx) 从中提取。例如:

func f() {
    logger := zerolog.New(os.Stdout)
    ctx := context.Background()

    // 将 Logger 附加到 context.Context
    ctx = logger.WithContext(ctx)
    someFunc(ctx)
}

func someFunc(ctx context.Context) {
    // 从 Go Context 获取 Logger。如果为 nil,则返回
    // `zerolog.DefaultContextLogger`,如果
    // `DefaultContextLogger` 为 nil,则返回一个禁用的日志记录器。
    logger := zerolog.Ctx(ctx)
    logger.Info().Msg("Hello")
}

第二种形式的 context.Context 集成允许你将当前的 context.Context 传递到记录的事件中,并从钩子中检索它。这对于记录存储在 Go 上下文中的跟踪和跨度 ID 或其他信息非常有用,并有助于在某些系统中统一日志记录和跟踪:

type TracingHook struct{}

func (h TracingHook) Run(e *zerolog.Event, level zerolog.Level, msg string) {
    ctx := e.GetCtx()
    spanId := getSpanIdFromContext(ctx) // 根据你的跟踪框架
    e.Str("span-id", spanId)
}

func f() {
    // 设置日志记录器
    logger := zerolog.New(os.Stdout)
    logger = logger.Hook(TracingHook{})

    ctx := context.Background()
    // 使用 Ctx 函数使上下文对钩子可用
    logger.Info().Ctx(ctx).Msg("Hello")
}

net/http 集成

github.com/rs/zerolog/hlog 包提供了一些辅助函数,用于将 zerolog 与 http.Handler 集成。

在这个例子中,我们使用 alice 来安装日志记录器,以提高可读性。

log := zerolog.New(os.Stdout).With().
    Timestamp().
    Str("role", "my-service").
    Str("host", host).
    Logger()

c := alice.New()

// 安装日志处理器,默认输出到控制台
c = c.Append(hlog.NewHandler(log))

// 安装一些提供的额外处理器来设置请求的上下文字段。
// 通过这个处理器,我们所有的日志都会带有一些预填充的字段。
c = c.Append(hlog.AccessHandler(func(r *http.Request, status, size int, duration time.Duration) {
    hlog.FromRequest(r).Info().
        Str("method", r.Method).
        Stringer("url", r.URL).
        Int("status", status).
        Int("size", size).
        Dur("duration", duration).
        Msg("")
}))
c = c.Append(hlog.RemoteAddrHandler("ip"))
c = c.Append(hlog.UserAgentHandler("user_agent"))
c = c.Append(hlog.RefererHandler("referer"))
c = c.Append(hlog.RequestIDHandler("req_id", "Request-Id"))

// 这是你最终的处理器
h := c.Then(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
    // 从请求的上下文中获取日志记录器。你可以安全地假设它
    // 总是存在的:如果处理器被移除,hlog.FromRequest
    // 将返回一个无操作的日志记录器。
    hlog.FromRequest(r).Info().
        Str("user", "current user").
        Str("status", "ok").
        Msg("Something happened")

    // 输出: {"level":"info","time":"2001-02-03T04:05:06Z","role":"my-service","host":"local-hostname","req_id":"b4g0l5t6tfid6dtrapu0","user":"current user","status":"ok","message":"Something happened"}
}))
http.Handle("/", h)

if err := http.ListenAndServe(":8080", nil); err != nil {
    log.Fatal().Err(err).Msg("Startup failed")
}

多重日志输出

可以使用 zerolog.MultiLevelWriter 将日志消息发送到多个输出。 在这个例子中,我们将日志消息同时发送到 os.Stdout 和内置的 ConsoleWriter。

func main() {
	consoleWriter := zerolog.ConsoleWriter{Out: os.Stdout}

	multi := zerolog.MultiLevelWriter(consoleWriter, os.Stdout)

	logger := zerolog.New(multi).With().Timestamp().Logger()

	logger.Info().Msg("Hello World!")
}

// 输出 (第1行: 控制台; 第2行: Stdout)
// 12:36PM INF Hello World!
// {"level":"info","time":"2019-11-07T12:36:38+03:00","message":"Hello World!"}

全局设置

可以更改一些设置,这些设置将应用于所有日志记录器:

  • log.Logger:你可以设置这个值来自定义全局日志记录器(用于包级别方法的日志记录器)。
  • zerolog.SetGlobalLevel:可以提高所有日志记录器的最低级别。使用 zerolog.Disabled 调用此函数可以完全禁用日志记录(静默模式)。
  • zerolog.DisableSampling:如果参数为 true,所有采样日志记录器将停止采样并发出 100% 的日志事件。
  • zerolog.TimestampFieldName:可以设置为自定义 Timestamp 字段名。
  • zerolog.LevelFieldName:可以设置为自定义级别字段名。
  • zerolog.MessageFieldName:可以设置为自定义消息字段名。
  • zerolog.ErrorFieldName:可以设置为自定义 Err 字段名。
  • zerolog.TimeFieldFormat:可以设置为自定义 Time 字段值的格式。如果设置为 zerolog.TimeFormatUnixzerolog.TimeFormatUnixMszerolog.TimeFormatUnixMicro,时间将格式化为 UNIX 时间戳。
  • zerolog.DurationFieldUnit:可以设置为自定义由 Dur 添加的 time.Duration 类型字段的单位(默认:time.Millisecond)。
  • zerolog.DurationFieldInteger:如果设置为 trueDur 字段将格式化为整数而不是浮点数(默认:false)。
  • zerolog.ErrorHandler:当 zerolog 无法在其输出上写入事件时调用。如果未设置,错误将打印到标准错误输出。此处理程序必须是线程安全的且非阻塞的。
  • zerolog.FloatingPointPrecision:如果设置为非 -1 的值,控制在 JSON 中格式化浮点数时的位数。有关更多详细信息,请参见 strconv.FormatFloat

字段类型

标准类型

  • Str
  • Bool
  • IntInt8Int16Int32Int64
  • UintUint8Uint16Uint32Uint64
  • Float32Float64

高级字段

  • Err:接受一个error并使用zerolog.ErrorFieldName字段名将其渲染为字符串。
  • Func:仅在启用该级别时运行func
  • Timestamp:插入一个使用zerolog.TimestampFieldName字段名的时间戳字段,格式化使用zerolog.TimeFieldFormat
  • Time:添加一个使用zerolog.TimeFieldFormat格式化的时间字段。
  • Dur:添加一个time.Duration字段。
  • Dict:作为事件的字段添加一个子键/值。
  • RawJSON:添加一个已编码JSON([]byte)的字段。
  • Hex:添加一个格式化为十六进制字符串的值字段([]byte)。
  • Interface:使用反射来序列化类型。

大多数字段也以切片格式提供(Strs用于[]stringErrs用于[]error等)。

二进制编码

除了默认的JSON编码外,zerolog还可以使用CBOR编码生成二进制日志。编码选择可以在编译时使用构建标签binary_log来决定,如下所示:

go build -tags binary_log .

要解码二进制编码的日志文件,可以使用任何CBOR解码器。经测试可与zerolog库一起使用的解码器是CSD

相关项目

  • grpc-zerolog:使用zerolog实现的grpclog.LoggerV2接口
  • overlog:使用zerolog实现的Mapped Diagnostic Context接口
  • zerologr:使用zerolog实现的logr.LogSink接口

基准测试

更全面和最新的基准测试请参见logbench

所有操作都是无分配的(这些数字包括JSON编码):

BenchmarkLogEmpty-8        100000000    19.1 ns/op     0 B/op       0 allocs/op
BenchmarkDisabled-8        500000000    4.07 ns/op     0 B/op       0 allocs/op
BenchmarkInfo-8            30000000     42.5 ns/op     0 B/op       0 allocs/op
BenchmarkContextFields-8   30000000     44.9 ns/op     0 B/op       0 allocs/op
BenchmarkLogFields-8       10000000     184 ns/op      0 B/op       0 allocs/op

有几个包含zerolog的Go日志基准测试和比较。

使用Uber的zap比较基准:

记录一条消息和10个字段:

时间分配字节数分配对象数
zerolog767 ns/op552 B/op6 allocs/op
:zap: zap848 ns/op704 B/op2 allocs/op
:zap: zap (sugared)1363 ns/op1610 B/op20 allocs/op
go-kit3614 ns/op2895 B/op66 allocs/op
lion5392 ns/op5807 B/op63 allocs/op
logrus5661 ns/op6092 B/op78 allocs/op
apex/log15332 ns/op3832 B/op65 allocs/op
log1520657 ns/op5632 B/op93 allocs/op

使用已有10个上下文字段的logger记录一条消息:

时间分配字节数分配对象数
zerolog52 ns/op0 B/op0 allocs/op
:zap: zap283 ns/op0 B/op0 allocs/op
:zap: zap (sugared)337 ns/op80 B/op2 allocs/op
lion2702 ns/op4074 B/op38 allocs/op
go-kit3378 ns/op3046 B/op52 allocs/op
logrus4309 ns/op4564 B/op63 allocs/op
apex/log13456 ns/op2898 B/op51 allocs/op
log1514179 ns/op2642 B/op44 allocs/op

记录一个静态字符串,不带任何上下文或printf风格的模板:

时间分配字节数分配对象数
zerolog50 ns/op0 B/op0 allocs/op
:zap: zap236 ns/op0 B/op0 allocs/op
标准库453 ns/op80 B/op2 allocs/op
:zap: zap (sugared)337 ns/op80 B/op2 allocs/op
go-kit508 ns/op656 B/op13 allocs/op
lion771 ns/op1224 B/op10 allocs/op
logrus1244 ns/op1505 B/op27 allocs/op
apex/log2751 ns/op584 B/op11 allocs/op
log155181 ns/op1592 B/op26 allocs/op

注意事项

字段重复

请注意,zerolog不会对字段进行去重。多次使用相同的键会在最终的JSON中创建多个键:

logger := zerolog.New(os.Stderr).With().Timestamp().Logger()
logger.Info().
       Timestamp().
       Msg("dup")
// 输出: {"level":"info","time":1494567715,"time":1494567715,"message":"dup"}

在这种情况下,许多消费者会取最后一个值,但这并不能保证;如有疑问,请检查您的消费者。

并发安全

使用UpdateContext时要小心。它不是并发安全的。使用With方法创建一个子logger:

func handler(w http.ResponseWriter, r *http.Request) {
    // 创建一个子logger以确保并发安全
    logger := log.Logger.With().Logger()

    // 添加上下文字段,例如来自HTTP头的User-Agent
    logger.UpdateContext(func(c zerolog.Context) zerolog.Context {
        ...
    })
}
项目侧边栏1项目侧边栏2
推荐项目
Project Cover

豆包MarsCode

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

Project Cover

AI写歌

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

Project Cover

有言AI

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

Project Cover

Kimi

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

Project Cover

阿里绘蛙

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

Project Cover

吐司

探索Tensor.Art平台的独特AI模型,免费访问各种图像生成与AI训练工具,从Stable Diffusion等基础模型开始,轻松实现创新图像生成。体验前沿的AI技术,推动个人和企业的创新发展。

Project Cover

SubCat字幕猫

SubCat字幕猫APP是一款创新的视频播放器,它将改变您观看视频的方式!SubCat结合了先进的人工智能技术,为您提供即时视频字幕翻译,无论是本地视频还是网络流媒体,让您轻松享受各种语言的内容。

Project Cover

美间AI

美间AI创意设计平台,利用前沿AI技术,为设计师和营销人员提供一站式设计解决方案。从智能海报到3D效果图,再到文案生成,美间让创意设计更简单、更高效。

Project Cover

AIWritePaper论文写作

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

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