4

I am trying to connect MS Word to Microsoft's QnAMaker using VBA to help answer a wide variety of similar questions I receive. My idea is select the question and then have vba query the answer and copy it to the clipboard (templates for replies are different, this way I can select where to output the answer).

Any help is appreciated. Thank you.

(I am using this JSON library: https://github.com/VBA-tools/VBA-JSON)

I have already applied the suggested solutions described in the issue section below: https://github.com/VBA-tools/VBA-JSON/issues/68

Sub copyAnswer()

'User Settings
Dim questionWorksheetName As String, questionsColumn As String, 
firstQuestionRow As String, kbHost As String, kbId As String, endpointKey 
As String
Dim str As String

str = Selection.Text

    kbHost = "https://rfp1.azurewebsites.net/********"
    kbId = "********-********-*********"
    endpointKey = "********-********-********"

'Loop through all non-blank cells
Dim answer, score As String
Dim myArray() As String
Dim obj As New DataObject

        answer = GetAnswer(str, kbHost, kbId, endpointKey)

        Call ClipBoard_SetData(answer)
End Sub

Function GetAnswer(question, kbHost, kbId, endpointKey) As String
'HTTP Request Settings
Dim qnaUrl As String
    qnaUrl = kbHost & "/knowledgebases/" & kbId & "/generateAnswer"
Dim contentType As String
    contentType = "application/json"
Dim data As String
    data = "{""question"":""" & question & """}"

'Send Request
Dim xmlhttp As New MSXML2.XMLHTTP60

xmlhttp.Open "POST", qnaUrl, False
    xmlhttp.setRequestHeader "Content-Type", contentType
    xmlhttp.setRequestHeader "Authorization", "EndpointKey " & endpointKey
**xmlhttp.send data**

'Convert response to JSON
Dim json As Scripting.Dictionary

Set json = JsonConverter.ParseJson(xmlhttp.responseText)

Dim answer As Scripting.Dictionary

For Each answer In json("answers")
'Return response
    GetAnswer = answer("answer")
Next

End Function

Private Function json_ParseObject(json_String As String, ByRef json_Index As Long) As Scripting.Dictionary
Dim json_Key As String
Dim json_NextChar As String

Set json_ParseObject = New Scripting.Dictionary
json_SkipSpaces json_String, json_Index

...

I am encountering the following error which I am uncertain how to resolve: "This method cannot be called after the send method has been called".

The error occurs on the line: xmlhttp.send data

enter image description here

Freelancer
  • 153
  • 1
  • 15

1 Answers1

3

The GitHub issue you linked kind of had the answer, but it's not complete. Here's what you do (from the VBA Dev Console in Word):

In Modules > JsonConverter

enter image description here

Go to Private Function json_ParseObject

Add Scripting. to Dictionary in two places:

from:

Private Function json_ParseObject(json_String As String, ByRef json_Index As Long) As Dictionary

to:

Private Function json_ParseObject(json_String As String, ByRef json_Index As Long) As Scripting.Dictionary

and from:

Set json_ParseObject = New Dictionary

to:

Set json_ParseObject = New Scripting.Dictionary

In GetAnswer():

Also change from:

Dim json As Dictionary

to:

Dim json As Scripting.Dictionary

and from:

Dim answer As Dictionary

to:

Dim answer As Scripting.Dictionary

Here's my full working code:

In ThisDocument:

Sub copyAnswer()

'User Settings
Dim kbHost As String, kbId As String, endpointKey As String
Dim str As String

str = "test"

    kbHost = "https:/*********.azurewebsites.net/qnamaker"
    kbId = "***************************"
    endpointKey = "*************************"

'Loop through all non-blank cells
Dim answer, score As String
Dim myArray() As String
    answer = GetAnswer(str, kbHost, kbId, endpointKey)
End Sub

Function GetAnswer(question, kbHost, kbId, endpointKey) As String
    'HTTP Request Settings
    Dim qnaUrl As String
        qnaUrl = kbHost & "/knowledgebases/" & kbId & "/generateAnswer"
    Dim contentType As String
        contentType = "application/json"
    Dim data As String
        data = "{""question"":""" & question & """}"

    'Send Request
    Dim xmlhttp As New MSXML2.XMLHTTP60

    xmlhttp.Open "POST", qnaUrl, False
        xmlhttp.setRequestHeader "Content-Type", contentType
        xmlhttp.setRequestHeader "Authorization", "EndpointKey " & endpointKey
    xmlhttp.send data

    'Convert response to JSON
    Dim json As Scripting.Dictionary
    Set json = JsonConverter.ParseJson(xmlhttp.responseText)

    Dim answer As Scripting.Dictionary

    For Each answer In json("answers")
    'Return response
        GetAnswer = answer("answer")
    Next

End Function

In Modules > JsonConverter

Private Function json_ParseObject(json_String As String, ByRef json_Index As Long) As Scripting.Dictionary
    Dim json_Key As String
    Dim json_NextChar As String

    Set json_ParseObject = New Scripting.Dictionary
    json_SkipSpaces json_String, json_Index
    If VBA.Mid$(json_String, json_Index, 1) <> "{" Then
        Err.Raise 10001, "JSONConverter", json_ParseErrorMessage(json_String, json_Index, "Expecting '{'")
    Else
        json_Index = json_Index + 1

        Do
            json_SkipSpaces json_String, json_Index
            If VBA.Mid$(json_String, json_Index, 1) = "}" Then
                json_Index = json_Index + 1
                Exit Function
            ElseIf VBA.Mid$(json_String, json_Index, 1) = "," Then
                json_Index = json_Index + 1
                json_SkipSpaces json_String, json_Index
            End If

            json_Key = json_ParseKey(json_String, json_Index)
            json_NextChar = json_Peek(json_String, json_Index)
            If json_NextChar = "[" Or json_NextChar = "{" Then
                Set json_ParseObject.Item(json_Key) = json_ParseValue(json_String, json_Index)
            Else
                json_ParseObject.Item(json_Key) = json_ParseValue(json_String, json_Index)
            End If
        Loop
    End If
End Function

enter image description here

mdrichardson
  • 7,141
  • 1
  • 7
  • 21
  • .thanks for having a look. I have now started over and implemented your suggestions, but I am still getting an error on the same line. Under 'references' I have Visual Basic for Applications, then Microsoft Scripting Runtime, Microsoft XML v6.0 and then Microsoft Word 16.0 Object Library. I assume it is still not differentiating between the possible dictionary libraries? The first time I relaunch and run the error is: ‘The system cannot locate the resource specified.’ The subsequent tries, the error is: This method cannot be called after the send method has been called". – Freelancer Apr 15 '19 at 07:24
  • if you have a working copy, could you share it with me perhaps? Thank you – Freelancer Apr 15 '19 at 07:25
  • @Freelancer I've added all of my working code. I removed some of the copy/paste stuff just to make sure the call to QnA, itself, works. I also included an image of all of my References. Ensure you imported `JsonConverter`. – mdrichardson Apr 15 '19 at 15:29
  • Thank for your input. I have done the described but I am still getting an error on the line: xmlhttp.send data. It states: "This method cannot be called after the send method has been called". – Freelancer Apr 17 '19 at 15:15
  • We need to narrow this down...if you start over in a new document and copy/paste my exact code, do you still run into the error? If it works, there's an issue in your code somewhere...maybe the script is being called multiple times in quick succession? – mdrichardson Apr 17 '19 at 15:18
  • Hello. No, I have started over with a new doc with only the code mentioned above.I am not performing any other calls. Before I change to scripting dictionary it stops at: xmlhttp.Open "POST", qnaUrl, False . With your amendments It still stops at xmlhttp.send data ... and in excel it works fine. – Freelancer Apr 17 '19 at 15:47
  • As mentioned, the error is first: ‘The system cannot locate the resource specified.’ The subsequent tries, the error is: This method cannot be called after the send method has been called". Perhaps it has to do with the library reference? – Freelancer Apr 17 '19 at 16:00
  • If you're using my same code (which works), I'm not sure how else I can help. Maybe try `Microsoft XML, v3.0` and `Dim xmlhttp As New MSXML2.XMLHTTP`? Otherwise, ensure 1) You updated the correct code in Modules > JsonConverter, 2) Your Tools > References are in the correct order, 3) You modified `kbHost`, `kbId`, and `endpointKey` correctly. Otherwise, maybe it's because of your version of Word. Try googling "xmlhttp Word method cannot be called". – mdrichardson Apr 17 '19 at 16:57
  • Thanks for your help and insights. I will keep trying – Freelancer Apr 18 '19 at 10:08