convert_with_ai.py 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. #!/usr/bin/env python3
  2. """
  3. Convert documents to Markdown with AI-enhanced image descriptions.
  4. This script demonstrates how to use MarkItDown with OpenRouter to generate
  5. detailed descriptions of images in documents (PowerPoint, PDFs with images, etc.)
  6. """
  7. import argparse
  8. import os
  9. import sys
  10. from pathlib import Path
  11. from markitdown import MarkItDown
  12. from openai import OpenAI
  13. # Predefined prompts for different use cases
  14. PROMPTS = {
  15. 'scientific': """
  16. Analyze this scientific image or diagram. Provide:
  17. 1. Type of visualization (graph, chart, microscopy, diagram, etc.)
  18. 2. Key data points, trends, or patterns
  19. 3. Axes labels, legends, and scales
  20. 4. Notable features or findings
  21. 5. Scientific context and significance
  22. Be precise, technical, and detailed.
  23. """.strip(),
  24. 'presentation': """
  25. Describe this presentation slide image. Include:
  26. 1. Main visual elements and their arrangement
  27. 2. Key points or messages conveyed
  28. 3. Data or information presented
  29. 4. Visual hierarchy and emphasis
  30. Keep the description clear and informative.
  31. """.strip(),
  32. 'general': """
  33. Describe this image in detail. Include:
  34. 1. Main subjects and objects
  35. 2. Visual composition and layout
  36. 3. Text content (if any)
  37. 4. Notable details
  38. 5. Overall context and purpose
  39. Be comprehensive and accurate.
  40. """.strip(),
  41. 'data_viz': """
  42. Analyze this data visualization. Provide:
  43. 1. Type of chart/graph (bar, line, scatter, pie, etc.)
  44. 2. Variables and axes
  45. 3. Data ranges and scales
  46. 4. Key patterns, trends, or outliers
  47. 5. Statistical insights
  48. Focus on quantitative accuracy.
  49. """.strip(),
  50. 'medical': """
  51. Describe this medical image. Include:
  52. 1. Type of medical imaging (X-ray, MRI, CT, microscopy, etc.)
  53. 2. Anatomical structures visible
  54. 3. Notable findings or abnormalities
  55. 4. Image quality and contrast
  56. 5. Clinical relevance
  57. Be professional and precise.
  58. """.strip()
  59. }
  60. def convert_with_ai(
  61. input_file: Path,
  62. output_file: Path,
  63. api_key: str,
  64. model: str = "anthropic/claude-opus-4.5",
  65. prompt_type: str = "general",
  66. custom_prompt: str = None
  67. ) -> bool:
  68. """
  69. Convert a file to Markdown with AI image descriptions.
  70. Args:
  71. input_file: Path to input file
  72. output_file: Path to output Markdown file
  73. api_key: OpenRouter API key
  74. model: Model name (default: anthropic/claude-opus-4.5)
  75. prompt_type: Type of prompt to use
  76. custom_prompt: Custom prompt (overrides prompt_type)
  77. Returns:
  78. True if successful, False otherwise
  79. """
  80. try:
  81. # Initialize OpenRouter client (OpenAI-compatible)
  82. client = OpenAI(
  83. api_key=api_key,
  84. base_url="https://openrouter.ai/api/v1"
  85. )
  86. # Select prompt
  87. if custom_prompt:
  88. prompt = custom_prompt
  89. else:
  90. prompt = PROMPTS.get(prompt_type, PROMPTS['general'])
  91. print(f"Using model: {model}")
  92. print(f"Prompt type: {prompt_type if not custom_prompt else 'custom'}")
  93. print(f"Converting: {input_file}")
  94. # Create MarkItDown with AI support
  95. md = MarkItDown(
  96. llm_client=client,
  97. llm_model=model,
  98. llm_prompt=prompt
  99. )
  100. # Convert file
  101. result = md.convert(str(input_file))
  102. # Create output with metadata
  103. content = f"# {result.title or input_file.stem}\n\n"
  104. content += f"**Source**: {input_file.name}\n"
  105. content += f"**Format**: {input_file.suffix}\n"
  106. content += f"**AI Model**: {model}\n"
  107. content += f"**Prompt Type**: {prompt_type if not custom_prompt else 'custom'}\n\n"
  108. content += "---\n\n"
  109. content += result.text_content
  110. # Write output
  111. output_file.parent.mkdir(parents=True, exist_ok=True)
  112. output_file.write_text(content, encoding='utf-8')
  113. print(f"✓ Successfully converted to: {output_file}")
  114. return True
  115. except Exception as e:
  116. print(f"✗ Error: {str(e)}", file=sys.stderr)
  117. return False
  118. def main():
  119. parser = argparse.ArgumentParser(
  120. description="Convert documents to Markdown with AI-enhanced image descriptions",
  121. formatter_class=argparse.RawDescriptionHelpFormatter,
  122. epilog=f"""
  123. Available prompt types:
  124. scientific - For scientific diagrams, graphs, and charts
  125. presentation - For presentation slides
  126. general - General-purpose image description
  127. data_viz - For data visualizations and charts
  128. medical - For medical imaging
  129. Examples:
  130. # Convert a scientific paper
  131. python convert_with_ai.py paper.pdf output.md --prompt-type scientific
  132. # Convert a presentation with custom model
  133. python convert_with_ai.py slides.pptx slides.md --model anthropic/claude-opus-4.5 --prompt-type presentation
  134. # Use custom prompt with advanced vision model
  135. python convert_with_ai.py diagram.png diagram.md --model anthropic/claude-opus-4.5 --custom-prompt "Describe this technical diagram"
  136. # Set API key via environment variable
  137. export OPENROUTER_API_KEY="sk-or-v1-..."
  138. python convert_with_ai.py image.jpg image.md
  139. Environment Variables:
  140. OPENROUTER_API_KEY OpenRouter API key (required if not passed via --api-key)
  141. Popular Models (use with --model):
  142. anthropic/claude-opus-4.5 - Recommended for scientific vision
  143. google/gemini-3-pro-preview - Gemini Pro Vision
  144. """
  145. )
  146. parser.add_argument('input', type=Path, help='Input file')
  147. parser.add_argument('output', type=Path, help='Output Markdown file')
  148. parser.add_argument(
  149. '--api-key', '-k',
  150. help='OpenRouter API key (or set OPENROUTER_API_KEY env var)'
  151. )
  152. parser.add_argument(
  153. '--model', '-m',
  154. default='anthropic/claude-opus-4.5',
  155. help='Model to use via OpenRouter (default: anthropic/claude-opus-4.5)'
  156. )
  157. parser.add_argument(
  158. '--prompt-type', '-t',
  159. choices=list(PROMPTS.keys()),
  160. default='general',
  161. help='Type of prompt to use (default: general)'
  162. )
  163. parser.add_argument(
  164. '--custom-prompt', '-p',
  165. help='Custom prompt (overrides --prompt-type)'
  166. )
  167. parser.add_argument(
  168. '--list-prompts', '-l',
  169. action='store_true',
  170. help='List available prompt types and exit'
  171. )
  172. args = parser.parse_args()
  173. # List prompts and exit
  174. if args.list_prompts:
  175. print("Available prompt types:\n")
  176. for name, prompt in PROMPTS.items():
  177. print(f"[{name}]")
  178. print(prompt)
  179. print("\n" + "="*60 + "\n")
  180. sys.exit(0)
  181. # Get API key
  182. api_key = args.api_key or os.environ.get('OPENROUTER_API_KEY')
  183. if not api_key:
  184. print("Error: OpenRouter API key required. Set OPENROUTER_API_KEY environment variable or use --api-key")
  185. print("Get your API key at: https://openrouter.ai/keys")
  186. sys.exit(1)
  187. # Validate input file
  188. if not args.input.exists():
  189. print(f"Error: Input file '{args.input}' does not exist")
  190. sys.exit(1)
  191. # Convert file
  192. success = convert_with_ai(
  193. input_file=args.input,
  194. output_file=args.output,
  195. api_key=api_key,
  196. model=args.model,
  197. prompt_type=args.prompt_type,
  198. custom_prompt=args.custom_prompt
  199. )
  200. sys.exit(0 if success else 1)
  201. if __name__ == '__main__':
  202. main()