func MakeIBMTaskFunction(audioURL string, emailAddresses []string, searchWords []string) (task func(string) error, onFailure func(string, string)) {
	task = func(id string) error {
		filePath, err := DownloadFileFromURL(audioURL)
		if err != nil {
			return errors.Trace(err)
		}
		defer os.Remove(filePath)
		log.WithField("task", id).
			Debugf("Downloaded file at %s to %s", audioURL, filePath)
		wavPath, err := ConvertAudioIntoFormat(filePath, "wav")
		if err != nil {
			return errors.Trace(err)
		}
		defer os.Remove(wavPath)
		log.WithField("task", id).
			Debugf("Converted file %s to %s", filePath, wavPath)
		wavPaths, err := SplitWavFile(wavPath)
		if err != nil {
			return errors.Trace(err)
		}
		for i := 0; i < len(wavPaths); i++ {
			defer os.Remove(wavPaths[i])
		}
		log.WithField("task", id).
			Debugf("Split file %s into %d file(s)", filePath, len(wavPaths))
		ibmResults := []*IBMResult{}
		for _, wavPath := range wavPaths {
			flacPath, err := ConvertAudioIntoFormat(wavPath, "flac")
			if err != nil {
				return errors.Trace(err)
			}
			defer os.Remove(flacPath)
			log.WithField("task", id).
				Debugf("Converted file %s to %s", wavPath, flacPath)
			ibmResult, err := TranscribeWithIBM(flacPath, searchWords, config.Config.IBMUsername, config.Config.IBMPassword)
			if err != nil {
				return errors.Trace(err)
			}
			ibmResults = append(ibmResults, ibmResult)
		}
		transcription := GetTranscription(ibmResults)
		if len(config.Config.BackblazeAccountID) > 0 {
			audioURL, err := UploadFileToBackblaze(filePath, config.Config.BackblazeAccountID, config.Config.BackblazeApplicationKey, config.Config.BackblazeBucket)
			if err != nil {
				return errors.Trace(err)
			}
			transcription.AudioURL = audioURL
			log.WithField("task", id).
				Debugf("Uploaded %s to backblaze", filePath)
		}
		if len(config.Config.MongoURL) > 0 {
			if err := WriteToMongo(transcription, config.Config.MongoURL); err != nil {
				return errors.Trace(err)
			}
			log.WithField("task", id).
				Debugf("Wrote to mongo")
		}
		if len(config.Config.EmailUsername) > 0 {
			if err := SendEmail(config.Config.EmailUsername, config.Config.EmailPassword, config.Config.EmailSMTPServer, config.Config.EmailPort, emailAddresses, fmt.Sprintf("IBM Transcription %s Complete", id), "The transcript is below. It can also be found in the database."+"\n\n"+transcription.Transcript); err != nil {
				return errors.Trace(err)
			}
		}
		log.WithField("task", id).
			Debugf("Sent email to %v", emailAddresses)
		return nil
	}
	onFailure = func(id string, errMessage string) {
		err := SendEmail(config.Config.EmailUsername, config.Config.EmailPassword, "smtp.gmail.com", 587, emailAddresses, fmt.Sprintf("IBM Transcription %s Failed", id), errMessage)
		if err != nil {
			log.WithField("task", id).
				Debugf("Could not send error email to %v because of the error %v", emailAddresses, err.Error())
			return
		}
		log.WithField("task", id).
			Debugf("Sent email to %v", emailAddresses)
	}
	return task, onFailure
}
MakeIBMTaskFunction returns a task function for transcription using IBM transcription functions.
TODO(#52): Quite a lot of the transcription process could be done concurrently.
package transcription
import (
	"fmt"
	"io"
	"net/http"
	"net/smtp"
	"os"
	"os/exec"
	"path/filepath"
	"strconv"
	"strings"
	"time"
	"gopkg.in/kothar/go-backblaze.v0"
	"gopkg.in/mgo.v2"
	log "github.com/Sirupsen/logrus"
	"github.com/jordan-wright/email"
	"github.com/juju/errors"
	"github.com/hack4impact/transcribe4all/config"
)
func SendEmail(username string, password string, host string, port int, to []string, subject string, body string) error {
	auth := smtp.PlainAuth("", username, password, host)
	addr := host + ":" + strconv.Itoa(port)
	message := email.Email{
		From:    username,
		To:      to,
		Subject: subject,
		Text:    []byte(body),
	}
	if err := message.Send(addr, auth); err != nil {
		return errors.Trace(err)
	}
	return nil
}
func ConvertAudioIntoFormat(filePath, fileExt string) (string, error) {
	newPath := filePath + "." + fileExt
	os.Remove(newPath)  
	cmd := exec.Command("ffmpeg", "-i", filePath, "-ar", "16000", "-ac", "1", newPath)
	if out, err := cmd.CombinedOutput(); err != nil {
		return "", errors.New(err.Error() + "\nCommand Output:" + string(out))
	}
	return newPath, nil
}
func DownloadFileFromURL(url string) (string, error) {
	filePath := filePathFromURL(url)
	file, err := os.Create(filePath)
	if err != nil {
		return "", errors.Trace(err)
	}
	defer file.Close()
	response, err := http.Get(url)
	if err != nil {
		return "", errors.Trace(err)
	}
	defer response.Body.Close()
	_, err = io.Copy(file, response.Body)
	if err != nil {
		return "", errors.Trace(err)
	}
	return filePath, nil
}
func filePathFromURL(url string) string {
	tokens := strings.Split(url, "/")
	filePath := tokens[len(tokens)-1]
	filePath = strings.Split(filePath, "?")[0]
	filePath = filePath + strconv.Itoa(int(time.Now().UnixNano()))
	return filePath
}
func SplitWavFile(wavFilePath string) ([]string, error) {
	numChunks, err := getNumChunks(wavFilePath)
	if err != nil {
		return []string{}, errors.Trace(err)
	}
	if numChunks == 1 {
		return []string{wavFilePath}, nil
	}
	chunkLengthInSeconds := 2968
	names := make([]string, numChunks)
	for i := 0; i < numChunks; i++ {
		startingSecond := i * chunkLengthInSeconds
		if i > 0 {
			startingSecond -= 5
		}
		newFilePath := strconv.Itoa(i) + "_" + wavFilePath
		if err := extractAudioSegment(wavFilePath, newFilePath, startingSecond, chunkLengthInSeconds); err != nil {
			return []string{}, errors.Trace(err)
		}
		names[i] = newFilePath
	}
	return names, nil
}
func getNumChunks(filePath string) (int, error) {
	file, err := os.Open(filePath)
	if err != nil {
		return -1, errors.Trace(err)
	}
	defer file.Close()
	stat, err := file.Stat()
	if err != nil {
		return -1, errors.Trace(err)
	}
	wavFileSize := int(stat.Size())
	fileSplitSize := 95000000
	numChunks := wavFileSize/fileSplitSize + 1
	return numChunks, nil
}
func extractAudioSegment(inFilePath string, outFilePath string, ss int, t int) error {
	cmd := exec.Command("ffmpeg", "-i", inFilePath, "-ss", strconv.Itoa(ss), "-t", strconv.Itoa(t), outFilePath)
	if out, err := cmd.CombinedOutput(); err != nil {
		return errors.New(err.Error() + "\nOutput:\n" + string(out))
	}
	return nil
}