Upload run_story.ps1 with huggingface_hub
Browse files- run_story.ps1 +159 -0
run_story.ps1
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# run_story.ps1 - Multi-page story runner
|
| 2 |
+
# Generates consistent pages using same base_prompt/seed across all pages
|
| 3 |
+
param(
|
| 4 |
+
[Parameter(Mandatory=$true)]
|
| 5 |
+
[string]$StoryFile
|
| 6 |
+
)
|
| 7 |
+
|
| 8 |
+
$storyPath = Join-Path ".\stories" $StoryFile
|
| 9 |
+
if (-not (Test-Path $storyPath)) {
|
| 10 |
+
Write-Host "Story not found: $storyPath" -ForegroundColor Red
|
| 11 |
+
return
|
| 12 |
+
}
|
| 13 |
+
|
| 14 |
+
$story = Get-Content $storyPath -Raw | ConvertFrom-Json
|
| 15 |
+
$storyStart = Get-Date
|
| 16 |
+
|
| 17 |
+
Write-Host "========================================" -ForegroundColor Cyan
|
| 18 |
+
Write-Host " STORY: $($story.story_title)" -ForegroundColor Cyan
|
| 19 |
+
Write-Host " Pages: $($story.pages.Count)" -ForegroundColor Cyan
|
| 20 |
+
Write-Host "========================================" -ForegroundColor Cyan
|
| 21 |
+
|
| 22 |
+
$storyOutput = ".\output\stories\$($story.story_id)"
|
| 23 |
+
New-Item -Path $storyOutput -ItemType Directory -Force | Out-Null
|
| 24 |
+
|
| 25 |
+
$pageNum = 0
|
| 26 |
+
foreach ($page in $story.pages) {
|
| 27 |
+
$pageNum++
|
| 28 |
+
Write-Host "
|
| 29 |
+
========================================" -ForegroundColor Yellow
|
| 30 |
+
Write-Host " PAGE $pageNum/$($story.pages.Count): $($page.page_title)" -ForegroundColor Yellow
|
| 31 |
+
Write-Host " Template: $($page.page_template) | Panels: $($page.panels.Count)" -ForegroundColor Yellow
|
| 32 |
+
Write-Host "========================================" -ForegroundColor Yellow
|
| 33 |
+
|
| 34 |
+
# Build temp scene JSON for this page
|
| 35 |
+
$pageScene = @{
|
| 36 |
+
scene_id = "$($story.story_id)_p$pageNum"
|
| 37 |
+
page_template = $page.page_template
|
| 38 |
+
panels = @()
|
| 39 |
+
global_settings = $story.global_settings
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
foreach ($panel in $page.panels) {
|
| 43 |
+
$pageScene.panels += @{
|
| 44 |
+
panel_id = $panel.panel_id
|
| 45 |
+
base_prompt = $story.base_prompt
|
| 46 |
+
seed = $story.base_seed
|
| 47 |
+
edit_prompt = $panel.edit_prompt
|
| 48 |
+
}
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
$tempFile = "_story_p$pageNum.json"
|
| 52 |
+
$pageScene | ConvertTo-Json -Depth 5 | Set-Content ".\scenes\$tempFile"
|
| 53 |
+
|
| 54 |
+
# Run full pipeline for this page
|
| 55 |
+
.\run_comic_pipeline.ps1 -SceneFile $tempFile
|
| 56 |
+
|
| 57 |
+
# Copy output to story folder
|
| 58 |
+
$pageFile = Get-ChildItem ".\output\stage3_pages" -Filter "page_$($story.story_id)_p$pageNum*" |
|
| 59 |
+
Sort-Object LastWriteTime -Descending | Select-Object -First 1
|
| 60 |
+
|
| 61 |
+
if ($pageFile) {
|
| 62 |
+
$destName = "page_$($pageNum.ToString('D2'))_$($page.page_title -replace ' ','_').png"
|
| 63 |
+
Copy-Item $pageFile.FullName -Destination (Join-Path $storyOutput $destName) -Force
|
| 64 |
+
Write-Host " Saved: $destName" -ForegroundColor Green
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
[System.Console]::Beep(800, 200)
|
| 68 |
+
}
|
| 69 |
+
|
| 70 |
+
# Add titles to all pages
|
| 71 |
+
Write-Host "
|
| 72 |
+
Adding titles..." -ForegroundColor Yellow
|
| 73 |
+
$pageFiles = Get-ChildItem $storyOutput -Filter "page_*.png" | Sort-Object Name
|
| 74 |
+
|
| 75 |
+
foreach ($pf in $pageFiles) {
|
| 76 |
+
$titleMatch = $pf.Name -match 'page_\d+_(.*?)\.png'
|
| 77 |
+
if ($titleMatch) {
|
| 78 |
+
$title = ($Matches[1] -replace '_',' ').ToUpper()
|
| 79 |
+
} else {
|
| 80 |
+
$title = "PAGE"
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
python -c "
|
| 84 |
+
from PIL import Image, ImageDraw, ImageFont
|
| 85 |
+
import math
|
| 86 |
+
img = Image.open(r'$($pf.FullName)')
|
| 87 |
+
pw, ph = img.size
|
| 88 |
+
bar_h = 140
|
| 89 |
+
new = Image.new('RGB', (pw, ph+bar_h), (10,8,20))
|
| 90 |
+
new.paste(img, (0, bar_h))
|
| 91 |
+
draw = ImageDraw.Draw(new)
|
| 92 |
+
font = ImageFont.truetype('C:/Windows/Fonts/impact.ttf', 90)
|
| 93 |
+
title = '$title'
|
| 94 |
+
bbox = draw.textbbox((0,0), title, font=font)
|
| 95 |
+
tw, th = bbox[2]-bbox[0], bbox[3]-bbox[1]
|
| 96 |
+
cx, cy = pw//2, bar_h//2
|
| 97 |
+
sweep, steps = 0.95, 100
|
| 98 |
+
r_top, r_bot = 220, 120
|
| 99 |
+
tp, bp = [], []
|
| 100 |
+
for i in range(steps+1):
|
| 101 |
+
t=i/steps; a=math.pi+(1-sweep)/2*math.pi+t*sweep*math.pi
|
| 102 |
+
tp.append((cx+int(pw*0.55*math.cos(a)), cy-15+r_top*math.sin(a)))
|
| 103 |
+
bp.append((cx+int(pw*0.55*math.cos(a)), cy+15+r_bot*math.sin(a)))
|
| 104 |
+
bp.reverse()
|
| 105 |
+
draw.polygon(tp+bp, fill=(100,10,10), outline=(0,0,0))
|
| 106 |
+
itp, ibp = [], []
|
| 107 |
+
for i in range(steps+1):
|
| 108 |
+
t=i/steps; a=math.pi+(1-sweep)/2*math.pi+t*sweep*math.pi
|
| 109 |
+
itp.append((cx+int(pw*0.53*math.cos(a)), cy-15+(r_top-10)*math.sin(a)))
|
| 110 |
+
ibp.append((cx+int(pw*0.53*math.cos(a)), cy+15+(r_bot+10)*math.sin(a)))
|
| 111 |
+
ibp.reverse()
|
| 112 |
+
draw.polygon(itp+ibp, fill=(190,20,20))
|
| 113 |
+
chars=list(title); cws=[]
|
| 114 |
+
for c in chars: b=draw.textbbox((0,0),c,font=font); cws.append(b[2]-b[0])
|
| 115 |
+
sp=8; ts=sum(cws)+sp*(len(chars)-1); cur=cx-ts//2
|
| 116 |
+
for i,c in enumerate(chars):
|
| 117 |
+
cw=cws[i]; ccx=cur+cw//2
|
| 118 |
+
t2=(ccx-cx)/(ts/2+1); yo=int(25*t2*t2); ad=-t2*9
|
| 119 |
+
tmp=Image.new('RGBA',(cw+30,th+30),(0,0,0,0)); td=ImageDraw.Draw(tmp)
|
| 120 |
+
for dx in [-4,-3,-2,0,2,3,4]:
|
| 121 |
+
for dy in [-4,-3,-2,0,2,3,4]:
|
| 122 |
+
if dx or dy: td.text((15+dx,15+dy),c,fill=(0,0,0,255),font=font)
|
| 123 |
+
td.text((15,15),c,fill=(255,215,0,255),font=font)
|
| 124 |
+
tmp=tmp.rotate(ad,expand=True,resample=Image.BICUBIC)
|
| 125 |
+
new.paste(tmp,(int(ccx-tmp.width//2),int(cy-th//2-10+yo)),tmp)
|
| 126 |
+
cur+=cw+sp
|
| 127 |
+
new.save(r'$($pf.FullName)')
|
| 128 |
+
print('Titled: $($pf.Name)')
|
| 129 |
+
"
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
# Build PDF
|
| 133 |
+
Write-Host "
|
| 134 |
+
Building PDF..." -ForegroundColor Yellow
|
| 135 |
+
$sortedPages = (Get-ChildItem $storyOutput -Filter "page_*.png" | Sort-Object Name | ForEach-Object { $_.FullName -replace '\\','/' })
|
| 136 |
+
$pyList = ($sortedPages | ForEach-Object { "'$_'" }) -join ","
|
| 137 |
+
|
| 138 |
+
python -c "
|
| 139 |
+
from PIL import Image
|
| 140 |
+
pages = [$pyList]
|
| 141 |
+
imgs = [Image.open(p).convert('RGB') for p in pages]
|
| 142 |
+
out = '$($storyOutput -replace '\\','/')/$($story.story_id)_complete.pdf'
|
| 143 |
+
imgs[0].save(out, save_all=True, append_images=imgs[1:], resolution=150)
|
| 144 |
+
print('PDF: ' + out + ' (' + str(len(imgs)) + ' pages)')
|
| 145 |
+
"
|
| 146 |
+
|
| 147 |
+
# Cleanup
|
| 148 |
+
Remove-Item ".\scenes\_story_*.json" -Force -ErrorAction SilentlyContinue
|
| 149 |
+
|
| 150 |
+
$totalMin = [math]::Round(((Get-Date)-$storyStart).TotalMinutes, 1)
|
| 151 |
+
Write-Host "
|
| 152 |
+
========================================" -ForegroundColor Green
|
| 153 |
+
Write-Host " STORY COMPLETE: $($story.story_title)" -ForegroundColor Green
|
| 154 |
+
Write-Host " Pages: $($story.pages.Count)" -ForegroundColor Green
|
| 155 |
+
Write-Host " Time: $totalMin min" -ForegroundColor Green
|
| 156 |
+
Write-Host " Output: $storyOutput" -ForegroundColor Green
|
| 157 |
+
Write-Host "========================================" -ForegroundColor Green
|
| 158 |
+
|
| 159 |
+
1000, 1200, 1500, 2000 | ForEach-Object { [System.Console]::Beep($_, 250) }
|