Skip to main content

Notifications

Community site session details

Community site session details

Session Id : lt77k+GgiBnTdeRTVKHOay

Edit Word Files With GPT

takolota1 Profile Picture Posted 09 Feb 2025 by takolota1 4,859 Super User 2025 Season 1


Want to automatically edit many Word documents?
Want to add summaries, translate, add/remove information related to a topic, highlight information related to a topic, redact information, change out links, or perform other updates on many Word documents?
Try this template to directly edit a Word file’s source code using GPT.

*Currently limited by the GPT4o-mini max output of about 60,000 characters. So your Word document can not exceed maybe 50,000 characters or about 10-20 pages of a text-heavy Word document.
**Template example is for 1 Word file, but if you have a use-case where you want to edit many Word documents with the same prompt, for example all word documents in a folder, then you can use something like a List files in folder action & move all relevant actions inside a loop running on the folder files outputs. 

Example

Here is a sample Word document with some headers, bold/italics/underline text, a table, a picture, & comments.


Here is the prompt in the flow to translate, change links, redact, summarize, & adjust fonts in the document.


Here is the final Word document the flow output with a Spanish translation, new link, redacted names, & highlighted summary. Unfortunately some things like adjusting fonts doesn't work as I think it requires changing style/theme Word source code & those code components are currently too long for GPT4o-mini's 16k output token limit. But it was still able to do most things.




Import & Set-Up

Find & download the Solution import package at the bottom of this main post. Go to the Power Apps home page (https://make.powerapps.com/). Select Solutions on the left-side menu, select Import solution, Browse your files & select the SplitPDFByComponentDocuments_1_0_0_xx.zip file you just downloaded. Then select Next & follow the menu prompts to apply or create the required connections for the solution flows. And finish importing the solution.


Once the solution is done importing, select the solution name in the list at the center of the screen. Once inside the solution click on the 3 vertical dots next to the flow name & select edit.


Inside the flow editor you should see the following. We will 1st work to set up the Python Azure Functions required for the workflow to extract XML from a Word document & to update a Word document with new XML source code.


To set up Azure Functions go to Azure (https://portal.azure.com/#home) & find the Function App option. Then on the Function App page select to Create a new function.


On the licensing plan page select Flex Consumption or Consumption. Click Select.


On the next page set up your subscription, resource group, & app name. Select Python runtime stack, select your closest region, & use the other defaults. Select Review + create and select through the following menus until you get to a page where your app must load/deploy. Once it is deployed you should select the Go to Resource button that appears. 


Once on the Function App's main page, select Create function under Create in Azure portal, select HTTP trigger in the pop-up menu, & select Next. You can keep the defaults on the next pop-up step & select Create.
​​​​​​​


Now a page should load for the default/template function code & trigger. Here is where we want to remove all the default code, go back to the template flow, copy all the code in the "Azure Function Python Script" action, & paste that Python code into the code editor. Then select to Save the new code.

Here is a copy of the Python code if you need it:
import azure.functions as func
import logging
import json
import base64
import io
import zipfile

app = func.FunctionApp(http_auth_level=func.AuthLevel.FUNCTION)


@app.route(route="extract_main_word_xml")
def extract_main_word_xml(req: func.HttpRequest) -> func.HttpResponse:
    
    try:
        # Parse request JSON
        req_body = req.get_json()
        file_content_base64 = req_body.get("file_content")["$content"]
        
        if not file_content_base64:
            return func.HttpResponse("Missing 'file_content' in request.", status_code=400)
        
        # Decode base64 content
        file_bytes = base64.b64decode(file_content_base64)
        
        # Load Word file as ZIP
        zip_buffer = io.BytesIO(file_bytes)
        extracted_data = {}
        
        with zipfile.ZipFile(zip_buffer, 'r') as docx_zip:
            for file_name in docx_zip.namelist():
                # Filter to relevant XML files
                if (file_name.startswith("word/document") or file_name=="word/comments.xml" or file_name.startswith("word/_rels/document") or file_name.startswith("word/header") or file_name.startswith("word/footer") or file_name.startswith("word/endnotes") or file_name.startswith("word/footnotes") or file_name.startswith("word/numbering")) and (file_name.endswith(".xml") or file_name.endswith(".rels")):
                    with docx_zip.open(file_name) as file:
                        extracted_data[file_name] = file.read().decode("utf-8")
        
        return func.HttpResponse(json.dumps(extracted_data, indent=2), mimetype="application/json")
    
    except Exception as e:
        logging.error(f"Error processing file: {e}")
        return func.HttpResponse(f"Error: {str(e)}", status_code=500)
    


@app.route(route="update_word_xml")
def update_word_xml(req: func.HttpRequest) -> func.HttpResponse:
    
    try:
        # Parse request JSON
        req_body = req.get_json()
        file_content_base64 = req_body.get("file_content", {}).get("$content")
        updated_xml_data = req_body.get("updated_xml")
        
        if not file_content_base64 or not updated_xml_data:
            return func.HttpResponse("Missing required inputs.", status_code=400)
        
        # Decode base64 original Word file
        file_bytes = base64.b64decode(file_content_base64)
        zip_buffer = io.BytesIO(file_bytes)
        output_buffer = io.BytesIO()
        
        with zipfile.ZipFile(zip_buffer, 'r') as docx_zip:
            with zipfile.ZipFile(output_buffer, 'w', zipfile.ZIP_DEFLATED) as new_docx_zip:
                for file_name in docx_zip.namelist():
                    with docx_zip.open(file_name) as file:
                        # Replace XML content if it's updated
                        if file_name in updated_xml_data:
                            new_content = updated_xml_data[file_name].encode("utf-8")
                        else:
                            new_content = file.read()
                        new_docx_zip.writestr(file_name, new_content)
                        
                # Add new XML files that are in updated_xml_data but not in the original document
                for new_file_name, new_content in updated_xml_data.items():
                    if new_file_name not in docx_zip.namelist():
                        new_docx_zip.writestr(new_file_name, new_content.encode("utf-8"))
        
        # Get base64-encoded updated Word file
        output_buffer.seek(0)
        base64_encoded_docx = base64.b64encode(output_buffer.getvalue()).decode("utf-8")
        
        response_data = {
            "$content-type": "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            "$content": base64_encoded_docx
        }
        
        return func.HttpResponse(json.dumps(response_data), mimetype="application/json")
    
    except Exception as e:
        logging.error(f"Error updating file: {e}")
        return func.HttpResponse(f"Error: {str(e)}", status_code=500)


After that we need to get the HTTP call URIs for each of our Extract & Update functions. So we need to select our Function App name in the file-tree across the top to go back one menu. Then select the extract_main_word_xml function to go into its function menu.


Once inside the menu for extract_main_word_xml we need to select Get function URL & copy the Function key. We will go back to the template flow & paste this key into the URI of our 1st HTTP action.


Once we have set up that 1st HTTP for the extract, we then need to back out to the previous menu again & this time select the update_word_xml function.


That should bring us to the update_word_xml function menu where we can again select Get function URL & copy the Function key so we can paste it into the 2nd flow HTTP action URI.



That's the main set-up pieces. If you want to run the flow you will need to select a Word file in the Get file content action & make any adjustments to the Prompt inputs to fit your use-case.
Also note the template flow is set to check the length of the XML content extracted from the Word file. If the Word file contents & relevant XML source code are greater than 60,000 characters it will stop & fail the flow because the current GPT4o-mini model can only output about 60,000 characters of new source code. So it can't update Word files that exceed this limit.
And if you have a use-case where you want to edit many Word documents with the same prompt, for example all word documents in a folder, then you will need to use something like a List files in folder action & move all these actions inside a loop running on the folder files outputs. 



Here is a copy of the prompt I used:
I want to edit a Word (.docx) file. I have un-zipped the file into its component xml parts & extracted some of the xml files, like word/document.xml, to a JSON object where the key labels are the xml file paths/names & the values are strings of the xml content from each file. The JSON is provided below between [Start JSON] & [End JSON]. Please edit the xml string value(s) in the JSON to accomplish my requested changes.
Requested changes:
-Translate all existing text & new text in the document to spanish.
-Change any links directed to www.google.com to direct to www.bing.com. (Changing links requires changing them in the word/document.xml.rels parameter/component.)
-Redact personally identifying information like names.
-Add a summary of the document's contents & seeming purpose to the end of the document. Do not duplicate the summary text. And apply yellow highlighting to that summary text. (Highlighting likely requires adding some xml like "<w:rPr><w:highlight w:val="yellow"/></w:rPr>" before the text xml).


[Start JSON]
@{body('HTTP_Extract_main_Word_xml')}
[End JSON]

Please output a JSON object that maintains key parameter labels from the above JSON for existing parameters like "word/document.xml", but now with updated xml strings. And if the xml string for a given parameter/component file doesn't have any updates, then you can exclude that parameter from the output JSON. For parameters/components with updates. do not abbreviate the xml string & do not provide only xml snippets with changes, I need the whole xml strings for the Word file components that have changes.


And if you imported the Solution file then the Create text with GPT action prompt should be pre-set. But if you need to manually set this up, all I did was go to Power Apps (https://make.powerapps.com/), go to AI hub on the left-side menu, selected Prompts, Selected Build your own prompt, named the prompt, inserted 1 text dynamic input, selected the default GPT4o-mini model, selected JSON output, tested the prompt, & selected Save. Then that prompt will be available in the Create text with GPT action.




Thanks for any feedback,

Please subscribe to my YouTube channel (https://youtube.com/@tylerkolota?si=uEGKko1U8D29CJ86).

And reach out on LinkedIn (https://www.linkedin.com/in/kolota/) if you want to hire me to consult or build more custom Microsoft solutions for you.


These functions & many other functions are available in one big import on the File & Utility Functions page along with a template Power Automate flow showing how to use most of them. I recommend following the instructions to import that full package of functions & example flow.

But if you just want to get the build shown in this thread...


Solution Zip Download Link: https://drive.google.com/file/d/1e6fhYHPcy5djhWTbgcTNDp-9My3sG972/view?usp=sharing

If for some reason you can not import the Solution, the instructions should still have enough information to manually re-create the flow & related functions.

Categories:

AI Builder

Comments