npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

paragrafs

v1.5.1

Published

A lightweight TypeScript library designed to reconstruct paragraphs from AI transcriptions.

Readme

paragrafs

wakatime Bun Node.js CI GitHub License GitHub Release codecov Size typescript npm GitHub issues GitHub stars CodeRabbit Pull Request Reviews

A lightweight TypeScript library designed to reconstruct paragraphs from AI transcriptions. It helps format unstructured text with appropriate paragraph breaks, handles timestamps for transcripts, and optimizes for readability.

Features

  • Segment Recognition: Intelligently groups text into logical paragraphs
  • Filler Removal: Identifies and removes common speech fillers (uh, umm, etc.)
  • Gap Detection: Detects significant pauses to identify paragraph breaks
  • Timestamp Formatting: Converts seconds to readable timestamps (HH:MM:SS)
  • Punctuation Awareness: Uses punctuation to identify natural segment breaks
  • Customizable Parameters: Configure minimum words per segment, max segment length, etc.
  • Arabic Support: Handles Arabic question marks and other non-Latin punctuation
  • Transcript Formatting: Converts raw token streams into readable text with appropriate line breaks
  • Ground-Truth Token Mapping: Aligns AI-generated word timestamps to human-edited transcript text using an LCS-based algorithm with intelligent interpolation

Installation

npm install paragrafs

or

pnpm install paragrafs

or

yarn add paragrafs

or

bun add paragrafs

Usage

Basic Example

import { estimateSegmentFromToken, markAndCombineSegments, mapSegmentsIntoFormattedSegments } from 'paragrafs';

// Example token from transcription
const token = {
    start: 0,
    end: 5,
    text: 'This is a sample text. It should be properly segmented.',
};

// Estimate segment with word-level tokens
const segment = estimateSegmentFromToken(token);

// Combine and format segments
const formattedSegments = mapSegmentsIntoFormattedSegments([segment]);

console.log(formattedSegments[0].text);
// Output: "This is a sample text. It should be properly segmented."

Working with Transcriptions

import {
    markAndCombineSegments,
    mapSegmentsIntoFormattedSegments,
    formatSegmentsToTimestampedTranscript,
} from 'paragrafs';

// Example transcription segments
const segments = [
    {
        start: 0,
        end: 6.5,
        text: 'The quick brown fox!',
        tokens: [
            { start: 0, end: 1, text: 'The' },
            { start: 1, end: 2, text: 'quick' },
            { start: 2, end: 3, text: 'brown' },
            { start: 3, end: 6.5, text: 'fox!' },
        ],
    },
    {
        start: 8,
        end: 13,
        text: 'Jumps right over the',
        tokens: [
            { start: 8, end: 9, text: 'Jumps' },
            { start: 9, end: 10, text: 'right' },
            { start: 10, end: 11, text: 'over' },
            { start: 12, end: 13, text: 'the' },
        ],
    },
];

// Options for segment formatting
const options = {
    fillers: ['uh', 'umm', 'hmmm'],
    gapThreshold: 3,
    maxSecondsPerSegment: 12,
    minWordsPerSegment: 3,
};

// Process the segments
const combinedSegments = markAndCombineSegments(segments, options);
const formattedSegments = mapSegmentsIntoFormattedSegments(combinedSegments);

// Get timestamped transcript
const transcript = formatSegmentsToTimestampedTranscript(combinedSegments, 10);

console.log(transcript);
// Output:
// 0:00: The quick brown fox!
// 0:08: Jumps right over the

Aligning AI Tokens to Human-Edited Text

import { updateSegmentWithGroundTruth } from 'paragrafs';

const rawSegment = {
    start: 0,
    end: 10,
    text: 'The Buick crown flock jumps right over the crazy dog.',
    tokens: [
        /* AI-generated word timestamps */
    ],
};

const aligned = updateSegmentWithGroundTruth(rawSegment, 'The quick brown fox jumps right over the lazy dog.');
console.log(aligned.tokens);
// Each token now matches the ground-truth words exactly,
// with missing words interpolated where needed.

API Reference

Core Functions

estimateSegmentFromToken(token: Token): Segment

Splits a single token into word-level tokens and estimates timing for each word.

markTokensWithDividers(tokens: Token[], options): MarkedToken[]

Marks tokens with segment breaks based on fillers, gaps, and punctuation.

groupMarkedTokensIntoSegments(markedTokens: MarkedToken[], maxSecondsPerSegment: number): MarkedSegment[]

Groups marked tokens into logical segments based on maximum segment length.

mergeShortSegmentsWithPrevious(segments: MarkedSegment[], minWordsPerSegment: number): MarkedSegment[]

Merges segments with too few words into the previous segment.

mapSegmentsIntoFormattedSegments(segments: MarkedSegment[], maxSecondsPerLine?: number): Segment[]

Converts marked segments into clean, formatted segments with proper text representation.

formatSegmentsToTimestampedTranscript(segments: MarkedSegment[], maxSecondsPerLine: number): string

Formats segments into a human-readable transcript with timestamps.

markAndCombineSegments(segments: Segment[], options): MarkedSegment[]

Combined utility that processes segments through all the necessary steps.

mapTokensToGroundTruth(segment: Segment): Segment

Synchronizes AI-generated word timestamps with the human-edited transcript (segment.text):

  • Uses a longest-common-subsequence (LCS) to find matching words and preserve their original timing.
  • Evenly interpolates timestamps for runs of missing words (only when two or more are missing).
  • Falls back to estimateSegmentFromToken if no matches are found.

Types

type Token = {
    start: number; // Start time in seconds
    end: number; // End time in seconds
    text: string; // The transcribed text
};

type Segment = Token & {
    tokens: Token[]; // Word-by-word breakdown with timings
};

type MarkedToken = 'SEGMENT_BREAK' | Token;

type MarkedSegment = {
    start: number;
    end: number;
    tokens: MarkedToken[];
};

Utility Functions

isEndingWithPunctuation(text: string): boolean

Checks if the text ends with punctuation (including Arabic punctuation).

formatSecondsToTimestamp(seconds: number): string

Formats seconds into a human-readable timestamp (H:MM:SS).

Use Cases

  • Transcript Formatting: Convert raw transcriptions into readable text
  • Subtitle Generation: Create properly formatted subtitles from audio transcriptions
  • Document Reconstruction: Rebuild properly formatted documents from extracted text

Contributing

Contributions are welcome! Please make sure your contributions adhere to the coding standards and are accompanied by relevant tests.

To get started:

  1. Fork the repository
  2. Install dependencies: bun install (requires Bun)
  3. Make your changes
  4. Run tests: bun test
  5. Submit a pull request

License

paragrafs is released under the MIT License. See the LICENSE.MD file for more details.

Author

Ragaeeb Haq


Built with TypeScript and Bun. Uses ESM module format.