def parse_struct_res()

in src/models/struxgpt_v2.py [0:0]


    def parse_struct_res(self, **kwargs):
        single_sent_ok = kwargs.get('single_sent_ok', True)
        # assert all(line.startswith('- Sentence ') for line in raw_query.splitlines()), raw_query
        if not all(line.startswith('- Sentence ') for line in self.raw_query.splitlines()):
            return False, 'input_error'
           
        query_lines = self.raw_query.splitlines()

        error_type = None
        try:  # check format
            error_type = 'result_spliter'
            if self.scfg.format_type == 'JSON':
                response = self.raw_response.split('```json\n')[1].split('\n```')[0]
                error_type = 'format_json'
                response = json.loads(response.replace('\\', '\\\\'))
            elif self.scfg.format_type == 'YAML':
                response = self.raw_response.split('```yaml\n')[1].split('\n```')[0]
                error_type = 'format_yaml'
                response = yaml.safe_load(response)
            else:
                raise ValueError('Uncognized format:', self.scfg.format_type)
            error_type = 'result_scope'
            self.scope = response[self.scfg.scope_key]
            error_type = 'result_scope_str'
            assert isinstance(self.scope, str) and self.scope
            error_type = 'result_aspect'
            self.aspects = [
                self.parse_aspect(aspect) \
                    for aspect in response[self.scfg.struct_key]
            ]
        except:
            self.scope = None
            self.aspects = []
            return False, error_type

        try:  # check content
            ### step1. reset sentence range for the first-level aspects
            for aspect in self.aspects:
                sent_range = aspect.sent_range
                for subaspect in aspect.subaspects:
                    sent_range.extend(subaspect.sent_range)
                aspect.sent_range = [min(sent_range), max(sent_range)]
            total_sent_num = len(query_lines)
            if any(flag in self.aspects[-1].name.lower() for flag in ['external link', 'reference', 'conclusion', 'see also'])\
                    and self.aspects[-1].sent_range[-1] <= total_sent_num:
                self.aspects[-1].sent_range[-1] = total_sent_num
            assert self.aspects[0].sent_range[0] == 1, 'range_start'
            assert self.aspects[-1].sent_range[-1] == total_sent_num, 'range_end'
            sent_prev = 0
            for aspect in self.aspects:
                sent_range = aspect.sent_range
                assert sent_range[0] == sent_prev + 1, 'range_middle'
                sent_prev = sent_range[1]
            ### step2. delete subaspect with single sentence
            for aspect in self.aspects:
                aspect.subaspects = self._delete_subaspect_with_single_sent(aspect.subaspects)
            ### step3. check result with single sentence for all aspects
            if not single_sent_ok:
                single_flag = True
                for aspect in self.aspects:
                    if aspect.sent_range[0] != aspect.sent_range[1]:
                        single_flag = False
                        break
                assert not single_flag, 'single_sent_aspect'

        except AssertionError as e:
            self.scope = None
            self.aspects = []
            return False, str(e)
        
        return True, self.to_json()