func (s *Service) text2Wikipedia(query string) (*wikipediaPage, error) {
	log.Info("Searching Wikipedia for: ", query)
	u, err := url.Parse("https://en.wikipedia.org/w/api.php")
	if err != nil {
		return nil, err
	}
	q := u.Query()
	q.Set("action", "query")   
	q.Set("prop", "extracts")  
	q.Set("format", "json")
	q.Set("redirects", "")
	q.Set("titles", query)  
	u.RawQuery = q.Encode()
	res, err := httpClient.Get(u.String())
	if res != nil {
		defer res.Body.Close()
	}
	if err != nil {
		return nil, err
	}
	if res.StatusCode < 200 || res.StatusCode >= 300 {
		return nil, fmt.Errorf("Request error: %d, %s", res.StatusCode, response2String(res))
	}
	var searchResults wikipediaSearchResults
	if err := json.NewDecoder(res.Body).Decode(&searchResults); err != nil {
		return nil, fmt.Errorf("ERROR - %s", err.Error())
	} else if len(searchResults.Query.Pages) < 1 {
		return nil, fmt.Errorf("No articles found")
	}
	for _, page := range searchResults.Query.Pages {
		if page.Extract != "" {
			return &page, nil
		}
	}
	return nil, fmt.Errorf("No articles with extracts found")
}
text2Wikipedia returns a Wikipedia article summary
package wikipedia
import (
	"encoding/json"
	"fmt"
	"io/ioutil"
	"net/http"
	"net/url"
	"strings"
	"github.com/jaytaylor/html2text"
	"github.com/matrix-org/go-neb/types"
	log "github.com/sirupsen/logrus"
	mevt "maunium.net/go/mautrix/event"
	"maunium.net/go/mautrix/id"
)
const ServiceType = "wikipedia"
const maxExtractLength = 1024  
var httpClient = &http.Client{}
type wikipediaSearchResults struct {
	Query wikipediaQuery `json:"query"`  
}
type wikipediaQuery struct {
	Pages map[string]wikipediaPage `json:"pages"`  
}
type wikipediaPage struct {
	PageID    int64  `json:"pageid"`     
	NS        int    `json:"ns"`         
	Title     string `json:"title"`      
	Touched   string `json:"touched"`    
	LastRevID int64  `json:"lastrevid"`  
	Extract   string `json:"extract"`    
}
type Service struct {
	types.DefaultService
}
func (s *Service) Commands(client types.MatrixClient) []types.Command {
	return []types.Command{
		{
			Path: []string{"wikipedia"},
			Command: func(roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) {
				return s.cmdWikipediaSearch(client, roomID, userID, args)
			},
		},
	}
}
func usageMessage() *mevt.MessageEventContent {
	return &mevt.MessageEventContent{
		MsgType: mevt.MsgNotice,
		Body:    "Usage: !wikipedia search_text",
	}
}
func (s *Service) cmdWikipediaSearch(client types.MatrixClient, roomID id.RoomID, userID id.UserID, args []string) (interface{}, error) {
	if len(args) < 1 {
		return usageMessage(), nil
	}
	querySentence := strings.Join(args, " ")
	searchResultPage, err := s.text2Wikipedia(querySentence)
	if err != nil {
		return nil, err
	}
	if searchResultPage == nil || searchResultPage.Extract == "" {
		return mevt.MessageEventContent{
			MsgType: "m.notice",
			Body:    "No results",
		}, nil
	}
	extractText, err := html2text.FromString(searchResultPage.Extract)
	if err != nil {
		return mevt.MessageEventContent{
			MsgType: "m.notice",
			Body:    "Failed to convert extract to plain text - " + err.Error(),
		}, nil
	}
	if len(extractText) > maxExtractLength {
		extractText = extractText[:maxExtractLength] + "..."
	}
	extractText += fmt.Sprintf("\nhttp://en.wikipedia.org/?curid=%d", searchResultPage.PageID)
	return mevt.MessageEventContent{
		MsgType: "m.notice",
		Body:    extractText,
	}, nil
}