sitateru tech blog: 作ってみた

sitateru tech blog

シタテルの技術やエンジニアの取り組みを紹介するテックブログです。

ラベル 作ってみた の投稿を表示しています。 すべての投稿を表示
ラベル 作ってみた の投稿を表示しています。 すべての投稿を表示

2019年2月21日木曜日

Alexaスキルを作ろう - 第2回

2月 21, 2019
こんにちは。シタテルでエンジニアをしている熊谷です。

SPECというサービスのバックエンド開発などを行っています。

今回は前回の続きで、Alexaスキルの作成について書いていきます。


今回は、前回作成したスキルから呼び出されるLambdaを作成します。

まずAWSコンソールにログインして、Lambda - 関数の作成に行きます。

そこから「一から作成」、「設計図」などが選べます。

「設計図」でalexaを検索すると、
それぞれのスキルタイプに合わせたsdkが用意されています。
使用したいタイプのsdkがある場合は、それを使用しましょう。

今回はとても単純なスキルを作成したので、「一から作成」を選択します。
いろいろな言語が選べますが、今回はNode.jsで作成しました。

関数を作成すると、シンプルなレスポンスを返す関数が書かれているので、その中身を変更します。

今回作成したスキルは、「言葉を逆さまにする」です。
シンプル...!

コードを記述します。

exports.handler = async (event) => {
  const word = event.request.intent.slots.word.value;
  const response = {
    "version": "1.0",
    "response": {
      "outputSpeech": {
        "type": "PlainText",
        "text": word.split('').reverse().join('')
      },
      "shouldEndSession": false
    },
    "sessionAttributes": {}
  };
  return response;
};

こんな感じになりました。

responseの形式について、詳しくは応答の形式を参考にしてください。
「intent.slots.word」の部分の「word」は前回設定した「スロット名」に対応します。

次にこのLambdaを呼び出すトリガーを設定します。

「トリガーの追加」から、「Alexa Skills Kit」を選択して、スキルID(alexa developer consoleを参照)を設定します。

alexa developer consoleでテストしてみましょう。

前回、スキルの呼び出し名とサンプル発話を設定しました。

テスト画面で、

「<スキルの呼び出し名>を開いて、<サンプル発話>おはよう」と入力すると‥


ちゃんと逆さまにして返してくれましたね!

シンプルなスキルですが動くと面白いと思います。


今回はここまでにします。

次回は実機でのテストとスキルの公開について書ければと思います。

ありがとうございました!

2018年12月12日水曜日

Alexaスキルを作ろう

12月 12, 2018

こんにちは。シタテルでエンジニアをしている熊谷です。

主にSPECというサービスのバックエンド開発(Rails)を行っています。

少し前にAlexaスキルの作成を試したので、その流れを簡単に説明していきます。

手順

1.Amazonアカウントを用意する

  • すでにamazon.co.jpの開発者アカウントがある場合は、それを使います。

  • お買い物用のAmazonアカウントを使用して、開発を開始できます。

  • Amazon Developerから、サインインして、情報を入力すると、開発用アカウントが登録されます。

    Amazon Developer

    ※ 画像のページで、ログインをして進みます。[Amazon Developerアカウントを作成]から進むと、amazon.com用のアカウントになってしまい、US向けのスキルになってしまうようです。

2.Alexa Developer Consoleにアクセス

3.[スキルの作成]をクリックし、スキル名などを入力する

スキルページ

4.スキルのページで、[呼び出し名]を設定する

5.エンドポイントを設定する

  • AWS Lambdaが推奨されているので、Lambdaでエンドポイントを作成するのが良いと思います。
  • リクエスト、レスポンスはJSON形式で送信します。
  • 作成したLambdaのARNを指定します。

6.インテントを作成する

  • [インテントを追加]をクリックし、カスタムインテントを作成します。

7.作成したインテントのページで、スキルの発話時に使用する、スロット(変数のようなもの)を設定する

  • スロットには、日付、数値、検索クエリー(文字列)などの型を指定できます

8.インテントを設定する

  • 作成したインテントの設定で、サンプル発話を登録します。
  • サンプル発話には上で作成したスロットを{スロット名}のような形で使用できます。

これで簡単なスキルを作成できました!

今回はざっくりした流れの紹介なので、ここまでにしたいと思います。

次回はLambdaの内容や、作成したスキルの公開、テストなどを説明していこうと思います。

2018年11月20日火曜日

独自マークアップ言語によるケアラベル(品質表示ネーム)エディター

11月 20, 2018

こんにちは、シタテルの茨木です。

衣服には必ずケアラベル(品質表示ネーム)というものがついています。洗濯の方法などが書いてあるアレですね。

凝ったデザインにすることもありますが、大体はパターンが決まっています。
今回は、独自のマークアップ言語でケアラベルを作れるようにしてみた、という内容です。

完成イメージ

  • 中央の入力欄で独自マークアップを入力すると、左にケアラベルがリアルタイムプレビューされる
  • 画像としてケアラベルをダウンロードできる
  • 右欄でCSSによるデザイン微調整が可能(おまけ)

ソースコード

https://github.com/tibaraki/care-label

目次

  1. マークアップをパースして配列に
  2. 配列からDOMを描画
  3. CSSを適用

マークアップをパースして配列に

本件の肝です。

パーサコンビネータparsimmonを使用します。

パーサコンビネータは文法要素の組み合わせで言語(文書)構造を定義していきます。
たとえば正規表現も文書構造を定義するものですが、正規表現は再帰が表現できないという限界があります。
今回使うようなパーサは再帰を記述できるので、理論上あらゆるプログラミング言語の文法チェックが可能です。

今回はこれをつかって、独自マークアップ言語の文法を定義してみます。

下記は入力例&出力例&パーサの本体です。
parseにマークアップを投げるとパース後の配列を返してくれます。

@id1
  aaa
@id2
  ccc
  @id2-1
    ddd
    eee
    @id2-1-1
      xxx
    fff
  @id2-2
    ggg
    hhh
[
  [
    "@id1",
    [
      [
        "aaa"
      ]
    ]
  ],
  [
    "@id2",
    [
      [
        "ccc"
      ],
      [
        "@id2-1",
        [
          [
            "ddd"
          ],
          [
            "eee"
          ],
          [
            "@id2-1-1",
            [
              [
                "xxx"
              ]
            ]
          ],
          [
            "fff"
          ]
        ]
      ],
      [
        "@id2-2",
        [
          [
            "ggg"
          ],
          [
            "hhh"
          ]
        ]
      ]
    ]
  ]
]
import {regex, string, lazy, seq} from 'parsimmon'

function lexeme(p) { return p.skip(regex(/[ \n]*/)) }

const lparen = lexeme(string('{'))
const rparen = lexeme(string('}'))

const elem = lazy('', () => { return block.or(line) })

const id   = lexeme(regex(/@[\w-]*/i))
const atom = regex(/[^\{\}\n ]+/).skip(regex(/ */))

const line  = regex(/[\n ]*/).then(atom.many()).skip(regex(/\n+/))
const block = regex(/[\n ]*/).then(seq(id, lparen.then(elem.many()).skip(rparen)))

const root = block.many()

export default {
  preserve(string) {
    let value = ''
    let level = 0
    string.split(/\r\n|\r|\n/).forEach((line) => {
      const indent = Math.floor(line.match(/^ */)[0].length / 2)
      if (level < indent) {
        value += "{".repeat(indent - level) + "\n" + line + "\n"
      } else if (level > indent) {
        value += "}".repeat(level - indent) + "\n" + line + "\n"
      } else {
        value += line + "\n"
      }
      level = indent
    })
    value += "}".repeat(level)
    return value
  },
  parse(string) {
    return root.parse(this.preserve(string)).value
  }
}

文書構造の定義

jsの前半部、constの並ぶ箇所は文書構造の定義です。
意味としては下記のような感じです。
elemとblockが相互参照して再帰しているのがわかるかと思います。

const elem = lazy('', () => { return block.or(line) })

elemはblockまたはlineで構成される

const block = regex(/[\n ]*/).then(seq(id, lparen.then(elem.many()).skip(rparen)))

blockはidで始まり、lparen{とrparen}で囲まれた複数個のelemで構成される

preserve

preserveは前処理です。

文書構造の定義でしれっと{}でブロックを定義していましたが、今回作りたいマークアップはインデントでネストを表現する方式なので、前処理でインデントを{}に変換しています。

ここもパーサでできればカッコいいのですが、うまいやり方は思いつきませんでした。pythonとかどうしてるんですかね?

配列からDOMを描画

vueで書きます。パース後の配列(persed)とバインドしておけば、リアルタイムに再描画されて楽です。

    div#view(:style="viewsize" ref="view")
      div(v-for="elem in parsed")

        div(v-if="check(elem, /^@mixings/)" :class="classname(elem)")
          table
            tr(v-for="mixing in take(elem)")
              td(v-for="i in columns(take(elem))") {{ mixing[i-1] || "" }}

        div(v-else-if="check(elem, /^@marks/)" :class="classname(elem)")
          div(v-for="mark in take(elem)")
            img(v-if="isValidMarkId(mark[0])" :src="`/img/${mark[0]}.jpg`")

        div(v-else-if="check(elem, /^@/)" :class="classname(elem)")
          div(v-for="e in take(elem)") {{ e.join(' ') }}

基本的には@hogeをそのままcssのclass(.hoge)として適用し、cssでデザインを定義していく戦略なので、あまり複雑なことはやりません。

ただし、@marksは画像(洗濯マーク)に差し替える必要があるのと、@mixingsはtableでレイアウトしたかったので、vue内で特別扱いしてあげます。

CSSの適用

CSSも書き直したらリアルタイムに反映されてほしいので、更新時に動的に差し替えに行きます。

    applyStyle() {
      const old = document.getElementById('inserted-style')
      old && old.parentNode.removeChild(old)
      const obj = document.createElement('style')
      obj.setAttribute('id', 'inserted-style')
      obj.appendChild(document.createTextNode(this.style))
      document.getElementsByTagName('head')[0].appendChild(obj)
    },

あまりキレイじゃないですが、head要素に無理やり差し込みます。

その他

HTMLからの画像化は、下記ライブラリを使用しています。
https://github.com/tsayen/dom-to-image
どうもフォントまわりの挙動が怪しく、OS/ブラウザによっては画像出力が上手くいかない場合があります。

まとめ

一通り作ってから、yamlでも良かったのでは、とちょっと思ってしまいました。

とはいえ、非エンジニアにはyamlも辛いでしょうし、目的特化して打鍵の少ない文法を定義したい、というところに独自マークアップの需要はあるかもしれません。WYSIWYGに発展できたりするといいですね。

ご参考になれば幸いです。

2018年11月6日火曜日

DXF TIIPビューワ

11月 06, 2018

こんにちは!
シタテル株式会社CTOの和泉です。

シタテルではユーザー様からの相談を相談をお受けして、衣服の生産管理を行っています。

その際、衣服のパターンデータをいただきますが、このパターンデータはDXFという形式のファイルで送られてきます。

正確にはDXFを拡張したアパレルCADデータ互換のTIIP規約としてフォーマットが規定されています。

アパレルCADデータ互換のTIIP規約

このファイルは通常、専用のソフトウェアを使って編集、閲覧するのですが、

「ブラウザ上でユーザー様とメッセージのやり取りをしている中でいちいちダウンロードして確認してというのは効率が良くないから、ブラウザで見たい!」

という現場からの要望がありました。

ということで、DXF TIIPのファイルをブラウザ上で閲覧できる簡易ビューワーを作りました!(1年ぐらい前に)
突貫工事で作ったのであまりできはよくないですが、ザックリとファイルの中身を 見られるので重宝していただいてます。

DXF TIIP Viewer - Github

DXF TIIP Viewer

シタテルの SCSやマイオペレーター、マイアトリエにも組み込まれています。スマホでも見られるので外出先でちょっと確認したいときにも便利です。

フォーマットが見つからなかった、、、

実装するときにファイルフォーマットをダウンロードしよう思ったのですが、ちょっと探しただけでは見つけられず。

いや、きっと私の探し方が悪かっただけだと思うんですが、、、

結果、バイナリエディタとにらめっこしながらなんとなくで作りました。

TIIPはDXFのコメントエントリ(用語適当です、ごめんなさい)の部分を拡張してあるフォーマットだったので、なんとなくで読み取ることができました。

DXFの読み取り

DXF自体の読み込みには three-dxf を利用しました。
そのままだと読み取りできない部分があったのでもとのリポジトリをフォークして少し編集しています。

Three DXF - Github

おわりに

今回のDXFの話はちょっとした部分を便利にしただけですが、 シタテルではこのように現場の声を毎日聞きながらエンジニアが開発を行うことで、現場にフィットした機能を作り、効率性を高めることで多くの相談をすばやく処理して、ユーザー様の衣服づくりをサポートしています。