<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: carl kevin</title>
    <description>The latest articles on DEV Community by carl kevin (@carl_kevin_99180e3b998739).</description>
    <link>https://dev.to/carl_kevin_99180e3b998739</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4110784%2F109cccd7-250c-46ef-b2b9-f255e6e4ded3.png</url>
      <title>DEV Community: carl kevin</title>
      <link>https://dev.to/carl_kevin_99180e3b998739</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/carl_kevin_99180e3b998739"/>
    <language>en</language>
    <item>
      <title>Transcript cleanup needs an editing policy, not a global filler-word filter</title>
      <dc:creator>carl kevin</dc:creator>
      <pubDate>Mon, 14 Sep 2026 09:04:19 +0000</pubDate>
      <link>https://dev.to/carl_kevin_99180e3b998739/transcript-cleanup-needs-an-editing-policy-not-a-global-filler-word-filter-2ch5</link>
      <guid>https://dev.to/carl_kevin_99180e3b998739/transcript-cleanup-needs-an-editing-policy-not-a-global-filler-word-filter-2ch5</guid>
      <description>&lt;p&gt;A text-cleaning step can quietly change what a speaker meant. Consider this invented example:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I sent fifteen—no, fifty invitations. Um, I haven’t received a reply.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Removing an empty “um” may fit a clean-verbatim brief. Deleting the self-correction or “haven’t” changes the statement. Treating every repeated word as noise can also erase emphasis or an answer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep the source and the editing policy
&lt;/h2&gt;

&lt;p&gt;For a transcript-processing workflow, keep the source recording and raw transcript alongside the edited reading copy. Write down what your output may remove, how you mark unclear speech, and whether you preserve false starts. Apply that policy before making blanket substitutions.&lt;/p&gt;

&lt;p&gt;A useful review sequence:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Compare names, numbers, negation and corrections with the recording.&lt;/li&gt;
&lt;li&gt;Keep speaker turns and meaningful short replies.&lt;/li&gt;
&lt;li&gt;Mark uncertainty instead of guessing.&lt;/li&gt;
&lt;li&gt;Check that punctuation hasn’t created a new meaning.&lt;/li&gt;
&lt;li&gt;Label a summary as a summary; don’t present it as verbatim speech.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Treat cleanup as an editorial transformation
&lt;/h2&gt;

&lt;p&gt;“Clean verbatim” and “full verbatim” are not perfectly universal specifications. Agree on the editing brief for the intended reader. A readable meeting note and an oral-history transcript can require different treatment of hesitation and non-speech events. A global regex cannot decide what an utterance means in context.&lt;/p&gt;

&lt;p&gt;Disclosure: I work on Wordtake. The full guide has paired examples, source references and a reusable brief:&lt;br&gt;
&lt;a href="https://wordtake.app/pages/blog/clean-verbatim-vs-full-verbatim?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=20260914_verbatim" rel="noopener noreferrer"&gt;Clean Verbatim vs Full Verbatim: What Should You Keep?&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The examples are invented. This is an editing workflow, not a measured accuracy benchmark. Prepared with AI assistance.&lt;/p&gt;

</description>
      <category>ai</category>
    </item>
    <item>
      <title>What a Four-Column Social Comment CSV Can—and Cannot—Tell You</title>
      <dc:creator>carl kevin</dc:creator>
      <pubDate>Mon, 14 Sep 2026 07:36:02 +0000</pubDate>
      <link>https://dev.to/carl_kevin_99180e3b998739/what-a-four-column-social-comment-csv-can-and-cannot-tell-you-4mmb</link>
      <guid>https://dev.to/carl_kevin_99180e3b998739/what-a-four-column-social-comment-csv-can-and-cannot-tell-you-4mmb</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Disclosure:&lt;/strong&gt; This tutorial and its code were prepared with AI assistance by the CommentTok editorial team, which publishes the exporter discussed below. The sample data is fictional, and the code was tested against the included fixture.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A CSV with &lt;code&gt;author&lt;/code&gt;, &lt;code&gt;handle&lt;/code&gt;, &lt;code&gt;comment&lt;/code&gt;, and &lt;code&gt;likes&lt;/code&gt; is enough to inspect a captured discussion and identify questions to review. It is not enough to establish complete coverage, recover reply relationships, or count distinct comments across repeated captures.&lt;/p&gt;

&lt;p&gt;That distinction belongs in the code, not just a footnote in a report. This tutorial builds a small Python validator that produces a JSON summary, flags possible repeated records, and deliberately leaves &lt;code&gt;coverage&lt;/code&gt; as &lt;code&gt;unknown&lt;/code&gt;.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What you'll build:&lt;/strong&gt; A local, read-only CSV analysis script using Python's standard library. It preserves the input, identifies structural problems, and reports repeated handle/text combinations without deleting them.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Start with the schema's actual meaning
&lt;/h2&gt;

&lt;p&gt;This example follows a real browser exporter whose four columns are fixed. It writes UTF-8 with a byte-order mark, surrounds each value with double quotes, and doubles embedded quote characters. The tutorial data below is entirely fictional: anonymous example labels, invented comments, and invented like counts. It contains no captured user data.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Field&lt;/th&gt;
&lt;th&gt;Useful interpretation&lt;/th&gt;
&lt;th&gt;Unsupported conclusion&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;author&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Display name returned with the record&lt;/td&gt;
&lt;td&gt;A stable identity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;handle&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Handle string returned with the record&lt;/td&gt;
&lt;td&gt;A verified unique person&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;comment&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Text available in this capture&lt;/td&gt;
&lt;td&gt;A unique comment identifier&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;likes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Like count reported for this row&lt;/td&gt;
&lt;td&gt;A measure of all audience opinion&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;There is no comment ID, parent ID, posting timestamp, source URL, or capture timestamp in this file. A value visible in a product interface does not necessarily exist in its export schema.&lt;/p&gt;

&lt;p&gt;The underlying capture can request replies, but the flat file cannot show which parent a reply belongs to. A successful download also says nothing about how much of the original discussion was accessible. Acquisition limits and schema limits are separate problems; fixing one does not fix the other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a deliberately awkward fixture
&lt;/h2&gt;

&lt;p&gt;Save this as &lt;code&gt;example-comments.csv&lt;/code&gt;. The line break in the final comment is intentional. Do not flatten it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;author,handle,comment,likes
"Example A","example_a","Does this come in blue, too?","4"
"Example B","example_b","How do I clean it?","2"
"Example A","example_a","Does this come in blue, too?","5"
"Example C","example_c","The label says ""hand wash"".","1"
"Example D","example_d","First line
second line","0"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These five records exercise three parsing cases: a comma inside text, a quoted phrase, and a multiline field. There is also a repeated handle/text pair with different likes.&lt;/p&gt;

&lt;p&gt;Do not parse this with &lt;code&gt;line.split(',')&lt;/code&gt;. The comma in the first comment is part of the comment. Counting physical lines also gives the wrong number of records because the last record spans two lines.&lt;/p&gt;

&lt;p&gt;Python's &lt;a href="https://docs.python.org/3/library/csv.html" rel="noopener noreferrer"&gt;&lt;code&gt;csv&lt;/code&gt; documentation&lt;/a&gt; recommends opening CSV files with &lt;code&gt;newline=''&lt;/code&gt;. &lt;code&gt;DictReader&lt;/code&gt; maps fields to header names and leaves values as strings by default. We will convert only the numeric field we intentionally validate.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validate first, then summarize
&lt;/h2&gt;

&lt;p&gt;Save the following as &lt;code&gt;analyze_comment_csv.py&lt;/code&gt;. It uses no external packages and makes no network requests. A Python 3 installation and a terminal are sufficient.&lt;/p&gt;

&lt;p&gt;The script reads the file into memory because this is a small-file tutorial. Its SHA-256 fingerprint covers the exact bytes being parsed. A fingerprint identifies a particular byte sequence; it does not prove who collected the file or whether the content is complete.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Validate a small four-column CSV and print a bounded JSON summary.

Usage: python3 analyze_comment_csv.py comments.csv
No network calls, third-party packages, or changes to the input file.
&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;json&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sys&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;collections&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Counter&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;pathlib&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;

&lt;span class="n"&gt;FIELDS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;author&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;handle&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;comment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;likes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;


&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;analyze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;raw&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;read_bytes&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;StringIO&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;utf-8-sig&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;newline&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;reader&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nc"&gt;DictReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;strict&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fieldnames&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="n"&gt;FIELDS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Expected exactly: author,handle,comment,likes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;record_number&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nf"&gt;enumerate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reader&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;start&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="nf"&gt;any&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;is&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;value&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;()):&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Record &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;record_number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: wrong number of fields&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;re&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fullmatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;r&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[0-9]+&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;likes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]):&lt;/span&gt;
            &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Record &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;record_number&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: likes must be a nonnegative integer&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="n"&gt;candidates&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;Counter&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;handle&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;comment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;row&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;sha256&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;hashlib&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;sha256&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;raw&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hexdigest&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;rows&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;distinct_nonempty_handle_strings&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;handle&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;handle&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]}),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blank_handle_rows&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;handle&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;blank_comment_rows&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;comment&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;likes_sum_across_rows&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;likes&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;rows&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;repeated_handle_text_groups&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;extra_rows_in_repeated_handle_text_groups&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;candidates&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;values&lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;deduplication_performed&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;coverage&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;unknown&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;


&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;__name__&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;__main__&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Usage: python3 analyze_comment_csv.py comments.csv&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;analyze&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="nf"&gt;except &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;OSError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;UnicodeError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;csv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;ValueError&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="nc"&gt;SystemExit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Cannot analyze CSV: &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;exc&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;dumps&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;indent&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Three choices are worth keeping when adapting this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Require the expected header.&lt;/strong&gt; An unexpected delimiter, renamed field, extra column, or missing file header should not silently produce a convincing summary.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Validate numeric strings.&lt;/strong&gt; An empty or malformed like count triggers an error instead of becoming a guessed zero. This tutorial's contract accepts nonnegative integer strings only.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Count candidates without removing them.&lt;/strong&gt; Matching a handle and comment text is a review signal. It is not proof of duplicate identity.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;utf-8-sig&lt;/code&gt; decoder accepts ordinary UTF-8 and skips an initial UTF-8 byte-order mark when present. That matters when matching the first header exactly. See Python's &lt;a href="https://docs.python.org/3/library/codecs.html#encodings.utf_8_sig" rel="noopener noreferrer"&gt;encoding documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Run it and interpret the output
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 analyze_comment_csv.py example-comments.csv
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Besides the file fingerprint, the output should contain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rows"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"distinct_nonempty_handle_strings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"blank_handle_rows"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"blank_comment_rows"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"likes_sum_across_rows"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;12&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"repeated_handle_text_groups"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"extra_rows_in_repeated_handle_text_groups"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"deduplication_performed"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"coverage"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"unknown"&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Those values describe only the fictional fixture. The script intentionally says “handle strings” rather than “people” and “likes sum across rows” rather than “total engagement.” If the same comment appears twice, adding its reported counts can double-count activity. Conversely, two identical texts from the same handle could be separate postings.&lt;/p&gt;

&lt;p&gt;Consider the first and third rows. There are at least two plausible explanations: one comment was captured twice as its like count changed, or the same account posted the same question twice. Nothing in these four columns resolves that ambiguity. Keeping whichever row has more likes would impose an assumption, not discover the truth.&lt;/p&gt;

&lt;p&gt;Even exact matches across all four columns do not solve it. Separate comments can share all four values. The correct action depends on your analysis goal and additional evidence, which is why this script never drops rows automatically.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add provenance before combining files
&lt;/h2&gt;

&lt;p&gt;Keep the original export unchanged. For each capture, maintain a small companion record with its source video URL, collection time including time zone, file fingerprint, and any status message or limitation noticed during collection.&lt;/p&gt;

&lt;p&gt;If you create a combined working table, carry that capture metadata onto each row. Use a local key such as &lt;code&gt;(file_fingerprint, record_number)&lt;/code&gt; to find the row again in your saved material. This locates a record in a file; it is not a platform comment ID.&lt;/p&gt;

&lt;p&gt;Do not fill a missing collection time with today's time and label it “captured at.” Record it as unknown, or distinguish the time you received the file from the time the original capture occurred. Neither value substitutes for the comment's posting time.&lt;/p&gt;

&lt;p&gt;For larger inputs, you could stream records and hash the input while reading. That is a separate engineering improvement; it does not remove the need to define provenance and identity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Add themes through an explicit review process
&lt;/h2&gt;

&lt;p&gt;For a small set, a human review column can be more useful than immediately adding an automatic sentiment model. Define labels against a concrete question, keep the original text, and include an “unclear” label.&lt;/p&gt;

&lt;p&gt;In the fictional fixture, possible themes include “available colours,” “care instructions,” and “needs context.” Decide whether multiple labels are allowed before counting them. If one row can have two labels, the sum of theme counts may exceed the number of rows; that is acceptable when reported clearly.&lt;/p&gt;

&lt;p&gt;Avoid a rule that labels every comment containing a question mark as a buying objection. A question can ask for instructions, make a joke, or refer to an absent parent comment. Missing context remains missing even when a classifier produces a confident answer.&lt;/p&gt;

&lt;p&gt;Report the unit you actually reviewed: for example, “five rows in this fixture.” Do not silently convert rows into distinct comments, handles into people, or the captured set into the entire audience.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep text as data throughout the workflow
&lt;/h2&gt;

&lt;p&gt;The Python script parses strings and prints only aggregate JSON; it never evaluates comment text. This does not certify the original CSV as safe for every downstream application.&lt;/p&gt;

&lt;p&gt;If you open unfamiliar comments in a spreadsheet, use an import path that preserves the text fields as literal text instead of allowing formula interpretation. CSV quotation protects field boundaries. It is not the same operation as preventing spreadsheet formulas. This exporter does not claim to sanitize formula-like values.&lt;/p&gt;

&lt;p&gt;Before trusting a new file, check that malformed numeric values fail, multiline comments remain single records, and candidate repeats remain in the original. The useful output is a summary whose boundaries are visible enough for the next person to assess.&lt;/p&gt;




&lt;p&gt;Written by the CommentTok editorial team. Product affiliation: the team publishes the exporter discussed here. This article and code were prepared with AI assistance. All sample rows and sample metrics are fictional; the code was run against the included fixture. This is a standalone technical tutorial.&lt;/p&gt;

</description>
      <category>python</category>
      <category>tutorial</category>
      <category>beginners</category>
      <category>dataengineering</category>
    </item>
    <item>
      <title>SRT to text: preserve spoken numbers, not just clean formatting</title>
      <dc:creator>carl kevin</dc:creator>
      <pubDate>Sat, 12 Sep 2026 11:07:45 +0000</pubDate>
      <link>https://dev.to/carl_kevin_99180e3b998739/srt-to-text-preserve-spoken-numbers-not-just-clean-formatting-3ocl</link>
      <guid>https://dev.to/carl_kevin_99180e3b998739/srt-to-text-preserve-spoken-numbers-not-just-clean-formatting-3ocl</guid>
      <description>&lt;p&gt;A subtitle-to-text export can look clean while silently deleting part of the speech. The risky shortcut is removing every numeric line: a line containing &lt;code&gt;42&lt;/code&gt; may be a spoken answer, not a cue identifier.&lt;/p&gt;

&lt;p&gt;Treat the file as structured cues before deciding what to remove.&lt;/p&gt;

&lt;h2&gt;
  
  
  What a safe conversion preserves
&lt;/h2&gt;

&lt;p&gt;This invented SRT example contains two cues:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1
00:00:01,000 --&amp;gt; 00:00:03,000
We reviewed 42 applications

2
00:00:03,000 --&amp;gt; 00:00:05,000
before the Friday meeting.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The reading copy becomes:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;We reviewed 42 applications before the Friday meeting.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The cue identifiers and timing ranges disappear. The spoken number stays. The sentence boundary comes from the speech, rather than from the blank line between cues.&lt;/p&gt;

&lt;p&gt;For a conversion pipeline, keep an untouched source file and make these checks explicit:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Recognize cue boundaries, sequence metadata, and timing lines before extracting text.&lt;/li&gt;
&lt;li&gt;Preserve numeric text inside a cue's payload.&lt;/li&gt;
&lt;li&gt;Keep speaker labels and meaningful sound descriptions.&lt;/li&gt;
&lt;li&gt;Join fragments only when they belong to the same sentence and speaker turn.&lt;/li&gt;
&lt;li&gt;Flag repeated passages for review rather than deleting them unconditionally.&lt;/li&gt;
&lt;li&gt;Compare the opening, ending, names, and numbers against the recording.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;An export from a caption editor is a useful starting point, but the result still needs inspection. A renamed &lt;code&gt;.txt&lt;/code&gt; file has not undergone a structural conversion.&lt;/p&gt;

&lt;h2&gt;
  
  
  WebVTT needs its own handling
&lt;/h2&gt;

&lt;p&gt;A file beginning with &lt;code&gt;WEBVTT&lt;/code&gt; is not simply SRT with different punctuation. MDN documents cue identifiers, timing settings, and &lt;code&gt;NOTE&lt;/code&gt;, &lt;code&gt;STYLE&lt;/code&gt;, and &lt;code&gt;REGION&lt;/code&gt; blocks. A timestamp-only replacement can leave those blocks in the transcript. Voice annotations may carry speaker information that should become a readable label.&lt;/p&gt;

&lt;p&gt;Use a format-aware parser or export tool, then inspect examples with speaker changes and formatting. See &lt;a href="https://developer.mozilla.org/en-US/docs/Web/API/WebVTT_API/Web_Video_Text_Tracks_Format" rel="noopener noreferrer"&gt;MDN's WebVTT format reference&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep a path back to the recording
&lt;/h2&gt;

&lt;p&gt;A reading copy can omit most timestamps. A reference copy can retain an occasional timestamp at a speaker turn or section boundary. Keep the original caption file either way: it makes an uncertain phrase much easier to locate.&lt;/p&gt;

&lt;p&gt;W3C WAI also explains that turning captions into a descriptive transcript may require adding visual information. If a presenter says “choose this setting,” check the picture and label the editorial description separately from the spoken words. See &lt;a href="https://www.w3.org/WAI/media/av/transcripts/" rel="noopener noreferrer"&gt;WAI's transcript guidance&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Disclosure: I work on Wordtake. The &lt;a href="https://wordtake.app/pages/blog/srt-to-text-readable-transcript?utm_source=devto&amp;amp;utm_medium=referral&amp;amp;utm_campaign=20260912_srt_to_text" rel="noopener noreferrer"&gt;full SRT-to-text workflow and review checklist&lt;/a&gt; covers source versions, reading copies, speaker changes, encoding checks, and publication. This is an editing workflow for existing subtitle files; it does not claim the product imports them.&lt;/p&gt;

</description>
      <category>coding</category>
      <category>softwaredevelopment</category>
      <category>tools</category>
    </item>
    <item>
      <title>How to Proofread an AI Transcript: A Three-Pass Checklist</title>
      <dc:creator>carl kevin</dc:creator>
      <pubDate>Wed, 09 Sep 2026 10:52:08 +0000</pubDate>
      <link>https://dev.to/carl_kevin_99180e3b998739/how-to-proofread-an-ai-transcript-a-three-pass-checklist-1f9i</link>
      <guid>https://dev.to/carl_kevin_99180e3b998739/how-to-proofread-an-ai-transcript-a-three-pass-checklist-1f9i</guid>
      <description>&lt;p&gt;An AI transcript can look clean while still being wrong in the places that matter. A missing &lt;strong&gt;not&lt;/strong&gt;, a swapped speaker, or a plausible spelling of the wrong company name may survive an ordinary read because the sentence remains grammatical.&lt;/p&gt;

&lt;p&gt;Use three separate passes instead of trying to fix everything at once.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pass one: structure, speakers, and meaning
&lt;/h2&gt;

&lt;p&gt;Read the complete transcript before polishing sentences. Look for missing sections, duplicated passages, abrupt topic jumps, and timestamp gaps. Confirm speaker changes wherever identity affects meaning.&lt;/p&gt;

&lt;p&gt;Replay sentences containing negation, comparison, permission, obligation, or uncertainty. Words such as &lt;em&gt;not&lt;/em&gt;, &lt;em&gt;only&lt;/em&gt;, &lt;em&gt;before&lt;/em&gt;, &lt;em&gt;after&lt;/em&gt;, &lt;em&gt;can&lt;/em&gt;, and &lt;em&gt;cannot&lt;/em&gt; can reverse a decision. Preserve later corrections instead of presenting both versions as equally current.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pass two: names, numbers, and technical terms
&lt;/h2&gt;

&lt;p&gt;Create a verification list for every person, company, product, place, publication, and event. Check participant lists, slides, official websites, or material supplied by the speaker. Watch for ordinary words that may actually be proper nouns.&lt;/p&gt;

&lt;p&gt;Search for every digit and number word. Replay each one and capture the unit, currency, percentage sign, or time period that gives it meaning. If figures do not add up, preserve the spoken wording and add an editorial query instead of inventing a correction.&lt;/p&gt;

&lt;p&gt;Collect uncertain technical terms and verify them using documentation, slides, code, product interfaces, or a subject-matter reviewer. Do not expand an acronym unless the recording or an authoritative source supports it in that context.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pass three: prepare for the destination
&lt;/h2&gt;

&lt;p&gt;Only after factual review should you improve punctuation, paragraph breaks, and obvious verbal clutter. Searchable meeting notes can be concise; a research transcript may need close fidelity; a published quotation must remain traceable to the recording.&lt;/p&gt;

&lt;p&gt;For captions, review timing and line breaks in the actual player. For articles and newsletters, retain source timestamps in working notes even if readers will not see them.&lt;/p&gt;

&lt;p&gt;Finish with the passages that carry the most consequence: headlines, quotations, decisions, tasks, prices, deadlines, claims, and calls to action. Record who reviewed the transcript, what was checked, and which timestamps remain uncertain.&lt;/p&gt;

&lt;p&gt;Read the complete checklist on Wordtake: &lt;a href="https://wordtake.app/pages/blog/proofread-ai-transcript-checklist" rel="noopener noreferrer"&gt;https://wordtake.app/pages/blog/proofread-ai-transcript-checklist&lt;/a&gt;&lt;/p&gt;

</description>
      <category>productivity</category>
      <category>tutorial</category>
      <category>ai</category>
      <category>writing</category>
    </item>
    <item>
      <title>How to Repurpose a Webinar into a Newsletter and Short Clips</title>
      <dc:creator>carl kevin</dc:creator>
      <pubDate>Mon, 07 Sep 2026 23:41:20 +0000</pubDate>
      <link>https://dev.to/carl_kevin_99180e3b998739/how-to-repurpose-a-webinar-into-a-newsletter-and-short-clips-1ed9</link>
      <guid>https://dev.to/carl_kevin_99180e3b998739/how-to-repurpose-a-webinar-into-a-newsletter-and-short-clips-1ed9</guid>
      <description>&lt;p&gt;A webinar can produce more than a replay link when its source material is easy to revisit. Keep the original recording, slides, chat export, speaker names, and a complete timestamped transcript together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Start with a complete, timestamped source
&lt;/h2&gt;

&lt;p&gt;Generate the transcript before choosing highlights. Review names, product terms, dates, prices, URLs, statistics, and specialist vocabulary against the recording.&lt;/p&gt;

&lt;h2&gt;
  
  
  Choose one audience and one outcome
&lt;/h2&gt;

&lt;p&gt;A newsletter can help attendees remember the main decision; a short clip can introduce one practical idea to people who missed the live session. Give each output a one sentence job before drafting.&lt;/p&gt;

&lt;h2&gt;
  
  
  Find moments that stand on their own
&lt;/h2&gt;

&lt;p&gt;Search for moments with a clear beginning, explanation, and conclusion. Read each candidate with the surrounding exchange and verify it against the recording.&lt;/p&gt;

&lt;h2&gt;
  
  
  Edit for context before speed
&lt;/h2&gt;

&lt;p&gt;Create captions from the reviewed transcript and watch the final clip with captions enabled. Check names, numbers, timing, speaker changes, and on screen text.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep an asset record
&lt;/h2&gt;

&lt;p&gt;Track asset type, audience, source timestamps, transcript status, owner, channel, approval status, and published URL. Linking every derivative to the recording makes corrections and future reuse faster.&lt;/p&gt;

&lt;p&gt;Read the complete workflow on Wordtake: &lt;a href="https://wordtake.app/pages/blog/repurpose-webinar-into-newsletter-and-clips" rel="noopener noreferrer"&gt;https://wordtake.app/pages/blog/repurpose-webinar-into-newsletter-and-clips&lt;/a&gt;&lt;/p&gt;

</description>
      <category>contentmarketing</category>
      <category>video</category>
      <category>transcription</category>
      <category>productivity</category>
    </item>
    <item>
      <title>SRT vs VTT: Choosing a Caption Format for Web and Editing Workflows</title>
      <dc:creator>carl kevin</dc:creator>
      <pubDate>Sat, 05 Sep 2026 07:02:18 +0000</pubDate>
      <link>https://dev.to/carl_kevin_99180e3b998739/srt-vs-vtt-choosing-a-caption-format-for-web-and-editing-workflows-8a8</link>
      <guid>https://dev.to/carl_kevin_99180e3b998739/srt-vs-vtt-choosing-a-caption-format-for-web-and-editing-workflows-8a8</guid>
      <description>&lt;p&gt;SRT and VTT both pair spoken words with time ranges, but they solve slightly different delivery problems. The right choice depends on where the file will be consumed.&lt;/p&gt;

&lt;h2&gt;
  
  
  The short answer
&lt;/h2&gt;

&lt;p&gt;Use &lt;strong&gt;SRT&lt;/strong&gt; for a portable subtitle handoff or a tool that expects numbered cues. Use &lt;strong&gt;VTT&lt;/strong&gt; for a browser-based player or a workflow that needs WebVTT text-track features. If one reviewed recording is going to several destinations, keep one source transcript and export both formats at the end.&lt;/p&gt;

&lt;h2&gt;
  
  
  SRT: a simple, portable cue list
&lt;/h2&gt;

&lt;p&gt;An SRT file normally contains a sequence number, a time range, and one or more lines of text:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;1
00:00:01,000 --&amp;gt; 00:00:03,500
Choose the format from the destination backwards.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The plain structure makes SRT easy to inspect in a text editor and easy for an editor, translator, or client to repair. It is a practical default when the receiving system only needs text and timing. Presentation details such as positioning are usually handled by the video editor or player rather than by the file itself.&lt;/p&gt;

&lt;h2&gt;
  
  
  VTT: timed text for the web
&lt;/h2&gt;

&lt;p&gt;A WebVTT file begins with a &lt;code&gt;WEBVTT&lt;/code&gt; header and uses timed cues:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;WEBVTT

00:00.000 --&amp;gt; 00:02.500
Choose the format from the destination backwards.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;VTT is designed for web text tracks and can carry optional cue identifiers, cue settings, regions, and limited text markup when the target player supports them. That makes it a natural fit for an HTML5 video or audio player. It also gives you more syntax to validate: the header, blank lines, time format, cue order, and optional settings all matter.&lt;/p&gt;

&lt;h2&gt;
  
  
  A practical decision guide
&lt;/h2&gt;

&lt;p&gt;Choose SRT when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;an editor or upload form explicitly requests SRT;&lt;/li&gt;
&lt;li&gt;people need to review or repair the file in plain text;&lt;/li&gt;
&lt;li&gt;the workflow needs a simple, numbered subtitle handoff.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Choose VTT when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;a browser player will load the file as a text track;&lt;/li&gt;
&lt;li&gt;you need web-oriented cue settings or regions;&lt;/li&gt;
&lt;li&gt;the integration is built around HTML5 video or audio.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Use both when the reviewed recording has multiple destinations. There is little value in forcing one delivery file to serve every system when both derivatives can come from the same source.&lt;/p&gt;

&lt;h2&gt;
  
  
  Validate before delivery
&lt;/h2&gt;

&lt;p&gt;Format conversion should happen after content review. Listen again to names, numbers, technical terms, negations, and any sentence that carries a claim. Then check timing at the beginning, middle, and end of the recording. Watch for cues that start too early, end too late, flash too quickly, or leave a gap while someone is speaking.&lt;/p&gt;

&lt;p&gt;For SRT, inspect cue numbering, time separators, blank lines, and readable line breaks. For VTT, inspect the &lt;code&gt;WEBVTT&lt;/code&gt; header, cue order, time syntax, and any settings supported by the destination player. Finally, test the actual file in the editor or browser player that your audience will use.&lt;/p&gt;

&lt;h2&gt;
  
  
  Keep one source of truth
&lt;/h2&gt;

&lt;p&gt;SRT and VTT are delivery choices, not separate versions of what happened. Keep one reviewed transcript beside the source recording, then generate the format required by each destination. When a correction is made, update the source and regenerate both derivatives so captions, quotes, notes, and translations do not drift apart.&lt;/p&gt;

&lt;p&gt;A longer workflow guide, including a pre-upload checklist, is available on Wordtake: &lt;a href="https://wordtake.app/pages/blog/srt-vs-vtt-caption-format" rel="noopener noreferrer"&gt;https://wordtake.app/pages/blog/srt-vs-vtt-caption-format&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>tutorial</category>
      <category>html</category>
      <category>seo</category>
    </item>
  </channel>
</rss>
