@farazirfan/costar-server-executor 1.7.37 → 1.7.39
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/agent.d.ts +90 -0
- package/dist/agent/agent.d.ts.map +1 -1
- package/dist/agent/agent.js +606 -0
- package/dist/agent/agent.js.map +1 -1
- package/dist/agent/pi-embedded-runner/run.d.ts.map +1 -1
- package/dist/agent/pi-embedded-runner/run.js +2 -1
- package/dist/agent/pi-embedded-runner/run.js.map +1 -1
- package/dist/agent/pi-embedded-runner/system-prompt.d.ts.map +1 -1
- package/dist/agent/pi-embedded-runner/system-prompt.js +16 -37
- package/dist/agent/pi-embedded-runner/system-prompt.js.map +1 -1
- package/dist/agent/pi-embedded-runner/tools.d.ts +4 -1
- package/dist/agent/pi-embedded-runner/tools.d.ts.map +1 -1
- package/dist/agent/pi-embedded-runner/tools.js +3 -1
- package/dist/agent/pi-embedded-runner/tools.js.map +1 -1
- package/dist/agent/pi-embedded-runner/types.d.ts +4 -0
- package/dist/agent/pi-embedded-runner/types.d.ts.map +1 -1
- package/dist/cli/env-loader.d.ts.map +1 -1
- package/dist/cli/env-loader.js +1 -0
- package/dist/cli/env-loader.js.map +1 -1
- package/dist/cli/setup.js +2 -2
- package/dist/cli/setup.js.map +1 -1
- package/dist/cron/normalize.d.ts +31 -0
- package/dist/cron/normalize.d.ts.map +1 -0
- package/dist/cron/normalize.js +211 -0
- package/dist/cron/normalize.js.map +1 -0
- package/dist/cron/scheduler.d.ts +33 -3
- package/dist/cron/scheduler.d.ts.map +1 -1
- package/dist/cron/scheduler.js +253 -48
- package/dist/cron/scheduler.js.map +1 -1
- package/dist/heartbeat/runner.d.ts +27 -12
- package/dist/heartbeat/runner.d.ts.map +1 -1
- package/dist/heartbeat/runner.js +82 -104
- package/dist/heartbeat/runner.js.map +1 -1
- package/dist/infra/heartbeat-events-filter.d.ts +29 -0
- package/dist/infra/heartbeat-events-filter.d.ts.map +1 -0
- package/dist/infra/heartbeat-events-filter.js +80 -0
- package/dist/infra/heartbeat-events-filter.js.map +1 -0
- package/dist/infra/index.d.ts +9 -0
- package/dist/infra/index.d.ts.map +1 -0
- package/dist/infra/index.js +9 -0
- package/dist/infra/index.js.map +1 -0
- package/dist/infra/system-events.d.ts +58 -2
- package/dist/infra/system-events.d.ts.map +1 -1
- package/dist/infra/system-events.js +80 -14
- package/dist/infra/system-events.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +6 -1
- package/dist/server.js.map +1 -1
- package/dist/services/platform-keys.d.ts +19 -0
- package/dist/services/platform-keys.d.ts.map +1 -0
- package/dist/services/platform-keys.js +74 -0
- package/dist/services/platform-keys.js.map +1 -0
- package/dist/subagent/registry.d.ts +96 -0
- package/dist/subagent/registry.d.ts.map +1 -0
- package/dist/subagent/registry.js +180 -0
- package/dist/subagent/registry.js.map +1 -0
- package/dist/tools/complete-turn.d.ts +2 -2
- package/dist/tools/complete-turn.js +10 -10
- package/dist/tools/complete-turn.js.map +1 -1
- package/dist/tools/contacts.d.ts +13 -0
- package/dist/tools/contacts.d.ts.map +1 -0
- package/dist/tools/contacts.js +80 -0
- package/dist/tools/contacts.js.map +1 -0
- package/dist/tools/cron.d.ts +17 -2
- package/dist/tools/cron.d.ts.map +1 -1
- package/dist/tools/cron.js +117 -35
- package/dist/tools/cron.js.map +1 -1
- package/dist/tools/google-maps.d.ts +6 -6
- package/dist/tools/google-maps.d.ts.map +1 -1
- package/dist/tools/google-maps.js +207 -262
- package/dist/tools/google-maps.js.map +1 -1
- package/dist/tools/index.d.ts +17 -7
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +40 -9
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/phone-call.d.ts +11 -0
- package/dist/tools/phone-call.d.ts.map +1 -0
- package/dist/tools/phone-call.js +151 -0
- package/dist/tools/phone-call.js.map +1 -0
- package/dist/tools/sessions-spawn.d.ts +33 -0
- package/dist/tools/sessions-spawn.d.ts.map +1 -0
- package/dist/tools/sessions-spawn.js +164 -0
- package/dist/tools/sessions-spawn.js.map +1 -0
- package/dist/tools/spotify.d.ts +12 -0
- package/dist/tools/spotify.d.ts.map +1 -0
- package/dist/tools/spotify.js +251 -0
- package/dist/tools/spotify.js.map +1 -0
- package/dist/tools/subagents.d.ts +23 -0
- package/dist/tools/subagents.d.ts.map +1 -0
- package/dist/tools/subagents.js +209 -0
- package/dist/tools/subagents.js.map +1 -0
- package/dist/tools/whatsapp.d.ts +13 -0
- package/dist/tools/whatsapp.d.ts.map +1 -0
- package/dist/tools/whatsapp.js +215 -0
- package/dist/tools/whatsapp.js.map +1 -0
- package/dist/tools/youtube.d.ts +12 -0
- package/dist/tools/youtube.d.ts.map +1 -0
- package/dist/tools/youtube.js +218 -0
- package/dist/tools/youtube.js.map +1 -0
- package/dist/utils/asterizk-auth.d.ts +43 -0
- package/dist/utils/asterizk-auth.d.ts.map +1 -0
- package/dist/utils/asterizk-auth.js +125 -0
- package/dist/utils/asterizk-auth.js.map +1 -0
- package/dist/web-server.d.ts.map +1 -1
- package/dist/web-server.js +132 -0
- package/dist/web-server.js.map +1 -1
- package/dist/workspace/index.d.ts +3 -4
- package/dist/workspace/index.d.ts.map +1 -1
- package/dist/workspace/index.js +3 -4
- package/dist/workspace/index.js.map +1 -1
- package/dist/workspace/templates.d.ts +8 -7
- package/dist/workspace/templates.d.ts.map +1 -1
- package/dist/workspace/templates.js +18 -127
- package/dist/workspace/templates.js.map +1 -1
- package/dist/workspace/workspace.d.ts +2 -4
- package/dist/workspace/workspace.d.ts.map +1 -1
- package/dist/workspace/workspace.js +7 -16
- package/dist/workspace/workspace.js.map +1 -1
- package/package.json +1 -1
- package/public/index.html +231 -0
- package/skills/docx/SKILL.md +468 -0
- package/skills/docx/scripts/__init__.py +1 -0
- package/skills/docx/scripts/accept_changes.py +181 -0
- package/skills/docx/scripts/comment.py +347 -0
- package/skills/docx/scripts/helpers/__init__.py +0 -0
- package/skills/docx/scripts/helpers/merge_runs.py +231 -0
- package/skills/docx/scripts/helpers/simplify_redlines.py +240 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/skills/docx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/skills/docx/scripts/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/skills/docx/scripts/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/skills/docx/scripts/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/skills/docx/scripts/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/skills/docx/scripts/ooxml/schemas/mce/mc.xsd +75 -0
- package/skills/docx/scripts/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
- package/skills/docx/scripts/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
- package/skills/docx/scripts/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
- package/skills/docx/scripts/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/skills/docx/scripts/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/skills/docx/scripts/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/skills/docx/scripts/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/skills/docx/scripts/ooxml/scripts/pack.py +159 -0
- package/skills/docx/scripts/ooxml/scripts/unpack.py +29 -0
- package/skills/docx/scripts/ooxml/scripts/validate.py +106 -0
- package/skills/docx/scripts/ooxml/scripts/validation/__init__.py +15 -0
- package/skills/docx/scripts/ooxml/scripts/validation/base.py +1023 -0
- package/skills/docx/scripts/ooxml/scripts/validation/docx.py +519 -0
- package/skills/docx/scripts/ooxml/scripts/validation/pptx.py +315 -0
- package/skills/docx/scripts/ooxml/scripts/validation/redlining.py +284 -0
- package/skills/docx/scripts/pack.py +166 -0
- package/skills/docx/scripts/templates/comments.xml +3 -0
- package/skills/docx/scripts/templates/commentsExtended.xml +3 -0
- package/skills/docx/scripts/templates/commentsExtensible.xml +3 -0
- package/skills/docx/scripts/templates/commentsIds.xml +3 -0
- package/skills/docx/scripts/templates/people.xml +3 -0
- package/skills/docx/scripts/unpack.py +134 -0
- package/skills/longform-video-generation/SKILL.md +298 -0
- package/skills/longform-video-generation/references/advanced_techniques.md +474 -0
- package/skills/longform-video-generation/references/google_api_guide.md +288 -0
- package/skills/longform-video-generation/scripts/video_generator.py +579 -0
- package/skills/pdf/FORMS.md +305 -0
- package/skills/pdf/REFERENCE.md +612 -0
- package/skills/pdf/SKILL.md +293 -0
- package/skills/pdf/scripts/check_bounding_boxes.py +70 -0
- package/skills/pdf/scripts/check_fillable_fields.py +12 -0
- package/skills/pdf/scripts/convert_pdf_to_images.py +35 -0
- package/skills/pdf/scripts/create_validation_image.py +41 -0
- package/skills/pdf/scripts/extract_form_field_info.py +152 -0
- package/skills/pdf/scripts/extract_form_structure.py +124 -0
- package/skills/pdf/scripts/fill_fillable_fields.py +116 -0
- package/skills/pdf/scripts/fill_pdf_form_with_annotations.py +136 -0
- package/skills/pptx/SKILL.md +171 -0
- package/skills/pptx/editing.md +205 -0
- package/skills/pptx/pptxgenjs.md +377 -0
- package/skills/pptx/scripts/add_slide.py +225 -0
- package/skills/pptx/scripts/clean.py +309 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
- package/skills/pptx/scripts/ooxml/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
- package/skills/pptx/scripts/ooxml/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
- package/skills/pptx/scripts/ooxml/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
- package/skills/pptx/scripts/ooxml/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
- package/skills/pptx/scripts/ooxml/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
- package/skills/pptx/scripts/ooxml/schemas/mce/mc.xsd +75 -0
- package/skills/pptx/scripts/ooxml/schemas/microsoft/wml-2010.xsd +560 -0
- package/skills/pptx/scripts/ooxml/schemas/microsoft/wml-2012.xsd +67 -0
- package/skills/pptx/scripts/ooxml/schemas/microsoft/wml-2018.xsd +14 -0
- package/skills/pptx/scripts/ooxml/schemas/microsoft/wml-cex-2018.xsd +20 -0
- package/skills/pptx/scripts/ooxml/schemas/microsoft/wml-cid-2016.xsd +13 -0
- package/skills/pptx/scripts/ooxml/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
- package/skills/pptx/scripts/ooxml/schemas/microsoft/wml-symex-2015.xsd +8 -0
- package/skills/pptx/scripts/ooxml/scripts/pack.py +159 -0
- package/skills/pptx/scripts/ooxml/scripts/unpack.py +29 -0
- package/skills/pptx/scripts/ooxml/scripts/validate.py +106 -0
- package/skills/pptx/scripts/ooxml/scripts/validation/__init__.py +15 -0
- package/skills/pptx/scripts/ooxml/scripts/validation/base.py +1023 -0
- package/skills/pptx/scripts/ooxml/scripts/validation/docx.py +519 -0
- package/skills/pptx/scripts/ooxml/scripts/validation/pptx.py +315 -0
- package/skills/pptx/scripts/ooxml/scripts/validation/redlining.py +284 -0
- package/skills/pptx/scripts/pack.py +168 -0
- package/skills/pptx/scripts/thumbnail.py +318 -0
- package/skills/pptx/scripts/unpack.py +86 -0
- package/skills/xlsx/SKILL.md +291 -0
- package/skills/xlsx/recalc.py +247 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Pack a directory into a DOCX file.
|
|
3
|
+
|
|
4
|
+
Validates with auto-repair, condenses XML formatting, and creates the DOCX.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import argparse
|
|
8
|
+
import shutil
|
|
9
|
+
import sys
|
|
10
|
+
import tempfile
|
|
11
|
+
import zipfile
|
|
12
|
+
from pathlib import Path
|
|
13
|
+
|
|
14
|
+
import defusedxml.minidom
|
|
15
|
+
|
|
16
|
+
from helpers.simplify_redlines import infer_author
|
|
17
|
+
from ooxml.scripts.validation import DOCXSchemaValidator, RedliningValidator
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def pack(
|
|
21
|
+
input_directory: str,
|
|
22
|
+
output_file: str,
|
|
23
|
+
original_file: str | None = None,
|
|
24
|
+
validate: bool = True,
|
|
25
|
+
) -> tuple[None, str]:
|
|
26
|
+
"""Pack a directory into a DOCX file.
|
|
27
|
+
|
|
28
|
+
Args:
|
|
29
|
+
input_directory: Path to unpacked DOCX directory
|
|
30
|
+
output_file: Path to output DOCX file
|
|
31
|
+
original_file: Path to original DOCX for validation comparison
|
|
32
|
+
validate: If True, run validation with auto-repair before packing
|
|
33
|
+
|
|
34
|
+
Returns:
|
|
35
|
+
(None, message) - message indicates success or failure
|
|
36
|
+
"""
|
|
37
|
+
input_dir = Path(input_directory)
|
|
38
|
+
output_path = Path(output_file)
|
|
39
|
+
|
|
40
|
+
if not input_dir.is_dir():
|
|
41
|
+
return None, f"Error: {input_dir} is not a directory"
|
|
42
|
+
|
|
43
|
+
if output_path.suffix.lower() != ".docx":
|
|
44
|
+
return None, f"Error: {output_file} must be a .docx file"
|
|
45
|
+
|
|
46
|
+
# Validate with auto-repair if requested and original file provided
|
|
47
|
+
if validate and original_file:
|
|
48
|
+
original_path = Path(original_file)
|
|
49
|
+
if original_path.exists():
|
|
50
|
+
success, output = _run_validation(input_dir, original_path)
|
|
51
|
+
if output:
|
|
52
|
+
print(output)
|
|
53
|
+
if not success:
|
|
54
|
+
return None, f"Error: Validation failed for {input_dir}"
|
|
55
|
+
|
|
56
|
+
# Work in temporary directory to avoid modifying original
|
|
57
|
+
with tempfile.TemporaryDirectory() as temp_dir:
|
|
58
|
+
temp_content_dir = Path(temp_dir) / "content"
|
|
59
|
+
shutil.copytree(input_dir, temp_content_dir)
|
|
60
|
+
|
|
61
|
+
# Process XML files to remove pretty-printing whitespace
|
|
62
|
+
for pattern in ["*.xml", "*.rels"]:
|
|
63
|
+
for xml_file in temp_content_dir.rglob(pattern):
|
|
64
|
+
_condense_xml(xml_file)
|
|
65
|
+
|
|
66
|
+
# Create final DOCX file as zip archive
|
|
67
|
+
output_path.parent.mkdir(parents=True, exist_ok=True)
|
|
68
|
+
with zipfile.ZipFile(output_path, "w", zipfile.ZIP_DEFLATED) as zf:
|
|
69
|
+
for f in temp_content_dir.rglob("*"):
|
|
70
|
+
if f.is_file():
|
|
71
|
+
zf.write(f, f.relative_to(temp_content_dir))
|
|
72
|
+
|
|
73
|
+
return None, f"Successfully packed {input_dir} to {output_file}"
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def _run_validation(unpacked_dir: Path, original_file: Path) -> tuple[bool, str | None]:
|
|
77
|
+
"""Run validation with auto-repair.
|
|
78
|
+
|
|
79
|
+
Returns:
|
|
80
|
+
(success, output) - success is True if all validations pass
|
|
81
|
+
"""
|
|
82
|
+
output_lines = []
|
|
83
|
+
|
|
84
|
+
# Infer author for redlining validation
|
|
85
|
+
try:
|
|
86
|
+
author = infer_author(unpacked_dir, original_file)
|
|
87
|
+
except ValueError as e:
|
|
88
|
+
print(f"Warning: {e} Using default author 'Costar'.", file=sys.stderr)
|
|
89
|
+
author = "Costar"
|
|
90
|
+
|
|
91
|
+
# Create validators
|
|
92
|
+
validators = [
|
|
93
|
+
DOCXSchemaValidator(unpacked_dir, original_file),
|
|
94
|
+
RedliningValidator(unpacked_dir, original_file, author=author),
|
|
95
|
+
]
|
|
96
|
+
|
|
97
|
+
# Run auto-repair
|
|
98
|
+
total_repairs = sum(v.repair() for v in validators)
|
|
99
|
+
if total_repairs:
|
|
100
|
+
output_lines.append(f"Auto-repaired {total_repairs} issue(s)")
|
|
101
|
+
|
|
102
|
+
# Run validation
|
|
103
|
+
success = all(v.validate() for v in validators)
|
|
104
|
+
|
|
105
|
+
if success:
|
|
106
|
+
output_lines.append("All validations PASSED!")
|
|
107
|
+
|
|
108
|
+
return success, "\n".join(output_lines) if output_lines else None
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def _condense_xml(xml_file: Path) -> None:
|
|
112
|
+
"""Strip unnecessary whitespace and remove comments from XML."""
|
|
113
|
+
try:
|
|
114
|
+
with open(xml_file, encoding="utf-8") as f:
|
|
115
|
+
dom = defusedxml.minidom.parse(f)
|
|
116
|
+
|
|
117
|
+
# Process each element to remove whitespace and comments
|
|
118
|
+
for element in dom.getElementsByTagName("*"):
|
|
119
|
+
# Skip text elements (w:t, a:t, etc.) - preserve their content
|
|
120
|
+
if element.tagName.endswith(":t"):
|
|
121
|
+
continue
|
|
122
|
+
|
|
123
|
+
# Remove whitespace-only text nodes and comment nodes
|
|
124
|
+
for child in list(element.childNodes):
|
|
125
|
+
if (
|
|
126
|
+
child.nodeType == child.TEXT_NODE
|
|
127
|
+
and child.nodeValue
|
|
128
|
+
and child.nodeValue.strip() == ""
|
|
129
|
+
) or child.nodeType == child.COMMENT_NODE:
|
|
130
|
+
element.removeChild(child)
|
|
131
|
+
|
|
132
|
+
# Write back the condensed XML
|
|
133
|
+
with open(xml_file, "wb") as f:
|
|
134
|
+
f.write(dom.toxml(encoding="UTF-8"))
|
|
135
|
+
except Exception as e:
|
|
136
|
+
print(f"ERROR: Failed to parse {xml_file.name}: {e}", file=sys.stderr)
|
|
137
|
+
raise
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
if __name__ == "__main__":
|
|
141
|
+
parser = argparse.ArgumentParser(description="Pack a directory into a DOCX file")
|
|
142
|
+
parser.add_argument("input_directory", help="Unpacked DOCX directory")
|
|
143
|
+
parser.add_argument("output_file", help="Output DOCX file")
|
|
144
|
+
parser.add_argument(
|
|
145
|
+
"--original",
|
|
146
|
+
help="Original DOCX file for validation comparison",
|
|
147
|
+
)
|
|
148
|
+
parser.add_argument(
|
|
149
|
+
"--validate",
|
|
150
|
+
type=lambda x: x.lower() == "true",
|
|
151
|
+
default=True,
|
|
152
|
+
metavar="true|false",
|
|
153
|
+
help="Run validation with auto-repair (default: true)",
|
|
154
|
+
)
|
|
155
|
+
args = parser.parse_args()
|
|
156
|
+
|
|
157
|
+
_, message = pack(
|
|
158
|
+
args.input_directory,
|
|
159
|
+
args.output_file,
|
|
160
|
+
original_file=args.original,
|
|
161
|
+
validate=args.validate,
|
|
162
|
+
)
|
|
163
|
+
print(message)
|
|
164
|
+
|
|
165
|
+
if "Error" in message:
|
|
166
|
+
sys.exit(1)
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<?xml version="1.0" ?>
|
|
2
|
+
<w:comments xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex" xmlns:cx1="http://schemas.microsoft.com/office/drawing/2015/9/8/chartex" xmlns:cx2="http://schemas.microsoft.com/office/drawing/2015/10/21/chartex" xmlns:cx3="http://schemas.microsoft.com/office/drawing/2016/5/9/chartex" xmlns:cx4="http://schemas.microsoft.com/office/drawing/2016/5/10/chartex" xmlns:cx5="http://schemas.microsoft.com/office/drawing/2016/5/11/chartex" xmlns:cx6="http://schemas.microsoft.com/office/drawing/2016/5/12/chartex" xmlns:cx7="http://schemas.microsoft.com/office/drawing/2016/5/13/chartex" xmlns:cx8="http://schemas.microsoft.com/office/drawing/2016/5/14/chartex" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:aink="http://schemas.microsoft.com/office/drawing/2016/ink" xmlns:am3d="http://schemas.microsoft.com/office/drawing/2017/model3d" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:oel="http://schemas.microsoft.com/office/2019/extlst" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16cex="http://schemas.microsoft.com/office/word/2018/wordml/cex" xmlns:w16cid="http://schemas.microsoft.com/office/word/2016/wordml/cid" xmlns:w16="http://schemas.microsoft.com/office/word/2018/wordml" xmlns:w16du="http://schemas.microsoft.com/office/word/2023/wordml/word16du" xmlns:w16sdtdh="http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash" xmlns:w16sdtfl="http://schemas.microsoft.com/office/word/2024/wordml/sdtformatlock" xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 w15 w16se w16cid w16 w16cex w16sdtdh w16sdtfl w16du wp14">
|
|
3
|
+
</w:comments>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<?xml version="1.0" ?>
|
|
2
|
+
<w15:commentsEx xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex" xmlns:cx1="http://schemas.microsoft.com/office/drawing/2015/9/8/chartex" xmlns:cx2="http://schemas.microsoft.com/office/drawing/2015/10/21/chartex" xmlns:cx3="http://schemas.microsoft.com/office/drawing/2016/5/9/chartex" xmlns:cx4="http://schemas.microsoft.com/office/drawing/2016/5/10/chartex" xmlns:cx5="http://schemas.microsoft.com/office/drawing/2016/5/11/chartex" xmlns:cx6="http://schemas.microsoft.com/office/drawing/2016/5/12/chartex" xmlns:cx7="http://schemas.microsoft.com/office/drawing/2016/5/13/chartex" xmlns:cx8="http://schemas.microsoft.com/office/drawing/2016/5/14/chartex" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:aink="http://schemas.microsoft.com/office/drawing/2016/ink" xmlns:am3d="http://schemas.microsoft.com/office/drawing/2017/model3d" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:oel="http://schemas.microsoft.com/office/2019/extlst" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16cex="http://schemas.microsoft.com/office/word/2018/wordml/cex" xmlns:w16cid="http://schemas.microsoft.com/office/word/2016/wordml/cid" xmlns:w16="http://schemas.microsoft.com/office/word/2018/wordml" xmlns:w16du="http://schemas.microsoft.com/office/word/2023/wordml/word16du" xmlns:w16sdtdh="http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash" xmlns:w16sdtfl="http://schemas.microsoft.com/office/word/2024/wordml/sdtformatlock" xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 w15 w16se w16cid w16 w16cex w16sdtdh w16sdtfl w16du wp14">
|
|
3
|
+
</w15:commentsEx>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<?xml version="1.0" ?>
|
|
2
|
+
<w16cex:commentsExtensible xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex" xmlns:cx1="http://schemas.microsoft.com/office/drawing/2015/9/8/chartex" xmlns:cx2="http://schemas.microsoft.com/office/drawing/2015/10/21/chartex" xmlns:cx3="http://schemas.microsoft.com/office/drawing/2016/5/9/chartex" xmlns:cx4="http://schemas.microsoft.com/office/drawing/2016/5/10/chartex" xmlns:cx5="http://schemas.microsoft.com/office/drawing/2016/5/11/chartex" xmlns:cx6="http://schemas.microsoft.com/office/drawing/2016/5/12/chartex" xmlns:cx7="http://schemas.microsoft.com/office/drawing/2016/5/13/chartex" xmlns:cx8="http://schemas.microsoft.com/office/drawing/2016/5/14/chartex" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:aink="http://schemas.microsoft.com/office/drawing/2016/ink" xmlns:am3d="http://schemas.microsoft.com/office/drawing/2017/model3d" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:oel="http://schemas.microsoft.com/office/2019/extlst" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16cex="http://schemas.microsoft.com/office/word/2018/wordml/cex" xmlns:w16cid="http://schemas.microsoft.com/office/word/2016/wordml/cid" xmlns:w16="http://schemas.microsoft.com/office/word/2018/wordml" xmlns:w16du="http://schemas.microsoft.com/office/word/2023/wordml/word16du" xmlns:w16sdtdh="http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash" xmlns:w16sdtfl="http://schemas.microsoft.com/office/word/2024/wordml/sdtformatlock" xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" xmlns:cr="http://schemas.microsoft.com/office/comments/2020/reactions" mc:Ignorable="w14 w15 w16se w16cid w16 w16cex w16sdtdh w16sdtfl cr w16du wp14">
|
|
3
|
+
</w16cex:commentsExtensible>
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
<?xml version="1.0" ?>
|
|
2
|
+
<w16cid:commentsIds xmlns:wpc="http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas" xmlns:cx="http://schemas.microsoft.com/office/drawing/2014/chartex" xmlns:cx1="http://schemas.microsoft.com/office/drawing/2015/9/8/chartex" xmlns:cx2="http://schemas.microsoft.com/office/drawing/2015/10/21/chartex" xmlns:cx3="http://schemas.microsoft.com/office/drawing/2016/5/9/chartex" xmlns:cx4="http://schemas.microsoft.com/office/drawing/2016/5/10/chartex" xmlns:cx5="http://schemas.microsoft.com/office/drawing/2016/5/11/chartex" xmlns:cx6="http://schemas.microsoft.com/office/drawing/2016/5/12/chartex" xmlns:cx7="http://schemas.microsoft.com/office/drawing/2016/5/13/chartex" xmlns:cx8="http://schemas.microsoft.com/office/drawing/2016/5/14/chartex" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:aink="http://schemas.microsoft.com/office/drawing/2016/ink" xmlns:am3d="http://schemas.microsoft.com/office/drawing/2017/model3d" xmlns:o="urn:schemas-microsoft-com:office:office" xmlns:oel="http://schemas.microsoft.com/office/2019/extlst" xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships" xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math" xmlns:v="urn:schemas-microsoft-com:vml" xmlns:wp14="http://schemas.microsoft.com/office/word/2010/wordprocessingDrawing" xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing" xmlns:w10="urn:schemas-microsoft-com:office:word" xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main" xmlns:w14="http://schemas.microsoft.com/office/word/2010/wordml" xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml" xmlns:w16cex="http://schemas.microsoft.com/office/word/2018/wordml/cex" xmlns:w16cid="http://schemas.microsoft.com/office/word/2016/wordml/cid" xmlns:w16="http://schemas.microsoft.com/office/word/2018/wordml" xmlns:w16du="http://schemas.microsoft.com/office/word/2023/wordml/word16du" xmlns:w16sdtdh="http://schemas.microsoft.com/office/word/2020/wordml/sdtdatahash" xmlns:w16sdtfl="http://schemas.microsoft.com/office/word/2024/wordml/sdtformatlock" xmlns:w16se="http://schemas.microsoft.com/office/word/2015/wordml/symex" xmlns:wpg="http://schemas.microsoft.com/office/word/2010/wordprocessingGroup" xmlns:wpi="http://schemas.microsoft.com/office/word/2010/wordprocessingInk" xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml" xmlns:wps="http://schemas.microsoft.com/office/word/2010/wordprocessingShape" mc:Ignorable="w14 w15 w16se w16cid w16 w16cex w16sdtdh w16sdtfl w16du wp14">
|
|
3
|
+
</w16cid:commentsIds>
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""Unpack DOCX files for editing.
|
|
3
|
+
|
|
4
|
+
Extracts the ZIP archive, pretty-prints XML files, and merges adjacent runs
|
|
5
|
+
with identical formatting (enabled by default).
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import argparse
|
|
9
|
+
import sys
|
|
10
|
+
import zipfile
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
import defusedxml.minidom
|
|
14
|
+
from helpers.merge_runs import merge_runs as do_merge_runs
|
|
15
|
+
from helpers.simplify_redlines import simplify_redlines as do_simplify_redlines
|
|
16
|
+
|
|
17
|
+
# Smart quotes that get mangled by the tokenizer - convert to XML entities
|
|
18
|
+
# Using hex escapes since we can't type the actual characters
|
|
19
|
+
SMART_QUOTE_REPLACEMENTS = {
|
|
20
|
+
"\u201c": "“", # Left double quote
|
|
21
|
+
"\u201d": "”", # Right double quote
|
|
22
|
+
"\u2018": "‘", # Left single quote
|
|
23
|
+
"\u2019": "’", # Right single quote
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def unpack(
|
|
28
|
+
input_file: str,
|
|
29
|
+
output_directory: str,
|
|
30
|
+
merge_runs: bool = True,
|
|
31
|
+
simplify_redlines: bool = True,
|
|
32
|
+
) -> tuple[None, str]:
|
|
33
|
+
"""Unpack a DOCX file and prepare for editing.
|
|
34
|
+
|
|
35
|
+
Args:
|
|
36
|
+
input_file: Path to DOCX file
|
|
37
|
+
output_directory: Path to output directory
|
|
38
|
+
merge_runs: If True, merge adjacent runs with identical formatting
|
|
39
|
+
simplify_redlines: If True, merge adjacent tracked changes from same author
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
(None, message) - message indicates success or failure
|
|
43
|
+
"""
|
|
44
|
+
input_path = Path(input_file)
|
|
45
|
+
output_path = Path(output_directory)
|
|
46
|
+
|
|
47
|
+
if not input_path.exists():
|
|
48
|
+
return None, f"Error: {input_file} does not exist"
|
|
49
|
+
|
|
50
|
+
if input_path.suffix.lower() != ".docx":
|
|
51
|
+
return None, f"Error: {input_file} must be a .docx file"
|
|
52
|
+
|
|
53
|
+
try:
|
|
54
|
+
# Create output directory
|
|
55
|
+
output_path.mkdir(parents=True, exist_ok=True)
|
|
56
|
+
|
|
57
|
+
# Extract ZIP contents
|
|
58
|
+
with zipfile.ZipFile(input_path, "r") as zf:
|
|
59
|
+
zf.extractall(output_path)
|
|
60
|
+
|
|
61
|
+
# Pretty print all XML files
|
|
62
|
+
xml_files = list(output_path.rglob("*.xml")) + list(output_path.rglob("*.rels"))
|
|
63
|
+
for xml_file in xml_files:
|
|
64
|
+
_pretty_print_xml(xml_file)
|
|
65
|
+
|
|
66
|
+
message = f"Unpacked {input_file} ({len(xml_files)} XML files)"
|
|
67
|
+
|
|
68
|
+
# Simplify tracked changes if requested (before merge_runs so more runs can merge)
|
|
69
|
+
if simplify_redlines:
|
|
70
|
+
simplify_count, _ = do_simplify_redlines(str(output_path))
|
|
71
|
+
message += f", simplified {simplify_count} tracked changes"
|
|
72
|
+
|
|
73
|
+
# Merge runs if requested
|
|
74
|
+
if merge_runs:
|
|
75
|
+
merge_count, _ = do_merge_runs(str(output_path))
|
|
76
|
+
message += f", merged {merge_count} runs"
|
|
77
|
+
|
|
78
|
+
# Escape smart quotes AFTER transformations (which rewrite files)
|
|
79
|
+
for xml_file in xml_files:
|
|
80
|
+
_escape_smart_quotes(xml_file)
|
|
81
|
+
|
|
82
|
+
return None, message
|
|
83
|
+
|
|
84
|
+
except zipfile.BadZipFile:
|
|
85
|
+
return None, f"Error: {input_file} is not a valid DOCX file"
|
|
86
|
+
except Exception as e:
|
|
87
|
+
return None, f"Error unpacking: {e}"
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _pretty_print_xml(xml_file: Path) -> None:
|
|
91
|
+
"""Pretty print an XML file with indentation."""
|
|
92
|
+
content = xml_file.read_text(encoding="utf-8")
|
|
93
|
+
dom = defusedxml.minidom.parseString(content)
|
|
94
|
+
xml_file.write_bytes(dom.toprettyxml(indent=" ", encoding="utf-8"))
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _escape_smart_quotes(xml_file: Path) -> None:
|
|
98
|
+
"""Replace smart quotes with XML entities so they survive tokenization."""
|
|
99
|
+
content = xml_file.read_text(encoding="utf-8")
|
|
100
|
+
for char, entity in SMART_QUOTE_REPLACEMENTS.items():
|
|
101
|
+
content = content.replace(char, entity)
|
|
102
|
+
xml_file.write_text(content, encoding="utf-8")
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
if __name__ == "__main__":
|
|
106
|
+
parser = argparse.ArgumentParser(description="Unpack a DOCX file for editing")
|
|
107
|
+
parser.add_argument("input_file", help="DOCX file to unpack")
|
|
108
|
+
parser.add_argument("output_directory", help="Output directory")
|
|
109
|
+
parser.add_argument(
|
|
110
|
+
"--merge-runs",
|
|
111
|
+
type=lambda x: x.lower() == "true",
|
|
112
|
+
default=True,
|
|
113
|
+
metavar="true|false",
|
|
114
|
+
help="Merge adjacent runs with identical formatting (default: true)",
|
|
115
|
+
)
|
|
116
|
+
parser.add_argument(
|
|
117
|
+
"--simplify-redlines",
|
|
118
|
+
type=lambda x: x.lower() == "true",
|
|
119
|
+
default=True,
|
|
120
|
+
metavar="true|false",
|
|
121
|
+
help="Merge adjacent tracked changes from same author (default: true)",
|
|
122
|
+
)
|
|
123
|
+
args = parser.parse_args()
|
|
124
|
+
|
|
125
|
+
_, message = unpack(
|
|
126
|
+
args.input_file,
|
|
127
|
+
args.output_directory,
|
|
128
|
+
merge_runs=args.merge_runs,
|
|
129
|
+
simplify_redlines=args.simplify_redlines,
|
|
130
|
+
)
|
|
131
|
+
print(message)
|
|
132
|
+
|
|
133
|
+
if "Error" in message:
|
|
134
|
+
sys.exit(1)
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: longform-video-generator
|
|
3
|
+
description: Generate videos longer than 8 seconds using Google Veo 3.1 API. Creates seamless multi-scene videos by chaining 8-second clips with frame-to-video references and smooth crossfade transitions. Supports enhanced mode with Nano Banana Pro for higher quality reference images. Use for creating multi-scene videos, cinematic narratives, product demos, marketing content, or any video requiring multiple consecutive scenes.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Long-Form Video Generator
|
|
7
|
+
|
|
8
|
+
Generate videos longer than 8 seconds using Google Veo 3.1 API by chaining multiple clips with frame-to-video references and smooth transitions.
|
|
9
|
+
|
|
10
|
+
## Core Concept
|
|
11
|
+
|
|
12
|
+
Veo 3.1 generates maximum 8-second clips. To create longer videos:
|
|
13
|
+
|
|
14
|
+
1. Generate first 8-second clip from text prompt (or enhanced reference image)
|
|
15
|
+
2. Extract last frame from generated video
|
|
16
|
+
3. Use extracted frame as reference for next clip
|
|
17
|
+
4. Maintain consistent character/style descriptions across scenes
|
|
18
|
+
5. Repeat for N scenes
|
|
19
|
+
6. Concatenate with smooth crossfade transitions
|
|
20
|
+
|
|
21
|
+
Optional: Use Nano Banana Pro (gemini-3-pro-image-preview) for first frame to achieve higher quality.
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
Run the video generation command from the skill directory:
|
|
26
|
+
|
|
27
|
+
## Command Format
|
|
28
|
+
|
|
29
|
+
Always run from the skill directory:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
cd /home/user/skills/longform-video-generation && python scripts/video_generator.py [OPTIONS] SCENE1 SCENE2 SCENE3...
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Parameters
|
|
36
|
+
|
|
37
|
+
Required:
|
|
38
|
+
SCENES Scene descriptions (at least one)
|
|
39
|
+
|
|
40
|
+
Optional:
|
|
41
|
+
-o, --output FILE Output filename (default: longform_video.mp4)
|
|
42
|
+
--enhanced Use Nano Banana Pro for first frame
|
|
43
|
+
--resolution {1K,2K,4K} Enhanced resolution (default: 2K)
|
|
44
|
+
--no-smooth Disable smooth transitions
|
|
45
|
+
--transition-duration FLOAT Transition length in seconds (default: 0.5)
|
|
46
|
+
--no-frame-chaining Disable frame chaining
|
|
47
|
+
|
|
48
|
+
## Enhanced Mode
|
|
49
|
+
|
|
50
|
+
Enable enhanced mode to use Nano Banana Pro for generating the first reference frame:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
python scripts/video_generator.py --enhanced --resolution 2K \
|
|
54
|
+
"Scene 1" "Scene 2" "Scene 3"
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Benefits: 30-50% better visual quality, higher resolution reference (up to 4K), improved composition.
|
|
58
|
+
Cost: +$0.036 (2K) or +$0.06 (4K) per video.
|
|
59
|
+
|
|
60
|
+
## Veo Prompt Writing Guide
|
|
61
|
+
|
|
62
|
+
### Essential Elements
|
|
63
|
+
|
|
64
|
+
Include these elements in every video prompt:
|
|
65
|
+
|
|
66
|
+
**Subject**: The main focus (person, animal, object, scenery)
|
|
67
|
+
- Examples: cityscape, nature, vehicles, puppies, woman in red jacket
|
|
68
|
+
|
|
69
|
+
**Action**: What the subject is doing
|
|
70
|
+
- Examples: walking, running, turning head, looking around
|
|
71
|
+
|
|
72
|
+
**Style**: Creative direction and aesthetic
|
|
73
|
+
- Examples: cinematic, sci-fi, horror film, film noir, cartoon, photorealistic
|
|
74
|
+
|
|
75
|
+
**Camera Positioning** (optional): Camera location and movement
|
|
76
|
+
- Examples: aerial view, eye-level, top-down shot, dolly shot, POV shot, tracking drone view
|
|
77
|
+
|
|
78
|
+
**Composition** (optional): How the shot is framed
|
|
79
|
+
- Examples: wide shot, close-up, medium shot, single-shot, two-shot
|
|
80
|
+
|
|
81
|
+
**Focus and Lens** (optional): Visual effects
|
|
82
|
+
- Examples: shallow focus, deep focus, soft focus, macro lens, wide-angle lens
|
|
83
|
+
|
|
84
|
+
**Ambiance** (optional): Color and lighting
|
|
85
|
+
- Examples: blue tones, night, warm tones, natural light, sunrise, cool blue tones
|
|
86
|
+
|
|
87
|
+
### Example Prompts
|
|
88
|
+
|
|
89
|
+
**Simple**:
|
|
90
|
+
```
|
|
91
|
+
A cute creature with snow leopard fur walking in winter forest, 3D cartoon style
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
**Detailed**:
|
|
95
|
+
```
|
|
96
|
+
Close-up cinematic shot follows a desperate man in weathered green trench coat as he dials
|
|
97
|
+
rotary phone mounted on gritty brick wall, bathed in eerie glow of green neon sign. Camera
|
|
98
|
+
dollies in, revealing tension in his jaw and desperation etched on face. Shallow depth of
|
|
99
|
+
field focuses on furrowed brow and black rotary phone, blurring background into sea of neon
|
|
100
|
+
colors and indistinct shadows, creating sense of urgency and isolation.
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
### Audio Prompting
|
|
104
|
+
|
|
105
|
+
Veo 3.1 generates audio natively. Include audio cues for best results:
|
|
106
|
+
|
|
107
|
+
**Dialogue**: Use quotes for specific speech
|
|
108
|
+
```
|
|
109
|
+
Man murmurs, "This must be it. That's the secret code."
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**Sound Effects**: Explicitly describe sounds
|
|
113
|
+
```
|
|
114
|
+
Tires screeching loudly, engine roaring, glass shattering
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Ambient Noise**: Describe environment soundscape
|
|
118
|
+
```
|
|
119
|
+
A faint eerie hum resonates in background, wind rustling through leaves
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Character Consistency
|
|
123
|
+
|
|
124
|
+
Repeat character descriptions in every scene:
|
|
125
|
+
|
|
126
|
+
```python
|
|
127
|
+
character = "Woman in red jacket, brown hair, professional attire"
|
|
128
|
+
scenes = [
|
|
129
|
+
f"{character}, walking through modern office, natural lighting",
|
|
130
|
+
f"{character}, presenting to colleagues, conference room",
|
|
131
|
+
f"{character}, shaking hands, successful meeting conclusion"
|
|
132
|
+
]
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
### Visual Continuity
|
|
136
|
+
|
|
137
|
+
Maintain style and atmosphere:
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
style = "Cinematic action movie, dramatic lighting, high contrast"
|
|
141
|
+
scenes = [
|
|
142
|
+
f"{style}. Agent running through alley, motion blur, neon lights",
|
|
143
|
+
f"{style}. Agent sliding across car hood, sparks flying",
|
|
144
|
+
f"{style}. Agent leaping through window, glass shattering"
|
|
145
|
+
]
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Scene Transitions
|
|
149
|
+
|
|
150
|
+
Design endings that lead to next scene:
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
scenes = [
|
|
154
|
+
"Person walking toward door, hand reaching for handle",
|
|
155
|
+
"Person opening door, stepping through threshold",
|
|
156
|
+
"Person entering room, looking around new space"
|
|
157
|
+
]
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### Negative Prompts
|
|
161
|
+
|
|
162
|
+
Specify what NOT to include (use descriptive terms, not instructions):
|
|
163
|
+
|
|
164
|
+
**Incorrect**: "No walls", "Don't show buildings"
|
|
165
|
+
**Correct**: "wall, frame, urban background, man-made structures"
|
|
166
|
+
|
|
167
|
+
```python
|
|
168
|
+
operation = client.models.generate_videos(
|
|
169
|
+
model="veo-3.1-generate-preview",
|
|
170
|
+
prompt="Solitary oak tree with leaves blowing in wind",
|
|
171
|
+
config=types.GenerateVideosConfig(
|
|
172
|
+
negative_prompt="urban background, man-made structures, dark, stormy"
|
|
173
|
+
)
|
|
174
|
+
)
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
## Nano Banana Pro Prompt Writing Guide
|
|
178
|
+
|
|
179
|
+
When using enhanced mode, the first frame is generated using Nano Banana Pro (gemini-3-pro-image-preview).
|
|
180
|
+
|
|
181
|
+
### Image Generation Best Practices
|
|
182
|
+
|
|
183
|
+
**Be Specific**: Include detailed visual descriptions
|
|
184
|
+
```
|
|
185
|
+
Professional woman in navy blue business suit, confident posture, modern glass office
|
|
186
|
+
building background, natural daylight, warm professional atmosphere, high resolution,
|
|
187
|
+
photorealistic
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**Specify Style**: Photography type and quality
|
|
191
|
+
```
|
|
192
|
+
Cinematic still frame, high-resolution professional photography, dramatic lighting,
|
|
193
|
+
ultra detailed, 16:9 aspect ratio, photorealistic
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Camera Details**: Perspective and composition
|
|
197
|
+
```
|
|
198
|
+
Medium shot, eye-level camera angle, rule of thirds composition, shallow depth of field
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
**Lighting**: Describe light sources and mood
|
|
202
|
+
```
|
|
203
|
+
Soft natural window light from left, warm golden hour glow, subtle rim lighting on subject
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
### Enhanced Reference Image Template
|
|
207
|
+
|
|
208
|
+
```python
|
|
209
|
+
image_prompt = f"""
|
|
210
|
+
Cinematic still frame for video scene.
|
|
211
|
+
{your_scene_description}
|
|
212
|
+
High-resolution, professional photography, dramatic lighting.
|
|
213
|
+
This will be starting frame of video sequence.
|
|
214
|
+
16:9 aspect ratio, photorealistic, ultra detailed.
|
|
215
|
+
"""
|
|
216
|
+
|
|
217
|
+
reference = generator.generate_reference_image(
|
|
218
|
+
prompt=image_prompt,
|
|
219
|
+
model="gemini-3-pro-image-preview",
|
|
220
|
+
resolution="2K" # or "4K" for maximum quality
|
|
221
|
+
)
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### Resolution Options
|
|
225
|
+
|
|
226
|
+
**1K** (1376×768): $0.024 - Good quality, fast
|
|
227
|
+
**2K** (2752×1536): $0.036 - Professional quality (recommended)
|
|
228
|
+
**4K** (5504×3072): $0.06 - Maximum quality
|
|
229
|
+
|
|
230
|
+
## Cost Analysis
|
|
231
|
+
|
|
232
|
+
### Standard Mode (3 scenes, 24 seconds)
|
|
233
|
+
- 3x Veo 3.1 generations: $0.45
|
|
234
|
+
- Smooth transitions: Included
|
|
235
|
+
- Quality: Good
|
|
236
|
+
|
|
237
|
+
### Enhanced Mode (3 scenes, 24 seconds)
|
|
238
|
+
- 1x Nano Banana Pro (2K): $0.036
|
|
239
|
+
- 3x Veo 3.1 generations: $0.45
|
|
240
|
+
- Total: $0.486 (+8%)
|
|
241
|
+
- Quality: Excellent (+30-50%)
|
|
242
|
+
|
|
243
|
+
Use enhanced mode for: Production videos, client deliverables, marketing content, high-quality requirements
|
|
244
|
+
Use standard mode for: Prototypes, testing, quick iterations, budget projects
|
|
245
|
+
|
|
246
|
+
## Complete Example
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
# Define scenes as bash variables for clarity
|
|
250
|
+
STYLE="Cinematic corporate video, professional lighting, modern aesthetic"
|
|
251
|
+
CHARACTER="Professional woman in navy blue suit, confident demeanor"
|
|
252
|
+
|
|
253
|
+
# Generate with enhanced quality
|
|
254
|
+
python scripts/video_generator.py --enhanced --resolution 2K \
|
|
255
|
+
-o corporate_video.mp4 \
|
|
256
|
+
--transition-duration 0.5 \
|
|
257
|
+
"$STYLE. $CHARACTER walking through modern glass office lobby. Wide shot transitions to medium shot. Natural daylight through windows. Sound of heels clicking on marble floor." \
|
|
258
|
+
"$STYLE. $CHARACTER enters conference room, greeting team with smile. Medium shot, eye-level camera. Colleagues visible in background. Sound of door opening, greetings." \
|
|
259
|
+
"$STYLE. $CHARACTER presenting at whiteboard, gesturing confidently. Close-up capturing engaged expression. Sound of marker on whiteboard, voice presenting ideas."
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
## Technical Details
|
|
263
|
+
|
|
264
|
+
**Processing Time**: 2-3 minutes per scene, +30 seconds for enhanced first frame, +10-15 seconds for concatenation
|
|
265
|
+
|
|
266
|
+
**Output**: Generated video saved to `/home/user/task/` directory. Default filename: `longform_video.mp4` (customize with `-o` option).
|
|
267
|
+
|
|
268
|
+
**Specifications**: 720p or 1080p (1080p only for 8s clips), 24fps, native audio with crossfade, SynthID watermark.
|
|
269
|
+
|
|
270
|
+
**Duration**: Approximately 2-3 minutes per scene.
|
|
271
|
+
|
|
272
|
+
## Troubleshooting
|
|
273
|
+
|
|
274
|
+
**Character Drift**: Use enhanced mode with consistent character descriptions to minimize drift across scenes
|
|
275
|
+
|
|
276
|
+
**Jerky Transitions**: Adjust transition duration:
|
|
277
|
+
```bash
|
|
278
|
+
python scripts/video_generator.py --transition-duration 0.7 "scene 1" "scene 2"
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
**Inconsistent Results**: Disable frame chaining if causing issues:
|
|
282
|
+
```bash
|
|
283
|
+
python scripts/video_generator.py --no-frame-chaining "scene 1" "scene 2"
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
## Reference Documentation
|
|
287
|
+
|
|
288
|
+
**API Details**: See [references/google_api_guide.md](references/google_api_guide.md) for complete API documentation including all parameters, model versions, and advanced features.
|
|
289
|
+
|
|
290
|
+
**Advanced Techniques**: See [references/advanced_techniques.md](references/advanced_techniques.md) for optimization strategies, complex workflows, and troubleshooting tips.
|
|
291
|
+
|
|
292
|
+
## Limitations
|
|
293
|
+
|
|
294
|
+
- Maximum clip length: 8 seconds per scene
|
|
295
|
+
- API rate limits: Pause 5 seconds between generations recommended
|
|
296
|
+
- SynthID watermark: Applied automatically, cannot be removed
|
|
297
|
+
- Video retention: 2 days on server, download promptly
|
|
298
|
+
- Regional limitations: Some regions restrict person generation settings
|