返回 oh-my-ppt
generation-image-intent-rules.ts
根目录 / src / main / agent-runtime / prompt / composers / generation-image-intent-rules.ts
1 import type { LayoutMasterTemplate } from '@shared/layout-master'
2 import type { DesignContract } from '@shared/generation'
3 import type { SlideSizePreset } from '@shared/slide-size'
4 import {
5 buildCanvasScenarioContentRules,
6 buildCanvasScenarioDeliveryGuard
7 } from './canvas-scenario'
8 import { formatDesignContract } from './shared'
9
10 export const buildGenerationImageIntentRules = (args: {
11 visualEnabled: boolean
12 template: LayoutMasterTemplate
13 hasStyleImageDirection?: boolean
14 }): string => {
15 if (!args.visualEnabled) {
16 return [
17 'Automatic image generation is disabled for this session.',
18 'Do not emit data-img-request or any other data-img-* attribute.'
19 ].join('\n')
20 }
21
22 if (!args.hasStyleImageDirection) {
23 return [
24 'Automatic image generation is enabled, but the active style does not declare image-generation direction.',
25 'Do not emit image requests for this page. Continue using the style skill for CSS, SVG, and other page-native visual treatment.'
26 ].join('\n')
27 }
28
29 const imageSlots = args.template.slots.filter((slot) => slot.role === 'visual' && slot.image)
30 if (imageSlots.length === 0) {
31 return [
32 'Automatic image generation is enabled, but this layout has no image-capable visual slot.',
33 'Do not emit image requests for this page.'
34 ].join('\n')
35 }
36
37 return [
38 'Automatic image generation is enabled for this session and the active style supports it.',
39 'Before writing HTML, decide independently whether this page needs one image: request it when the active style skill\'s 配图 strategy matches the page and an identifiable subject, scene, evidence, or atmosphere improves the message. The strategy is a positive signal, not a quota.',
40 'Do not request an image merely because the style or layout allows it. For pages led by data, relationships, steps, comparison, timelines, frameworks, or precise conclusions, use page-native CSS, SVG, charts, and diagrams instead.',
41 'For one selected image-capable visual slot, add the empty data-img-request attribute to the same rendered element that has data-ppt-slot. Add data-img-placement="background" only when the image must become that slot\'s background; otherwise omit it for a normal visual image. Do not add JSON, scripts, request IDs, image prompts, data-img-slot, data-img-placeholder, or data-img-finalization.',
42 'Example: <div data-ppt-slot="metric-visual" data-img-request class="aspect-square ...">...</div>. The system has a dedicated image director that creates the image prompt and derives all technical fields from this layout slot.',
43 'Use only one image request per page. Do not reference a generated image path during this first pass. After generation, the system places the local asset directly into this slot without rewriting the rest of the page.',
44 'Allowed image slots:',
45 ...imageSlots.map(
46 (slot) =>
47 `- ${slot.id}: ${slot.image!.role}, ${slot.image!.policy}, ${slot.image!.aspectHint || 'no aspect hint'}`
48 ),
49 'The dedicated image director receives the active style image direction separately. Do not write or infer an image prompt in this pass.'
50 ].join('\n')
51 }
52
53 export const buildGenerationImageLayoutRefinementPrompt = (args: {
54 pageId: string
55 referenceRangeBound?: boolean
56 slideSize?: SlideSizePreset
57 designContract?: DesignContract
58 layoutPrompt?: string
59 assets: Array<{
60 slotId: string
61 layoutSlotId: string
62 relativePath: string
63 role: string
64 prompt?: string
65 }>
66 }): string =>
67 [
68 'Refine this complete slide after automatic image placement.',
69 `First read the current ${args.pageId}.html. It already contains the generated local image in its intended layout slot.`,
70 `Use edit_file on /${args.pageId}.html for minimal, targeted replacements only. Do not use write_file, update_single_page_file, or update_page_file.`,
71 'Review the whole composition at the slide viewport: correct overflow, preserve actual nonzero gaps between independent modules, improve type hierarchy, rebalance the image area against the text, and ensure the visual is cropped and contained deliberately.',
72 'Preserve the slide meaning, all required data-ppt-slot attributes, data-block-id attributes, and every listed generated asset path. Do not create new image requests, remove a generated asset, use staging or remote paths, or modify another page.',
73 'You may adjust layout, CSS classes, sizing, flex/grid distribution, image object-fit/object-position, text-safe overlays, and local decoration when needed for a balanced final slide.',
74 args.layoutPrompt
75 ? `Keep the page's selected layout family as a creative direction, not a fixed grid:\n${args.layoutPrompt}`
76 : '',
77 args.designContract
78 ? `Keep the active deck design contract coherent:\n${formatDesignContract(args.designContract)}`
79 : '',
80 args.slideSize
81 ? [
82 'Keep the image refinement consistent with this canvas scenario:',
83 buildCanvasScenarioContentRules(args.slideSize, {
84 referenceTextLocked: Boolean(args.referenceRangeBound)
85 }),
86 buildCanvasScenarioDeliveryGuard(args.slideSize, {
87 referenceTextLocked: Boolean(args.referenceRangeBound)
88 })
89 ].join('\n')
90 : '',
91 args.referenceRangeBound
92 ? 'Reference Range Content Boundary applies: preserve source facts, qualifiers, relationships, uncertainty, and business conclusions. You may adjust layout, styling, and visual hierarchy; do not introduce outside facts or change the source meaning. For density, first clarify hierarchy, group related material, and use compact layout; scale only bounded internal modules as a final measure; never scale the page root, section/page shell, `main[data-role="content"]`, or canvas.'
93 : '',
94 'Generated assets:',
95 ...args.assets.map(
96 (asset) =>
97 `- ${asset.relativePath}: slot ${asset.slotId}, layout slot ${asset.layoutSlotId}, role ${asset.role}${asset.prompt ? `, image description: ${asset.prompt}` : ''}`
98 )
99 ].join('\n')
100
100 lines TYPESCRIPT