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 🙏

© 2026 – Pkg Stats / Ryan Hefner

@linto-ai/linto

v1.3.0

Published

Wrapper around LinTO Studio API

Downloads

222

Readme

LinTO Studio SDK

LinTO Studio SDK is a wrapper around LinTO Studio API. You can generate an auth token from LinTO Studio in the organization settings.

It is available in Python and Javascript (NodeJS and web browser).

Install

Python

pip install linto

NodeJS or compiled front-end project

npm install @linto-ai/linto

Plain JS in web browser

<script type="module" src="https://unpkg.com/@linto-ai/linto/index.js"></script>

Quick start

NodeJS or Web browser

// NodeJS
import LinTO from "@linto-ai/linto"
let linTO = new LinTO({
  authToken: "authToken",
})

// Browser
let linTO = new window.LinTO({
  authToken: "authToken",
})

// Choose depending on your environment

// NodeJS
import fs from "fs"
const file = await fs.openAsBlob("path/to/audio.mp3")

// Browser :
// From an <input type='file'/>
const file = document.getElementById("file").files[0]

const handle = await linTO.transcribe(file)

handle.addEventListener("update", (e) => {
  console.log("Audio transcription processing", e.detail)
})

handle.addEventListener("done", (e) => {
  console.log("Audio transcription completed")
  console.log("Full text", e.detail.fullText)
  console.log("Formated output", e.detail.toFormat())
  console.log("Turns list", e.detail.turns)
  console.log("Api response", e.detail.response)
})

handle.addEventListener("error", () => {
  console.log("Error while processing the audio")
})

Full example

Python

import os
from linto import LinTO

linTO = LinTO(auth_token="auth_token")

with open("path/to/audio.mp3", "rb") as f:
    file = f.read()

handle = await linTO.transcribe(file)

def on_update(data):
    print("Audio transcription processing", data)

def on_done(data):
    print("Audio transcription completed")
    print("Full text", data.full_text)
    print("Formated output", data.to_format())
    print("Turns list", data.turns)
    print("Api response", data.response)

def on_error(data):
    print("Error while processing the audio")

handle.on("update", on_update)
handle.on("done", on_done)
handle.on("error", on_error)

See complete python script at python/test.py

API reference

Method names and options in camelCase are the same in snake_case for Python (e.g. enableDiarizationenable_diarization, setConversationOwnerset_conversation_owner).

Initialisation

// Javascript
const linTO = new LinTO({ authToken: "auth_token", ...options })
# Python
linTO = LinTO(auth_token="auth_token", **options)

Options

| Parameter | required | value | description | default value | | --------- | -------- | ------ | ------------------- | ------------------------------ | | authToken | yes | String | Studio auth token | | | baseUrl | no | String | Studio API base url | https://studio.linto.ai/cm-api |


Transcription

transcribe

Upload a media file and start a transcription job. Returns a polling handle that emits update, done, and error events.

// Javascript
const handle = await linTO.transcribe(file, { ...options })

handle.addEventListener("update", callback)
handle.addEventListener("done", callback)
handle.addEventListener("error", callback)
# Python
handle = await linTO.transcribe(file, **options)

handle.on("update", callback)
handle.on("done", callback)
handle.on("error", callback)

| Parameter | required | value | description | default value | | ----------------- | -------- | ------------------------------- | ---------------------------------------------------------------------------------------- | ----------------------- | | file | yes | File or Blob | Audio file to transcribe | | | enableDiarization | no | Bool | Enable speaker diarization | True | | numberOfSpeaker | no | Int | Number of speakers for diarization, 0 means auto | 0 | | language | no | 2 letters language code or "*" | Language the audio should be transcribed. "*" means auto-detection + multiple languages | "*" | | enablePunctuation | no | Bool | Enable automatic punctuation recognition | True | | name | no | String | Name of the media in LinTO Studio | "imported file ${date}" | | membersRight | no | Int | Default permission bitmask for organization members on the resulting conversation (1 = read) | None |

listServices

List ASR (speech-to-text) services available to the current account. Each service exposes a service_name field that can be referenced elsewhere.

// Javascript
const services = await linTO.listServices()
# Python
services = await linTO.list_services()

LLM summaries

listLlmServices

List LLM services available for summarization.

// Javascript
const services = await linTO.listLlmServices()
# Python
services = await linTO.list_llm_services()

summarize

Trigger an LLM summary and return a polling handle. Events are the same shape as transcribe: update, done (with { content, jobId }), error.

// Javascript
const handle = await linTO.summarize(conversationId, serviceRoute, { ...options })

handle.addEventListener("done", (e) => console.log(e.detail.content))
# Python
handle = await linTO.summarize(conversation_id, service_route, **options)

handle.on("done", lambda e: print(e["content"]))

| Parameter | required | value | description | default value | | -------------- | -------- | ------ | ------------------------------------------------------ | ------------- | | conversationId | yes | String | Target conversation id | | | serviceRoute | yes | String | LLM service route (see listLlmServices) | | | flavor | no | String | Optional flavor / preset name | None |


Export & download

downloadConversation

Download the raw transcription (no LLM step). Binary formats (docx, odt, verbatim) return a Blob (browser) or ArrayBuffer (Node); other formats return JSON.

// Javascript
const blob = await linTO.downloadConversation(conversationId, { format: "docx" })
# Python
content = await linTO.download_conversation(conversation_id, format="docx")

| Parameter | required | value | description | default value | | -------------- | -------- | ------ | --------------------------------- | ------------- | | conversationId | yes | String | Target conversation id | | | format | no | String | "docx", "odt", "json", ... | "docx" |

getExportList

List existing export jobs attached to a conversation.

// Javascript
const jobs = await linTO.getExportList(conversationId)
# Python
jobs = await linTO.get_export_list(conversation_id)

getExportContent

Fetch the content of a finished export job.

// Javascript
const content = await linTO.getExportContent(conversationId, jobId)
# Python
content = await linTO.get_export_content(conversation_id, job_id)

getPublicationTemplates

List publication templates available on the organization.

// Javascript
const templates = await linTO.getPublicationTemplates()
# Python
templates = await linTO.get_publication_templates()

getTemplatePlaceholders

Get placeholders defined on a publication template.

// Javascript
const placeholders = await linTO.getTemplatePlaceholders(templateId)
# Python
placeholders = await linTO.get_template_placeholders(template_id)

exportWithTemplate

Render a publication template to a downloadable document.

// Javascript
const file = await linTO.exportWithTemplate(jobId, { ...options })
# Python
file = await linTO.export_with_template(job_id, **options)

| Parameter | required | value | description | default value | | ------------- | -------- | ------ | -------------------------- | ------------- | | jobId | yes | String | Source export job id | | | format | no | String | Output format | "pdf" | | templateId | no | String | Publication template id | None | | versionNumber | no | Int | Template version | None |


Taxonomy

A LinTO Studio organization can group media in two complementary ways:

  • Categories & tags: a category holds a flat list of tags; each conversation can carry any number of tags. The built-in "tags" category is the one whose entries surface as chips on media cards.
  • Folders: a hierarchical tree; each conversation can live in at most one folder.

listCategories

List taxonomy categories on the current organization.

// Javascript
const categories = await linTO.listCategories()
# Python
categories = await linTO.list_categories()

listTags

List tags inside a category.

// Javascript
const tags = await linTO.listTags(categoryId)
# Python
tags = await linTO.list_tags(category_id)

createTag

Create a tag inside a category.

// Javascript
const tag = await linTO.createTag(categoryId, name, { ...options })
# Python
tag = await linTO.create_tag(category_id, name, **options)

| Parameter | required | value | description | default value | | ---------- | -------- | ------ | -------------- | ------------- | | categoryId | yes | String | Parent category| | | name | yes | String | Tag name | | | color | no | String | Hex color | None | | emoji | no | String | Unicode emoji | None |

ensureTag

Return the id of tag name, creating it if needed. Defaults to the built-in "tags" category, falling back to the first available category if the named one is missing. Returns null when no category exists at all.

// Javascript
const tagId = await linTO.ensureTag("important")
await linTO.addConversationTag(conversationId, tagId)
# Python
tag_id = await linTO.ensure_tag("important")
await linTO.add_conversation_tag(conversation_id, tag_id)

| Parameter | required | value | description | default value | | ------------ | -------- | ------ | ---------------------------------------------------- | ------------- | | name | yes | String | Tag name (case-insensitive lookup) | | | categoryName | no | String | Category to look into | "tags" | | color | no | String | Color used if the tag has to be created | None | | emoji | no | String | Emoji used if the tag has to be created | None |

addConversationTag

Append a tag to a conversation, preserving existing tags.

// Javascript
await linTO.addConversationTag(conversationId, tagId)
# Python
await linTO.add_conversation_tag(conversation_id, tag_id)

listFolders

List folders on the current organization.

// Javascript
const folders = await linTO.listFolders()
# Python
folders = await linTO.list_folders()

createFolder

Create a folder.

// Javascript
const folder = await linTO.createFolder(name, { ...options })
# Python
folder = await linTO.create_folder(name, **options)

| Parameter | required | value | description | default value | | ---------- | -------- | ---------------------- | ---------------------------------------------------- | ------------- | | name | yes | String | Folder name | | | parentId | no | String | Parent folder id (root if omitted) | None | | color | no | String | Hex color | None | | emoji | no | String | Unicode emoji | None | | visibility | no | "public" / "private" | Folder visibility for members below MAINTAINER | "public" |

ensureFolder

Return the id of folder name, creating it if needed. Matches on (name, parentId) so the same name at different levels stays distinct. With visibility: "private", the service account becomes the owner and moved conversations are hidden from members below MAINTAINER.

// Javascript
const folderId = await linTO.ensureFolder(name, { ...options })
# Python
folder_id = await linTO.ensure_folder(name, **options)

| Parameter | required | value | description | default value | | ---------- | -------- | ---------------------- | ---------------------------------------------------- | ------------- | | name | yes | String | Folder name | | | parentId | no | String | Match within this parent folder (root if omitted) | None | | visibility | no | "public" / "private" | Visibility used if the folder has to be created | "public" |

moveToFolder

Move a conversation into a folder.

// Javascript
await linTO.moveToFolder(folderId, conversationId)
# Python
await linTO.move_to_folder(folder_id, conversation_id)

Sharing & users

shareConversation

Share a conversation with a user by email. By default LinTO Studio sends a notification email — pass notify: false to suppress it.

// Javascript
await linTO.shareConversation(conversationId, email, { ...options })
# Python
await linTO.share_conversation(conversation_id, email, **options)

| Parameter | required | value | description | default value | | -------------- | -------- | ------ | ---------------------------------------- | ------------- | | conversationId | yes | String | Target conversation id | | | email | yes | String | Recipient email | | | right | no | Int | Permission bitmask (1 = read) | 1 | | notify | no | Bool | Send notification email | True |

searchUsers

Search users by email or display name. Mostly useful as a building block for higher-level helpers like setConversationOwner.

// Javascript
const users = await linTO.searchUsers(search)
# Python
users = await linTO.search_users(search)

updateConversation

Patch arbitrary conversation fields (e.g. owner, sharedWithUsers, tags). Mostly useful as a building block — prefer the specialized helpers when one exists.

// Javascript
await linTO.updateConversation(conversationId, { owner: userId, tags: [tagId] })
# Python
await linTO.update_conversation(conversation_id, {"owner": user_id, "tags": [tag_id]})

setConversationOwner

Transfer conversation ownership to the user matching email. Resolves the user via searchUsers, then sets owner and clears sharedWithUsers. Returns the resolved user id, or null if the email cannot be matched.

// Javascript
const userId = await linTO.setConversationOwner(conversationId, "[email protected]")
if (!userId) console.warn("user not found")
# Python
user_id = await linTO.set_conversation_owner(conversation_id, "[email protected]")
if not user_id:
    print("user not found")

Media output

The object emitted on the done event of transcribe exposes the helpers below.

| Property / method | description | | ----------------- | ------------------------------------------------------------------------------------ | | fullText | Plain text of the full transcript (no speaker, language or timestamp metadata). | | turns | Array of { speaker, lang, text, stime, etime } objects. | | response | Raw API response (escape hatch for fields the SDK doesn't surface). | | toFormat(opts) | Render the transcript as a single string with configurable metadata and separators. |

toFormat options

| Parameter | required | value | description | default value | | -------------- | -------- | ------ | ------------------------------------------------------------------------------------------------------- | ---------------------------------------------- | | sep | no | String | Separator between metadatas | " - " | | metaTextSep | no | String | Separator between metadata and text | " : " | | eol | no | String | End of line character ("CRLF" or "LF" or None). If neither "CRLF" or "LF", no carriage return is added. | "CRLF" | | ensureFinalEOL | no | Bool | Whether to ensure final end of line | false | | include | no | Object | Which metadata to include (speaker, lang, timestamp) | { speaker: true, lang: true, timestamp: true } | | order | no | Array | Order of metadata in output | ["speaker", "lang", "timestamp"] |

Coming soon 🏗️

Transcribe video conference

const meeting = await linTO.transcribeVideoConference({ type, url, ...options })
meeting.addEventListener("connected", callback)
meeting.addEventListener("meeting_start", callback)
meeting.addEventListener("people_join", callback)
meeting.addEventListener("meeting_end", callback)
meeting.addEventListener("transcription", callback)

handle = await meeting.offlineTranscription({ ...options })
handle.addEventListener("update", callback)
handle.addEventListener("done", callback)
handle.addEventListener("error", callback)

Live transcription

const live = await linTO.transcribeLive({ ...option })
live.connectAudio(source)
live.startTranscription()
live.stopTranscription()
live.addEventListener("transcription", callback)