Skip to content

Commit

Permalink
First implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
igolaizola committed Jul 27, 2023
1 parent 23ef7b4 commit 76a5c50
Show file tree
Hide file tree
Showing 13 changed files with 856 additions and 5 deletions.
26 changes: 26 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
name: ci

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
ci:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Setup go
uses: actions/setup-go@v4
with:
go-version-file: 'go.mod'
- name: Build
run: go build -v ./...
- name: Lint
uses: golangci/golangci-lint-action@v3
- name: Test
run: go test -v ./...
29 changes: 29 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: goreleaser

on:
push:
tags:
- '*'

permissions:
contents: write

jobs:
goreleaser:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- run: git fetch --force --tags
- uses: actions/setup-go@v3
with:
go-version-file: 'go.mod'
cache: true
- uses: goreleaser/goreleaser-action@v4
with:
distribution: goreleaser
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
11 changes: 6 additions & 5 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
# If you prefer the allow list template instead of the deny list, see community template:
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
#
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
bin

# Test binary, built with `go test -c`
*.test
Expand All @@ -17,5 +15,8 @@
# Dependency directories (remove the comment below to include it)
# vendor/

# Go workspace file
go.work
# Other
.history
.vscode
*.conf
logs/
14 changes: 14 additions & 0 deletions .goreleaser.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
builds:
- id: vidai
binary: vidai
main: ./cmd/vidai
goarch:
- amd64
- arm64
- arm
archives:
- id: vidai
builds:
- vidai
format: zip
name_template: 'vidai_{{ .Version }}_{{- if eq .Os "darwin" }}macos{{- else }}{{ .Os }}{{ end }}_{{ .Arch }}'
15 changes: 15 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# builder image
FROM golang:alpine as builder
ARG TARGETPLATFORM
COPY . /src
WORKDIR /src
RUN apk add --no-cache make bash git
RUN make app-build PLATFORMS=$TARGETPLATFORM

# running image
FROM alpine
WORKDIR /home
COPY --from=builder /src/bin/vidai-* /bin/vidai

# executable
ENTRYPOINT [ "/bin/vidai" ]
74 changes: 74 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/bin/bash

SHELL = /bin/bash
PLATFORMS ?= linux/amd64 darwin/amd64 windows/amd64
IMAGE_PREFIX ?= igolaizola
REPO_NAME ?= vidai
COMMIT_SHORT ?= $(shell git rev-parse --verify --short HEAD)
VERSION ?= $(COMMIT_SHORT)
VERSION_NOPREFIX ?= $(shell echo $(VERSION) | sed -e 's/^[[v]]*//')

# Build the binaries for the current platform
.PHONY: build
build:
os=$$(go env GOOS); \
arch=$$(go env GOARCH); \
PLATFORMS="$$os/$$arch" make app-build

# Build the binaries
# Example: PLATFORMS=linux/amd64 make app-build
.PHONY: app-build
app-build:
@for platform in $(PLATFORMS) ; do \
os=$$(echo $$platform | cut -f1 -d/); \
arch=$$(echo $$platform | cut -f2 -d/); \
arm=$$(echo $$platform | cut -f3 -d/); \
arm=$${arm#v}; \
ext=""; \
if [ "$$os" == "windows" ]; then \
ext=".exe"; \
fi; \
file=./bin/$(REPO_NAME)-$(VERSION_NOPREFIX)-$$(echo $$platform | tr / -)$$ext; \
GOOS=$$os GOARCH=$$arch GOARM=$$arm CGO_ENABLED=0 \
go build \
-a -x -tags netgo,timetzdata -installsuffix cgo -installsuffix netgo \
-ldflags " \
-X main.Version=$(VERSION_NOPREFIX) \
-X main.GitRev=$(COMMIT_SHORT) \
" \
-o $$file \
./cmd/$(REPO_NAME); \
if [ $$? -ne 0 ]; then \
exit 1; \
fi; \
chmod +x $$file; \
done

# Build the docker image
# Example: PLATFORMS=linux/amd64 make docker-build
.PHONY: docker-build
docker-build:
rm -rf bin; \
@platforms=($(PLATFORMS)); \
platform=$${platforms[0]}; \
if [[ $${#platforms[@]} -ne 1 ]]; then \
echo "Multi-arch build not supported"; \
exit 1; \
fi; \
docker build --platform $$platform -t $(IMAGE_PREFIX)/$(REPO_NAME):$(VERSION) .; \
if [ $$? -ne 0 ]; then \
exit 1; \
fi

# Build the docker images using buildx
# Example: PLATFORMS="linux/amd64 darwin/amd64 windows/amd64" make docker-buildx
.PHONY: docker-buildx
docker-buildx:
@platforms=($(PLATFORMS)); \
platform=$$(IFS=, ; echo "$${platforms[*]}"); \
docker buildx build --platform $$platform -t $(IMAGE_PREFIX)/$(REPO_NAME):$(VERSION) .

# Clean binaries
.PHONY: clean
clean:
rm -rf bin
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
# vidai

Video generation using AI
116 changes: 116 additions & 0 deletions cmd/vidai/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
package main

import (
"context"
"flag"
"fmt"
"log"
"os"
"os/signal"
"runtime/debug"
"strings"
"time"

"github.com/igolaizola/vidai"
"github.com/peterbourgon/ff/v3"
"github.com/peterbourgon/ff/v3/ffcli"
)

// Build flags
var version = ""
var commit = ""
var date = ""

func main() {
// Create signal based context
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
defer cancel()

// Launch command
cmd := newCommand()
if err := cmd.ParseAndRun(ctx, os.Args[1:]); err != nil {
log.Fatal(err)
}
}

func newCommand() *ffcli.Command {
fs := flag.NewFlagSet("vidai", flag.ExitOnError)

return &ffcli.Command{
ShortUsage: "vidai [flags] <subcommand>",
FlagSet: fs,
Exec: func(context.Context, []string) error {
return flag.ErrHelp
},
Subcommands: []*ffcli.Command{
newVersionCommand(),
newGenerateCommand(),
},
}
}

func newVersionCommand() *ffcli.Command {
return &ffcli.Command{
Name: "version",
ShortUsage: "vidai version",
ShortHelp: "print version",
Exec: func(ctx context.Context, args []string) error {
v := version
if v == "" {
if buildInfo, ok := debug.ReadBuildInfo(); ok {
v = buildInfo.Main.Version
}
}
if v == "" {
v = "dev"
}
versionFields := []string{v}
if commit != "" {
versionFields = append(versionFields, commit)
}
if date != "" {
versionFields = append(versionFields, date)
}
fmt.Println(strings.Join(versionFields, " "))
return nil
},
}
}

func newGenerateCommand() *ffcli.Command {
cmd := "generate"
fs := flag.NewFlagSet(cmd, flag.ExitOnError)
_ = fs.String("config", "", "config file (optional)")
debug := fs.Bool("debug", false, "debug mode")
wait := fs.Duration("wait", 2*time.Second, "wait time between requests")
token := fs.String("token", "", "runway token")
image := fs.String("image", "", "source image")
prompt := fs.String("prompt", "", "prompt text")

return &ffcli.Command{
Name: cmd,
ShortUsage: fmt.Sprintf("vidai %s [flags] <key> <value data...>", cmd),
Options: []ff.Option{
ff.WithConfigFileFlag("config"),
ff.WithConfigFileParser(ff.PlainParser),
ff.WithEnvVarPrefix("VIDAI"),
},
ShortHelp: fmt.Sprintf("vidai %s command", cmd),
FlagSet: fs,
Exec: func(ctx context.Context, args []string) error {
if *token == "" {
return fmt.Errorf("token is required")
}
if *image == "" {
return fmt.Errorf("image is required")
}
c := vidai.New(*token, *wait, *debug, nil)
u, err := c.Generate(ctx, *image, *prompt)
if err != nil {
return err
}
fmt.Println("Video URL:", u)
return nil
},
}
}
5 changes: 5 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module github.com/igolaizola/vidai

go 1.20

require github.com/peterbourgon/ff/v3 v3.3.0
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
github.com/peterbourgon/ff/v3 v3.3.0 h1:PaKe7GW8orVFh8Unb5jNHS+JZBwWUMa2se0HM6/BI24=
github.com/peterbourgon/ff/v3 v3.3.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ=
47 changes: 47 additions & 0 deletions internal/ratelimit/ratelimit.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package ratelimit

import (
"context"
"math/rand"
"sync"
"time"
)

type Lock interface {
Lock(ctx context.Context) func()
LockWithDuration(ctx context.Context, d time.Duration) func()
}

type lock struct {
lck *sync.Mutex
duration time.Duration
}

// New creates a new rate limit lock.
func New(d time.Duration) Lock {
return &lock{
lck: &sync.Mutex{},
duration: d,
}
}

// Lock locks the rate limit for the given duration and returns a function that
// unlocks the rate limit with a delay time based on the given duration.
func (l *lock) LockWithDuration(ctx context.Context, d time.Duration) func() {
l.lck.Lock()
// Apply a factor between 0.85 and 1.15 to the duration
d = time.Duration(float64(d) * (0.85 + rand.Float64()*0.3))
return func() {
defer l.lck.Unlock()
select {
case <-ctx.Done():
case <-time.After(d):
}
}
}

// Lock locks the rate limit for the default duration and returns a function that
// unlocks the rate limit with a delay time based on the default duration.
func (l *lock) Lock(ctx context.Context) func() {
return l.LockWithDuration(ctx, l.duration)
}
Loading

0 comments on commit 76a5c50

Please sign in to comment.