devendra-skill-package 1.0.2
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/.github/skills/boiler-project-generator/SKILL.md +103 -0
- package/.github/skills/boiler-project-generator/assets/templates/android/README.md +3 -0
- package/.github/skills/boiler-project-generator/assets/templates/angular/README.md +3 -0
- package/.github/skills/boiler-project-generator/assets/templates/flutter/README.md +3 -0
- package/.github/skills/boiler-project-generator/assets/templates/ios/README.md +3 -0
- package/.github/skills/boiler-project-generator/assets/templates/react/README.md +3 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/README.md +3 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/api-setup.ts +76 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/component-primary-button.tsx +29 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/env-config.env +4 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/feature-auth-screen.tsx +45 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/feature-dashboard-screen.tsx +45 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/feature-profile-screen.tsx +45 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/hook-use-app-boot.ts +11 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/navigation-setup.tsx +25 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/project-structure.md +24 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/redux-hooks.ts +5 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/redux-session-slice.ts +29 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/redux-store.ts +15 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/theme-index.ts +23 -0
- package/.github/skills/boiler-project-generator/assets/templates/react-native/utils-helpers.ts +7 -0
- package/.github/skills/boiler-project-generator/metadata.yaml +29 -0
- package/.github/skills/boiler-project-generator/references/android.md +19 -0
- package/.github/skills/boiler-project-generator/references/angular.md +14 -0
- package/.github/skills/boiler-project-generator/references/flutter.md +17 -0
- package/.github/skills/boiler-project-generator/references/ios.md +17 -0
- package/.github/skills/boiler-project-generator/references/react-native.md +103 -0
- package/.github/skills/boiler-project-generator/references/react.md +17 -0
- package/.github/skills/boiler-project-generator/scripts/angular.js +43 -0
- package/.github/skills/boiler-project-generator/scripts/generate-project.mjs +107 -0
- package/.github/skills/boiler-project-generator/scripts/init.js +105 -0
- package/.github/skills/boiler-project-generator/scripts/react-native.js +1041 -0
- package/.github/skills/boiler-project-generator/scripts/react.js +32 -0
- package/.github/skills/clean-architecture-generator/SKILL.md +235 -0
- package/.github/skills/clean-architecture-generator/references/architecture-core.md +126 -0
- package/.github/skills/clean-architecture-generator/references/platform-angular.md +374 -0
- package/.github/skills/clean-architecture-generator/references/platform-flutter.md +366 -0
- package/.github/skills/clean-architecture-generator/references/platform-react-native.md +590 -0
- package/.github/skills/clean-architecture-generator/references/platform-react.md +261 -0
- package/.github/skills/code-test-coverage-analyzer/SKILL.md +1358 -0
- package/.github/skills/code-test-coverage-analyzer/assets/config-questionnaire.md +118 -0
- package/.github/skills/code-test-coverage-analyzer/assets/conflict-resolution-protocol.md +99 -0
- package/.github/skills/code-test-coverage-analyzer/assets/coverage-calculation-rules.md +294 -0
- package/.github/skills/code-test-coverage-analyzer/assets/multi-strategy-search.md +145 -0
- package/.github/skills/code-test-coverage-analyzer/assets/output-file-contracts.md +651 -0
- package/.github/skills/code-test-coverage-analyzer/assets/status-definitions.md +273 -0
- package/.github/skills/code-test-coverage-analyzer/examples/example-invocation.md +208 -0
- package/.github/skills/code-test-coverage-analyzer/references/android-patterns.md +229 -0
- package/.github/skills/code-test-coverage-analyzer/references/angular-patterns.md +177 -0
- package/.github/skills/code-test-coverage-analyzer/references/backend-patterns.md +383 -0
- package/.github/skills/code-test-coverage-analyzer/references/flutter-patterns.md +254 -0
- package/.github/skills/code-test-coverage-analyzer/references/ios-patterns.md +228 -0
- package/.github/skills/code-test-coverage-analyzer/references/react-native-patterns.md +431 -0
- package/.github/skills/code-test-coverage-analyzer/references/react-patterns.md +206 -0
- package/.github/skills/code-test-coverage-analyzer/scripts/detect-platform.ps1 +261 -0
- package/.github/skills/code-test-coverage-analyzer/scripts/scan-repository.ps1 +242 -0
- package/.github/skills/code-test-coverage-analyzer/templates/brd-compliance-row.md +107 -0
- package/.github/skills/code-test-coverage-analyzer/templates/test-case-row.md +130 -0
- package/.github/skills/code-test-coverage-analyzer/templates/user-story-compliance-row.md +170 -0
- package/.github/skills/custom-font-integrator/SKILL.md +373 -0
- package/.github/skills/custom-font-integrator/assets/FontTestScreen.js +150 -0
- package/.github/skills/custom-font-integrator/references/example-info-plist.xml +21 -0
- package/.github/skills/custom-font-integrator/scripts/setup-fonts.sh +99 -0
- package/.github/skills/encryption-decryption-utility/Instructions.md +282 -0
- package/.github/skills/encryption-decryption-utility/README.md +222 -0
- package/.github/skills/encryption-decryption-utility/SKILL.md +645 -0
- package/.github/skills/encryption-decryption-utility/assets/encryption-config-template.json +13 -0
- package/.github/skills/encryption-decryption-utility/assets/platform-matrix.json +180 -0
- package/.github/skills/encryption-decryption-utility/metadata.yaml +51 -0
- package/.github/skills/encryption-decryption-utility/references/android-crypto.md +157 -0
- package/.github/skills/encryption-decryption-utility/references/angular-crypto.md +130 -0
- package/.github/skills/encryption-decryption-utility/references/approach-1-webcrypto.md +95 -0
- package/.github/skills/encryption-decryption-utility/references/approach-2-rsa-aes-cbc.md +111 -0
- package/.github/skills/encryption-decryption-utility/references/approach-3-aes-sharedkey.md +114 -0
- package/.github/skills/encryption-decryption-utility/references/architecture.md +233 -0
- package/.github/skills/encryption-decryption-utility/references/backend-alignment.md +506 -0
- package/.github/skills/encryption-decryption-utility/references/dependency-guidance.md +234 -0
- package/.github/skills/encryption-decryption-utility/references/ec-implementation.md +832 -0
- package/.github/skills/encryption-decryption-utility/references/error-handling-playbook.md +234 -0
- package/.github/skills/encryption-decryption-utility/references/flutter-crypto.md +105 -0
- package/.github/skills/encryption-decryption-utility/references/ios-crypto.md +338 -0
- package/.github/skills/encryption-decryption-utility/references/native-rsa-implementation.md +373 -0
- package/.github/skills/encryption-decryption-utility/references/node-crypto.md +86 -0
- package/.github/skills/encryption-decryption-utility/references/react-crypto.md +105 -0
- package/.github/skills/encryption-decryption-utility/references/react-native-crypto.md +1001 -0
- package/.github/skills/encryption-decryption-utility/references/react-web-crypto.md +668 -0
- package/.github/skills/encryption-decryption-utility/references/security-checklist.md +176 -0
- package/.github/skills/encryption-decryption-utility/references/web-crypto.md +74 -0
- package/.github/skills/encryption-decryption-utility/scripts/detect.js +128 -0
- package/.github/skills/encryption-decryption-utility/scripts/install.js +1713 -0
- package/.github/skills/encryption-decryption-utility/scripts/setup.js +800 -0
- package/.github/skills/encryption-decryption-utility/template.md +241 -0
- package/.github/skills/encryption-decryption-utility/templates/config-questionnaire.md +467 -0
- package/.github/skills/encryption-decryption-utility/templates/delivery-checklist.md +206 -0
- package/.github/skills/encryption-decryption-utility/templates/implementation-plan.md +304 -0
- package/.github/skills/feature-generator/SKILL.MD +2741 -0
- package/.github/skills/feature-generator/assets/fingerprint-schema.json +385 -0
- package/.github/skills/feature-generator/assets/spec-template.md +172 -0
- package/.github/skills/feature-generator/assets/transform-rules.json +82 -0
- package/.github/skills/feature-generator/references/api-envelope-patterns.md +327 -0
- package/.github/skills/feature-generator/references/screen-logic-patterns.md +399 -0
- package/.github/skills/feature-generator/references/state-library-patterns.md +464 -0
- package/.github/skills/figma-ui-mapper/README.md +34 -0
- package/.github/skills/figma-ui-mapper/SKILL.md +101 -0
- package/.github/skills/figma-ui-mapper/assets/templates/component-map-template.md +30 -0
- package/.github/skills/figma-ui-mapper/assets/templates/generation-report-template.md +49 -0
- package/.github/skills/figma-ui-mapper/metadata.yaml +22 -0
- package/.github/skills/figma-ui-mapper/references/android.md +11 -0
- package/.github/skills/figma-ui-mapper/references/angular.md +18 -0
- package/.github/skills/figma-ui-mapper/references/capacitor.md +18 -0
- package/.github/skills/figma-ui-mapper/references/common.md +23 -0
- package/.github/skills/figma-ui-mapper/references/expo.md +18 -0
- package/.github/skills/figma-ui-mapper/references/flutter.md +18 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/angular/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/capacitor/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/expo/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/flutter/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/ionic/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/kotlin-multiplatform/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/native-android/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/native-ios/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/next/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/nuxt/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/react/rules.md +19 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/react-native/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/svelte/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/frameworks/vue/rules.md +23 -0
- package/.github/skills/figma-ui-mapper/references/ionic.md +18 -0
- package/.github/skills/figma-ui-mapper/references/ios.md +11 -0
- package/.github/skills/figma-ui-mapper/references/kotlin-multiplatform.md +18 -0
- package/.github/skills/figma-ui-mapper/references/native-android.md +18 -0
- package/.github/skills/figma-ui-mapper/references/native-ios.md +18 -0
- package/.github/skills/figma-ui-mapper/references/next.md +18 -0
- package/.github/skills/figma-ui-mapper/references/nuxt.md +18 -0
- package/.github/skills/figma-ui-mapper/references/react-figma-guideline.md +21 -0
- package/.github/skills/figma-ui-mapper/references/react-native.md +18 -0
- package/.github/skills/figma-ui-mapper/references/react.md +18 -0
- package/.github/skills/figma-ui-mapper/references/script-usage.md +46 -0
- package/.github/skills/figma-ui-mapper/references/svelte.md +18 -0
- package/.github/skills/figma-ui-mapper/references/vue.md +18 -0
- package/.github/skills/figma-ui-mapper/references/workflow.md +74 -0
- package/.github/skills/figma-ui-mapper/scripts/generate-page-through-figma.js +635 -0
- package/.github/skills/figma-ui-mapper/scripts/generate-react-page-through-figma.js +4 -0
- package/.github/skills/frontend-task-breakdown/SKILL.md +734 -0
- package/.github/skills/md-file-converter/SKILL.md +291 -0
- package/.github/skills/md-file-converter/config/formats.json +114 -0
- package/.github/skills/md-file-converter/extractors/extract-docx.sh +120 -0
- package/.github/skills/md-file-converter/extractors/extract-eml.py +108 -0
- package/.github/skills/md-file-converter/extractors/extract-pdf.sh +97 -0
- package/.github/skills/md-file-converter/extractors/extract-pptx.py +143 -0
- package/.github/skills/md-file-converter/extractors/extract-xlsx.py +175 -0
- package/.github/skills/md-file-converter/scripts/check-tools.sh +47 -0
- package/.github/skills/md-file-converter/scripts/extract-archive.sh +83 -0
- package/.github/skills/md-file-converter/scripts/extract-ocr.sh +77 -0
- package/.github/skills/md-file-converter/scripts/get-metadata.sh +57 -0
- package/.github/skills/md-file-converter/templates/output.md +73 -0
- package/.github/skills/md-file-converter/templates/unsupported-object.md +6 -0
- package/.github/skills/mockAPI-contract-generator/SKILL.md +607 -0
- package/.github/skills/test-case-validator/CHANGELOG.md +155 -0
- package/.github/skills/test-case-validator/CONFIGURATION.md +130 -0
- package/.github/skills/test-case-validator/EXAMPLES.md +50 -0
- package/.github/skills/test-case-validator/QUALITY_SCORING.md +98 -0
- package/.github/skills/test-case-validator/README.md +111 -0
- package/.github/skills/test-case-validator/REPORT_TEMPLATE.md +116 -0
- package/.github/skills/test-case-validator/SKILL.md +209 -0
- package/.github/skills/test-case-validator/SYSTEM_PROMPT.md +127 -0
- package/.github/skills/test-case-validator/TRACEABILITY_ENGINE.md +152 -0
- package/.github/skills/test-case-validator/VALIDATION_RULES.md +411 -0
- package/.github/skills/test-case-validator/config/default.config.yaml +62 -0
- package/.github/skills/test-case-validator/docs/ARCHITECTURE.md +66 -0
- package/.github/skills/test-case-validator/docs/EXTENDING.md +85 -0
- package/.github/skills/test-case-validator/docs/FAQ.md +88 -0
- package/.github/skills/test-case-validator/docs/VERSIONING.md +55 -0
- package/.github/skills/test-case-validator/examples/example-1-manual-qa-ecommerce/input-brd.md +43 -0
- package/.github/skills/test-case-validator/examples/example-1-manual-qa-ecommerce/input-test-cases.csv +9 -0
- package/.github/skills/test-case-validator/examples/example-1-manual-qa-ecommerce/input-user-story.md +29 -0
- package/.github/skills/test-case-validator/examples/example-1-manual-qa-ecommerce/output-report.md +303 -0
- package/.github/skills/test-case-validator/examples/example-2-automated-frontend-suite/input-spec.md +43 -0
- package/.github/skills/test-case-validator/examples/example-2-automated-frontend-suite/input-test-files-index.md +56 -0
- package/.github/skills/test-case-validator/examples/example-2-automated-frontend-suite/output-report.md +274 -0
- package/.github/skills/test-case-validator/prompts/00-applicability-resolution.md +61 -0
- package/.github/skills/test-case-validator/prompts/01-extraction-user-story.md +58 -0
- package/.github/skills/test-case-validator/prompts/02-extraction-brd.md +64 -0
- package/.github/skills/test-case-validator/prompts/03-extraction-test-cases.md +92 -0
- package/.github/skills/test-case-validator/prompts/04-traceability-matrix.md +41 -0
- package/.github/skills/test-case-validator/prompts/05-coverage-analysis.md +46 -0
- package/.github/skills/test-case-validator/prompts/06-missing-scenario-detection.md +32 -0
- package/.github/skills/test-case-validator/prompts/07-duplicate-detection.md +36 -0
- package/.github/skills/test-case-validator/prompts/08-risk-analysis.md +39 -0
- package/.github/skills/test-case-validator/prompts/09-gated-wiring-validation.md +53 -0
- package/.github/skills/test-case-validator/prompts/10-observation-report.md +56 -0
- package/.github/skills/test-case-validator/prompts/11-final-report-assembly.md +57 -0
- package/.github/skills/test-case-validator/templates/coverage-table.md +25 -0
- package/.github/skills/test-case-validator/templates/executive-summary.md +38 -0
- package/.github/skills/test-case-validator/templates/final-summary-block.md +87 -0
- package/.github/skills/test-case-validator/templates/observation-entry.md +41 -0
- package/.github/skills/test-case-validator/templates/rtm-row.md +25 -0
- package/.github/skills/validation-engine-builder/README.md +50 -0
- package/.github/skills/validation-engine-builder/SKILL.md +241 -0
- package/.github/skills/validation-engine-builder/references/core.md +158 -0
- package/.github/skills/validation-engine-builder/references/platform-angular.md +166 -0
- package/.github/skills/validation-engine-builder/references/platform-flutter.md +118 -0
- package/.github/skills/validation-engine-builder/references/platform-react-native.md +170 -0
- package/.github/skills/validation-engine-builder/references/platform-react.md +94 -0
- package/.github/skills/validation-engine-builder/scripts/apply-to-project.js +80 -0
- package/.github/skills/validation-engine-builder/scripts/generate-angular.js +271 -0
- package/.github/skills/validation-engine-builder/scripts/generate-flutter.js +298 -0
- package/.github/skills/validation-engine-builder/scripts/generate-react-native.js +217 -0
- package/.github/skills/validation-engine-builder/scripts/generate-react.js +163 -0
- package/.github/skills/validation-engine-builder/scripts/install-deps.js +53 -0
- package/.github/skills/validation-engine-builder/scripts/shared/detect-platform.js +68 -0
- package/.github/skills/validation-engine-builder/scripts/shared/npm-deps.js +103 -0
- package/.github/skills/validation-engine-builder/scripts/shared/rhf-hook.js +43 -0
- package/.github/skills/validation-engine-builder/scripts/shared/ts-messages-regex.js +62 -0
- package/.github/skills/validation-engine-builder/scripts/shared/util.js +44 -0
- package/.github/skills/validation-engine-builder/scripts/shared/yup-schemas.js +80 -0
- package/.github/skills/validation-engine-builder/template.md +73 -0
- package/.github/skills/validation-engine-builder/templates/messages.json +22 -0
- package/.github/skills/validation-engine-builder/templates/regex.json +16 -0
- package/.github/skills/validation-engine-builder/templates/schemas.json +48 -0
- package/bin/index.js +145 -0
- package/package.json +22 -0
- package/readme.md +0 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# PDF extractor. Tries pdftotext → pandoc → PyPDF2 in order.
|
|
3
|
+
# Usage: bash extractors/extract-pdf.sh <file.pdf> [start_page] [end_page]
|
|
4
|
+
# start_page and end_page are optional (1-based). Omit for full document.
|
|
5
|
+
|
|
6
|
+
FILE="$1"
|
|
7
|
+
START="${2:-}"
|
|
8
|
+
END="${3:-}"
|
|
9
|
+
|
|
10
|
+
if [ -z "$FILE" ]; then
|
|
11
|
+
echo "Usage: extract-pdf.sh <file.pdf> [start_page] [end_page]"
|
|
12
|
+
exit 1
|
|
13
|
+
fi
|
|
14
|
+
|
|
15
|
+
if [ ! -f "$FILE" ]; then
|
|
16
|
+
echo "Error: File not found: $FILE"
|
|
17
|
+
exit 1
|
|
18
|
+
fi
|
|
19
|
+
|
|
20
|
+
echo "=== PDF Extraction ==="
|
|
21
|
+
echo "File : $FILE"
|
|
22
|
+
[ -n "$START" ] && echo "Pages : $START to ${END:-end}"
|
|
23
|
+
echo ""
|
|
24
|
+
|
|
25
|
+
# Strategy 1: pdftotext (poppler-utils) — preserves layout best
|
|
26
|
+
if command -v pdftotext >/dev/null 2>&1; then
|
|
27
|
+
echo "Method: pdftotext"
|
|
28
|
+
echo ""
|
|
29
|
+
echo "--- Content ---"
|
|
30
|
+
if [ -n "$START" ] && [ -n "$END" ]; then
|
|
31
|
+
pdftotext -layout -f "$START" -l "$END" "$FILE" -
|
|
32
|
+
else
|
|
33
|
+
pdftotext -layout "$FILE" -
|
|
34
|
+
fi
|
|
35
|
+
EXIT_CODE=$?
|
|
36
|
+
if [ $EXIT_CODE -eq 0 ]; then
|
|
37
|
+
echo ""
|
|
38
|
+
echo "Extraction Status: SUCCESS (pdftotext)"
|
|
39
|
+
exit 0
|
|
40
|
+
fi
|
|
41
|
+
echo "pdftotext failed (exit $EXIT_CODE), trying fallback..."
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
# Strategy 2: pandoc
|
|
45
|
+
if command -v pandoc >/dev/null 2>&1; then
|
|
46
|
+
echo "Method: pandoc"
|
|
47
|
+
echo ""
|
|
48
|
+
echo "--- Content ---"
|
|
49
|
+
pandoc "$FILE" -t markdown --wrap=none 2>/dev/null
|
|
50
|
+
EXIT_CODE=$?
|
|
51
|
+
if [ $EXIT_CODE -eq 0 ]; then
|
|
52
|
+
echo ""
|
|
53
|
+
echo "Extraction Status: SUCCESS (pandoc)"
|
|
54
|
+
exit 0
|
|
55
|
+
fi
|
|
56
|
+
echo "pandoc failed (exit $EXIT_CODE), trying fallback..."
|
|
57
|
+
fi
|
|
58
|
+
|
|
59
|
+
# Strategy 3: PyPDF2 via Python
|
|
60
|
+
if command -v python3 >/dev/null 2>&1 && python3 -c "import PyPDF2" 2>/dev/null; then
|
|
61
|
+
echo "Method: PyPDF2"
|
|
62
|
+
echo ""
|
|
63
|
+
echo "--- Content ---"
|
|
64
|
+
python3 - "$FILE" "${START:-}" "${END:-}" <<'PYEOF'
|
|
65
|
+
import PyPDF2, sys
|
|
66
|
+
|
|
67
|
+
path = sys.argv[1]
|
|
68
|
+
start = int(sys.argv[2]) - 1 if sys.argv[2] else 0
|
|
69
|
+
end = int(sys.argv[3]) if sys.argv[3] else None
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
with open(path, "rb") as f:
|
|
73
|
+
reader = PyPDF2.PdfReader(f)
|
|
74
|
+
pages = reader.pages[start:end]
|
|
75
|
+
for i, page in enumerate(pages, start + 1):
|
|
76
|
+
print(f"\n--- Page {i} ---\n")
|
|
77
|
+
text = page.extract_text()
|
|
78
|
+
if text:
|
|
79
|
+
print(text)
|
|
80
|
+
else:
|
|
81
|
+
print("[No extractable text on this page — may require OCR]")
|
|
82
|
+
print("\nExtraction Status: SUCCESS (PyPDF2)")
|
|
83
|
+
except Exception as e:
|
|
84
|
+
print(f"PyPDF2 failed: {e}", file=sys.stderr)
|
|
85
|
+
sys.exit(1)
|
|
86
|
+
PYEOF
|
|
87
|
+
exit $?
|
|
88
|
+
fi
|
|
89
|
+
|
|
90
|
+
# All strategies failed
|
|
91
|
+
echo "Extraction Status: FAILED"
|
|
92
|
+
echo "No PDF extractor available."
|
|
93
|
+
echo "Install options:"
|
|
94
|
+
echo " pdftotext : sudo apt install poppler-utils (or brew install poppler)"
|
|
95
|
+
echo " pandoc : https://pandoc.org/installing.html"
|
|
96
|
+
echo " PyPDF2 : pip install PyPDF2"
|
|
97
|
+
exit 1
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
PowerPoint extractor. Converts every slide to Markdown.
|
|
4
|
+
Captures: titles, text boxes, tables, images, charts, speaker notes.
|
|
5
|
+
Usage: python3 extractors/extract-pptx.py <file.pptx> [start_slide] [end_slide]
|
|
6
|
+
Slide numbers are 1-based. Omit to process all slides.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
FILE = sys.argv[1] if len(sys.argv) > 1 else None
|
|
13
|
+
START_SLIDE = int(sys.argv[2]) if len(sys.argv) > 2 else 1
|
|
14
|
+
END_SLIDE = int(sys.argv[3]) if len(sys.argv) > 3 else None
|
|
15
|
+
|
|
16
|
+
if not FILE:
|
|
17
|
+
print("Usage: extract-pptx.py <file.pptx> [start_slide] [end_slide]")
|
|
18
|
+
sys.exit(1)
|
|
19
|
+
|
|
20
|
+
if not os.path.exists(FILE):
|
|
21
|
+
print(f"Error: File not found: {FILE}")
|
|
22
|
+
sys.exit(1)
|
|
23
|
+
|
|
24
|
+
try:
|
|
25
|
+
from pptx import Presentation
|
|
26
|
+
from pptx.util import Inches
|
|
27
|
+
from pptx.enum.shapes import MSO_SHAPE_TYPE
|
|
28
|
+
except ImportError:
|
|
29
|
+
print("Extraction Status: FAILED")
|
|
30
|
+
print("python-pptx not installed. Run: pip install python-pptx")
|
|
31
|
+
sys.exit(1)
|
|
32
|
+
|
|
33
|
+
print(f"=== PowerPoint Extraction ===")
|
|
34
|
+
print(f"File : {FILE}")
|
|
35
|
+
print(f"Slides : {START_SLIDE} to {END_SLIDE or 'end'}")
|
|
36
|
+
print("")
|
|
37
|
+
|
|
38
|
+
prs = Presentation(FILE)
|
|
39
|
+
total_slides = len(prs.slides)
|
|
40
|
+
end = min(END_SLIDE, total_slides) if END_SLIDE else total_slides
|
|
41
|
+
|
|
42
|
+
slide_range = range(START_SLIDE - 1, end)
|
|
43
|
+
|
|
44
|
+
images_found = 0
|
|
45
|
+
tables_found = 0
|
|
46
|
+
charts_found = 0
|
|
47
|
+
notes_found = 0
|
|
48
|
+
|
|
49
|
+
for idx in slide_range:
|
|
50
|
+
slide = prs.slides[idx]
|
|
51
|
+
slide_num = idx + 1
|
|
52
|
+
|
|
53
|
+
print(f"---")
|
|
54
|
+
print(f"## Slide {slide_num} of {total_slides}")
|
|
55
|
+
print("")
|
|
56
|
+
|
|
57
|
+
for shape in slide.shapes:
|
|
58
|
+
# Title
|
|
59
|
+
if shape.shape_type == MSO_SHAPE_TYPE.PLACEHOLDER and hasattr(shape, "placeholder_format"):
|
|
60
|
+
ph_type = shape.placeholder_format.type
|
|
61
|
+
if ph_type is not None and ph_type == 1: # PP_PLACEHOLDER.TITLE = 1
|
|
62
|
+
if shape.has_text_frame and shape.text_frame.text.strip():
|
|
63
|
+
print(f"### {shape.text_frame.text.strip()}")
|
|
64
|
+
print("")
|
|
65
|
+
continue
|
|
66
|
+
|
|
67
|
+
# Text frames
|
|
68
|
+
if shape.has_text_frame:
|
|
69
|
+
text = shape.text_frame.text.strip()
|
|
70
|
+
if text:
|
|
71
|
+
for para in shape.text_frame.paragraphs:
|
|
72
|
+
para_text = para.text.strip()
|
|
73
|
+
if para_text:
|
|
74
|
+
level = para.level
|
|
75
|
+
prefix = " " * level + "- " if level > 0 else ""
|
|
76
|
+
print(f"{prefix}{para_text}")
|
|
77
|
+
print("")
|
|
78
|
+
|
|
79
|
+
# Tables
|
|
80
|
+
if shape.has_table:
|
|
81
|
+
tables_found += 1
|
|
82
|
+
table = shape.table
|
|
83
|
+
print(f"**Table {tables_found}:**\n")
|
|
84
|
+
rows = table.rows
|
|
85
|
+
if rows:
|
|
86
|
+
# Header
|
|
87
|
+
header_cells = [cell.text.strip() for cell in rows[0].cells]
|
|
88
|
+
print("| " + " | ".join(header_cells) + " |")
|
|
89
|
+
print("| " + " | ".join(["---"] * len(header_cells)) + " |")
|
|
90
|
+
for row in rows[1:]:
|
|
91
|
+
cells = [cell.text.strip() for cell in row.cells]
|
|
92
|
+
print("| " + " | ".join(cells) + " |")
|
|
93
|
+
print("")
|
|
94
|
+
|
|
95
|
+
# Charts
|
|
96
|
+
if shape.shape_type == MSO_SHAPE_TYPE.CHART:
|
|
97
|
+
charts_found += 1
|
|
98
|
+
chart = shape.chart
|
|
99
|
+
chart_title = ""
|
|
100
|
+
try:
|
|
101
|
+
chart_title = chart.chart_title.text_frame.text if chart.has_title else "Untitled Chart"
|
|
102
|
+
except Exception:
|
|
103
|
+
chart_title = "Chart"
|
|
104
|
+
|
|
105
|
+
print(f"**Chart {charts_found}: {chart_title}**\n")
|
|
106
|
+
|
|
107
|
+
try:
|
|
108
|
+
for series in chart.series:
|
|
109
|
+
series_name = series.name if series.name else "Series"
|
|
110
|
+
values = list(series.values) if series.values else []
|
|
111
|
+
print(f"- Series: {series_name}")
|
|
112
|
+
if values:
|
|
113
|
+
print(f" Values: {values}")
|
|
114
|
+
except Exception:
|
|
115
|
+
print(" [Chart data not extractable — describe visually if needed]")
|
|
116
|
+
print("")
|
|
117
|
+
|
|
118
|
+
# Images
|
|
119
|
+
if shape.shape_type == MSO_SHAPE_TYPE.PICTURE:
|
|
120
|
+
images_found += 1
|
|
121
|
+
img_name = getattr(shape, "name", f"image{images_found}")
|
|
122
|
+
print(f"")
|
|
123
|
+
print(f"> Image on slide {slide_num}. Run OCR extractor if text extraction needed.")
|
|
124
|
+
print("")
|
|
125
|
+
|
|
126
|
+
# Speaker notes
|
|
127
|
+
if slide.has_notes_slide:
|
|
128
|
+
notes_text = slide.notes_slide.notes_text_frame.text.strip()
|
|
129
|
+
if notes_text:
|
|
130
|
+
notes_found += 1
|
|
131
|
+
print(f"**Speaker Notes:**")
|
|
132
|
+
print(f"> {notes_text}")
|
|
133
|
+
print("")
|
|
134
|
+
|
|
135
|
+
print("---")
|
|
136
|
+
print(f"")
|
|
137
|
+
print(f"=== Extraction Summary ===")
|
|
138
|
+
print(f"Slides processed : {len(slide_range)} of {total_slides}")
|
|
139
|
+
print(f"Tables found : {tables_found}")
|
|
140
|
+
print(f"Charts found : {charts_found}")
|
|
141
|
+
print(f"Images found : {images_found}")
|
|
142
|
+
print(f"Slides with notes: {notes_found}")
|
|
143
|
+
print(f"Extraction Status: SUCCESS (python-pptx)")
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Excel / ODS extractor. Converts every worksheet to Markdown tables.
|
|
4
|
+
Captures: cell values, formulas, merged cells, comments, hidden sheets.
|
|
5
|
+
Usage: python3 extractors/extract-xlsx.py <file> [sheet_name]
|
|
6
|
+
Omit sheet_name to process all sheets.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
import sys
|
|
10
|
+
import os
|
|
11
|
+
|
|
12
|
+
FILE = sys.argv[1] if len(sys.argv) > 1 else None
|
|
13
|
+
SHEET_NAME = sys.argv[2] if len(sys.argv) > 2 else None
|
|
14
|
+
|
|
15
|
+
if not FILE:
|
|
16
|
+
print("Usage: extract-xlsx.py <file.xlsx> [sheet_name]")
|
|
17
|
+
sys.exit(1)
|
|
18
|
+
|
|
19
|
+
if not os.path.exists(FILE):
|
|
20
|
+
print(f"Error: File not found: {FILE}")
|
|
21
|
+
sys.exit(1)
|
|
22
|
+
|
|
23
|
+
EXT = os.path.splitext(FILE)[1].lower()
|
|
24
|
+
|
|
25
|
+
# ── openpyxl (primary — XLSX/XLSM) ─────────────────────────────────────────
|
|
26
|
+
def extract_openpyxl(path, target_sheet=None):
|
|
27
|
+
import openpyxl
|
|
28
|
+
from openpyxl.utils import get_column_letter
|
|
29
|
+
|
|
30
|
+
wb = openpyxl.load_workbook(path, data_only=False) # data_only=False keeps formulas
|
|
31
|
+
wb_vals = openpyxl.load_workbook(path, data_only=True) # data_only=True gets computed values
|
|
32
|
+
|
|
33
|
+
sheet_names = [target_sheet] if target_sheet else wb.sheetnames
|
|
34
|
+
|
|
35
|
+
for name in sheet_names:
|
|
36
|
+
if name not in wb.sheetnames:
|
|
37
|
+
print(f"## Sheet: {name}\n\n> Sheet not found.\n")
|
|
38
|
+
continue
|
|
39
|
+
|
|
40
|
+
ws = wb[name]
|
|
41
|
+
ws_vals = wb_vals[name] if name in wb_vals.sheetnames else ws
|
|
42
|
+
hidden = ws.sheet_state != "visible"
|
|
43
|
+
|
|
44
|
+
print(f"## Sheet: {name}{' [HIDDEN]' if hidden else ''}\n")
|
|
45
|
+
|
|
46
|
+
# Dimensions
|
|
47
|
+
if ws.max_row == 0:
|
|
48
|
+
print("> Empty sheet.\n")
|
|
49
|
+
continue
|
|
50
|
+
|
|
51
|
+
# Build table
|
|
52
|
+
rows = list(ws.iter_rows())
|
|
53
|
+
if not rows:
|
|
54
|
+
print("> Empty sheet.\n")
|
|
55
|
+
continue
|
|
56
|
+
|
|
57
|
+
# Collect all cell data
|
|
58
|
+
table_data = []
|
|
59
|
+
for row in rows:
|
|
60
|
+
row_data = []
|
|
61
|
+
for cell in row:
|
|
62
|
+
formula = str(cell.value) if cell.value is not None else ""
|
|
63
|
+
computed = ws_vals.cell(cell.row, cell.column).value
|
|
64
|
+
computed_str = str(computed) if computed is not None else ""
|
|
65
|
+
|
|
66
|
+
if formula.startswith("="):
|
|
67
|
+
display = f"{formula} → {computed_str}"
|
|
68
|
+
else:
|
|
69
|
+
display = formula
|
|
70
|
+
|
|
71
|
+
# Check for comment
|
|
72
|
+
if cell.comment:
|
|
73
|
+
display += f" [Comment: {cell.comment.text.strip()}]"
|
|
74
|
+
|
|
75
|
+
row_data.append(display)
|
|
76
|
+
table_data.append(row_data)
|
|
77
|
+
|
|
78
|
+
# Render as Markdown table
|
|
79
|
+
if table_data:
|
|
80
|
+
# Header row
|
|
81
|
+
header = table_data[0]
|
|
82
|
+
col_count = max(len(r) for r in table_data)
|
|
83
|
+
|
|
84
|
+
# Pad all rows to same column count
|
|
85
|
+
for r in table_data:
|
|
86
|
+
while len(r) < col_count:
|
|
87
|
+
r.append("")
|
|
88
|
+
|
|
89
|
+
# Print header
|
|
90
|
+
print("| " + " | ".join(header) + " |")
|
|
91
|
+
print("| " + " | ".join(["---"] * col_count) + " |")
|
|
92
|
+
|
|
93
|
+
# Print data rows
|
|
94
|
+
for row in table_data[1:]:
|
|
95
|
+
print("| " + " | ".join(row) + " |")
|
|
96
|
+
|
|
97
|
+
# Named ranges
|
|
98
|
+
if hasattr(wb, 'defined_names') and wb.defined_names:
|
|
99
|
+
named = []
|
|
100
|
+
defined_names_iter = (
|
|
101
|
+
wb.defined_names.definedName if hasattr(wb.defined_names, 'definedName')
|
|
102
|
+
else wb.defined_names.values()
|
|
103
|
+
)
|
|
104
|
+
for defn in defined_names_iter:
|
|
105
|
+
if name in str(defn.attr_text):
|
|
106
|
+
named.append(f" - `{defn.name}` = `{defn.attr_text}`")
|
|
107
|
+
if named:
|
|
108
|
+
print("\n**Named Ranges:**")
|
|
109
|
+
print("\n".join(named))
|
|
110
|
+
|
|
111
|
+
print("")
|
|
112
|
+
|
|
113
|
+
print("Extraction Status: SUCCESS (openpyxl)")
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
# ── xlrd (fallback — older .xls) ────────────────────────────────────────────
|
|
117
|
+
def extract_xlrd(path, target_sheet=None):
|
|
118
|
+
import xlrd
|
|
119
|
+
wb = xlrd.open_workbook(path)
|
|
120
|
+
sheet_names = [target_sheet] if target_sheet else wb.sheet_names()
|
|
121
|
+
|
|
122
|
+
for name in sheet_names:
|
|
123
|
+
try:
|
|
124
|
+
ws = wb.sheet_by_name(name)
|
|
125
|
+
except xlrd.XLRDError:
|
|
126
|
+
print(f"## Sheet: {name}\n\n> Sheet not found.\n")
|
|
127
|
+
continue
|
|
128
|
+
|
|
129
|
+
print(f"## Sheet: {name}\n")
|
|
130
|
+
|
|
131
|
+
if ws.nrows == 0:
|
|
132
|
+
print("> Empty sheet.\n")
|
|
133
|
+
continue
|
|
134
|
+
|
|
135
|
+
rows = [[str(ws.cell_value(r, c)) for c in range(ws.ncols)] for r in range(ws.nrows)]
|
|
136
|
+
|
|
137
|
+
print("| " + " | ".join(rows[0]) + " |")
|
|
138
|
+
print("| " + " | ".join(["---"] * ws.ncols) + " |")
|
|
139
|
+
for row in rows[1:]:
|
|
140
|
+
print("| " + " | ".join(row) + " |")
|
|
141
|
+
|
|
142
|
+
print("")
|
|
143
|
+
|
|
144
|
+
print("Extraction Status: SUCCESS (xlrd)")
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
# ── Main dispatch ────────────────────────────────────────────────────────────
|
|
148
|
+
print(f"=== Excel Extraction ===")
|
|
149
|
+
print(f"File : {FILE}")
|
|
150
|
+
print(f"Sheet : {SHEET_NAME or 'ALL'}")
|
|
151
|
+
print("")
|
|
152
|
+
|
|
153
|
+
if EXT in (".xlsx", ".xlsm", ".ods"):
|
|
154
|
+
try:
|
|
155
|
+
extract_openpyxl(FILE, SHEET_NAME)
|
|
156
|
+
sys.exit(0)
|
|
157
|
+
except ImportError:
|
|
158
|
+
print("openpyxl not available, trying xlrd...")
|
|
159
|
+
except Exception as e:
|
|
160
|
+
print(f"openpyxl failed: {e}, trying xlrd...")
|
|
161
|
+
|
|
162
|
+
if EXT in (".xls", ".xlsx"):
|
|
163
|
+
try:
|
|
164
|
+
extract_xlrd(FILE, SHEET_NAME)
|
|
165
|
+
sys.exit(0)
|
|
166
|
+
except ImportError:
|
|
167
|
+
print("xlrd not available.")
|
|
168
|
+
except Exception as e:
|
|
169
|
+
print(f"xlrd failed: {e}")
|
|
170
|
+
|
|
171
|
+
print("Extraction Status: FAILED")
|
|
172
|
+
print("No Excel library available.")
|
|
173
|
+
print("Install: pip install openpyxl (for .xlsx)")
|
|
174
|
+
print("Install: pip install xlrd (for legacy .xls)")
|
|
175
|
+
sys.exit(1)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Detects which extraction tools are available in the current environment.
|
|
3
|
+
# Run this FIRST before any conversion. Output is used to determine strategy.
|
|
4
|
+
# Usage: bash scripts/check-tools.sh
|
|
5
|
+
|
|
6
|
+
echo "=== Tool Detection Report ==="
|
|
7
|
+
echo ""
|
|
8
|
+
|
|
9
|
+
echo "--- Document Extractors ---"
|
|
10
|
+
command -v pandoc >/dev/null 2>&1 && echo "pandoc : AVAILABLE" || echo "pandoc : NOT available (DOCX/ODT/RTF fallback unavailable)"
|
|
11
|
+
command -v pdftotext >/dev/null 2>&1 && echo "pdftotext : AVAILABLE" || echo "pdftotext : NOT available (PDF text extraction unavailable)"
|
|
12
|
+
command -v pdfinfo >/dev/null 2>&1 && echo "pdfinfo : AVAILABLE" || echo "pdfinfo : NOT available (PDF metadata unavailable)"
|
|
13
|
+
command -v pdfimages >/dev/null 2>&1 && echo "pdfimages : AVAILABLE" || echo "pdfimages : NOT available (PDF image listing unavailable)"
|
|
14
|
+
command -v unrtf >/dev/null 2>&1 && echo "unrtf : AVAILABLE" || echo "unrtf : NOT available (RTF fallback unavailable)"
|
|
15
|
+
|
|
16
|
+
echo ""
|
|
17
|
+
echo "--- Python & Libraries ---"
|
|
18
|
+
command -v python3 >/dev/null 2>&1 && echo "python3 : AVAILABLE ($(python3 --version 2>&1))" || echo "python3 : NOT available"
|
|
19
|
+
|
|
20
|
+
if command -v python3 >/dev/null 2>&1; then
|
|
21
|
+
python3 -c "import openpyxl" 2>/dev/null && echo "openpyxl : AVAILABLE" || echo "openpyxl : NOT available (Excel extraction unavailable — pip install openpyxl)"
|
|
22
|
+
python3 -c "from pptx import Presentation" 2>/dev/null && echo "python-pptx : AVAILABLE" || echo "python-pptx : NOT available (PowerPoint extraction unavailable — pip install python-pptx)"
|
|
23
|
+
python3 -c "import PyPDF2" 2>/dev/null && echo "PyPDF2 : AVAILABLE" || echo "PyPDF2 : NOT available (PDF fallback unavailable)"
|
|
24
|
+
python3 -c "import easyocr" 2>/dev/null && echo "easyocr : AVAILABLE" || echo "easyocr : NOT available (OCR fallback unavailable — pip install easyocr)"
|
|
25
|
+
fi
|
|
26
|
+
|
|
27
|
+
echo ""
|
|
28
|
+
echo "--- OCR Tools ---"
|
|
29
|
+
command -v tesseract >/dev/null 2>&1 && echo "tesseract : AVAILABLE ($(tesseract --version 2>&1 | head -1))" || echo "tesseract : NOT available (primary OCR unavailable — install tesseract-ocr)"
|
|
30
|
+
command -v exiftool >/dev/null 2>&1 && echo "exiftool : AVAILABLE" || echo "exiftool : NOT available (extended metadata unavailable)"
|
|
31
|
+
|
|
32
|
+
echo ""
|
|
33
|
+
echo "--- Archive Tools ---"
|
|
34
|
+
command -v unzip >/dev/null 2>&1 && echo "unzip : AVAILABLE" || echo "unzip : NOT available (.zip extraction unavailable)"
|
|
35
|
+
command -v tar >/dev/null 2>&1 && echo "tar : AVAILABLE" || echo "tar : NOT available (.tar/.gz extraction unavailable)"
|
|
36
|
+
command -v 7z >/dev/null 2>&1 && echo "7z : AVAILABLE" || echo "7z : NOT available (.7z extraction unavailable)"
|
|
37
|
+
command -v unrar >/dev/null 2>&1 && echo "unrar : AVAILABLE" || echo "unrar : NOT available (.rar extraction unavailable)"
|
|
38
|
+
command -v gunzip >/dev/null 2>&1 && echo "gunzip : AVAILABLE" || echo "gunzip : NOT available (.gz extraction unavailable)"
|
|
39
|
+
|
|
40
|
+
echo ""
|
|
41
|
+
echo "--- Core Utilities ---"
|
|
42
|
+
command -v file >/dev/null 2>&1 && echo "file : AVAILABLE" || echo "file : NOT available"
|
|
43
|
+
command -v stat >/dev/null 2>&1 && echo "stat : AVAILABLE" || echo "stat : NOT available"
|
|
44
|
+
command -v wc >/dev/null 2>&1 && echo "wc : AVAILABLE" || echo "wc : NOT available"
|
|
45
|
+
|
|
46
|
+
echo ""
|
|
47
|
+
echo "=== End of Tool Detection ==="
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Extracts any supported archive format into a target directory.
|
|
3
|
+
# Usage: bash scripts/extract-archive.sh <archive_path> <output_dir>
|
|
4
|
+
# After extraction, lists all files for Claude to process individually.
|
|
5
|
+
|
|
6
|
+
ARCHIVE="$1"
|
|
7
|
+
OUTPUT_DIR="$2"
|
|
8
|
+
|
|
9
|
+
if [ -z "$ARCHIVE" ] || [ -z "$OUTPUT_DIR" ]; then
|
|
10
|
+
echo "Usage: extract-archive.sh <archive_path> <output_dir>"
|
|
11
|
+
exit 1
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
if [ ! -f "$ARCHIVE" ]; then
|
|
15
|
+
echo "Error: Archive not found: $ARCHIVE"
|
|
16
|
+
exit 1
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
mkdir -p "$OUTPUT_DIR"
|
|
20
|
+
|
|
21
|
+
FILENAME=$(basename "$ARCHIVE")
|
|
22
|
+
EXT_LOWER=$(echo "$FILENAME" | tr '[:upper:]' '[:lower:]')
|
|
23
|
+
|
|
24
|
+
echo "=== Archive Extraction ==="
|
|
25
|
+
echo "Archive : $ARCHIVE"
|
|
26
|
+
echo "Output : $OUTPUT_DIR"
|
|
27
|
+
echo ""
|
|
28
|
+
|
|
29
|
+
# Detect format and extract
|
|
30
|
+
if echo "$EXT_LOWER" | grep -q '\.zip$'; then
|
|
31
|
+
echo "Format: ZIP"
|
|
32
|
+
unzip -o "$ARCHIVE" -d "$OUTPUT_DIR" && echo "Extraction: SUCCESS" || { echo "Extraction: FAILED"; exit 1; }
|
|
33
|
+
|
|
34
|
+
elif echo "$EXT_LOWER" | grep -qE '\.(tar\.gz|tgz)$'; then
|
|
35
|
+
echo "Format: TAR.GZ"
|
|
36
|
+
tar -xzf "$ARCHIVE" -C "$OUTPUT_DIR" && echo "Extraction: SUCCESS" || { echo "Extraction: FAILED"; exit 1; }
|
|
37
|
+
|
|
38
|
+
elif echo "$EXT_LOWER" | grep -q '\.tar\.bz2$'; then
|
|
39
|
+
echo "Format: TAR.BZ2"
|
|
40
|
+
tar -xjf "$ARCHIVE" -C "$OUTPUT_DIR" && echo "Extraction: SUCCESS" || { echo "Extraction: FAILED"; exit 1; }
|
|
41
|
+
|
|
42
|
+
elif echo "$EXT_LOWER" | grep -q '\.tar\.xz$'; then
|
|
43
|
+
echo "Format: TAR.XZ"
|
|
44
|
+
tar -xJf "$ARCHIVE" -C "$OUTPUT_DIR" && echo "Extraction: SUCCESS" || { echo "Extraction: FAILED"; exit 1; }
|
|
45
|
+
|
|
46
|
+
elif echo "$EXT_LOWER" | grep -q '\.tar$'; then
|
|
47
|
+
echo "Format: TAR"
|
|
48
|
+
tar -xf "$ARCHIVE" -C "$OUTPUT_DIR" && echo "Extraction: SUCCESS" || { echo "Extraction: FAILED"; exit 1; }
|
|
49
|
+
|
|
50
|
+
elif echo "$EXT_LOWER" | grep -q '\.gz$'; then
|
|
51
|
+
echo "Format: GZ (single file)"
|
|
52
|
+
DEST="$OUTPUT_DIR/$(basename "$ARCHIVE" .gz)"
|
|
53
|
+
gunzip -c "$ARCHIVE" > "$DEST" && echo "Extraction: SUCCESS" || { echo "Extraction: FAILED"; exit 1; }
|
|
54
|
+
|
|
55
|
+
elif echo "$EXT_LOWER" | grep -q '\.7z$'; then
|
|
56
|
+
echo "Format: 7Z"
|
|
57
|
+
if command -v 7z >/dev/null 2>&1; then
|
|
58
|
+
7z x "$ARCHIVE" -o"$OUTPUT_DIR" -y && echo "Extraction: SUCCESS" || { echo "Extraction: FAILED"; exit 1; }
|
|
59
|
+
else
|
|
60
|
+
echo "Error: 7z not installed. Run: apt install p7zip-full"
|
|
61
|
+
exit 1
|
|
62
|
+
fi
|
|
63
|
+
|
|
64
|
+
elif echo "$EXT_LOWER" | grep -q '\.rar$'; then
|
|
65
|
+
echo "Format: RAR"
|
|
66
|
+
if command -v unrar >/dev/null 2>&1; then
|
|
67
|
+
unrar x "$ARCHIVE" "$OUTPUT_DIR/" && echo "Extraction: SUCCESS" || { echo "Extraction: FAILED"; exit 1; }
|
|
68
|
+
else
|
|
69
|
+
echo "Error: unrar not installed. Run: apt install unrar"
|
|
70
|
+
exit 1
|
|
71
|
+
fi
|
|
72
|
+
|
|
73
|
+
else
|
|
74
|
+
echo "Error: Unsupported archive format: $FILENAME"
|
|
75
|
+
exit 1
|
|
76
|
+
fi
|
|
77
|
+
|
|
78
|
+
echo ""
|
|
79
|
+
echo "=== Extracted Files ==="
|
|
80
|
+
find "$OUTPUT_DIR" -type f | sort
|
|
81
|
+
echo ""
|
|
82
|
+
echo "Total files: $(find "$OUTPUT_DIR" -type f | wc -l)"
|
|
83
|
+
echo "=== End Extraction ==="
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# OCR extractor for image files. Tries tesseract first, then easyocr.
|
|
3
|
+
# Usage: bash scripts/extract-ocr.sh <image_path> [language]
|
|
4
|
+
# language defaults to "eng". For multi-language: "eng+fra"
|
|
5
|
+
|
|
6
|
+
IMAGE="$1"
|
|
7
|
+
LANG="${2:-eng}"
|
|
8
|
+
|
|
9
|
+
if [ -z "$IMAGE" ]; then
|
|
10
|
+
echo "Usage: extract-ocr.sh <image_path> [language]"
|
|
11
|
+
exit 1
|
|
12
|
+
fi
|
|
13
|
+
|
|
14
|
+
if [ ! -f "$IMAGE" ]; then
|
|
15
|
+
echo "Error: Image not found: $IMAGE"
|
|
16
|
+
exit 1
|
|
17
|
+
fi
|
|
18
|
+
|
|
19
|
+
echo "=== OCR Extraction ==="
|
|
20
|
+
echo "Image : $IMAGE"
|
|
21
|
+
echo "Language : $LANG"
|
|
22
|
+
echo ""
|
|
23
|
+
|
|
24
|
+
# Strategy 1: tesseract (preferred — fast, no GPU needed)
|
|
25
|
+
if command -v tesseract >/dev/null 2>&1; then
|
|
26
|
+
echo "Method: tesseract"
|
|
27
|
+
echo ""
|
|
28
|
+
echo "--- Extracted Text ---"
|
|
29
|
+
tesseract "$IMAGE" stdout -l "$LANG" 2>/dev/null
|
|
30
|
+
EXIT_CODE=$?
|
|
31
|
+
if [ $EXIT_CODE -eq 0 ]; then
|
|
32
|
+
echo ""
|
|
33
|
+
echo "OCR Status: SUCCESS (tesseract)"
|
|
34
|
+
exit 0
|
|
35
|
+
else
|
|
36
|
+
echo "tesseract failed (exit $EXIT_CODE), trying fallback..."
|
|
37
|
+
fi
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Strategy 2: easyocr via Python
|
|
41
|
+
if command -v python3 >/dev/null 2>&1 && python3 -c "import easyocr" 2>/dev/null; then
|
|
42
|
+
echo "Method: easyocr"
|
|
43
|
+
echo ""
|
|
44
|
+
echo "--- Extracted Text ---"
|
|
45
|
+
python3 - "$IMAGE" "$LANG" <<'PYEOF'
|
|
46
|
+
import easyocr
|
|
47
|
+
import sys
|
|
48
|
+
|
|
49
|
+
image_path = sys.argv[1]
|
|
50
|
+
lang_arg = sys.argv[2] if len(sys.argv) > 2 else "en"
|
|
51
|
+
|
|
52
|
+
# easyocr uses 2-letter codes: eng->en, fra->fr, etc.
|
|
53
|
+
lang = lang_arg.split("+")[0][:2]
|
|
54
|
+
|
|
55
|
+
try:
|
|
56
|
+
reader = easyocr.Reader([lang], gpu=False, verbose=False)
|
|
57
|
+
results = reader.readtext(image_path, detail=0, paragraph=True)
|
|
58
|
+
for line in results:
|
|
59
|
+
print(line)
|
|
60
|
+
print("")
|
|
61
|
+
print("OCR Status: SUCCESS (easyocr)")
|
|
62
|
+
except Exception as e:
|
|
63
|
+
print(f"easyocr failed: {e}", file=sys.stderr)
|
|
64
|
+
sys.exit(1)
|
|
65
|
+
PYEOF
|
|
66
|
+
exit $?
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
# No OCR tool available
|
|
70
|
+
echo "OCR Status: FAILED"
|
|
71
|
+
echo "No OCR tool available."
|
|
72
|
+
echo "Install options:"
|
|
73
|
+
echo " tesseract : sudo apt install tesseract-ocr (or brew install tesseract)"
|
|
74
|
+
echo " easyocr : pip install easyocr"
|
|
75
|
+
echo ""
|
|
76
|
+
echo "Alternative: Upload the image directly into the Claude chat window to use vision-based OCR."
|
|
77
|
+
exit 1
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Universal metadata extractor. Tries multiple tools in priority order.
|
|
3
|
+
# Usage: bash scripts/get-metadata.sh <file_path>
|
|
4
|
+
# Output: key-value pairs, one per line
|
|
5
|
+
|
|
6
|
+
FILE="$1"
|
|
7
|
+
|
|
8
|
+
if [ -z "$FILE" ]; then
|
|
9
|
+
echo "Usage: get-metadata.sh <file_path>"
|
|
10
|
+
exit 1
|
|
11
|
+
fi
|
|
12
|
+
|
|
13
|
+
if [ ! -f "$FILE" ]; then
|
|
14
|
+
echo "Error: File not found: $FILE"
|
|
15
|
+
exit 1
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
echo "=== File Metadata ==="
|
|
19
|
+
echo "File Name : $(basename "$FILE")"
|
|
20
|
+
echo "File Path : $(realpath "$FILE" 2>/dev/null || echo "$FILE")"
|
|
21
|
+
echo "File Size : $(wc -c < "$FILE" 2>/dev/null) bytes"
|
|
22
|
+
echo "MIME Type : $(file --mime-type -b "$FILE" 2>/dev/null || echo "Not Available")"
|
|
23
|
+
echo "Encoding : $(file -b "$FILE" 2>/dev/null || echo "Not Available")"
|
|
24
|
+
|
|
25
|
+
# stat for timestamps (cross-platform safe subset)
|
|
26
|
+
if command -v stat >/dev/null 2>&1; then
|
|
27
|
+
echo "Modified Date : $(stat -c '%y' "$FILE" 2>/dev/null || stat -f '%Sm' "$FILE" 2>/dev/null || echo "Not Available")"
|
|
28
|
+
fi
|
|
29
|
+
|
|
30
|
+
EXT="${FILE##*.}"
|
|
31
|
+
EXT_LOWER=$(echo "$EXT" | tr '[:upper:]' '[:lower:]')
|
|
32
|
+
|
|
33
|
+
# PDF-specific metadata
|
|
34
|
+
if [ "$EXT_LOWER" = "pdf" ] && command -v pdfinfo >/dev/null 2>&1; then
|
|
35
|
+
echo ""
|
|
36
|
+
echo "=== PDF Metadata (pdfinfo) ==="
|
|
37
|
+
pdfinfo "$FILE" 2>/dev/null || echo "pdfinfo failed"
|
|
38
|
+
fi
|
|
39
|
+
|
|
40
|
+
# Extended metadata via exiftool (universal)
|
|
41
|
+
if command -v exiftool >/dev/null 2>&1; then
|
|
42
|
+
echo ""
|
|
43
|
+
echo "=== Extended Metadata (exiftool) ==="
|
|
44
|
+
exiftool "$FILE" 2>/dev/null || echo "exiftool failed"
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
# Line/word count for text files
|
|
48
|
+
if file -b "$FILE" 2>/dev/null | grep -qi "text"; then
|
|
49
|
+
echo ""
|
|
50
|
+
echo "=== Text Statistics ==="
|
|
51
|
+
echo "Line Count : $(wc -l < "$FILE" 2>/dev/null)"
|
|
52
|
+
echo "Word Count : $(wc -w < "$FILE" 2>/dev/null)"
|
|
53
|
+
echo "Char Count : $(wc -m < "$FILE" 2>/dev/null)"
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
echo ""
|
|
57
|
+
echo "=== End Metadata ==="
|