rescript

package module
v0.0.0-...-50ca29f Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 31, 2021 License: MIT Imports: 22 Imported by: 0

README

reScript

Handwriting recognition for reMarkable notes.

This is a small tool to extract text from handwritten notes created on the reMarkable tablet.

It uses the reMarkable cloud API and the MyScript handwriting recognition ReST API.

Configuration and Setup

You need to enable "cloud sync" for your remarkable tablet to make your notes available for this tool.

When first run, reScript will ask for a "one time code" which can be obtained at https://my.remarkable.com/:

$ rescript
Enter one time code from https://my.remarkable.com/:
_

You also need a MyScript developer account, specifically an application key and HMAC key which needs to be added to the configuration file at ~/.config/hwr-conf.yaml:

datadir: /home/USERNAME/.local/share/hwr
cachedir: /home/USERNAME/.cache/hwr
appkey: bbd1419d-aa40-4803-9607-5115c3085de9
hmackey: 33b89262-dde1-4f92-a183-034255db6895

The datadir and cachedir both contain sensitivity values, namely the authentication token for the reMarkable API, all downloaded notes and cached handwriting recognition results.

Usage

Only one use case is supported:

$ rescript NAME_OF_NOTE -l LANGUAGE -f FORMAT

NAME_OF_NOTE is the display name of the notebook you want to convert into text. It is case-insensitive and supports partial matches. IF multiple notebooks match, all of them will be converted.

The LANGUAGE must be one of the languages supported by MyScript. The parameter is optional and defaults to en.

FORMAT specifies the output format. It is either txt for plain text or md for markdown. The parameter is optional and defaults to plain text.

The result is written to a file named after the notebook in the current directory.

Example:

$ rescript handwr
… download notebook "Handwriting Recognition"
… recognize handwriting for "Handwriting Recognition"
✓ write "Handwriting Recognition" to "Handwriting Recognition.md"
✓ Done.

Documentation

Index

Constants

View Source
const (
	LangEN LanguageCode = "en_US"
	LangDE LanguageCode = "de_DE"

	Pen    PointerType = "PEN"
	Touch  PointerType = "TOUCH"
	Eraser PointerType = "ERASER"
)
View Source
const Version = "0.1.1"

Version is the semantic version

Variables

This section is empty.

Functions

This section is empty.

Types

type BoundingBox

type BoundingBox struct {
	X      float64 `json:"x"`
	Y      float64 `json:"y"`
	Width  float64 `json:"width"`
	Height float64 `json:"height"`
}

Coordinates are in **millimeters**

func (BoundingBox) IsZero

func (b BoundingBox) IsZero() bool

type Char

type Char struct {
	Label       string      `json:"label"`
	Word        int         `json:"word"`
	Grid        []Point     `json:"grid"`
	BoundingBox BoundingBox `json:"bounding-box,omitempty"`
	Items       []Item      `json:"items,omitempty"`
}

type ComposeFunc

type ComposeFunc func(w io.Writer, m Metadata, r map[string]*Node) error

ComposeFunc is a function that generates an output document from the given set of tokens. THe result is written to the given writer.

func NewMarkdownComposer

func NewMarkdownComposer() ComposeFunc

NewMarkdownComposer creates a new composer which generates output in markdown format.

func NewPlaintextComposer

func NewPlaintextComposer() ComposeFunc

NewPlaintextComposer creates a new composer which creates plain text output for a regicnition result.

type Configuration

type Configuration struct {
	Language   LanguageCode             `json:"lang"`
	Text       *TextConfiguration       `json:"text,omitempty"`
	Export     *ExportConfiguration     `json:"export,omitempty"`
	RawContent *RawContentConfiguration `json:"raw-content,omitempty"`
}

Configuration is the root object for configuration options to a batch call.

func NewConfiguration

func NewConfiguration(lang LanguageCode, guides, bbox, chars, words bool) Configuration

NewConfiguration creates a new configuration object with the given values.

type ExportConfiguration

type ExportConfiguration struct {
	Jiix            JiixConfiguration `json:"jiix"`
	ImageResolution int64             `json:"image-resolution"`
}

ExportConfiguration holds settings for the API response.

func NewExportConfiguration

func NewExportConfiguration(bbox, chars, words bool) *ExportConfiguration

NewExportConfiguration creates an export config.

type GuidesConfiguration

type GuidesConfiguration struct {
	Enable bool `json:"enable"`
}

type Item

type Item struct {
	ID              string      `json:"id"`
	Type            string      `json:"type"`
	Timestamp       string      `json:"timestamp"` // 2021-01-09 13:23:42.196250
	Label           string      `json:"label"`
	Baseline        float64     `json:"baseline"`
	XHeight         float64     `json:"x-height"`
	LeftSideBearing float64     `json:"left-side-bearing"`
	BoundingBox     BoundingBox `json:"bounding-box"`
}

type JiixConfiguration

type JiixConfiguration struct {
	Strokes     bool     `json:"strokes"`
	BoundingBox bool     `json:"bounding-box"`
	Style       bool     `json:"style"`
	Text        JiixText `json:"text"`
}

JiixConfiguration holds options for the JIIX format.

JIIX is the "deep dive" format from the MyScript API.

func NewJiixConfiguration

func NewJiixConfiguration(bbox, chars, words bool) JiixConfiguration

NewJiixConfiguration creates a JIIX configuration with the given flags.

If bbox is set, each recognition result is additionally described by a bounding box which refers to the input drawing.

If words is set, the result will contain additional entries for each word, if chars is also set, the character index for each word is included.

type JiixText

type JiixText struct {
	Chars bool `json:"chars"`
	Words bool `json:"words"`
}

type LanguageCode

type LanguageCode string

type Linebreak

type Linebreak struct {
	Line int `json:"line"`
}

type MarginConfiguration

type MarginConfiguration struct {
	Top    int32 `json:"top"`
	Left   int32 `json:"left"`
	Right  int32 `json:"right"`
	Bottom int32 `json:"bottom"`
}

type Metadata

type Metadata struct {
	Title   string
	PageIDs []string
}

Metadata holds information about a document.

type MyScript

type MyScript struct {
	// contains filtered or unexported fields
}

MyScript is the client for the MyScript ReST API.

func NewMyScript

func NewMyScript(appKey, hmacKey string) *MyScript

NewMyScript sets up a new client.

It requires the application key and the HMAC key from ypur MyScript account.

func (*MyScript) Batch

func (m *MyScript) Batch(r Request) (Result, error)

Batch is the single endpoint fif the ReST API. It performs handwriting recognition.

type Node

type Node struct {
	// contains filtered or unexported fields
}

Node is an element in a doubly linked list of Tokens.

func Dehyphenate

func Dehyphenate(n *Node) *Node

Dehyphenate merges words that are separated by a hyphen.

func NewNode

func NewNode(t *Token) *Node

NewNode creates a new Node wrapping the given Token.

func (*Node) Ahead

func (n *Node) Ahead(count int) *Node

Ahead returns the node `count` steps ahead of this one (or nil).

func (*Node) Behind

func (n *Node) Behind(count int) *Node

Behind returns the node `count` steps behind of this one (or nil).

func (*Node) InsertAfter

func (n *Node) InsertAfter(o *Node)

InsertAfter adds the given not after this one

func (*Node) InsertBefore

func (n *Node) InsertBefore(o *Node)

InsertBefore inserts the given Node before this one

func (*Node) IsHead

func (n *Node) IsHead() bool

IsHead tells if this is the last node in the list.

func (*Node) IsTail

func (n *Node) IsTail() bool

IsTail tells if this is the first node in the list.

func (*Node) Next

func (n *Node) Next() *Node

Next returns the next node or nil if this is the HEAD.

func (*Node) Prev

func (n *Node) Prev() *Node

Prev returns the revious node or nil if this is the TAIL.

func (*Node) Remove

func (n *Node) Remove()

Remove drops this token from the list and directly links the previous and next nodes.

func (*Node) Token

func (n *Node) Token() *Token

Token returns the Token for this node.

func (*Node) Update

func (n *Node) Update(t *Token)

Update replaces the Token payload for this node with another token.

type PipelineFunc

type PipelineFunc func(n *Node) *Node

PipelineFunc is a function that can be chained to process a set of tokens.

The output is the modified set of tokens. A PipelineFunc may change, remove or insert tokens.

func BuildPipeline

func BuildPipeline(p ...PipelineFunc) PipelineFunc

BuildPipeline combines several pipeline functions into one.

type Point

type Point struct {
	X float64 `json:"x"`
	Y float64 `json:"y"`
}

type PointerType

type PointerType string

type RawContentConfiguration

type RawContentConfiguration struct {
	Recognition RawRecognitionConfiguration `json:"recognition"`
	Text        RawTextConfiguration        `json:"text"`
}

func NewRawContentConfiguration

func NewRawContentConfiguration() *RawContentConfiguration

type RawRecognitionConfiguration

type RawRecognitionConfiguration struct {
	Text  bool `json:"text"`
	Shape bool `json:"shape"`
}

type RawTextConfiguration

type RawTextConfiguration struct {
	CustomResources []string `json:"customResources,omitempty"`
	CustomLexicon   []string `json:"customLexicon,omitempty"`
	AddLKText       bool     `json:"addLKText"`
}

type Recognizer

type Recognizer struct {
	// contains filtered or unexported fields
}

The Recognizer organizes calls to the MyScript API to convert notbooks from handwriting to a recognize Result.

The recognizer also manages caching to avoid repeated calls to the API if a page has not changed.

func NewRecognizer

func NewRecognizer(appKey, hmacKey, cacheDir string) *Recognizer

NewRecognizer creates a recognizer withthe given credentials for the MyScript API.

If cacheDir is non-empty, it will be used to cache responses from the API. If it is empty, caching is disabled.

func (*Recognizer) Recognize

func (r *Recognizer) Recognize(doc *rmtool.Document, l LanguageCode) (map[string]*Node, error)

Recognize performs handwriting recognition on all pages of the given document. It resturns a map of page-IDs and recognition results.

type Request

type Request struct {
	Width  int64 `json:"width"`
	Height int64 `json:"height"`
	// ContentType controls the "recognition type" of the MyScript API.
	// It must be one of Text, Diagram, Math, Raw Content, Text Document
	ContentType string `json:"contentType"`
	// Must be DIGITAL_EDIT when the ReST API is used.
	ConversionState string        `json:"conversionState"`
	XDpi            int64         `json:"xDPI"`
	YDpi            int64         `json:"yDPI"`
	Theme           string        `json:"theme"`
	StrokeGroups    []StrokeGroup `json:"strokeGroups"`
	Configuration   Configuration `json:"configuration"`
}

Request is the root element for requests against the batch enpoint.

func NewRequest

func NewRequest() Request

NewRequest creates a request with default values.

type Result

type Result struct {
	ID          string      `json:"id"`
	Version     string      `json:"version"`
	Type        string      `json:"type"`
	Label       string      `json:"label"`
	BoundingBox BoundingBox `json:"bounding-box"`
	Words       []Word      `json:"words"`
	Chars       []Char      `json:"chars"`
	Linebreaks  []Linebreak `json:"linebreaks"`
}

Result is the response returned by the MyScript batch enpoint.

The Label field contains the complete recognized text. If the "words" option was enabled, the liust of Words contains the individual words and whitespace.

type Stroke

type Stroke struct {
	ID          string      `json:"id,omitempty"`          // opt
	PointerType PointerType `json:"pointerType,omitempty"` // opt
	PointerID   int         `json:"pointerId,omitempty"`   // opt
	X           []int       `json:"x"`
	Y           []int       `json:"y"`
	Timestamp   []int64     `json:"t"`
	Pressure    []float64   `json:"p"` // opt
}

A Stroke is a single stroke of digital ink.

It consists of a series of X,Y coordinates and their related timestamps and optional pressure values.

The Timestamp can be based on "0" as long as it increases from point to point.

func NewStroke

func NewStroke() Stroke

NewStroke creates a stroke with default values and no points.

type StrokeGroup

type StrokeGroup struct {
	PenStyle string   `json:"penStyle"`
	Strokes  []Stroke `json:"strokes"`
}

A StrokeGroup contains the digital ink strokes, i.e. the actual handwriting.

func ConvertLayer

func ConvertLayer(tOffset int64, l lines.Layer) (StrokeGroup, int64)

ConvertLayer convert a Layer from a reMarkable drawing to a MyScript stroke group.

func NewStrokeGroup

func NewStrokeGroup() StrokeGroup

NewStrokeGroup creates and empty stroke group.

type TextConfiguration

type TextConfiguration struct {
	Guides        GuidesConfiguration  `json:"guides"`
	Margin        MarginConfiguration  `json:"margin"`
	Configuration RawTextConfiguration `json:"configuration"`
}

TextConfiguration holds settings holds settings for text recognition.

func NewTextConfiguration

func NewTextConfiguration(guides bool) *TextConfiguration

NewTextConfiguration creates a default configuration.

type Token

type Token struct {
	// contains filtered or unexported fields
}

Token represents a single text element that was reconized from the handwriting input. The fully reconized text consists of a list of tokens.

RULES for tokenization:

- consecutive whitespace is split into multiple tokens - punctuation is a single token

func NewToken

func NewToken(s string) *Token

NewToken creates a new token with the given content.

func (*Token) IsDash

func (t *Token) IsDash() bool

IsDash tells if this token is a dash ("-"), including several unicode variants.

func (*Token) IsNewline

func (t *Token) IsNewline() bool

IsNewline tells if this token is a newline.

func (*Token) IsPunctuation

func (t *Token) IsPunctuation() bool

IsPunctuation tells if this token belongs to the punctuation group.

func (*Token) IsWhitespace

func (t *Token) IsWhitespace() bool

IsWhitespace tells whether this token is a single whiotespace character. For a typical recognition result, this will be either a single space or newline.

func (*Token) IsWord

func (t *Token) IsWord() bool

IsWord tells if this token is a "word".

This is determined by looking at the recongnized characters. This may still be a poorly recognized word.

func (*Token) StartsUpper

func (t *Token) StartsUpper() bool

StartsUpper tells if this token starts with an uppercase letter

func (*Token) String

func (t *Token) String() string

type Word

type Word struct {
	Label       string      `json:"label"`
	ReflowLabel string      `json:"reflow-label"`
	FirstChar   int         `json:"first-char,omitempty"`
	LastChar    int         `json:"last-char,omitempty"`
	BoundingBox BoundingBox `json:"bounding-box,omitempty"`
	Candidates  []string    `json:"candidates,omitempty"`
	Items       []Item      `json:"items,omitempty"`
}

Word is a single recognized "word", including whitespace or punctuation.

The recognized content is held in the `Label`; concatenating all labesl gives the full text. See: https://developer.myscript.com/docs/interactive-ink/1.4/reference/web/jiix/#word-object

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL