Blog

  • rp2040-motor-controller

    rp2040-motor-controller

    A dual channel brushless motor controller based on the RP2040 microcontroller

    The boards cost between $15 and $40 each depending on version and quantity.

    NOTE: This design is still changing. There is currently one board version in
    this repo. This is our dual CPU version with CAN bus and extra connectors for
    our robot. This version also improves the current measurement circuit compared
    to the first rev.
    
    Once we have verified the improved current measurement circuit, we will also
    support a single CPU version which is smaller and slightly cheaper. This will
    look similar to our first prototype version shown in the top of the photo at the
    bottom of this document. To view the files for that board see this commit:
    https://github.com/Twisted-Fields/rp2040-motor-controller/commit/ceeeb0ee0d24856a9ad8b6b036be5baf15e3ead6
    

    Warning These files are still under development and undergoing testing. While we do aspire to produce a design that others can easily fabricate, we do not yet recommend making them for yourself! Please post questions on board status to our community forum at community.twistedfields.com.

    Our dream is that you will fab your own boards, make changes, and share your work – giving this design life beyond our efforts.

    Designed by Taylor Alexander for Twisted Fields, for the Acorn Precision Farming Rover.

    Many thanks to Daniel Theobald. Without your financial support and encouragement this project would not have been possible.

    Thanks to all of our supporters on Open Collective. Your contributions are helping grow this project in to a sustainable open source organization.

    You can support this project yourself at our Open Collective Page.

    To learn more about Acorn, please see our announcement blog post. Or see a more recent technical update here.

    A photo of both PCB designs

    Visit original content creator repository https://github.com/Twisted-Fields/rp2040-motor-controller
  • tftp-server

    TFTP Server

    Author:
    
    Vin Colgin
    mcolgin@gmail.com
    https://github.com/marvincolgin
    https://www.linkedin.com/in/mcolgin
    https://marvincolgin.com
    

    Scope

    TFTP Server, written in Go, following the RFC-1370 specification.

    TODO

    There are several features that I’d like to continue building:

    TEST: Incomplete Files should not Appear

    • Expire a Loaded File with TTL
    • Implement Timeouts
    • Tests with Lots of Clients TESTED with 5/10/20/50
    • Date/Time Stamps to Messages
    • Progress Indicators for Each Thread like NPM (Pie-in-the-Sky)
    • Speed-Up in allocation of byte buffers on WRITE

    Limitations

    • Does not support later RFC specifications
    • Only octet aka “binary” mode is supported

    Building

    go get github.com/pborman/getopt
    go build -o <path to resulting binary>
    

    Parameters

    Parameters follow posix standards using the Google getopt go package.

    TABLE: Command-line Parameters

    param desc default
    help Help for Parameters
    ip IP Address for Listener 127.0.0.1
    port Port for Listener 69
    threads Number of Threads 16
    timeout Seconds for Timeout 1

    Example

    Help on Parameters

    tftp --help
    

    Start Listener on 192.168.0.1:6969

    tftp --ip 192.168.0.1 --port 6969
    

    Restrict Listener to 4 threads

    tftp --threads 4
    

    Sample Execution

    ~$ tftp
    
    Listener: 127.0.0.1:69
    Threads: 16 Starting...Done
    Listener: Loop Running
    READ: REQUEST file:[test-even.dat], client:[127.0.0.1:61073]
    READ: SUCCESS file:[test-even.dat], client:[127.0.0.1:61073]
    READ: REQUEST file:[test-odd.dat], client:[127.0.0.1:61075]
    READ: SUCCESS file:[test-odd.dat], client:[127.0.0.1:61075]
    

    Testing

    Unit Test

    cd src
    go test
    

    Integration Test

    The following scripts will great two large files, one with a filesize that is even 512 blocks, the other is not. Compare the two MD5 hashs to confirm that the same file generated locally, sent to the tftp-server, then pulled back down is the same.

    Test Single

    Parameters

    ~$ ./test-entrypoint.sh <uniqe-id, required> <filesize, default 100000>
    

    Example

    ~$ cd test
    ~$ ./test-entrypoint.sh 1 100000
    
    OK #1: Perfect Match
    

    Concurrency Testing

    This testing script will spawn off X number of calls to “./test-entrypoint.sh”

    Parameters

    ./test.sh <# of concurrent clients>
    

    Example

    ~$ cd test
    ~$ ./test.sh 5
    Spawning 1
    Spawning 2
    Spawning 3
    Spawning 4
    Spawning 5
    
    OK #1: Perfect Match
    OK #2: Perfect Match
    OK #3: Perfect Match
    OK #4: Perfect Match
    OK #5: Perfect Match
    

    Scripting

    This software supports exit-codes for errors resulting in abnormal execution:

    Code Desc
    0 No Error
    1 Listener Error: IP
    2 Listener Error: Port


    Visit original content creator repository
    https://github.com/marvincolgin/tftp-server

  • hydroCHISQR

    hydroCHISQR

    R package to apply a Chi – Squared test for hydrological frequency analysis

    Requirements

    Dependencies:
    grDevices, ggplot2, reshape2, stats, ggpubr, FAmle, FAdist

    Recomendations:
    actuar package

    Installation

    You can install the development version of hydroCHISQR from GitHub with this R command:

    # install.packages("remotes")
    remotes::install_github("Alobondo/hydroCHISQR")
    library(hydroCHISQR)
    

    Usage

    Functions Description
    hydroCHISQR(df, list_fit, nc, dist_param, alpha, c_test, c_method) Apply the Chi – Squared test for hydrological frequency analysis.
    df Data frame with observations and distributions adjusted.
    list_fit List with distributions and parameters fitted (only used with method 2).
    nc Number of classes, default 1 for Sturges, 2 for Scott, 3 for Freedman-Diaconis.
    dist_param Number of parameters of the distributions in df.
    alpha Significance level, typical 0.05.
    c_test Statistical result or plot, default 1 for statistical and 2 for plot.
    c_method Chi – Squared test method: 1 (Varas & Bois, 1998) and 2 (Chow, 1949).

    hydroCHISQR::example_2_params Example of frequency analysis result for 2 parameters distributions, with first column as observations.

    hydroCHISQR::example_3_params Example of frequency analysis result for 3 parameters distributions, with first column as observations.

    hydroCHISQR::fit_2_params Example of 2 parameters distributions fitted.

    hydroCHISQR::fit_3_params Example of 3 parameters distributions fitted.

    Reporting bugs

    If you find an error in some function, want to report a typo in the documentation or submit a recommendation, you can do it here

    Keywords

    Hydrology, R package, Frequency analysis

    Visit original content creator repository
    https://github.com/Alobondo/hydroCHISQR

  • exercises-vba

    Excel & VBA

    Exercises in VBA for Microsoft Excel.

    Excel

    Documentation

    Installation

    Excel help & learning

    colors

    Excel & Python

    [ d ][ g ] Python in Excel

    • [ b ] Microsoft Excel. (22 Aug 2023). “Announcing Python in Excel: Combining the power of Python and the flexibility of Excel”.
    • [ b ] Anaconda. “The Versatility of Excel + The Power of Anaconda”.

    [ h ] Zurnstein, Felix. (2021). Python for Excel: A Modern Environment for Automation and Data Analysis. O’Reilly.

    VBA

    Documentation

    Language reference for Visual Basic for Applications (VBA)

    Getting started with VBA in Office

    Concepts (Excel VBA reference)

    [ d ] VBA for Excel

    • [ d ] Range object
      • [ d ] Range.AutoFit method
      • [ d ] Range.Count property
      • [ d ] Range.End property
      • [ d ] Range.NumberFormat property
        • [ d ] Number format codes
      • [ d ] Range.NumberFormatLocal property
      • [ d ] Range.Row property
      • [ d ] Range.Style property
    • [ d ] Sheets object
    • [ d ] Style object
    • [ d ] Styles object
    • [ d ] WorksheetFunction.Match method
    • [ d ] Worksheet objet
      • [ d ] Worksheet.Name property
    • [ d ] Worksheets object

    data types

    • [ d ] Currency

    [ d ] Error messages

    • [ d ] Error 009 Subscript out of range
    • [ d ] Error 013 Type mismatch
    • [ d ] Error 450 Wrong number of arguments

    Terms

    • [ w ] Basic
    • [ w ] Cell
    • [ w ] Column Label
    • [ w ] Conditional Formatting
    • [ w ] Filter
    • [ w ] Formula
    • [ w ] Freeze
    • [ w ] Function
    • [ w ] Macro
    • [ w ] Microsoft Excel
    • [ w ] Microsoft Office
    • [ w ] Module
    • [ w ] Pane
    • [ w ] Pivot Chart
    • [ w ] Pivot Table
    • [ w ] Row Index
    • [ w ] Sheet
    • [ w ] Spreadsheet
    • [ w ] Subroutine
    • [ w ] Tablular Data
    • [ w ] VBScript
    • [ w ] VB Visual Basic
    • [ w ] VB .NET
    • [ w ] VBA Visual Basic for Applications
    • [ w ] Worksheet

    Notes

    .xlsx Excel Workbook
    .xlsm Excel Workbook (macro-enabled)

    Module (right-click > “Insert” > “Module”)

    • an organizational unit of VBA code that’s usually attached to a workbook or worksheet

    Specify cells of a spreadsheet

    • Cells(<row>, <col>) numeric, coordinate-based
      • Cells(1, 1) designates row 1, col 1
    • Ranges
      • F5:F7 contiguous
      • R2,D2 noncontiguous
    • .Value

    clears

    • .Clear
    • .ClearContents
    • .ClearFormats
    • ActiveSheet.UsedRange.Delete
    • Sheets("Sheet1").Cells.Clear

    Comments '

    Variable Declaration
    Dim <name> As <type>

    Types

    • Double
    • Integer
    • String
      • Split

    Cast

    • int to string Str()
    • string to int Int()

    Arrays

    • zero-indexed

    Conditionals If Then End If ElseIf Else And Or For Each

    Visit original content creator repository
    https://github.com/heracliteanflux/exercises-vba

  • simple-push-center

    系统功能


    概述

    针对各子系统普遍需要消息推送的功能需求(订单流程中的短信、邮件消息推送),为避免冗余代码,将推送的功能抽为一独立的平台,各子系统通过通过普通的RESTful接口或者消息(kafka)生成任务。 推送功能从推送方式可以是邮件、短信、WebSocket、App任意一种类型,任务可以立即执行,也可以是定时执行,为满足多次提醒的功能,在延时任务的基础之上又扩展了循环任务。循环任务是一种特殊的延时任务,任务执行之后根据任务类型标记动态的重新注入任务,直至全部任务完成,(详解见系统编码)

    结构图

    系统需求功能设计

    技术难点

    redis任务队列

    1. 定时任务|任务队列 定时任务的实现方式有很多,node定时模块node-schedule、原生API中的定时器适合单一任务的执行,并不适合多任务并行的情况(不适合 !== 不能)。
    
    * 引入消息队列主要是用于各服务的解耦;
    * 就系统本身而言,推送任务可能会存在看消息量大,并发量高的问题,而引入消息队列可以起到削峰的作用
    * 消息推送中有特别重要的一点:异步,服务的调用方在大部分的场合可能对消息推送结果的回调的需求并不是很高,消息生产者通过特定的通道发起一个消费的请求后,可以继续之后的流程;(只适合不依赖执行反馈的情景【串行不适合】)
    
    

    系统中使用了node生态中比较好的模块bull,流程图如下,系统调用方发起任务请求,系统首先对请求的合法性进行校验(权限校验见下一部分),之后根据不同类型push进任务执行栈,在bull中的任务大致有六种状态,等待,延时,激活,完成,失败,在任务栈中的任务状态标记为激活时,任务进入执行阶段,直到结束进入下一任务。

    
    * bull:github: https://github.com/OptimalBits/bull
    * bull:底层利用的redis的发布订阅特性
    

    bull流程图

    权限校验

    1、身份校验 为防止系统被恶意调用,恶意注入任务,应用入口以及网关层面做身份鉴权是非常有必要的,本文只对应用入口的鉴权进行讲解,关于网关的校验的会在之后的博客中讲解。 系统中也是采用主流的JWT的token机制,服务生成token,之后客户端每一次请求必须携带token,单微服务的设计来说,单系统的身份认证完全可以迁移到网关层面去实现。

    2、应用鉴权 应用鉴权在单系统中是主要的功能,系统中采用node中负责安全的模块crypto crypto的简单使用见一下代码块

    • crypto.publicEncrypt(key, buffer)(加密)
    • crypto.privateDecrypt(privateKey, buffer)(解密)
    import moment = require('crypto');
    // 加密
    const encrypt = (data, key) => {
        return crypto.publicEncrypt(key, Buffer.from(data));
    }
    // 解密
    const decrypt = (data, key) => {
        return crypto.privateDecrypt(key, encrypted);
    }
    const test = '测试加密信息'
    // 加密
    const crypted = encrypt(test, keys.pubKey);
     // 解密
    const decrypted = decrypt(crypted, keys.privKey);
    
    
    
    keys.privKey   keys.pubKey  分别为对应的私钥和公钥
    [crypto](https://nodejs.org/api/crypto.html)
    
    

    系统编码

    此次博文中对各模块的具体实现不做详细讲解,只对通用方法进行讲解

    • redis通用方法封装
    ## redis封装
    import {HttpService, Inject, Injectable} from '@nestjs/common';
    import { RedisService } from 'nestjs-redis';
    @Injectable()
    export class RedisCacheService {[https://github.com/OptimalBits/bull](https://github.com/OptimalBits/bull)
        public client;
        constructor(@Inject(RedisService) private redisService: RedisService) {
            this.getClient().then(r => {} );
        }
        async getClient() {
            this.client = await this.redisService.getClient();
        }
    
        // 设置值的方法
        async set(key: string, value: any, seconds?: number) {
            value = JSON.stringify(value);
            if (!this.client) {
                await this.getClient();
            }
            if (!seconds) {
                await this.client.set(key, value);
            } else {
                await this.client.set(key, value, 'EX', seconds);
            }
        }
    
        // 获取值的方法
        async get(key: string) {
            if (!this.client) {
                await this.getClient();
            }
            const data: any = await this.client.get(key);
            if (!data) { return; }
            return JSON.parse(data);
        }
    }
    
    
    • bull任务注入
    export class TaskService {
        constructor(
            // 服务中注入已经创建好的任务队列的实例
            @InjectQueue('email') private readonly emailNoticeQueue: Queue,
            @InjectQueue('message') private readonly messageNoticeQueue: Queue,
        ) { }
        // delayValue: 延时时长
        public async addTask() {
             await this.emailNoticeQueue.add('emitEmail', {
                     id: taskResult.insertedId,
                    config: config.name,
             }, { delay: delayValue});
        }
    }
    
    
    @Injectable()
    @Processor('email')
    export class NoticeEmailProcessor {
        constructor(
            @InjectQueue('email') private readonly emailNoticeQueue: Queue,
            private readonly redisCacheService: RedisCacheService,
            private readonly taskLogService: TaskLogService,
            private readonly taskEmitEmailService: TaskEmitEmailService,
            @Inject(TaskService)
            private readonly taskService: TaskService,
        ) {}
    
        @Process('emitEmail')
        public async handleTranscode(job: Job) {
    
        }
    
        /**
         * 下一步执行任务()
         */
        protected async nextLoopTak(task: TaskEntity, isSuccessFlag: boolean, status: number) {
    
        }
    }
    
    • 日期处理采用moment.js
    
    https://github.com/moment/moment
    

    系统部署

    系统采用docker的部署,系统默认会启动在10001端口之上

    1、DOCKERFILE

    FROM ubuntu
    MAINTAINER canyuegongzi
    ENV HOST 0.0.0.0
    RUN mkdir -p /app
    COPY .. /app
    WORKDIR /app
    EXPOSE 10001
    RUN apt-get update && \
        apt-get install redis-server && \
        npm config set registry https://registry.npm.taobao.org && \
        npm install && \
        npm install pm2 -g
    CMD ["sh", "-c", "redis-server && pm2-runtime start ecosystem.config.js"]
    

    2、pm2启动脚本

    ## ecosystem.config.js
    module.exports = [{
        script: 'dist/main.js',
        name: 'simpleNoticeCenterApi',
        exec_mode: 'cluster',
        instances: 2
    }]
    
    

    结言

    系统目前处于持续迭代开发中,可能会存在不同程度的问题,就普通的消息推送还是可以完成的,之后将进一步提升系统的安全性,其他的功能也会陆续迭代。详细代码讲解会在后续博客讲解,包括前后端。

    Visit original content creator repository https://github.com/canyuegongzi/simple-push-center
  • fabric

    Visit original content creator repository
    https://github.com/lambertzhao1991/fabric

  • mesos-operator-api-client

    mesos-operator-api-client

    Package version Package downloads Package license

    A generic client to listen to the Mesos Operator API’s events.

    Usage

    Install as a dependency like this:

    npm install mesos-operator-api-client --save

    Master client

    The Master client can be used to connect to the Mesos Operator API like.

    Events

    Known Mesos Operator API events

    As of the Mesos Operator API documentation and the Mesos master.proto there are currently the following events:

    • SUBSCRIBED
    • TASK_ADDED
    • TASK_UPDATED
    • AGENT_ADDED
    • AGENT_REMOVED

    Those events will be emitted by this client as well if they occur.

    Internal events

    The Mesos Operator API events slient itself emits the following events:

    • subscribed: Is emitted after a successful subscription to the Mesos Operator API.
    • unsubscribed: Is emitted after unsubscribe() is called.
    • reconciled: Is emitted after reconcile() is called. This queries the Operator API with a separate call to the GET_STATE method.
    • error: Is emitted in case of internal or upstream errors.

    Using the client

    Options

    You can specify the following properties when instantiating the Mesos Operator API events client:

    • masterHost: The Mesos Master hostname (or ip address). Default is leader.mesos.
    • masterPort: The Mesos Master port. Default is 5050.
    • masterProtocol: The Mesos Operator API protocol (http or https). Default is http.
    • masterApiUri: The relative path where the Mesos Operator API endpoint can be found. Default is /api/v1.
    • masterConnectionTimeout: The time in milliseconds after which the connection to the Mesos Master is deemed as timed out. Default is 5000.
    • eventTypes: An array of event types emitted by the Mesos Master (see above for a list). Default is ["SUBSCRIBED", "TASK_ADDED", "TASK_UPDATED", "AGENT_ADDED", "AGENT_REMOVED"].
    • handlers: A map object consisting of handler functions for the individual Mesos Operator API events. See below for an explanation. No defaults.

    Methods for events

    The Mesos Operator API events client only exposes the subscribe() and the unsubscribe() methods. You can catch all above events via on(<eventType>, function (data) { ... }.

    Supported methods for specific Operator API calls

    The callback(error, data) function is optional, you need to add it only if you directly want to handle the results. Otherwise, those methods will trigger an event (starting with received_ appended by the lowercase method name, e.g. for GET_STATE is received_get_state), which applications can listen to to receive the responses in an asynchronous way.

    • getHealth(callback): This calls the GET_HEALTH method.
    • getFlags(callback): This calls the GET_FLAGS method.
    • getVersion(callback): This calls the GET_VERSION method.
    • getMetrics(callback): This calls the GET_METRICS method.
    • getLoggingLevel(callback): This calls the GET_LOGGING_LEVEL method.
    • getState(callback): This calls the GET_STATE method.
    • getAgents(callback): This calls the GET_AGENTS method.
    • getFrameworks(callback): This calls the GET_FRAMEWORKS method.
    • getExecutors(callback): This calls the GET_EXECUTORS method.
    • getTasks(callback): This calls the GET_TASKS method.
    • getRoles(callback): This calls the GET_ROLES method.
    • getWeights(callback): This calls the GET_WEIGHTS method.
    • getMaster(callback): This calls the GET_MASTER method.
    • getMaintenanceStatus(callback): This calls the GET_MAINTENANCE_STATUS method.
    • getMaintenanceSchedule(callback): This calls the GET_MAINTENANCE_SCHEDULE method.
    • getQuota(callback): This calls the GET_QUOTA method.

    Event handler functions

    The custom event handler functions can be configured by setting a map object as handlers property during the instantiation. Each map object’s property represents a event handling function. The property name needs to match on of the Marathon event types from the list of known Marathon events.

    This is an example handlers map object:

    { // Specify the custom event handlers
        "TASK_ADDED": function (data) {
            console.log("We have a new TASK_ADDED event!");
        },
        "TASK_UPDATED": function (data) {
            console.log("We have a new TASK_UPDATED event!");
        }
    }

    The function arguments are:

    • data: The emitted data for the respective event

    Example code

    For a complete example, have a look at examples/masterExample.js.

    "use strict";
    
    // Use the MesosOperatorApiClient
    const MasterClient = require("mesos-operator-api-client").masterClient;
    
    // Create MesosOperatorApiClient instance
    const eventsClient = new MasterClient({
        masterHost: "172.17.11.101" // Replace with your Mesos Leader hostname or ip address
    });
    
    // Wait for "subscribed" event
    eventsClient.on("subscribed", function () {
        console.log("Subscribed to the Mesos Operator API events!");
        // Call GET_AGENTS
        eventsClient.getAgents(function (err, data) {
            console.log("Got result for GET_AGENTS");
            console.log(JSON.stringify(data));
        });
        // Do a reconcile after 3000ms. Demo!
        setTimeout(function () {
            eventsClient.reconcile();
        }, 3000);
    });
    
    // Wait for "unsubscribed" event
    eventsClient.on("unsubscribed", function () {
        console.log("Unsubscribed from the Mesos Operator API events!");
    });
    
    // Catch error events
    eventsClient.on("error", function (errorObj) {
        console.log("Got an error");
        console.log(JSON.stringify(errorObj));
    });
    
    // Log SUBSCRIBED event
    eventsClient.on("SUBSCRIBED", function (eventObj) {
        console.log("Got SUBSCRIBED");
        console.log(JSON.stringify(eventObj));
    });
    
    // Log TASK_ADDED event
    eventsClient.on("TASK_ADDED", function (eventObj) {
        console.log("Got TASK_ADDED");
        console.log(JSON.stringify(eventObj));
    });
    
    // Log TASK_UPDATED event
    eventsClient.on("TASK_UPDATED", function (eventObj) {
        console.log("Got TASK_UPDATED");
        console.log(JSON.stringify(eventObj));
    });
    
    // Log AGENT_ADDED event
    eventsClient.on("AGENT_ADDED", function (eventObj) {
        console.log("Got AGENT_ADDED");
        console.log(JSON.stringify(eventObj));
    });
    
    // Log AGENT_REMOVED event
    eventsClient.on("AGENT_REMOVED", function (eventObj) {
        console.log("Got AGENT_REMOVED");
        console.log(JSON.stringify(eventObj));
    });
    
    // Subscribe to Mesos Operator API events
    eventsClient.subscribe();
    
    // Unsubscribe after 10sec. Demo!
    setTimeout(function () {
        eventsClient.unsubscribe();
    }, 10000);

    Agent client

    Using the client

    Options

    You can specify the following properties when instantiating the Mesos Operator API events client:

    • agentHost: The Mesos Agent hostname (or ip address). Default is 127.0.0.1.
    • agentPort: The Mesos Agent port. Default is 5051.
    • agentProtocol: The Mesos Operator API protocol (http or https). Default is http.
    • agentApiUri: The relative path where the Mesos Operator API endpoint can be found. Default is /api/v1.
    • agentConnectionTimeout: The time in milliseconds after which the connection to the Mesos Agent is deemed as timed out. Default is 5000.

    Example code

    For a complete example, have a look at examples/agentExample.js.

    "use strict";
    
    // Use the agentClient
    const AgentClient = require("mesos-operator-api-client").agentClient;
    
    // Create agentClient instance
    const agent = new AgentClient({
        agentHost: "172.17.11.102"
    });
    
    // Call GET_HEALTH
    agent.getHealth(function (err, data) {
        console.log(JSON.stringify(data));
    });

    Supported methods for specific Operator API calls

    The callback(error, data) function is optional, you need to add it only if you directly want to handle the results. Otherwise, those methods will trigger an event (starting with received_ appended by the lowercase method name, e.g. for GET_STATE is received_get_state), which applications can listen to to receive the responses in an asynchronous way.

    • getHealth(callback): This calls the GET_HEALTH method.
    • getFlags(callback): This calls the GET_FLAGS method.
    • getVersion(callback): This calls the GET_VERSION method.
    • getMetrics(callback): This calls the GET_METRICS method.
    • getState(callback): This calls the GET_STATE method.
    • getContainers(callback): This calls the GET_CONTAINERS method.
    • getFrameworks(callback): This calls the GET_FRAMEWORKS method.
    • getExecutors(callback): This calls the GET_EXECUTORS method.
    • getTasks(callback): This calls the GET_TASKS method.
    • getAgent(callback): This calls the GET_AGENT method.
    Visit original content creator repository https://github.com/tobilg/mesos-operator-api-client
  • qr-notify-bot

    QR-Notify Bot

    A test project to showcase one of potential implementations of SAP SQL Anywhere RDMS in chat-bot development.

    Table of Contents

    Click to expand

    Summary

    Asynchronous bot for Telegram messaging app utilizing a SAP (Sybase) SQL Anywhere RDMS and Computer Vision elements. It’s implied that a machine this bot runs on is connected to a webcam and has got a SAP SQL Anywhere 17 database running. The bot is able to send its users specific messages based on a QR-code the webcam captures from its live video feed. This particular code simulates delivery notification system but via an instant messenger (Telegram), not e-mail. For the details, please see the comment block at the beginning of main.py file. We also tried to thoroughly document the source code, so feel free to browse it.

    Main Features

    • Asynchronous HTTP requests
    • Detection and decoding QR-codes on the fly
    • Detailed and customizable logging system
    • Scalability and low imprint on hardware
    • Easily repurposable for different tasks involving QR-codes.

    Modules Used

    Learn More

    This project is featured and meticulously explained in several articles:

    It also got hosted as a sample under the official SAP Samples repository. Main development has been moved there.

    Installation

    The full installation process consists of several steps involving different pieces of software. There’s nothing complicated, but we’ll try to go through this process step-by-step, explaining it as clearly as possible, so hopefully you’ll end up with a minimal working example.

    Disclaimer

    This is merely an example of a possible technical integration of SAP SQL Anywhere RDMS into a Python-based project. The code of this particular sample heavily relies on Telegram messaging app and its Bot API to function properly. By proceeding, running and using the sample’s code, the user becomes

    This sample is also provided “as-is” without any guarantee or warranty that raised issues will be answered or addressed in future releases.

    Prerequisites

    Before proceeding, please ensure that all of the following conditions are met:

    Getting started

    First, clone this repository:

    git clone https://github.com/gevartrix/qr-notify-bot.git

    Change directory to this project’s root folder. Create and activate a virtual environment (in this case, running on Windows) and install the required modules:

    python -m venv venv
    venv\Scripts\activate
    python -m pip install -r requirements.txt

    Getting Telegram-related Data

    You’ll need to know your Telegram ID to store it in the database, so later the bot will be able to send you notifications. Your Telegram ID is just an integer, the quickest way to acquire it is via @MyIDBot: open it in your Telegram app, start it and send it the /getid command. It should reply with your ID (say, 123456789).

    You should also create your own Telegram bot. To do that, search for the @BotFather Telegram bot and enter the /newbot command to create a new bot. Follow the instructions and provide a screen-name and a username for your bot. The username must, however, be unique and end with “bot”; the screen-name can be whatever you like. You should then receive a message with a new API token generated for your bot (say, 11111:XXXXXXXXXXX). Now you can find your newly created bot on Telegram based on the username you gave it.

    QR-coding the address

    The bot interprets QR-codes on the webcam feed as encoded addresses in our model. Let’s turn an address into a QR-code and print it, so we can show it to the webcam later. The QR-code below encodes WDF 01 BU04 Dietmar-Hopp-Allee 16 69190 Walldorf:

    Example QR-code

    You can download it by clicking it and print it on a white sheet of paper or just open it on your smartphone. Alternatively, you may encode your preferred address online.

    Preparing the Database

    Now when you’ve got every piece of data, you can create a database and fill all required columns. First, create an additional folder (in this case, named db) inside this project’s root folder:

    mkdir db

    Create a database file using dbinit (in this case, named orders.db; admin as UID and YourPassword as password (change it, it’s just an example)):

    dbinit -dba admin,YourPassword -p 4k -z UTF8 -ze UTF8 -zn UTF8 db/orders.db

    Now you’ve got a database file orders.db located in the db folder of this project (you may store this database file wherever you’d like). Open SQL Central and proceed with the following steps:

    • right-click on “SQL Anywhere 17” and hit “Connect…”,
    • fill the “User ID” and “Password” fields with the same values you provided to dbinit (in this case, admin and YourPassword respectively),
    • under “Action” choose “Start and connect to a database on this computer”,
    • provide full path to the database file you’ve just created (in this case, it’s full/path/to/this/project/db/orders.db) and hit “Connect”.

    You’re connected to the SQL Anywhere database and can interact with it. Right-click anywhere to open the Interactive SQL window, so you may execute SQL queries in the database.

    First, create a table of orders (in our case, named Orders):

    CREATE TABLE Orders (
        id UNSIGNED INT PRIMARY KEY NOT NULL IDENTITY,
        product NVARCHAR(24) NOT NULL,
        model NVARCHAR(20),
        price DECIMAL(10,2) NOT NULL,
        amount UNSIGNED INT NOT NULL DEFAULT 1,
        weight DECIMAL(8,3) NOT NULL,
        first_name NVARCHAR(16) NOT NULL,
        last_name NVARCHAR(20),
        address NVARCHAR(48) NOT NULL,
        telegram_id UNSIGNED INT NOT NULL,
        timezone NVARCHAR(16) DEFAULT 'UTC',
        locale NVARCHAR(5) DEFAULT 'en_US'
    );

    Then you can add an example order record to test the bot:

    INSERT INTO "admin"."Orders"(product, model, price, weight, first_name, last_name, address, telegram_id, timezone) VALUES (
        'Lenovo Thinkpad',
        'X220',
        150.00,
        1.725,
        'Jon',
        'Doe',
        'WDF 01 BU04 Dietmar-Hopp-Allee 16 69190 Walldorf',
        123456789,
        'Europe/Berlin'
    );

    where WDF 01 BU04 Dietmar-Hopp-Allee 16 69190 Walldorf is the address encoded in the QR-code you printed by following the “QR-coding the address” section, and 123456789 is your Telegram ID sent by @MyIDBot from the “Getting Telegram-related Data” section. Obviously, you may customize other values however you like.

    Make sure to close the Interactive SQL window afterwards, as it blocks query execution from any other source.

    Setting the Environment Variables

    For the sake of convenience we store all required environment variables in a .env file. This repository contains a .env.dist file filled with dummy data in the root folder, so you’ll need to copy it to .env file and change its values, as it’s currently preset to the example values.

    You’ll absolutely have to set the PROD_BOT_TOKEN variable to the API token sent to you by @BotFather, so it looks like this: PROD_BOT_TOKEN="11111:XXXXXXXXXXX". The sqlanydb module also requires the SQLANY_API_DLL variable to be set to the full path of dbcapi.dll. Unfortunately, SQL Anywhere doesn’t create this variable automatically upon installation anymore, hence you have to specify it manually. On Windows this path is usually C:\Program Files\SQL Anywhere 17\Bin64\dbcapi.dll. However, if you run the 32-bit version of Python, you should change Bin64 to Bin32 in the path above.

    So, if you’re using the 64-bit version of Python on Windows and all our example values, the variables inside your .env file should end up looking like this:

    SQLANY_API_DLL="C:\Program Files\SQL Anywhere 17\Bin64\dbcapi.dll"
    PROD_BOT_TOKEN="11111:XXXXXXXXXXX"
    PROD_DB_USER="admin"
    PROD_DB_PASSWORD="YourPassword"
    PROD_DB_TABLENAME="Orders"

    You may also set the DEV variables using different values meant for testing, if you’re going to run the bot with the --dev flag.

    Running and Testing Bot

    Make sure that you still have the virtual environment activated, the QR-code printed, your webcam connected and the SQL Anywhere database connection established. Start the bot by running

    python main.py

    in the project’s root directory. After the Updates were skipped successfully log message, a window with your webcam’s video stream should appear. Search for the bot you’ve created with @BotFather and start it. If everything is right, the bot should respond by offering you to select the language.

    So now, whenever you show the QR-code encoding your address to your webcam, the bot should alert you with a notification. With the example record from our table, the notification should look like this:

    Hello, Jon!
    
    As of 25/10/2020 18:47:19 CET, your order 1 has arrived to our base.
    We are going to deliver it to your address "WDF 01 BU04 Dietmar-Hopp-Allee 16 69190 Walldorf" no later than in 3 days.
    
    Product Details:
    Product: Lenovo Thinkpad
    Model: X220
    Price: €150.00
    Amount: 1
    Weight: 1.725 kg
    ID: 1
    

    You may configure the camera UI via the CLI arguments. To see all configurable options of the bot, run python main.py --help.

    Contributing

    If you’d like to contribute to this little project, please follow these steps:

    1. Fork this repository.
    2. Create a branch: git checkout -b feature/foo.
    3. Make your changes and commit them: git commit -am 'Add foo feature'.
    4. Push your changes to the branch: git push origin feature/foo.
    5. Create a new pull request.

    Pull requests are warmly welcome!

    Style Guide

    We try our best sticking to the PEP 8 Style Guide, using type hints (PEP 484) and providing descriptive docstrings adhering to the Google Python Style Guide. So we check that our code is formatted properly using Flake8 and black code formatter; the type checking is handled by mypy.

    Install these modules in your virtual environment by running

    python -m pip install -r dev-requirements.txt

    so you can either run the checks manually, or set up this great pre-commit that will be running it for you.

    You may also check out the configuration we use in pyproject.toml and setup.cfg.

    License

    Copyright (c) 2019-2021 Artemy Gevorkov. This project is licensed under the Apache Software License, version 2.0.

    Visit original content creator repository https://github.com/gevartrix/qr-notify-bot
  • RentML

    RentML – Car Rental Management System

    Problem

    Managing a car rental business requires meticulous documentation. Each vehicle handover involves:

    • Verifying current mileage
    • Identifying the vehicle
    • Recording date and time
    • Filling, signing and archiving protocols

    When done manually, this process is time-consuming and error-prone.

    App is working on authentic data for a Polish car rental business. Because of that, some elements are named in Polish language.

    This is a portfolio README focused on business problem solving. Technical README with setup instructions and project structure is available in modules/README.md.

    Solution

    RentML automates car rental management processes:

    Main application screen

    Key Features:

    1. Automated Data Recognition

      • Dashboard image analysis
      • Vehicle model identification
      • Mileage reading with OCR
    2. Smart Prediction

      • System suggests vehicle model based on historical data
      • Auto-filled forms save time
    3. Document Generation

      • Instant handover protocol creation
      • Print-ready format (DOCX)
      • Easily adjustable template
    4. Data Visualization

      • Interactive mileage charts
      • Fleet usage trend analysis

    Mileage chart

    Benefits

    • Time Saving: Registration process reduced from minutes to seconds
    • Error Elimination: Automatic recognition prevents documentation mistakes
    • Easy Data Access: Mileage history and usage always available
    • Mobility: Register directly from mobile device

    How It Works

    1. Take a dashboard photo or upload existing one
    2. System automatically recognizes model and mileage
    3. Verify and complete data in the form
    4. Save to database and/or generate protocol

    Confirmation form

    Tech Stack

    • Python: Core programming language
    • PyTorch: Binary classification model trained for dashboard recognition
    • EasyOCR: Optical Character Recognition for mileage reading
    • Pandas: Data manipulation and analysis
    • Altair: Interactive data visualization
    • Streamlit: Web application interface
    • SKLearn: Data clustering

    Challenges Faced

    • Dashboard Similarity: Two delivery vehicles had identical dashboards, making trained ML model classification insufficient
    • Clustering Solution: Implemented a clustering approach to differentiate between similar dashboard types
    • OCR Quality: The dataset wasn’t created with OCR in mind. Extremely poor outliers were removed, and while some reading fluctuations remain (shouldn’t happen while measuring car mileage increase over time), the results were deemed acceptable for practical use.

    Recognized by ML model Raw Dashboard Images Clustered Clustered Dashboard Analysis

    Project created by Mateusz Ratajczak as a post-mortem automation of own business.

    Visit original content creator repository https://github.com/Ne0bliviscaris/RentML
  • text2cinemagraph

    Text2Cinemagraph

    This is the official PyTorch implementation of “Text-Guided Synthesis of Eulerian Cinemagraphs”.


    Method Details


    We introduce a fully automated method, Text2Cinemagraph, for creating cinemagraphs from text descriptions – an especially challenging task when prompts feature imaginary elements and artistic styles, given the complexity of interpreting the semantics and motions of these images. In this method, we propose an idea of synthesizing image twins from a single text prompt using Stable Diffusion – a pair of an artistic image and its pixel-aligned corresponding natural-looking twin. While the artistic image depicts the style and appearance detailed in our text prompt, the realistic counterpart greatly simplifies layout and motion analysis. Leveraging existing natural image and video datasets, we accurately segment the realistic image and predict plausible motion given the semantic information. The predicted motion is then transferred to the artistic image to create the final cinemagraph.

    Getting Started

    Environment Setup

    • Run the following commands to set up the dependencies reqiured for this project.
      git clone https://github.com/text2cinemagraph/artistic-cinemagraph.git
      cd text2cinemagraph
      conda create -n t2c python=3.9
      conda activate t2c
      conda install pytorch=1.13.1 torchvision=0.14.1 pytorch-cuda=11.6 -c pytorch -c nvidia
      conda install -c "nvidia/label/cuda-11.6.1" libcusolver-dev
      conda install -c conda-forge gxx_linux-64=11.2
      pip install git+https://github.com/NVlabs/ODISE.git
      pip install -r requirements.txt
      conda install -c anaconda cupy
      
      If there are ninja related errors in installing mask2former refer to this link

    Download Pretrained Models

    • Run the following command to download the preatrined (Optical Flow Prediction, Text-Direction Guided Optical Flow Prediction, Video Generation) models,
      gdown https://drive.google.com/u/4/uc?id=1Cx64SC12wXzDjg8U0ujnKx8V2G6SbCIb&export=download
      tar -xvf checkpoints.tar
      
    • Download sd-v1-4-full-ema.ckpt using,
      mkdir -p img2img/models/ldm/stable-diffusion-v1
      cd img2img/models/ldm/stable-diffusion-v1
      wget https://huggingface.co/CompVis/stable-diffusion-v-1-4-original/resolve/main/sd-v1-4-full-ema.ckpt
      cd ../../../../
      
    • Download diffusers stable-diffusion-v1-4
      cd checkpoints
      git lfs install
      git clone https://huggingface.co/CompVis/stable-diffusion-v1-4
      cd ../
      
      If there are issues with installing git-lfs refer to this issue

    Inference (Artistic Domain)

    • To generate the first result from above exmaple, run the following command,
      python inference_t2c.py --config configs/inference.yaml
      
    • To generate the text guided direction result displayed above, run the following command,
      #to generate the left example
      python  inference_t2c.py \
                --config configs/inference_directional.yaml \
                --use_hint \
                --prompt "a large river flowing in left to right, downwards direction in front of a mountain in the style of starry nights painting"
      
      #to generate the right example
      python  inference_t2c.py \
                --config configs/inference_directional.yaml \
                --use_hint \
                --prompt "a large river flowing in upwards, right to left direction in front of a mountain in the style of starry nights painting"
      
      Note that since we randomly sample a theta based on quadrant which the text direction corresponds to, exact replicability might not be possible.
    Artistic Image (s1) Natural Image (s21) ODISE Mask (s3)
    Self-Attention Mask (s4) Optical Flow (s5) Cinemagraph (s6)
    • Since the total time needed to run all the components might be large and the user might not be satisfied with the end result due to output of some intermediate compont, we suggest the user to run each component separately in such scenario. Below we show how to run inference in a stage-wise manner,
      python inference_t2c.py --config configs/inference.yaml --stage s1
      
      # Generate the twin (natural) image
      python inference_t2c.py --config configs/inference.yaml --stage s2
      
      # Generate ODISE mask
      python inference_t2c.py --config configs/inference.yaml --stage s3
      
      # Generate Self-Attention mask (guided using ODISE mask)
      python inference_t2c.py --config configs/inference.yaml --stage s4
      
      # Predict optical flow
      python inference_t2c.py --config configs/inference.yaml --stage s5
      
      # Generate the cinemagraph
      python inference_t2c.py --config configs/inference.yaml --stage s6
      

    Tip and Tricks for achieving better results (Artistic Domain)
    Change the following parameters in inference.yaml or inference_directional.yaml if you do not achieve desired results,

    • twin_extraction:prompt: change the input text prompt if the images generated by --stage s1 are not desirable.
    • twin_extraction:seed: change the seed if the images generated by --stage s1 are not desirable and the user does not want to change the prompt.
    • twin_generation:prompt: by default it can be None. If the output of --stage s2 does not look semantically similar to the artistic image, try spacifying the edit prompt manually.
    • odise:vocab: if the ODISE generated mask is including some regions that the user does not want, change the vocab to specify only the desired regions.
    • attn_mask:n_clusters: change the number of clusters if the generated mask from --stage s4 is not representative of the desired regions of motion in the final cinemagraph.
    • attn_mask:threshold: it specifies what is the minimum percentage of pixel overlap between the ODISE mask and the Self-Attention cluster to be considered inside the mask. Increase the value to reduce the amount of Self-Attention clusters included in the final mask and vice versa.
    • attn_mask:cluster_type: change the cluster type between kmeans or spectral (this is only for very fine-grained refinement).
    • attn_mask:erosion_iter: if the mask is slightly overlaping with boundaries of static region in --stage s4 increase the value of erosion_iter between [2,5] at intervals of 1 to retract the mask slightly.
    • video:n_frames: use 60 in cases of motion restricted to small regions (like waterfall) and 120 for large body motion (like sea).
    • video:speed: change the speed (recommended value between [0.25, 3]) to change the speed of motion in the generated cinemagraph. If the user notices grey rigions apprearing in the cienmagraph, try lowering the speed.

    Data Preparation for Training

    Optical Flow and Videos

    • The dataset for ground-truth optical flows and videos are taken from Animating Pictures with Eulerian Motion Fields. Download the train and validation dataset using,
      gdown https://drive.google.com/u/0/uc?id=19f2PsKEaeAmspd1ceGkOEMhZsZNquZyF&export=download
      cd dataset
      unzip eulerian_data.zip
      
      Note that we use the entire validation dataset as test dataset (and do not use it during training process).

    Masks (ODISE)

    • For testing on real-domain data, we use masks generated by ODISE. To generate the masks (after completing the above step), run the following command,
      python demo/gen_mask.py \
                --input dataset/eulerian_data/validation \
                --output dataset/eulerian_data/validation_masks_odise \
                --vocab "water, waterfall, river, ocean, lake, sea"
      

    Text Guided Direction Control

    • For training the optical flow prediction model that can predict flow following the direction of motion in the input prompt, we generate optical dense flow hint maps, similar to Controllable Animation of Fluid Elements in Still Images. The optical flow hints are generated from Ground-Truth optical flow with 1,2,3,4 and 5 hints. The code for generating hints is taken from SLR-SFS.
      python dataset/generate_flow_hint.py \
                --dataroot dataset/eulerian_data/train \
                --save_path dataset/eulerian_data/train_motion_hints \
                --n_clusters 5
      

    Artistic Domain Prompts

    • The prompts used to generate artistic domain examples are located in dataset/prompts.txt and the corresponding edit prompts (used to generate the natural verion of the artistic images) are located in dataset/prompts_twin.txt. Note that the edit prompts can be specified manually or can also be atumatically derived from the artistic prompts if not specified otherwise.

    Training

    Optical Flow Prediction

    • For training the optical flow prediction model, that predicts optical flow without taking text direction guidance, use the following command,

      python train_motion.py \
                --name <expriment-name-1> \
                --gpu_ids 0,1,2,3 \
                --no_instance \
                --label_nc 0 \
                --input_nc 4 \
                --output_nc 2 \
                --fineSize 512 \
                --batchSize 16 \
                --norm instance \
                --dataset_name motion \
                --motion_norm 64.0 \
                --netG spadexattnunetsd \
                --dataroot dataset/eulerian_data/train \
                --no_vgg_loss \
                --use_epe_loss \
                --use_prompts \
                --use_mask \
                --mask_path dataset/eulerian_data/train_masks_odise \
                --captions_file ./dataset/captions/file2captions-eularian-train-blip2-20-15.txt
      

      Note that in addition to the input image and mask, we condition the flow prediction on text prompt. We generate the text prompts for the images in the train and validation dataset using BLIP2.

    Optical Flow Prediction (for text guidance direction)

    • For training the optical flow prediction model, that predicts optical flow conditioned on text direction guidance, use the following command,

      python train_motion.py \
                --name <expriment-name-2> \
                --gpu_ids 0,1,2,3 \
                --no_instance \
                --label_nc 0 \
                --input_nc 6 \
                --output_nc 2 \
                --fineSize 512 \
                --batchSize 16 \
                --norm sync:spectral_instance \
                --dataset_name motion \
                --motion_norm 64.0 \
                --netG spadeunet \
                --dataroot dataset/eulerian_data/train \
                --no_vgg_loss \
                --use_epe_loss \
                --use_mask \
                --mask_path dataset/eulerian_data/train_masks_odise \
                --use_hint \
                --hints_path dataset/eulerian_data/train_motion_hints
      

      Note that in our experiments, for predicting optical flow conditioned on text direction guidance, we do not use text conditoning by Cross-Attention layers, as the input consists of the image, mask and dense optical flow hint. The motivation for using text conditioning along with image and mask in previous method was that text inherently contains class information, like a ‘waterfall’ or ‘river’, which can be useful to determine the natural direction in the predicted flow. However, in this case direction is already given as input dense flow hint. This helps in reducing the model size (as we do not need to use expensive Cross-Attention layers).

    Video Generation

    • For first stage training (training using Ground-Truth Optical Flow) of the video generation model, use the following command,

      python train_video.py \
                --name <expriment-name-3> \
                --gpu_ids 0,1,2,3 \
                --no_instance \
                --label_nc 0 \
                --input_nc 8 \
                --output_nc 3 \
                --fineSize 512 \
                --batchSize 16 \
                --norm_G sync:spectral_instance \
                --dataset_name frame \
                --netG spadeunet4softmaxsplating \
                --dataroot dataset/eulerian_data/train \
                --use_l1_loss \
                --tr_stage stage1 \
                --frames_basepath dataset/eulerian_data/train
      
    • We train the flow perdiction model additionally for 50 epochs on optical flow predicted by the Optical Flow Prediction model. To make the training process more efficient, we precompute and store all the optical flow predictions for training data before starting training. To generate the optical flow using the Optical Flow Prediction model use the following command,

      python test_motion.py \
                --<expriment-name-1> \
                --phase train \
                --no_instance \
                --label_nc 0 \
                --input_nc 4 \
                --output_nc 2 \
                --fineSize 512 \
                --batchSize 1 \
                --which_epoch 200 \
                --netG spadexattnunetsd \
                --dataroot dataset/eulerian_data/train \
                --use_mask \
                --use_prompts \
                --captions_file ./dataset/captions/file2captions-eularian-train-blip2-20-15.txt
      
    • For second stage training (training using Optical Flow predicted by model) of the video generation model, use the following command,

      python train_video.py \
                --name <experiment-name-3> \
                --continue_train \
                --niter 150 \
                --gpu_ids 0,1,2,3 \
                --no_instance \
                --label_nc 0 \
                --input_nc 8 \
                --output_nc 3 \
                --fineSize 512 \
                --batchSize 16 \
                --norm_G sync:spectral_instance \
                --dataset_name frame \
                --netG spadeunet4softmaxsplating \
                --dataroot dataset/eulerian_data/train \
                --use_l1_loss \
                --tr_stage stage2 \
                --frames_basepath dataset/eulerian_data/train \
                --motion_basepath results/motion-7-1/train_200/images \
                --motion_norm 64.0
      

      Note that we use the Video Generation model, trained with Optical Flow Prediction model (w/o using text direction guidance) to generate videos for both the scenarios, i.e., w/ and w/o text direction guidance.

    Evaluation (Real Domain)

    Generate Results

    • To predict Optical Flow for the validation dataset on single images, use the following command,
      python test_motion.py \
                --name <experiment-name-1> \
                --no_instance \
                --label_nc 0 \
                --input_nc 4 \
                --output_nc 2 \
                --fineSize 512 \
                --batchSize 1 \
                --netG spadexattnunetsd \
                --dataset_name motion \
                --dataroot dataset/eulerian_data/validation \
                --use_mask \
                --use_seg_mask \
                --use_prompts \
                --mask_path dataset/eulerian_data/validation_masks_odise \
                --captions_file dataset/captions/file2captions-eularian-validation-blip2-20-15.txt
      
      Note that to predict optical flows in using our pretrained models, after downloading the models, replace <experiment-name-1> with motion-pretrained.
    • To generate cinemagraphs using the predicted optical flows, in previous step, for the validation dataset, use the following command,
      python test_video.py \
                --name<experiment-name-3> \
                --no_instance \
                --label_nc 0 \
                --input_nc 8 \
                --output_nc 3 \
                --fineSize 512 \
                --batchSize 1 \
                --dataset_name frame \
                --netG spadeunet4softmaxsplating \
                --dataroot dataset/eulerian_data/validation \
                --motion_basepath results/<experiment-name-1>/test_latest/images \
                --speed 1.0
      
      Note that to generate cinemagraphs in using our pretrained models, after downloading the models, replace <experiment-name-3> with video-pretrained.

    Compute FVD on Real Domain Results

    • To predict FVD_16, where frames are samples at a rate=3 (with total 16 frames sampled out of 60) use the following command,

      python evaluate/compute_fvd.py \
                --pred_path <generated-video-dir> \
                --gt_path dataset/eulerian_data/validation \
                --type fvd_16
      
    • To predict FVD_60, where frames are samples at a rate=1 (with all 60 frames samples) use the following command,

      python evaluate/compute_fvd.py \
                --pred_path <generated-video-dir> \
                --gt_path dataset/eulerian_data/validation \
                --type fvd_60
      

    The code for FVD computation has been taken from StyleGAN-V.

    Citation

    @article{mahapatra2023synthesizing,
        title={Text-Guided Synthesis of Eulerian Cinemagraphs},
        author={Mahapatra, Aniruddha and Siarohin, Aliaksandr and Lee, Hsin-Ying and Tulyakov, Sergey and Zhu, Jun-Yan},
        journal={arXiv preprint arXiv:2307.03190},
        year={2023}
    }

    Acknowledgments

    The code for this project was built using the codebase of pix2pixHD, ODISE, plug-and-play, SLR-SFS. The symmetric-splatting code was built on top of softmax-splatting. The code for evalution metric (FVD) was build on codebase of StyleGAN-V. We are very thankful to the authors of the corresponding works for releasing their code.

    We are also grateful to Nupur Kumari, Gaurav Parmar, Or Patashnik, Songwei Ge, Sheng-Yu Wang, Chonghyuk (Andrew) Song, Daohan (Fred) Lu, Richard Zhang, and Phillip Isola for fruitful discussions. This work is partly supported by Snap Inc. and was partly done while Aniruddha was an intern at Snap Inc.

    Visit original content creator repository https://github.com/text2cinemagraph/text2cinemagraph