github.com/sharovik/devbot@v1.0.1-0.20240308094637-4a0387c40516/internal/service/analiser/analyser.go (about)

     1  package analiser
     2  
     3  import (
     4  	"github.com/sharovik/devbot/internal/service/message/conversation"
     5  	_time "github.com/sharovik/devbot/internal/service/time"
     6  
     7  	"github.com/sharovik/devbot/internal/container"
     8  	"github.com/sharovik/devbot/internal/database"
     9  	"github.com/sharovik/devbot/internal/dto"
    10  	"github.com/sharovik/devbot/internal/helper"
    11  	"github.com/sharovik/devbot/internal/log"
    12  )
    13  
    14  // Message the message object, from which we will generate the dto.DictionaryMessage
    15  type Message struct {
    16  	Channel string
    17  	User    string
    18  	Text    string
    19  }
    20  
    21  // GetDmAnswer retrieves the Dictionary Message Answer
    22  func GetDmAnswer(message Message) (dmAnswer dto.DictionaryMessage, err error) {
    23  	//Now we need to check if there was already opened conversation for this channel
    24  	//If so, then we need to get the Answer from this scenario
    25  	openConversation := conversation.GetConversation(message.Channel)
    26  
    27  	//If that was a stop word, we need to cancel the conversation
    28  	IsScenarioStopTriggered := conversation.IsScenarioStopTriggered(message.Text)
    29  	if IsScenarioStopTriggered {
    30  		dmAnswer = dto.DictionaryMessage{
    31  			ScenarioID:            0,
    32  			EventID:               0,
    33  			Answer:                "Ok, no more questions!",
    34  			QuestionID:            0,
    35  			Question:              message.Text,
    36  			Regex:                 "",
    37  			MainGroupIndexInRegex: "",
    38  			ReactionType:          "text",
    39  		}
    40  		conversation.FinaliseConversation(message.Channel)
    41  
    42  		return dmAnswer, nil
    43  	}
    44  
    45  	//If there was a scenario triggered for this conversation, we trigger the scenario handling logic
    46  	if openConversation.ScenarioID != 0 {
    47  		setAnswerToVariable(message.Text, &openConversation)
    48  
    49  		return generateDmForConversation(message, openConversation)
    50  	}
    51  
    52  	dmAnswer, err = container.C.Dictionary.FindAnswer(message.Text)
    53  	if err != nil {
    54  		return dto.DictionaryMessage{}, err
    55  	}
    56  
    57  	questions, err := getVariableQuestionsByScenarioID(dmAnswer.ScenarioID)
    58  	//if we don't have an error here, then we can proceed with the questions preparing for scenarios
    59  	if err != nil {
    60  		log.Logger().AddError(err).Msg("Failed to get the list of question by the scenarioID")
    61  	}
    62  
    63  	isHelpAnswerTriggered, err := helper.HelpMessageShouldBeTriggered(message.Text)
    64  	if err != nil {
    65  		log.Logger().AddError(err).Msg("Failed to parse the help template")
    66  	}
    67  
    68  	if dmAnswer.ReactionType != "" && isHelpAnswerTriggered {
    69  		dmAnswer.Answer = container.C.DefinedEvents[dmAnswer.ReactionType].Help()
    70  		dmAnswer.IsHelpTriggered = true
    71  
    72  		return dmAnswer, nil
    73  	}
    74  
    75  	//If the questions amount is more than 1, we need to start the conversation algorithm
    76  	if len(questions) > 1 && !isHelpAnswerTriggered {
    77  		scenario := database.EventScenario{}
    78  		SetScenarioQuestions(&scenario, questions)
    79  		conversation.AddConversation(scenario, dto.BaseChatMessage{
    80  			Channel:           message.Channel,
    81  			Text:              message.Text,
    82  			AsUser:            false,
    83  			Ts:                _time.Service.Now(),
    84  			DictionaryMessage: dmAnswer,
    85  			OriginalMessage: dto.BaseOriginalMessage{
    86  				Text: message.Text,
    87  				User: message.User,
    88  			},
    89  		})
    90  
    91  		dmAnswer.Answer = scenario.GetUnAnsweredQuestion()
    92  	}
    93  
    94  	return dmAnswer, nil
    95  }
    96  
    97  func SetScenarioQuestions(scenario *database.EventScenario, questions []database.QuestionObject) {
    98  	for _, q := range questions {
    99  		scenario.Questions = append(scenario.Questions, database.Question{
   100  			Question: q.Question,
   101  			Answer:   q.Answer,
   102  		})
   103  
   104  		if q.IsVariable {
   105  			scenario.RequiredVariables = append(scenario.RequiredVariables, database.ScenarioVariable{
   106  				Question: q.Answer,
   107  			})
   108  		}
   109  	}
   110  }
   111  
   112  func getVariableQuestionsByScenarioID(scenarioID int64) (result []database.QuestionObject, err error) {
   113  	questions, err := container.C.Dictionary.GetQuestionsByScenarioID(scenarioID, true)
   114  	if err != nil {
   115  		log.Logger().AddError(err).Msg("Failed to get the list of questions by the scenarioID")
   116  		return result, err
   117  	}
   118  
   119  	for _, q := range questions {
   120  		if q.Question != "" {
   121  			continue
   122  		}
   123  
   124  		result = append(result, q)
   125  	}
   126  
   127  	return result, err
   128  }
   129  
   130  func setAnswerToVariable(answer string, openConversation *conversation.Conversation) {
   131  	if len(openConversation.Scenario.RequiredVariables) == 0 {
   132  		return
   133  	}
   134  
   135  	for i, variable := range openConversation.Scenario.RequiredVariables {
   136  		if variable.Value != "" || openConversation.LastQuestion.Text != variable.Question {
   137  			continue
   138  		}
   139  
   140  		openConversation.Scenario.RequiredVariables[i].Value = answer
   141  		return
   142  	}
   143  }
   144  
   145  func generateDmForConversation(message Message, openConversation conversation.Conversation) (dto.DictionaryMessage, error) {
   146  	if len(openConversation.Scenario.RequiredVariables) == 0 {
   147  		return dto.DictionaryMessage{}, nil
   148  	}
   149  
   150  	for _, variable := range openConversation.Scenario.RequiredVariables {
   151  		if variable.Value != "" {
   152  			continue
   153  		}
   154  
   155  		dmAnswer := dto.DictionaryMessage{
   156  			ScenarioID:   openConversation.ScenarioID,
   157  			EventID:      openConversation.EventID,
   158  			Answer:       variable.Question,
   159  			ReactionType: openConversation.ReactionType,
   160  		}
   161  
   162  		return dmAnswer, nil
   163  	}
   164  
   165  	conversation.MarkAsReadyEventToBeExecuted(message.Channel)
   166  
   167  	return dto.DictionaryMessage{
   168  		ScenarioID:   openConversation.ScenarioID,
   169  		EventID:      openConversation.ScenarioID,
   170  		Answer:       "Ok",
   171  		ReactionType: openConversation.ReactionType,
   172  	}, nil
   173  }