Author SHA1 Message Date
tangent fe7824d49a Trying to make Gemini prompt better. 2026-09-20 23:35:52 -06:00
tangent 17f553d543 Update ReadMe.md 2026-09-14 02:46:55 -06:00
tangent 66037e4a11 Update ReadMe.md 2026-09-03 13:26:05 -06:00
tangent acda9e188e Merge pull request 'Additional compression 2' (#4) from additional-compression-2 into main
Reviewed-on: #4
2026-09-03 13:20:45 -06:00
tangent d2ce10d416 mark additional compression done
This is a duplicate of the ReadMe portion of
addbb5e3d4
from 2026-08-31
2026-09-03 13:20:06 -06:00
tangent b991835d96 additional layer of compression quick and dirty redo
This is a duplicate of the code portion of
addbb5e3d4
from 2026-08-31
2026-09-03 13:19:40 -06:00
tangent c135a14a85 Update ReadMe.md 2026-09-03 13:13:59 -06:00
tangent 27c25f6b2a idk what I messed up here and did not commit 2026-08-30 22:14:16 -06:00
tangent 0d5a3de8f5 Update ReadMe.md 2026-08-28 02:35:09 -06:00
tangent e03d14191a updating Gemini prompt 2026-08-27 02:05:12 -06:00
tangent 875ff97a0d Update ReadMe.md 2026-08-24 00:01:39 -06:00
tangent 5c7fabf79c Merge pull request 'Resumable intermediates' (#2) from resumable-intermediates into main
Reviewed-on: #2
2026-08-23 23:59:38 -06:00
3 changed files with 73 additions and 23 deletions
+28 -22
View File
@@ -1,4 +1,6 @@
# llm-covers
Makes placeholder cover briefs for ebooks.
A simple tool for using local LLMs to generate cover briefs for ebooks.
## Requirements
@@ -14,10 +16,11 @@ A simple tool for using local LLMs to generate cover briefs for ebooks.
4. Run `make_cover_briefs.lua`
Cover briefs will be placed in `cover_briefs`. A prompt ready to paste directly
into Gemini will be in `for_gemini`. An extra border is prompted for to make
cropping easy to remove the Gemini watermark. (There are other small changes to
increase likelihood of Gemini following the prompt correctly and making a good
output.)
into Gemini will be in `for_gemini`.
The local model sometimes completely forgets critical details of characters, so
it's important you have some familiarity with the work before running the
generator to check accuracy.
### Config file format
```json
@@ -39,32 +42,35 @@ None of this works unless you **disable Gemini's personalization/memory**,
because it pollutes context extremely badly and will randomly add elements and
rejections from different conversations everywhere.
If Gemini rejects the prompt, adding
<code id="d2651e">Remove any elements that may go against guidelines before generating the image.</code>
<button onclick="navigator.clipboard.writeText(d2651e.textContent)">⧉</button>
to the opening paragraph can fix that issue.
- This suddenly got a lot less effective. I recommend instead telling it to
rewrite the prompt and then in a separate conversation, use that instead. I
also recommend one retry before modifying it.
If you are able to use Gemini Flash or Flash-Lite, it works far better than Pro.
Pro tends to invent additional details, refuse to respond, fail to respond, or
make modifications you didn't ask for. I genuinely cannot understand how it is
*so much worse* at this.
Gemini is really bad about adding hardcover seams. Despite being instructed not
to, it shows up sometimes. More strong prompting breaks other requested
to, it shows up often. More strong prompting breaks other requested
features, so the best way to deal with it is to request its removal after the
initial image is generated.
The local model sometimes completely forgets critical details of characters, so
it's important you have some familiarity with the work before running the
generator to check accuracy.
If Gemini rejects the prompt, adding
<code id="d2651e">Remove any elements that may go against guidelines before generating the image.</code>
<button onclick="navigator.clipboard.writeText(d2651e.textContent)">⧉</button>
to the opening paragraph can *sometimes* fix that issue.
- Telling it to rewrite the prompt and then using *that* in a separate
conversation tends to work better.
- I typically just re-send it repeatedly, as it's easier and eventually works
most of the time.
## Tasks
- [ ] Add timestamps to when a prompt is sent.
- [ ] Specify ETA when sending a prompt (2.5-8 minutes depending on length). (Show as end time as well as relative time.)
- [ ] Specify ETA when sending a prompt (use numbers from current estimator depending on length). (Show as end time as well as relative time.)
- [ ] option to delete input files or intermediate files at end of each major operation segment (or after its finisher..)
- [x] instead of placeholder directories, `mkdir -p` should be used to only make them when necessary
- [x] make script resumable instead of having to restart per book
- [x] dry run to estimate total time before running full script, print starting ETA
- [x] Build a list of files to work on and current states before doing anything by looping over source directories
- [x] Combine everything into one script to manage things
- [ ] Allow specifying a filter on what to process
- [ ] Allow changing the maximum bytes per prompt dynamically (run smaller while I'm doing other things, run full while I'm asleep)
- [x] specify config format
- [ ] `argparse` + ability to
- [ ] only convert ebooks or
- [ ] only generate cover briefs or
- [ ] only generate single pass cover briefs or
- [ ] list how many are left only
- [x] I have an item with over 300 parts in it. Another level of compression needs to be added!
- [ ] Change Gemini prompt because it is *obsessed* with putting colons EVERYWHERE.
+1 -1
View File
@@ -63,7 +63,7 @@ prompts.cover_brief = [[Generate a cover brief from the following:
prompts.for_gemini = [[
Generate an ebook cover inset within an empty white border 10% larger than the cover using the following cover brief. It should be a flat graphic design file, with no artifacts of a physical object. The aspect ratio of an ebook is tall, not wide. The white border is very important, and should take up 10% of the area of the image. The title and author should only appear once on the cover. It must be sutiable for printing. Do not include the word "by" when adding the author's name to the cover.
Generate an ebook cover using the following cover brief. It should be a flat graphic design file, with no artifacts of a physical object. The aspect ratio of an ebook is tall, not wide. The title and author should only appear once on the cover. It must be sutiable for printing. Do not include the word "by" on the cover. An underscore in the title should be replaced with a colon, but not hyphens or as a separator between the title and author. The author is separated from the title by the last hyphen on the line showing the title and author.
]]
+44
View File
@@ -173,6 +173,45 @@ local convert_ebooks = function(books)
end
end
-- TODO deal with the fact that this function is a clone with only a couple line changes
local compress_it_again = function(name, data, sections)
local condensed_sections = {}
while #sections > 2 do -- this intentionally can skip the end of a book?
local sections_slice = {}
for i = 1, 10 do
if #sections >= 1 then
sections_slice[#sections_slice + 1] = table.remove(sections, 1)
end
end
local intermediate_condensation_file = "intermediates/" .. name .. "-" .. (#condensed_sections + 1) .. "-super-condensed.txt"
if utility.path_exists(intermediate_condensation_file) then
condensed_sections[#condensed_sections + 1] = read_all(intermediate_condensation_file)
print("Loaded condensed summary segment. " .. #sections .. " sections remaining.")
else
print("Condensing summary. " .. #sections .. " sections remaining.")
local text = send_prompt(prompts.combine_summaries .. table.concat(sections_slice, "\n\n"))
condensed_sections[#condensed_sections + 1] = text
print(#text .. " characters added to final context.")
write_all(intermediate_condensation_file, text)
end
end
text = table.concat(condensed_sections, "\n\n")
local condensed_intermediate_file = "intermediates/" .. name .. " SUPER CONDENSED.txt"
write_all(condensed_intermediate_file, text)
data.condensed_intermediate_file = condensed_intermediate_file
-- if deleted any sooner, could break resuming
for i = 1, #condensed_sections do
local intermediate_condensation_file = "intermediates/" .. name .. "-" .. i .. "-super-condensed.txt"
os.execute("rm " .. intermediate_condensation_file:enquote())
end
return text
end
local condense_summary = function(name, data, sections)
local condensed_sections = {}
@@ -202,6 +241,10 @@ local condense_summary = function(name, data, sections)
write_all(condensed_intermediate_file, text)
data.condensed_intermediate_file = condensed_intermediate_file
if #condensed_sections > 15 then
text = compress_it_again(name, data, condensed_sections)
end
-- if deleted any sooner, could break resuming
for i = 1, #condensed_sections do
local intermediate_condensation_file = "intermediates/" .. name .. "-" .. i .. "-condensed.txt"
@@ -279,6 +322,7 @@ local estimate_time_required = function(books)
for name, data in pairs(books) do
local function loop()
if data.cover_brief_file then return end
if not data.extracted_file then return end
sum = sum + 60 * (1.5 + data.extracted_file_size/(config.llm_covers.maximum_bytes/6))
count = count + 1
end