<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Curtis Evans</title>
    <description>The latest articles on DEV Community by Curtis Evans (@cie247).</description>
    <link>https://dev.to/cie247</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F848623%2F09bd65d0-b4a5-422c-90cb-1f3b0e21a787.jpeg</url>
      <title>DEV Community: Curtis Evans</title>
      <link>https://dev.to/cie247</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cie247"/>
    <language>en</language>
    <item>
      <title>How RAG &amp; MCP solve model limitations differently</title>
      <dc:creator>Curtis Evans</dc:creator>
      <pubDate>Wed, 16 Apr 2025 23:56:09 +0000</pubDate>
      <link>https://dev.to/aws/how-rag-mcp-solve-model-limitations-differently-pjm</link>
      <guid>https://dev.to/aws/how-rag-mcp-solve-model-limitations-differently-pjm</guid>
      <description>&lt;p&gt;Large language models (LLMs) like Claude, and GPT-4o have impressive capabilities but face two major limitations: the knowledge they contain is frozen in time (more specifically, at training time), and the context windows that determine how much information they can process at once are finite. Two approaches that can address these limitations are &lt;strong&gt;Retrieval-Augmented Generation&lt;/strong&gt; (RAG), and &lt;strong&gt;Model Context Protocol&lt;/strong&gt; (MCP). In this article, I'll provide an overview of how they both work, along with some differences that distinguish them from each other.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retrieval-Augmented Generation
&lt;/h2&gt;

&lt;p&gt;RAG is a technique that enhances LLMs by incorporating a separate retrieval system that collects relevant information from external sources before the model generates a response. RAG works using three main steps,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;Query Processing&lt;/em&gt;: The user's query is processed to identify key information needs.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Retrieval&lt;/em&gt;: Relevant documents or information snippets are fetched from external databases or knowledge bases.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Augmented Generation&lt;/em&gt;: The retrieved documents are added to the context window of the LLM, which then generates a response based on both its pre-trained knowledge and the collected information.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach bridges the gap between static pre-trained knowledge and dynamic information retrieval systems.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fshcsxyaynx5s6ccocnq2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fshcsxyaynx5s6ccocnq2.png" alt="RAG Model Diagram" width="725" height="506"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Benefits of RAG&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enhanced accuracy that provides factual, up-to-date information&lt;/li&gt;
&lt;li&gt;Reduced hallucinations by using information in the knowledge base&lt;/li&gt;
&lt;li&gt;Customizable knowledge obtained from domain-specific sources&lt;/li&gt;
&lt;li&gt;Transparency through citations provided by the source&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Imagine a university chatbot that is prompted by a student:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"When is the CS301 final exam?"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Using a RAG implementation, the system would:&lt;/p&gt;

&lt;p&gt;a) Process this query&lt;br&gt;
b) Retrieve the current semester's exam schedule from a university database&lt;br&gt;
c) Provide this information to the LLM along with the query&lt;/p&gt;

&lt;p&gt;The LLM would then generate an accurate response with up-to-date information,&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;"The CS301 final exam is scheduled for December 15th at 2:00 PM in Lecture Hall B."&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;RAG allows systems to access up-to-date information and specialized knowledge without retraining the model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Model Context Protocol
&lt;/h2&gt;

&lt;p&gt;MCP uses a different approach to extending AI capabilities. While RAG focuses on retrieval &lt;em&gt;before&lt;/em&gt; generation, MCP provides a standardized interface for LLMs to request additional information or perform actions &lt;em&gt;during&lt;/em&gt; the generation process. MCP works by,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;em&gt;Recognition&lt;/em&gt;: The model recognizes when it needs additional information or tools.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Protocol Execution&lt;/em&gt;: Following a predefined protocol, the model outputs a structured request.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;External Processing&lt;/em&gt;: This request is handled by external systems to fetch data or perform actions.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;Continued Generation&lt;/em&gt;: The model incorporates the results and continues its response.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi3bdspi8ymfkvon6y2yi.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi3bdspi8ymfkvon6y2yi.png" alt="MCP Model Diagram" width="715" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Benefits of MCP&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Context optimization to make the most of limited context windows&lt;/li&gt;
&lt;li&gt;Structured information using schemas and formats that models understand better&lt;/li&gt;
&lt;li&gt;Information hierarchy that prioritizes crucial information for the task&lt;/li&gt;
&lt;li&gt;Consistency which provides standardized formatting for predictable model behavior&lt;/li&gt;
&lt;li&gt;Performance improvement that achieves better reasoning with the same context size&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;MCP is especially valuable when dealing with complex tasks that require multiple information sources but must operate within the constraints of a model's context window capacity.&lt;/p&gt;

&lt;p&gt;Using the university chatbot scenario implemented with MCP, when a student asks about the CS301 exam:&lt;/p&gt;

&lt;p&gt;a) The model recognizes it needs the current exam schedule&lt;br&gt;
b) It produces a structured MCP call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{action: "fetch_exam_schedule", course: "CS301", semester: "current"}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;c) An external system processes this call and returns the exam details&lt;/p&gt;

&lt;p&gt;The model incorporates this information into the response,&lt;br&gt;
&lt;/p&gt;

&lt;p&gt;&lt;code&gt;"The CS301 final exam is on December 15th at 2:00 PM in Lecture Hall B."&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Both RAG and MCP are powerful approaches to extending AI capabilities beyond their initial training limitations. RAG is generally easier to implement, and works well for straightforward information retrieval. MCP offers more flexibility for complex, multi-step tasks requiring various tools, and data sources.&lt;/p&gt;

&lt;p&gt;In practice, many advanced AI systems are beginning to combine elements of both approaches - using RAG for broad knowledge access and MCP for specific tool use and dynamic information retrieval. As you start to develop more AI applications, consider whether one approach, or a combination of both suits your specific use case.&lt;/p&gt;

</description>
      <category>genai</category>
      <category>llm</category>
      <category>rag</category>
      <category>mcp</category>
    </item>
    <item>
      <title>Using modern AI tools to manage an old "growing" problem</title>
      <dc:creator>Curtis Evans</dc:creator>
      <pubDate>Sat, 05 Apr 2025 01:11:41 +0000</pubDate>
      <link>https://dev.to/aws/using-modern-ai-tools-to-manage-an-old-growing-problem-5189</link>
      <guid>https://dev.to/aws/using-modern-ai-tools-to-manage-an-old-growing-problem-5189</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;Sharing a personal account of how I regained control of a document management problem with help from a single Python library and &lt;a href="https://aws.amazon.com/blogs/devops/introducing-the-enhanced-command-line-interface-in-amazon-q-developer?trk=9ff26abb-282e-49a3-82fe-d185d6344181&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Amazon Q Developer CLI&lt;/a&gt;. Take a look at the solution as well as the code I provided to draw inspiration along with a few tips to address your next development challenge.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Amazon Q Developer CLI is a command-line tool that acts like a personal assistant right in your terminal. It's always there and ready to answer your programming questions, or help manage tasks. Here's some of what Q Developer CLI can do:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Answer questions about programming concepts, AWS services, and a variety of software development best practices&lt;/li&gt;
&lt;li&gt;Write and debug code for many popular languages&lt;/li&gt;
&lt;li&gt;Explain errors, and suggest fixes&lt;/li&gt;
&lt;li&gt;Interact with many services, and tools through the CLI interface&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The beauty of Q Developer CLI is you don't need to switch between the terminal and a web browser when coding. Just type &lt;code&gt;q chat&lt;/code&gt; and start a conversation from your command line. When finished, type &lt;code&gt;/quit&lt;/code&gt; to exit.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Recently, I came to the realization that my catalogue of personal PDF files has become a mess. For years, I've been &lt;em&gt;digitizing&lt;/em&gt; my life opting out of paper statements like bank records, invoices, and magazines, converting it all into pile-free electronic euphoria. It has prevented my home from becoming a mountain of paper, plus I'm able to carry documents with me anywhere on my mobile devices. Life was good, until it wasn't anymore. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy2fmm68vp0k1mrlg6jjq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fy2fmm68vp0k1mrlg6jjq.png" alt="Ain't no mountain high enough to conquer!" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I saw it coming for some time, but pretended it wasn't an issue. Today, my iPad and storage on my PC is the digital equivalent of the paper mountain I worked long and hard to avoid. I tried moving PDFs to the cloud, but that basically created another paper mountain...only this time in the cloud where the mountain rises even higher! &lt;/p&gt;

&lt;h2&gt;
  
  
  The Opportunity
&lt;/h2&gt;

&lt;p&gt;It was time to figure out what to do next, and I decided to consolidate the chaos. Storage wasn't the issue,  &lt;strong&gt;management&lt;/strong&gt; was. How could I maintain my digital well being in a useful way? Thankfully, I found a convenient, Do-It-Yourself solution that combines months (in some cases years!) of e-docs into a single one. It hasn't solved my problem entirely, but it is &lt;strong&gt;&lt;em&gt;REAL&lt;/em&gt;&lt;/strong&gt; progress! &lt;/p&gt;

&lt;h2&gt;
  
  
  The Tools
&lt;/h2&gt;

&lt;p&gt;Enter Amazon Q Developer CLI and &lt;a href="https://pypdf.readthedocs.io/en/latest/index.html" rel="noopener noreferrer"&gt;pypdf&lt;/a&gt;. Earlier, I described a few of Q Developer CLI's capabilities. You can find additional details along with a link to installation and setup instructions &lt;a href="https://aws.amazon.com/blogs/devops/introducing-the-enhanced-command-line-interface-in-amazon-q-developer/?trk=a59f8d3f-589a-44bf-8569-17c313bd4e50&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;here&lt;/a&gt;. pypdf is a free, open source library for creating and managing PDF documents. Among the many features, consolidating multiple files together is what intrigued me the most. I've done file consolidation before using printer utilities, but that approach is clunky, not very intuitive, or efficient.&lt;/p&gt;

&lt;p&gt;Make sure you have Python 3.9 or higher installed on your system. Instructions for setting up Python for your operating system can be found &lt;a href="https://www.python.org/downloads/" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fov3nhtkln0rd3480w4n5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fov3nhtkln0rd3480w4n5.png" alt="Ask Amazon Q Developer CLI anything" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  The Fix
&lt;/h2&gt;

&lt;p&gt;After pouring over the pypdf &lt;a href="https://pypdf.readthedocs.io/en/latest/user/migration-1-to-2.html" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; I knew my solution was doable, but to make it more intuitive I thought, &lt;/p&gt;

&lt;p&gt;&lt;em&gt;"...why not go further and build a simple app that lets me drop files into a browser interface to combine them?!"&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Works for me because it is also efficient, and it would put me back in control. Not wanting to procrastinate given the opportunity, I launched Q Developer CLI and started my project. &lt;code&gt;q chat&lt;/code&gt; to the rescue!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhmqbklm9hkxq1zzpnooy.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhmqbklm9hkxq1zzpnooy.jpg" alt=" " width="800" height="580"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 1: The Basics&lt;/strong&gt;&lt;br&gt;
First, I needed to familiarize myself with pypdf as this was my first dive into using the library. The docs were helpful, and I was able to write a first program in a few minutes. What I created was a routine that was able to read and extract info from any PDF. With the code below, I created the file &lt;code&gt;get_doc_info.py&lt;/code&gt; and then conducted a brief test in the virtual environment created with the steps illustrated. This was simple enough that I didn't seek help from Q Developer CLI, but feel free if you need to on your first attempt!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# from PyPDF2 import PdfFileReader
from PyPDF2 import PdfReader
import sys
import os

def get_info(path):
    try:
        with open(path, 'rb') as f:
            pdf = PdfReader(f)
            info = pdf.metadata
            number_of_pages = len(pdf.pages)

        print(f"\nInformation for PDF: {path}")
        print(f"{'=' * 40}")
        print(info)
        print(f"Number of pages: {number_of_pages}")

        author = info.author
        creator = info.creator
        producer = info.producer
        subject = info.subject
        title = info.title

        # Print additional extracted information
        print(f"\nExtracted metadata:")
        print(f"Title: {title}")
        print(f"Author: {author}")
        print(f"Creator: {creator}")
        print(f"Producer: {producer}")
        print(f"Subject: {subject}")

    except Exception as e:
        print(f"Error processing {path}: {e}")

def print_usage():
    print(f"Usage: python {os.path.basename(__file__)} &amp;lt;pdf_file1&amp;gt; [pdf_file2] [pdf_file3] ...")
    print("Example: python get_doc_info.py document.pdf")

if __name__ == '__main__':
    # Check if any command line arguments were provided
    if len(sys.argv) &amp;lt; 2:
        print("Error: No PDF files specified.")
        print_usage()
        sys.exit(1)

    # Process each PDF file provided as an argument
    for pdf_path in sys.argv[1:]:
        get_info(pdf_path)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following steps are as follows,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cd project_dir/
$ python -m venv venv
$ source venv/bin/activate
$ pip install pypdf2

# To run the program
$ python get_doc_info.py [your_file].PDF
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsy1pmvroniqal9erkloe.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsy1pmvroniqal9erkloe.png" alt=" " width="800" height="355"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Everything works...great! Now we can move on to the next task.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 2: Add more features&lt;/strong&gt;&lt;br&gt;
With the first hurdle cleared, I began focusing on addressing the reason I started this journey...merging my PDFs. A lot of the files are saved by &lt;em&gt;month&lt;/em&gt;, &lt;em&gt;quarter&lt;/em&gt;, or &lt;em&gt;year&lt;/em&gt;. For example, bank statements are arranged in a folder structure like this,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── bank_name
│   └── YYYY      
│       └── statement-Jan.pdf        
│       └── statement-Feb.pdf      
│                :
│       └── statement-Dec.pdf        
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some directory structures include 7+ years of statements. What I wanted to do was take a year's worth of statements, and merge those PDFs into one. In other words turn,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;.
├── bank_name
│   └── 2021      
│       └── statement-Jan-2021.pdf        
│       └── statement-Feb-2021.pdf      
│                :
│       └── statement-Dec-2021.pdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;into a single &lt;code&gt;bank_name/2021/statements-2021.pdf&lt;/code&gt; file. For my needs, combining transaction records from four years ago into a single doc shouldn't be a problem.&lt;/p&gt;

&lt;p&gt;The same logic can be applied to practically any set of docs. They could be utility bills, medical records, or school transcripts. As owner of the docs, you get to decide what's best for your management style.&lt;/p&gt;

&lt;p&gt;Here is where I started to ask Q Developer CLI for help. Before I proceed with more details, please note that I don't want to take away from your own experience with Q Developer CLI and have kept that in mind with the descriptions and screen captures provided! It's plenty to help you progress, but I'm confident you'll get the most benefit out of witnessing the magic first hand!&lt;/p&gt;

&lt;p&gt;I began by launching &lt;code&gt;q chat&lt;/code&gt; and entering my first prompt,&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;gt;analyze the get_info_doc.py file and develop a new program. This new program should leverage the pypdf2 library and identify one or more PDF files, and consolidate those files into a single document. Make the program as efficient as possible.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj4mguuli3v91sn079398.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fj4mguuli3v91sn079398.png" alt=" " width="800" height="291"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And off Q Developer CLI goes! In a nutshell here are the steps the tool executed in the development of the next program,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Reads and examines &lt;code&gt;get_doc_info.py&lt;/code&gt; to understand its functionality, coding style, and how the pypdf library was being used.&lt;/li&gt;
&lt;li&gt;Drafted a version of &lt;code&gt;pdf_merger.py&lt;/code&gt; adding functionality for merging PDFs, handling command line arguments, errors, and implementing a file output directory structure.&lt;/li&gt;
&lt;li&gt;Made recommendations for testing and refinement.&lt;/li&gt;
&lt;li&gt;Documented the code with instructions for how to setup and run the pdf_merger.py program. If it doesn't do it for you automatically, be sure to ask Q Developer CLI to document the project. You'll be glad you did!&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Here is the generated code for &lt;code&gt;pdf_merger.py&lt;/code&gt;,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env python3
# pdf_merger.py

from PyPDF2 import PdfMerger
import sys
import os
import datetime

def merge_pdfs(input_paths, output_path):
    """
    Merge multiple PDF files into a single PDF file

    Args:
        input_paths (list): List of paths to input PDF files
        output_path (str): Path where the merged PDF will be saved
    """
    try:
        merger = PdfMerger()

        # Add each PDF to the merger
        for pdf_path in input_paths:
            print(f"Adding {pdf_path} to merger...")
            merger.append(pdf_path)

        # Create output directory if it doesn't exist
        os.makedirs(os.path.dirname(output_path), exist_ok=True)

        # Write the merged PDF to the output file
        print(f"Writing merged PDF to {output_path}")
        merger.write(output_path)
        merger.close()

        print(f"\nSuccessfully merged {len(input_paths)} PDF files into {output_path}")
        print(f"Output file size: {os.path.getsize(output_path) / 1024:.2f} KB")

    except Exception as e:
        print(f"Error merging PDFs: {e}")
        return False

    return True

def print_usage():
    print(f"Usage: python {os.path.basename(__file__)} &amp;lt;pdf_file1&amp;gt; [pdf_file2] [pdf_file3] ...")
    print("Example: python pdf_merger.py document1.pdf document2.pdf")
    print("Output will be saved to ./pdfoutput/merged_YYYYMMDD_HHMMSS.pdf")

if __name__ == '__main__':
    # Check if any command line arguments were provided
    if len(sys.argv) &amp;lt; 2:
        print("Error: No PDF files specified.")
        print_usage()
        sys.exit(1)

    # Get input PDF files from command line arguments
    input_files = sys.argv[1:]

    # Validate that all input files exist
    invalid_files = [f for f in input_files if not os.path.exists(f)]
    if invalid_files:
        print("Error: The following files do not exist:")
        for file in invalid_files:
            print(f"  - {file}")
        sys.exit(1)

    # Generate output filename with timestamp
    timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
    output_file = f"./pdfoutput/merged_{timestamp}.pdf"

    # Merge the PDFs
    if merge_pdfs(input_files, output_file):
        print("\nPDF merging completed successfully!")
    else:
        print("\nPDF merging failed.")
        sys.exit(1)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To test, I used a few PDFs from some online exams I had taken awhile ago and executed &lt;code&gt;pdf_merger.py&lt;/code&gt; inside the virtual environment configured earlier,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6sbnb1tprlmhpxz86cog.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6sbnb1tprlmhpxz86cog.png" alt=" " width="800" height="177"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Great, another functioning program. The needs of the solution are now met, but we still want to create that intuitive interface.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Step 3: Build a web interface&lt;/strong&gt;&lt;br&gt;
This next step should be pretty self-explanatory, so I'll jump right into the details and show some of the exciting results. First, I asked Q Developer CLI to write the interface,&lt;/p&gt;

&lt;p&gt;&lt;code&gt;&amp;gt;expand the project by creating a browser inteface that can handle file uploads. process the selected PDFs as arguments to pdf_merger.py, and provide a download utility for storing the merged files. Be sure to include all of the basic error handling, file validation, and list needs. Use HTML, css, and javascript in an efficient manner.&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcfxqky9q7ldpjktao45e.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fcfxqky9q7ldpjktao45e.png" alt=" " width="800" height="354"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Thinking through and executing on those prompt details, Q Developer CLI exceeded most of my expectations. The result was a browser interface using Flask that delivered on the requirements. The lone exception (which I'm currently working at the moment!) is fixing the drag feature in the drag &amp;amp; drop capabilities. I can drop files, but can't drag them yet. Not worried though as I'm confident I'll get it resolved. If anyone beats me to the punch, feel free to include a comment to this article on how you fixed it!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/env python3
# app.py - Web interface for PDF merger

from flask import Flask, render_template, request, redirect, url_for, flash, send_from_directory
import os
import datetime
from werkzeug.utils import secure_filename
from pdf_merger import merge_pdfs

app = Flask(__name__)
app.secret_key = 'pdf_merger_secret_key'  # Required for flash messages

# Configure upload folder
UPLOAD_FOLDER = 'uploads'
OUTPUT_FOLDER = 'pdfoutput'
ALLOWED_EXTENSIONS = {'pdf'}

app.config['UPLOAD_FOLDER'] = UPLOAD_FOLDER
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024  # 16MB max upload size

# Create necessary directories
os.makedirs(UPLOAD_FOLDER, exist_ok=True)
os.makedirs(OUTPUT_FOLDER, exist_ok=True)

def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS

@app.route('/')
def index():
    return render_template('index.html')

@app.route('/merge', methods=['POST'])
def merge():
    # Check if the post request has the file part
    if 'files[]' not in request.files:
        flash('No files selected')
        return redirect(request.url)

    files = request.files.getlist('files[]')

    # If user does not select file, browser also
    # submit an empty part without filename
    if not files or files[0].filename == '':
        flash('No files selected')
        return redirect(url_for('index'))

    # Filter out non-PDF files
    pdf_files = [f for f in files if f and allowed_file(f.filename)]

    if not pdf_files:
        flash('No PDF files selected')
        return redirect(url_for('index'))

    # Save uploaded files
    file_paths = []
    for file in pdf_files:
        filename = secure_filename(file.filename)
        file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
        file.save(file_path)
        file_paths.append(file_path)

    # Generate output filename with timestamp
    timestamp = datetime.datetime.now().strftime("%Y%m%d_%H%M%S")
    output_filename = f"merged_{timestamp}.pdf"
    output_path = os.path.join(OUTPUT_FOLDER, output_filename)

    # Merge PDFs
    success = merge_pdfs(file_paths, output_path)

    # Clean up uploaded files
    for file_path in file_paths:
        try:
            os.remove(file_path)
        except:
            pass

    if success:
        flash('PDFs merged successfully!')
        return redirect(url_for('download_file', filename=output_filename))
    else:
        flash('Error merging PDFs')
        return redirect(url_for('index'))

@app.route('/download/&amp;lt;filename&amp;gt;')
def download_file(filename):
    return render_template('download.html', filename=filename)

@app.route('/get_file/&amp;lt;filename&amp;gt;')
def get_file(filename):
    return send_from_directory(OUTPUT_FOLDER, filename, as_attachment=True)

if __name__ == '__main__':
    app.run(debug=True)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, I setup a virtual environment to launch the browser. Note that Q Developer CLI added a &lt;code&gt;requirements.txt&lt;/code&gt; file making it easier to load all of the application dependencies.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# requirements.txt
PyPDF2==3.0.1
Flask==2.3.3
Werkzeug==2.3.7

$ cd project_dir/
$ python -m venv venv
$ source venv/bin/activate
$ pip install -r requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsiobu61wwc7upt6yua51.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsiobu61wwc7upt6yua51.png" alt=" " width="800" height="481"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We're now ready to run flask and launch a web browser,&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# To run the program
$ python app.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fimhbfpbzikkid82h9nw3.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fimhbfpbzikkid82h9nw3.png" alt=" " width="800" height="162"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Connect to &lt;code&gt;http://127.0.0.1:5000&lt;/code&gt; and you should see the following PDFMerger interface,&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuigcv4t3w7uidc89bqq3.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fuigcv4t3w7uidc89bqq3.jpg" alt=" " width="800" height="462"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I then conduct another run to merge the test documents using the browser interface this time, &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frauuuauo6x6ldfa4hp5w.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frauuuauo6x6ldfa4hp5w.jpg" alt=" " width="800" height="620"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SUCCESS!!!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxkdax1laao3q5uxy14bx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxkdax1laao3q5uxy14bx.jpg" alt=" " width="800" height="507"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CONCLUSION&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Have problem, will travel!&lt;/em&gt; I just walked you through an example use case of how Amazon Q Developer CLI with its AI-powered features can help you get things done fast and efficient. If you're a developer that wants to take advantage of the benefits available to you from the command line, I highly recommend that you give this tool a try. Installation instructions and much more can be found in the &lt;a href="https://docs.aws.amazon.com/amazonq/latest/qdeveloper-ug/command-line-installing.html?trk=9ff26abb-282e-49a3-82fe-d185d6344181&amp;amp;sc_channel=el" rel="noopener noreferrer"&gt;Q Developer user guide&lt;/a&gt;, so have a look and set yourself up for the next great development journey! &lt;/p&gt;

</description>
      <category>ai</category>
      <category>aws</category>
      <category>development</category>
      <category>python</category>
    </item>
  </channel>
</rss>
