lindera-wasm 0.43.0

A morphological analysis library for WebAssembly.
Documentation
<script lang="ts">
	import CONSTANTS from '$lib/constants';
	import { tokenizeByJavaScript, tokenizeByWASM } from '$lib';
	import Spinner from '$lib/components/Spinner.svelte';
	import TokenResult from '$lib/components/TokenResult.svelte';

	const dataSources = $state(CONSTANTS.texts);

	let selected = $state(0);
	let state = $state({
		isRunning: false,
		JavaScript: {
			tokens: [],
			loadTime: 0,
			executionTime: 0
		},
		WASM: {
			tokens: [],
			loadTime: 0,
			executionTime: 0
		}
	});
	function processTime(s) {
		return s.executionTime - s.loadTime;
	}

	async function runComparison() {
		// initialize
		state.JavaScript.tokens = [];
		state.WASM.tokens = [];
		state.isRunning = true;

		const resultJS = await tokenizeByJavaScript(CONSTANTS.texts[selected].text);
		state.JavaScript.tokens = resultJS.tokens;
		state.JavaScript.loadTime = resultJS.loadTime;
		state.JavaScript.executionTime = resultJS.executionTime;
		const resultWASM = await tokenizeByWASM(CONSTANTS.texts[selected].text);
		state.WASM.tokens = resultWASM.tokens;
		state.WASM.loadTime = resultWASM.loadTime;
		state.WASM.executionTime = resultWASM.executionTime;
	}
</script>

<div class="container">
	<h1>パフォーマンス比較</h1>
	<div class="data-source-selector">
		<label for="data-source">データソース:</label>
		<select id="data-source" bind:value={selected}>
			{#each dataSources as dataSource}
				<option value={dataSource.id}>
					{dataSource.display}
				</option>
			{/each}
		</select>
	</div>
	<div class="controls">
		<button onclick={runComparison}>比較開始</button>
	</div>
	{#if state.isRunning}
		<div id="comparison-results" class="comparison-container">
			{#if state.JavaScript.tokens.length === 0}
				<Spinner />
			{:else}
				<div class="comparison-item">
					<div class="implementation-name">JavaScript実装</div>
					<div class="execution-time">
						総実行時間: <span
							class="result-time {state.JavaScript.executionTime < state.WASM.executionTime
								? 'fastest'
								: 'slowest'}"
						>
							{state.JavaScript.executionTime.toFixed(2) + ' ms'}
						</span>
					</div>
					<div class="execution-time">
						辞書読み込み時間: <span
							class="result-time {state.JavaScript.loadTime < state.WASM.loadTime
								? 'fastest'
								: 'slowest'}"
						>
							{state.JavaScript.loadTime.toFixed(2) + ' ms'}
						</span>
					</div>
					<div class="execution-time">
						トークナイズ実行時間: <span
							class="result-time {processTime(state.JavaScript) < processTime(state.WASM)
								? 'fastest'
								: 'slowest'}"
						>
							{processTime(state.JavaScript).toFixed(2) + ' ms'}
						</span>
					</div>
					<div class="result-container">
						<span class="result-label">出力:</span>
						<TokenResult tokens={state.JavaScript.tokens}/>
					</div>
				</div>
			{/if}
			{#if state.WASM.tokens.length === 0}
				<Spinner />
			{:else}
				<div class="comparison-item">
					<div class="implementation-name">WASM実装</div>
					<div class="execution-time">
						総実行時間: <span
							class="result-time {state.WASM.executionTime < state.JavaScript.executionTime
								? 'fastest'
								: 'slowest'}"
						>
							{state.WASM.executionTime.toFixed(2) + ' ms'}
						</span>
					</div>
					<div class="execution-time">
						辞書読み込み時間: <span
							class="result-time {state.WASM.loadTime < state.JavaScript.loadTime
								? 'fastest'
								: 'slowest'}"
						>
							{state.WASM.loadTime.toFixed(2) + ' ms'}
						</span>
					</div>
					<div class="execution-time">
						トークナイズ実行時間: <span
							class="result-time {processTime(state.WASM) < processTime(state.JavaScript)
								? 'fastest'
								: 'slowest'}"
						>
							{processTime(state.WASM).toFixed(2) + ' ms'}
						</span>
					</div>
					<div class="result-container">
						<span class="result-label">出力:</span>
						<TokenResult tokens={state.WASM.tokens}/>
					</div>
				</div>
			{/if}
		</div>
	{/if}
</div>

<style>
	.container {
		background-color: #fff;
		padding: 30px;
		border-radius: 8px;
		box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
		text-align: center;
	}

	.data-source-selector {
		margin-bottom: 20px;
		display: flex;
		align-items: center;
		justify-content: center;
	}

	.data-source-selector label {
		margin-right: 10px;
		font-weight: bold;
		color: #555;
	}

	.data-source-selector select {
		padding: 8px 12px;
		border: 1px solid #ccc;
		border-radius: 4px;
		font-size: 16px;
	}

	.comparison-container {
		display: flex;
		gap: 20px; /* 項目間のスペース */
		margin-bottom: 20px;
	}

	.comparison-item {
		flex: 1; /* 各項目が同じ幅になるように */
		border: 1px solid #ddd;
		padding: 15px;
		border-radius: 6px;
		text-align: left; /* 内部のテキストは左寄せ */
		position: relative; /* スピナーの基準位置 */
	}

	.implementation-name {
		font-weight: bold;
		color: #555;
		margin-bottom: 10px;
	}

	.controls button {
		padding: 10px 20px;
		margin:8px;
		background-color: #28a745;
		color: white;
		border: none;
		border-radius: 4px;
		cursor: pointer;
		font-size: 16px;
		transition: background-color 0.3s ease;
		margin-right: 10px;
	}

	.controls button:hover {
		background-color: #218838;
	}

	.result-container {
		margin-top: 10px;
	}

	.result-label {
		font-weight: bold;
		color: #777;
		margin-right: 5px;
	}

	.execution-time {
		font-size: 18px;
		margin-top: 5px;
	}

	.fastest {
		color: green;
		font-weight: bold;
	}

	.slowest {
		color: red;
		font-weight: bold;
	}
</style>