Move JSON to cache, add site generation, reorganize rake files
Intermediate transcription files now live in cache/<transcriber>/
instead of alongside the rendered text. Rake files moved to
lib/tasks/. Site task generates a static HTML transcript viewer.

Assisted-by: Claude Opus 4.6 via pi
change zxmsoynwnktxptvnpzzvurooszkvytyr
commit 28da7fb17e2fffb7aff72bcf8c82cccede3cc033
author Alpha Chen <alpha@kejadlen.dev>
date
parent quutyoso
diff --git a/.gitignore b/.gitignore
index f56f3a3..b319076 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 /cache/
 /sous_chef/.build/
+/site
diff --git a/Rakefile b/Rakefile
index fca577e..a4c4675 100644
--- a/Rakefile
+++ b/Rakefile
@@ -24,9 +24,9 @@ file HRN_FEED.to_s => CACHE_DIR.to_s do
   HRN_FEED.write(response.body)
 end
 
-load File.expand_path("transcribers.rake", __dir__)
+load File.expand_path("lib/tasks/transcribers.rake", __dir__)
 
-TRANSCRIBER = Transcribers.resolve(ENV.fetch("TRANSCRIBER", "whisper-cpp-large"))
+TRANSCRIBER = Transcribers.resolve(ENV.fetch("TRANSCRIBER", "sous_chef"))
 TRANSCRIBER.register
 
 Rake::Task[HRN_FEED.to_s].invoke
@@ -37,18 +37,23 @@ def audio_path(ep)
   (AUDIO_DIR / "#{ep.slug}.mp3").to_s
 end
 
+TRANSCRIBER_CACHE_DIR = CACHE_DIR / TRANSCRIBER.name
+
+directory TRANSCRIBER_CACHE_DIR.to_s
+
 def transcript_path(ep)
-  (TRANSCRIPTS_DIR / TRANSCRIBER.name / "#{ep.slug}.json").to_s
+  (TRANSCRIBER_CACHE_DIR / "#{ep.slug}.json").to_s
 end
 
 def text_path(ep)
   (TRANSCRIPTS_DIR / TRANSCRIBER.name / "#{ep.slug}.txt").to_s
 end
 
-EPISODES.values.each do |ep|
-  transcript_dir = (TRANSCRIPTS_DIR / TRANSCRIBER.name).to_s
-  directory transcript_dir
+TEXT_DIR = TRANSCRIPTS_DIR / TRANSCRIBER.name
 
+directory TEXT_DIR.to_s
+
+EPISODES.values.each do |ep|
   audio = audio_path(ep)
   transcript = transcript_path(ep)
 
@@ -57,13 +62,13 @@ EPISODES.values.each do |ep|
     CookingIssues::Download.fetch(ep.audio_url, audio)
   end
 
-  file transcript => [audio, transcript_dir, *TRANSCRIBER.prereqs] do
+  file transcript => [audio, TRANSCRIBER_CACHE_DIR.to_s, *TRANSCRIBER.prereqs] do
     TRANSCRIBER.call(audio, transcript)
   end
 
   txt = text_path(ep)
 
-  file txt => transcript do
+  file txt => [transcript, TEXT_DIR.to_s] do
     TRANSCRIBER.render(transcript, txt)
   end
 end
@@ -96,6 +101,21 @@ task :transcribe, [:number] do |_t, args|
   Rake::Task[text_path(ep)].invoke
 end
 
+desc "Move intermediate files from transcripts/ to cache/"
+task :migrate_cache do
+  EPISODES.values.each do |ep|
+    old_path = TRANSCRIPTS_DIR / TRANSCRIBER.name / "#{ep.slug}.json"
+    new_path = Pathname(transcript_path(ep))
+    next unless old_path.exist?
+
+    new_path.dirname.mkpath
+    FileUtils.mv(old_path.to_s, new_path.to_s)
+    puts "Moved #{old_path} → #{new_path}"
+  end
+end
+
+load File.expand_path("lib/tasks/site.rake", __dir__)
+
 desc "Re-transcribe an episode (e.g., rake retranscribe[42])"
 task :retranscribe, [:number] do |_t, args|
   abort "Usage: rake retranscribe[NUMBER]" unless args[:number]
diff --git a/lib/site.html.erb b/lib/site.html.erb
new file mode 100644
index 0000000..3e336ac
--- /dev/null
+++ b/lib/site.html.erb
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="utf-8">
+<meta name="viewport" content="width=device-width, initial-scale=1">
+<title>Cooking Issues Transcripts</title>
+<style>
+  * { box-sizing: border-box; margin: 0; padding: 0; }
+  body { font-family: system-ui, sans-serif; line-height: 1.6; color: #222; max-width: 50rem; margin: 0 auto; padding: 1rem; }
+  h1 { margin-bottom: 1rem; }
+  .episode { margin: 1.5rem 0; }
+  .episode-header { cursor: pointer; padding: 0.5rem 0; border-bottom: 1px solid #eee; }
+  .episode-header h2 { font-size: 1.1rem; }
+  .episode-header:hover h2 { color: #0066cc; }
+  .episode-body { display: none; padding: 1rem 0; }
+  .episode-body.open { display: block; }
+  .episode-body p { margin-bottom: 1em; }
+  .timestamp { color: #888; font-size: 0.85rem; font-family: monospace; }
+</style>
+</head>
+<body>
+
+<h1>Cooking Issues Transcripts</h1>
+
+<div id="episodes">
+<% transcripts.each do |ep| %>
+  <div class="episode">
+    <div class="episode-header" onclick="toggle(this)">
+      <h2><%= CGI.escapeHTML("#{ep[:number]}. #{ep[:title]}") %></h2>
+    </div>
+    <div class="episode-body">
+      <% ep[:text].split("\n\n").each do |para| %>
+        <% if para =~ /\A\[([^\]]+)\]\s*(.*)/ %>
+          <p><span class="timestamp">[<%= CGI.escapeHTML($1) %>]</span> <%= CGI.escapeHTML($2) %></p>
+        <% else %>
+          <p><%= CGI.escapeHTML(para) %></p>
+        <% end %>
+      <% end %>
+    </div>
+  </div>
+<% end %>
+</div>
+
+<script>
+function toggle(header) {
+  header.nextElementSibling.classList.toggle('open');
+}
+</script>
+
+</body>
+</html>
diff --git a/lib/tasks/site.rake b/lib/tasks/site.rake
new file mode 100644
index 0000000..1a8492f
--- /dev/null
+++ b/lib/tasks/site.rake
@@ -0,0 +1,25 @@
+require "cgi"
+require "erb"
+
+SITE_DIR = Pathname("site")
+
+desc "Generate an HTML page of transcripts"
+task :site do
+  episodes = EPISODES.values.sort_by(&:number).select { |ep| Pathname(text_path(ep)).exist? }
+
+  transcripts = episodes.map do |ep|
+    {
+      number: ep.number,
+      title: ep.title,
+      slug: ep.slug,
+      text: File.read(text_path(ep))
+    }
+  end
+
+  template = File.read(File.expand_path("lib/site.html.erb", __dir__))
+  html = ERB.new(template).result(binding)
+
+  SITE_DIR.mkpath
+  (SITE_DIR / "index.html").write(html)
+  puts "Generated site/index.html with #{transcripts.length} episodes."
+end
diff --git a/transcribers.rake b/lib/tasks/transcribers.rake
similarity index 100%
rename from transcribers.rake
rename to lib/tasks/transcribers.rake