0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

luaでもmagikaを使いたい。

Last updated at Posted at 2024-11-26

概要

どうも、shypkです。
lua基盤にmagikaを導入した流れをお見せしたいと思います。

magikaとは

magikaはgoogleが開発したAIでfiletype判別できる技術らしいです。
javascript, rust, python などで対応していて、残念ながら現時点ではluaに対応はしていません。

mluaでラッピング

過去の経験から、luaで使いたい場合はラッピングしちゃえばなんとかなる気がします。
せっかくrust対応もしているので、速いだろうと信じて、rust版のmagikaをラッピングしたいと思います。

rustにはmluaというcrateがあり、luaで使える動的ライブラリを簡単に作れます。
luastring を受け取れるidentify_content_label関数を登録してみます。

lumagika/src/lib.rs
use mlua::{Lua};
use mlua::prelude::*;

fn identify_content_label(_: &Lua, content: LuaString) -> LuaResult<String> { ... }

#[mlua::lua_module]
fn liblumagika(lua: &Lua) -> LuaResult<LuaTable> {
    let exports = lua.create_table()?;
    exports.set("identify_content_label", lua.create_function(identify_content_label)?)?;
    Ok(exports)
}

magikaを呼び出す。

あとはmagikaのcrateを呼び出すだけ。
こちらの説明によると

magika.identify_file_sync("src/lib.rs")?.info().label, "rust");
magika.identify_content_sync(&b"#!/bin/sh\necho hello"[..])?;

こういった使い方ができるらしいので、
今回はファイル内容を受け取って、そのlabelを返すという動作をしたいと思います。
上で繋いだidentify_content_labelの関数を内容を実装していきます。
そのコードがこちら。

lumagika/src/lib.rs
fn identify_content_label(_: &Lua, content: LuaString) -> LuaResult<String> {
    let ret: &str;
    let _ = match Session::new() {
        Ok(magika) => {
            let result = magika.identify_content_sync(&*content.as_bytes());
            match result {
                Ok(result) => {
                    ret = result.content_type().unwrap_or(ContentType::Unknown).info().label;
                },
                Err(e) => {
                    ret = "Error";
                    println!("Error identifying content: {:?}", e);
                },
            }

        },
        Err(e) => {
            ret = "Error";
            println!("Error identifying content: {:?}", e);
        }
    };

    Ok(ret.to_string())
}

cargo

cargoでビルドしたいので、Cargo.tomlに忘れずdependencyを追加しておきます。

lumagika/Cargo.toml
[dependencies]
magika = { version = "0.1.0-rc.1" }
mlua = { version = "0.10.0", features = ["lua51","module"] }
mlua-sys = { version = "0.6.3", features = ["lua51","module"] }

(mlua::lua_module を使うには features=moduleが必要です。)

テスト

他のluaスクリプトで呼び出す準備ができました。
実際使っているコードは見せづらいので、ここではlua interpreterで簡単にテストしてみます。

Lua 5.1.5  Copyright (C) 1994-2012 Lua.org, PUC-Rio
> package.cpath = package.cpath .. ";./target/release/?.so"
local lumagika = require("liblumagika")
local type = lumagika.identify_content_label("<html><body>some empty body</body><html>")
print(type)
html
> package.cpath = package.cpath .. ";./target/release/?.so"
local lumagika = require("liblumagika")
local type = lumagika.identify_content_label("<note><to>Tove</to><from>Jani</from><heading>Reminder</heading><body>Don't forget me this weekend!</body></note>")
print(type)
xml

ちゃんとhtml, xmlと出ました。
(都合上テキストだけのテストを表示していますが、pngなどbinaryもちゃんと判別できています。)

最後に

上で作られたlumagikaは下のgitにも隔離しています。

実際lumagikaで使われているコードはsasankaで公開しています。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?