예제 #1
0
 def __init__(self, argv):
     super(MRA_Module, self).__init__(argv)
     self.tasks = ['BUILD-MODEL', 'EXPAND-MODEL']
     self.models = []
     for task in self.tasks:
         msg_txt =\
             '(subscribe :content (request &key :content (%s . *)))' % task
         self.send(KQMLPerformative.from_string(msg_txt))
     # Instantiate a singleton MRA agent
     self.mra = MRA()
     self.ready()
     super(MRA_Module, self).start()
예제 #2
0
 def __init__(self, argv):
     super(MRA_Module, self).__init__(argv)
     self.tasks = ["BUILD-MODEL", "EXPAND-MODEL", "MODEL-HAS-MECHANISM"]
     self.models = []
     for task in self.tasks:
         msg_txt = "(subscribe :content (request &key :content (%s . *)))" % task
         self.send(KQMLPerformative.from_string(msg_txt))
     # Instantiate a singleton MRA agent
     self.mra = MRA()
     self.ready()
     super(MRA_Module, self).start()
예제 #3
0
class MRA_Module(KQMLModule):
    def __init__(self, argv):
        super(MRA_Module, self).__init__(argv)
        self.tasks = ["BUILD-MODEL", "EXPAND-MODEL", "MODEL-HAS-MECHANISM"]
        self.models = []
        for task in self.tasks:
            msg_txt = "(subscribe :content (request &key :content (%s . *)))" % task
            self.send(KQMLPerformative.from_string(msg_txt))
        # Instantiate a singleton MRA agent
        self.mra = MRA()
        self.ready()
        super(MRA_Module, self).start()

    def receive_tell(self, msg, content):
        tell_content = content[0].to_string().upper()
        if tell_content == "START-CONVERSATION":
            logger.info("MRA resetting")
            # self.mra = MRA()
            # self.models = []

    def receive_request(self, msg, content):
        """
        If a "request" message is received, decode the task and the content
        and call the appropriate function to prepare the response. A reply
        "tell" message is then sent back.
        """
        try:
            task_str = content[0].to_string().upper()
        except Exception as e:
            logger.error("Could not get task string from request.")
            logger.error(e)
            self.error_reply(msg, "Invalid task")
        if task_str == "BUILD-MODEL":
            try:
                reply_content = self.respond_build_model(content)
            except InvalidModelDescriptionError as e:
                logger.error("Invalid model description.")
                logger.error(e)
                fail_msg = "(FAILURE :reason INVALID_DESCRIPTION)"
                reply_content = KQMLList.from_string(fail_msg)
        elif task_str == "EXPAND-MODEL":
            try:
                reply_content = self.respond_expand_model(content)
            except InvalidModelIdError as e:
                logger.error("Invalid model ID.")
                logger.error(e)
                fail_msg = "(FAILURE :reason INVALID_MODEL_ID)"
                reply_content = KQMLList.from_string(fail_msg)
            except InvalidModelDescriptionError as e:
                logger.error("Invalid model description.")
                logger.error(e)
                fail_msg = "(FAILURE :reason INVALID_DESCRIPTION)"
                reply_content = KQMLList.from_string(fail_msg)
        elif task_str == "MODEL-HAS-MECHANISM":
            reply_content = self.respond_has_mechanism(content)
        else:
            self.error_reply(msg, "Unknown task " + task_str)
            return
        reply_msg = KQMLPerformative("reply")
        reply_msg.set_parameter(":content", reply_content)
        self.reply(msg, reply_msg)

    def respond_build_model(self, content_list):
        """
        Response content to build-model request
        """
        try:
            descr_arg = content_list.get_keyword_arg(":description")
            descr = descr_arg[0].to_string()
            descr = self.decode_description(descr)
            model = self.mra.build_model_from_ekb(descr)
        except Exception as e:
            raise InvalidModelDescriptionError(e)
        if model is None:
            raise InvalidModelDescriptionError
        self.get_context(model)
        self.models.append(model)
        model_id = len(self.models)
        model_enc = self.encode_model(model)
        try:
            model_diagram = self.get_model_diagram(model, model_id)
        except DiagramGenerationError as e:
            logger.error("Could not generate model diagram.")
            logger.error(e)
            model_diagram = ""
        except DiagramConversionError as e:
            logger.error("Could not save model diagram.")
            logger.error(e)
            model_diagram = ""
        reply_content = KQMLList.from_string(
            '(SUCCESS :model-id %s :model "%s" :diagram "%s")' % (model_id, model_enc, model_diagram)
        )
        return reply_content

    def respond_expand_model(self, content_list):
        """
        Response content to expand-model request
        """
        try:
            descr_arg = content_list.get_keyword_arg(":description")
            descr = descr_arg[0].to_string()
            descr = self.decode_description(descr)
        except Exception as e:
            raise InvalidModelDescriptionError(e)
        model_id_arg = content_list.get_keyword_arg(":model-id")
        if model_id_arg is None:
            logger.error("Model ID missing.")
            raise InvalidModelIdError
        try:
            model_id_str = model_id_arg.to_string()
            model_id = int(model_id_str)
        except Exception as e:
            logger.error("Could not get model ID as integer.")
            raise InvalidModelIdError(e)
        if model_id < 1 or model_id > len(self.models):
            logger.error("Model ID does not refer to an existing model.")
            raise InvalidModelIdError

        try:
            model = self.mra.expand_model_from_ekb(descr, model_id)
        except Exception as e:
            raise InvalidModelDescriptionError
        self.get_context(model)
        self.models.append(model)
        new_model_id = len(self.models)
        model_enc = self.encode_model(model)
        try:
            model_diagram = self.get_model_diagram(model, new_model_id)
        except DiagramGenerationError:
            model_diagram = ""
        except DiagramConversionError:
            model_diagram = ""
        reply_content = KQMLList.from_string(
            '(SUCCESS :model-id %s :model "%s" :diagram "%s")' % (new_model_id, model_enc, model_diagram)
        )
        return reply_content

    def respond_has_mechanism(self, content_list):
        """
        Response content to model-has-mechanism request
        """
        try:
            descr_arg = content_list.get_keyword_arg(":description")
            descr = descr_arg[0].to_string()
            descr = self.decode_description(descr)
        except Exception as e:
            raise InvalidModelDescriptionError(e)
        model_id_arg = content_list.get_keyword_arg(":model-id")
        if model_id_arg is None:
            logger.error("Model ID missing.")
            raise InvalidModelIdError
        try:
            model_id_str = model_id_arg.to_string()
            model_id = int(model_id_str)
        except Exception as e:
            logger.error("Could not get model ID as integer.")
            raise InvalidModelIdError(e)
        if model_id < 1 or model_id > len(self.models):
            logger.error("Model ID does not refer to an existing model.")
            raise InvalidModelIdError

        try:
            has_mechanism = self.mra.has_mechanism(descr, model_id)
        except Exception as e:
            raise InvalidModelDescriptionError
        reply_content = KQMLList.from_string("(SUCCESS :model-id %s :has-mechanism %s)" % (model_id, has_mechanism))
        return reply_content

    @staticmethod
    def get_model_diagram(model, model_id=None):
        try:
            for m in model.monomers:
                pysb_assembler.set_extended_initial_condition(model, m, 0)
            fname = "model%d" % ("" if model_id is None else model_id)
            diagram_dot = render_reactions.run(model)
        # TODO: use specific PySB/BNG exceptions and handle them
        # here to show meaningful error messages
        except Exception as e:
            raise DiagramGenerationError(e)
        try:
            with open(fname + ".dot", "wt") as fh:
                fh.write(diagram_dot)
            subprocess.call(("dot -T png -o %s.png %s.dot" % (fname, fname)).split(" "))
            abs_path = os.path.abspath(os.getcwd())
            if abs_path[-1] != "/":
                abs_path = abs_path + "/"
            full_path = abs_path + fname + ".png"
        except Exception as e:
            raise DiagramConversionError(e)
        return full_path

    @staticmethod
    def get_context(model):
        # TODO: Here we will have to query the context
        # for now it is not used
        pass

    @staticmethod
    def decode_description(descr):
        if descr[0] == '"':
            descr = descr[1:]
        if descr[-1] == '"':
            descr = descr[:-1]
        descr = descr.replace('\\"', '"')
        return descr

    @staticmethod
    def encode_model(model):
        model_str = pysb.export.export(model, "pysb_flat")
        model_str = str(model_str.strip())
        model_str = model_str.replace('"', '\\"')
        return model_str
예제 #4
0
파일: server.py 프로젝트: jivechang/mra
urlmap(style, "styles", ())
# Layers, layer styles and data fields:
urlmap(layers, "layers")
urlmap(layer, "layers", ())
urlmap(layerstyles, "layers", (), "styles")
urlmap(layerstyle, "layers", (), "styles", ())
urlmap(layerfields, "layers", (), "fields")
# Layergroups:
urlmap(layergroups, "layergroups")
urlmap(layergroup, "layergroups", ())
# OGC Web Services:
urlmap(OWSGlobalSettings, "services", "(wms|wfs|wcs)", "settings")

urls = tuple(urlmap)

mra = MRA(os.path.join(sys.path[0], "mra.yaml"))

mralogs.setup(mra.config["logging"]["level"], mra.config["logging"]["file"],
              mra.config["logging"]["format"])

web.config.debug = mra.config["debug"].get("web_debug", False)
webapp.exceptionManager.raise_all = mra.config["debug"].get("raise_all", False)
HTTPCompatible.return_logs = mra.config["logging"].get("web_logs", False)

for pdir in mra.config["plugins"].get("loadpaths", []):
    plugins.load_plugins_dir(pdir)

app = web.application(urls, globals())

if __name__ == "__main__":
    app.run()
예제 #5
0
 def __init__(self, **kwargs):
     # Instantiate a singleton MRA agent
     self.mra = MRA()
     super(MRA_Module, self).__init__(**kwargs)
예제 #6
0
class MRA_Module(Bioagent):
    name = "MRA"
    tasks = [
        'BUILD-MODEL', 'EXPAND-MODEL', 'MODEL-HAS-MECHANISM',
        'MODEL-REPLACE-MECHANISM', 'MODEL-REMOVE-MECHANISM', 'MODEL-UNDO',
        'MODEL-GET-UPSTREAM'
    ]

    def __init__(self, **kwargs):
        # Instantiate a singleton MRA agent
        self.mra = MRA()
        super(MRA_Module, self).__init__(**kwargs)

    def receive_tell(self, msg, content):
        tell_content = content.head().upper()
        if tell_content == 'START-CONVERSATION':
            logger.info('MRA resetting')

    def receive_request(self, msg, content):
        """Handle request messages and respond.

        If a "request" message is received, decode the task and the content
        and call the appropriate function to prepare the response. A reply
        message is then sent back.
        """
        ret = None
        try:
            ret = super(MRA_Module, self).receive_request(msg, content)
        except InvalidModelDescriptionError as e:
            logger.error('Invalid model description.')
            logger.error(e)
            reply_content = self.make_failure('INVALID_DESCRIPTION')
        except InvalidModelIdError as e:
            logger.error('Invalid model ID.')
            logger.error(e)
            reply_content = self.make_failure('INVALID_MODEL_ID')
        except Exception as e:
            logger.error(e)
            reply_content = self.make_failure('INTERNAL_FAILURE')
        if ret is None:
            ret = self.reply_with_content(msg, reply_content)
        return ret

    def respond_build_model(self, content):
        """Return response content to build-model request."""
        descr = content.gets('description')
        descr_format = content.gets('format')
        no_display = content.get('no-display')
        try:
            if not descr_format or descr_format == 'ekb':
                res = self.mra.build_model_from_ekb(descr)
            elif descr_format == 'indra_json':
                res = self.mra.build_model_from_json(descr)
            else:
                err_msg = 'Invalid description format: %s' % descr_format
                raise InvalidModelDescriptionError(err_msg)
        except Exception as e:
            raise InvalidModelDescriptionError(e)
        model_id = res.get('model_id')
        if model_id is None:
            raise InvalidModelDescriptionError()
        # Start a SUCCESS message
        msg = KQMLPerformative('SUCCESS')
        # Add the model id
        msg.set('model-id', str(model_id))
        # Add the INDRA model json
        model = res.get('model')
        model_msg = encode_indra_stmts(model)
        msg.sets('model', model_msg)
        # Add the diagrams
        diagrams = res.get('diagrams')
        if not no_display:
            if diagrams:
                rxn_diagram = diagrams.get('reactionnetwork')
                if rxn_diagram:
                    msg.sets('diagram', rxn_diagram)
                if not self.testing:
                    self.send_display_model(model_msg, diagrams)
        ambiguities = res.get('ambiguities')
        if ambiguities:
            ambiguities_msg = get_ambiguities_msg(ambiguities)
            msg.set('ambiguities', ambiguities_msg)
        return msg

    def respond_expand_model(self, content):
        """Return response content to expand-model request."""
        descr = content.gets('description')
        model_id = self._get_model_id(content)
        descr_format = content.gets('format')
        no_display = content.get('no-display')
        try:
            if not descr_format or descr_format == 'ekb':
                res = self.mra.expand_model_from_ekb(descr, model_id)
            elif descr_format == 'indra_json':
                res = self.mra.expand_model_from_json(descr, model_id)
            else:
                err_msg = 'Invalid description format: %s' % descr_format
                raise InvalidModelDescriptionError(err_msg)
        except Exception as e:
            raise InvalidModelDescriptionError(e)
        new_model_id = res.get('model_id')
        if new_model_id is None:
            raise InvalidModelDescriptionError()
        # Start a SUCCESS message
        msg = KQMLPerformative('SUCCESS')
        # Add the model id
        msg.set('model-id', str(new_model_id))
        # Add the INDRA model json
        model = res.get('model')
        model_msg = encode_indra_stmts(model)
        msg.sets('model', model_msg)
        # Add the INDRA model new json
        model_new = res.get('model_new')
        if model_new:
            model_new_msg = encode_indra_stmts(model_new)
            msg.sets('model-new', model_new_msg)
        # Add the diagram
        if not no_display:
            diagrams = res.get('diagrams')
            if diagrams:
                rxn_diagram = diagrams.get('reactionnetwork')
                if rxn_diagram:
                    msg.sets('diagram', rxn_diagram)
                if not self.testing:
                    self.send_display_model(model_msg, diagrams)
        ambiguities = res.get('ambiguities')
        if ambiguities:
            ambiguities_msg = get_ambiguities_msg(ambiguities)
            msg.set('ambiguities', ambiguities_msg)
        return msg

    def respond_model_undo(self, content):
        """Return response content to model-undo request."""
        res = self.mra.model_undo()
        no_display = content.get('no-display')
        new_model_id = res.get('model_id')
        # Start a SUCCESS message
        msg = KQMLPerformative('SUCCESS')
        # Add the model id
        msg.set('model-id', str(new_model_id))
        # Add the INDRA model json
        model = res.get('model')
        model_msg = encode_indra_stmts(model)
        msg.sets('model', model_msg)
        # Add the diagram
        diagrams = res.get('diagrams')
        if not no_display:
            if diagrams:
                rxn_diagram = diagrams.get('reactionnetwork')
                if rxn_diagram:
                    msg.sets('diagram', rxn_diagram)
                if not self.testing:
                    self.send_display_model(model_msg, diagrams)
        return msg

    def respond_has_mechanism(self, content):
        """Return response content to model-has-mechanism request."""
        ekb = content.gets('description')
        model_id = self._get_model_id(content)
        try:
            res = self.mra.has_mechanism(ekb, model_id)
        except Exception as e:
            raise InvalidModelDescriptionError(e)
        # Start a SUCCESS message
        msg = KQMLPerformative('SUCCESS')
        # Add the model id
        msg.set('model-id', str(model_id))
        # Add TRUE or FALSE for has-mechanism
        has_mechanism_msg = 'TRUE' if res['has_mechanism'] else 'FALSE'
        msg.set('has-mechanism', has_mechanism_msg)
        query = res.get('query')
        if query:
            query_msg = encode_indra_stmts([query])
            msg.sets('query', query_msg)
        return msg

    def respond_remove_mechanism(self, content):
        """Return response content to model-remove-mechanism request."""
        ekb = content.gets('description')
        model_id = self._get_model_id(content)
        no_display = content.get('no-display')
        try:
            res = self.mra.remove_mechanism(ekb, model_id)
        except Exception as e:
            raise InvalidModelDescriptionError(e)
        model_id = res.get('model_id')
        if model_id is None:
            raise InvalidModelDescriptionError('Could not find model id.')
        # Start a SUCCESS message
        msg = KQMLPerformative('SUCCESS')
        # Add the model id
        msg.set('model-id', str(model_id))
        # Add the INDRA model json
        model = res.get('model')
        model_msg = encode_indra_stmts(model)
        msg.sets('model', model_msg)
        # Add the removed statements
        removed = res.get('removed')
        if removed:
            removed_msg = encode_indra_stmts(removed)
            msg.sets('removed', removed_msg)
        # Add the diagram
        diagrams = res.get('diagrams')
        if not no_display:
            if diagrams:
                rxn_diagram = diagrams.get('reactionnetwork')
                if rxn_diagram:
                    msg.sets('diagram', rxn_diagram)
                if not self.testing:
                    self.send_display_model(model_msg, rxn_diagram)
        return msg

    def respond_model_get_upstream(self, content):
        """Return response content to model-upstream request."""
        target_arg = content.gets('target')
        target = get_target(target_arg)
        try:
            model_id = self._get_model_id(content)
        except Exception as e:
            model_id = 1
        upstream = self.mra.get_upstream(target, model_id)
        terms = []
        names = []
        for agent in upstream:
            term = ekb_from_agent(agent)
            if term is not None:
                names.append(KQMLString(agent.name))
                terms.append(KQMLString(term))
        reply = KQMLList('SUCCESS')
        reply.set('upstream', KQMLList(terms))
        reply.set('upstream-names', KQMLList(names))
        return reply

    def send_display_model(self, model, diagrams):
        msg = KQMLPerformative('tell')
        content = KQMLList('display-model')
        content.set('type', 'indra')
        content.sets('model', model)
        msg.set('content', content)
        self.send(msg)
        for diagram_type, path in diagrams.items():
            if not path:
                continue
            msg = KQMLPerformative('tell')
            content = KQMLList('display-image')
            content.set('type', diagram_type)
            content.sets('path', path)
            msg.set('content', content)
            self.send(msg)

    def _get_model_id(self, content):
        model_id_arg = content.get('model-id')
        if model_id_arg is None:
            logger.error('Model ID missing.')
            raise InvalidModelIdError
        try:
            model_id_str = model_id_arg.to_string()
            model_id = int(model_id_str)
        except Exception as e:
            logger.error('Could not get model ID as integer.')
            raise InvalidModelIdError(e)
        if not self.mra.has_id(model_id):
            logger.error('Model ID does not refer to an existing model.')
            raise InvalidModelIdError
        return model_id
예제 #7
0
class MRA_Module(trips_module.TripsModule):
    def __init__(self, argv):
        super(MRA_Module, self).__init__(argv)
        self.tasks = ['BUILD-MODEL', 'EXPAND-MODEL']
        self.models = []
        for task in self.tasks:
            msg_txt =\
                '(subscribe :content (request &key :content (%s . *)))' % task
            self.send(KQMLPerformative.from_string(msg_txt))
        # Instantiate a singleton MRA agent
        self.mra = MRA()
        self.ready()
        super(MRA_Module, self).start()

    def receive_tell(self, msg, content):
        tell_content = content[0].to_string().upper()
        if tell_content == 'START-CONVERSATION':
            logger.info('MRA resetting')
            #self.mra = MRA()
            #self.models = []

    def receive_request(self, msg, content):
        '''
        If a "request" message is received, decode the task and the content
        and call the appropriate function to prepare the response. A reply
        "tell" message is then sent back.
        '''
        try:
            task_str = content[0].to_string().upper()
        except Exception as e:
            logger.error('Could not get task string from request.')
            logger.error(e)
            self.error_reply(msg, 'Invalid task')
        if task_str == 'BUILD-MODEL':
            try:
                reply_content = self.respond_build_model(content)
            except InvalidModelDescriptionError as e:
                logger.error('Invalid model description.')
                logger.error(e)
                fail_msg = '(FAILURE :reason INVALID_DESCRIPTION)'
                reply_content = KQMLList.from_string(fail_msg)
        elif task_str == 'EXPAND-MODEL':
            try:
                reply_content = self.respond_expand_model(content)
            except InvalidModelIdError as e:
                logger.error('Invalid model ID.')
                logger.error(e)
                fail_msg = '(FAILURE :reason INVALID_MODEL_ID)'
                reply_content = KQMLList.from_string(fail_msg)
            except InvalidModelDescriptionError as e:
                logger.error('Invalid model description.')
                logger.error(e)
                fail_msg = '(FAILURE :reason INVALID_DESCRIPTION)'
                reply_content = KQMLList.from_string(fail_msg)
        else:
            self.error_reply(msg, 'Unknown task ' + task_str)
            return
        reply_msg = KQMLPerformative('reply')
        reply_msg.set_parameter(':content', reply_content)
        self.reply(msg, reply_msg)

    def respond_build_model(self, content_list):
        '''
        Response content to build-model request
        '''
        try:
            descr_arg = content_list.get_keyword_arg(':description')
            descr = descr_arg[0].to_string()
            descr = self.decode_description(descr)
            model = self.mra.build_model_from_ekb(descr)
        except Exception as e:
            raise InvalidModelDescriptionError(e)
        if model is None:
            raise InvalidModelDescriptionError
        self.get_context(model)
        self.models.append(model)
        model_id = len(self.models)
        model_enc = self.encode_model(model)
        try:
            model_diagram = self.get_model_diagram(model, model_id)
        except DiagramGenerationError as e:
            logger.error('Could not generate model diagram.')
            logger.error(e)
            model_diagram = ''
        except DiagramConversionError as e:
            logger.error('Could not save model diagram.')
            logger.error(e)
            model_diagram = ''
        reply_content =\
            KQMLList.from_string(
            '(SUCCESS :model-id %s :model "%s" :diagram "%s")' %\
                (model_id, model_enc, model_diagram))
        return reply_content

    def respond_expand_model(self, content_list):
        '''
        Response content to expand-model request
        '''
        try:
            descr_arg = content_list.get_keyword_arg(':description')
            descr = descr_arg[0].to_string()
            descr = self.decode_description(descr)
        except Exception as e:
            raise InvalidModelDescriptionError(e)
        model_id_arg = content_list.get_keyword_arg(':model-id')
        if model_id_arg is None:
            logger.error('Model ID missing.')
            raise InvalidModelIdError
        try:
            model_id_str = model_id_arg.to_string()
            model_id = int(model_id_str)
        except Exception as e:
            logger.error('Could not get model ID as integer.')
            raise InvalidModelIdError(e)
        if model_id < 1 or model_id > len(self.models):
            logger.error('Model ID does not refer to an existing model.')
            raise InvalidModelIdError

        try:
            model = self.mra.expand_model_from_ekb(descr, model_id)
        except Exception as e:
            raise InvalidModelDescriptionError
        self.get_context(model)
        self.models.append(model)
        new_model_id = len(self.models)
        model_enc = self.encode_model(model)
        try:
            model_diagram = self.get_model_diagram(model, new_model_id)
        except DiagramGenerationError:
            model_diagram = ''
        except DiagramConversionError:
            model_diagram = ''
        reply_content =\
            KQMLList.from_string(
            '(SUCCESS :model-id %s :model "%s" :diagram "%s")' %\
                (new_model_id, model_enc, model_diagram))
        return reply_content

    @staticmethod
    def get_model_diagram(model, model_id=None):
        try:
            for m in model.monomers:
                pysb_assembler.set_extended_initial_condition(model, m, 0)
            fname = 'model%d' % ('' if model_id is None else model_id)
            diagram_dot = render_reactions.run(model)
        #TODO: use specific PySB/BNG exceptions and handle them
        # here to show meaningful error messages
        except Exception as e:
            raise DiagramGenerationError(e)
        try:
            with open(fname + '.dot', 'wt') as fh:
                fh.write(diagram_dot)
            subprocess.call(
                ('dot -T png -o %s.png %s.dot' % (fname, fname)).split(' '))
            abs_path = os.path.abspath(os.getcwd())
            if abs_path[-1] != '/':
                abs_path = abs_path + '/'
            full_path = abs_path + fname + '.png'
        except Exception as e:
            raise DiagramConversionError(e)
        return full_path

    @staticmethod
    def get_context(model):
        # TODO: Here we will have to query the context
        # for now it is not used
        pass

    @staticmethod
    def decode_description(descr):
        if descr[0] == '"':
            descr = descr[1:]
        if descr[-1] == '"':
            descr = descr[:-1]
        descr = descr.replace('\\"', '"')
        return descr

    @staticmethod
    def encode_model(model):
        model_str = pysb.export.export(model, 'pysb_flat')
        model_str = str(model_str.strip())
        model_str = model_str.replace('"', '\\"')
        return model_str