#!/usr/bin/env python3

# Copyright (c) Facebook, Inc. and its affiliates.
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
"""Build the candidate responses for a retrieval model.

Examples
--------

.. code-block:: shell

  python build_candidates.py -t convai2 --outfile /tmp/cands.txt
"""

from parlai.core.params import ParlaiParser
from parlai.agents.repeat_label.repeat_label import RepeatLabelAgent
from parlai.core.worlds import create_task
from parlai.core.utils import TimeLogger
import random
import tempfile


def build_cands(opt):
    # create repeat label agent and assign it to the specified task
    agent = RepeatLabelAgent(opt)
    world = create_task(opt, agent)
    if opt['outfile'] is None:
        outfile = tempfile.mkstemp(
            prefix='{}_{}_'.format(opt['task'], opt['datatype']), suffix='.txt'
        )[1]
    else:
        outfile = opt['outfile']

    if opt.get('num_examples', -1) == -1:
        num_examples = world.num_examples()
    else:
        num_examples = opt['num_examples']
    log_timer = TimeLogger()

    print('[ starting to build candidates from task.. (ex:' + str(num_examples) + ')]')
    print('[ saving output to {} ]'.format(outfile))
    cands = []
    for _ in range(num_examples):
        world.parley()
        # We get the acts of the first agent, which is the teacher.
        acts = world.get_acts()[0]
        if isinstance(acts, dict):
            # We turn into a batch of 1 example, in case batching is being used.
            acts = [acts]
        for a in acts:
            candidate = a.get('labels', a.get('eval_labels', None))
            if candidate is not None:
                candidate = candidate[0]
                cands.append(candidate)
        if log_timer.time() > opt['log_every_n_secs']:
            text, _log = log_timer.log(world.total_parleys, world.num_examples())
            print(text)
        if world.epoch_done():
            print('EPOCH DONE')
            break
    fw = open(outfile, 'w')
    fw.write('\n'.join(cands))
    fw.close()


def main():
    random.seed(42)
    # Get command line arguments
    parser = ParlaiParser()
    parser.add_argument(
        '-n',
        '--num-examples',
        default=-1,
        type=int,
        help='Total number of exs to convert, -1 to convert all examples',
    )
    parser.add_argument(
        '-of',
        '--outfile',
        default=None,
        type=str,
        help='Output file where to save, by default will be created in /tmp',
    )
    parser.add_argument('-ltim', '--log-every-n-secs', type=float, default=2)
    parser.set_defaults(datatype='train:evalmode')
    opt = parser.parse_args()
    build_cands(opt)


if __name__ == '__main__':
    main()

parlai/scripts/build_candidates.py
#!/usr/bin/env python3

# Copyright (c) Facebook, Inc. and its affiliates.
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
"""Build the candidate responses for a retrieval model.

Examples
--------

.. code-block:: shell

  python build_candidates.py -t convai2 --outfile /tmp/cands.txt
"""

from parlai.core.params import ParlaiParser
from parlai.agents.repeat_label.repeat_label import RepeatLabelAgent
from parlai.core.worlds import create_task
from parlai.core.utils import TimeLogger
import random
import tempfile


def build_cands(opt):
    # create repeat label agent and assign it to the specified task
    if opt['numthreads'] > 1:
        # Broken in hogwild mode. Just fall back to single processing mode
        opt['numthreads'] = 1
    agent = RepeatLabelAgent(opt)
    world = create_task(opt, agent)
    if opt['outfile'] is None:
        outfile = tempfile.mkstemp(
            prefix='{}_{}_'.format(opt['task'], opt['datatype']), suffix='.txt'
        )[1]
    else:
        outfile = opt['outfile']

    if opt.get('num_examples', -1) == -1:
        num_examples = world.num_examples()
    else:
        num_examples = opt['num_examples']
    log_timer = TimeLogger()

    print('[ starting to build candidates from task.. (ex:' + str(num_examples) + ')]')
    print('[ saving output to {} ]'.format(outfile))
    cands = []
    for _ in range(num_examples):
        world.parley()
        # We get the acts of the first agent, which is the teacher.
        acts = world.get_acts()[0]
        if isinstance(acts, dict):
            # We turn into a batch of 1 example, in case batching is being used.
            acts = [acts]
        for a in acts:
            candidate = a.get('labels', a.get('eval_labels', None))
            if candidate is not None:
                candidate = candidate[0]
                cands.append(candidate)
        if log_timer.time() > opt['log_every_n_secs']:
            text, _log = log_timer.log(world.total_parleys, world.num_examples())
            print(text)
        if world.epoch_done():
            print('EPOCH DONE')
            break
    fw = open(outfile, 'w')
    fw.write('\n'.join(cands))
    fw.close()


def main():
    random.seed(42)
    # Get command line arguments
    parser = ParlaiParser()
    parser.add_argument(
        '-n',
        '--num-examples',
        default=-1,
        type=int,
        help='Total number of exs to convert, -1 to convert all examples',
    )
    parser.add_argument(
        '-of',
        '--outfile',
        default=None,
        type=str,
        help='Output file where to save, by default will be created in /tmp',
    )
    parser.add_argument('-ltim', '--log-every-n-secs', type=float, default=2)
    parser.set_defaults(datatype='train:evalmode')
    opt = parser.parse_args()
    build_cands(opt)


if __name__ == '__main__':
    main()

parlai/scripts/build_candidates.py
diff --git a/parlai/scripts/build_candidates.py b/parlai/scripts/build_candidates.py
index db5d55ce615..b95959be4d4 100644
--- a/parlai/scripts/build_candidates.py
+++ b/parlai/scripts/build_candidates.py
@@ -23,6 +23,9 @@
 
 def build_cands(opt):
     # create repeat label agent and assign it to the specified task
+    if opt['numthreads'] > 1:
+        # Broken in hogwild mode. Just fall back to single processing mode
+        opt['numthreads'] = 1
     agent = RepeatLabelAgent(opt)
     world = create_task(opt, agent)
     if opt['outfile'] is None:

Quickstart AttributeError: 'HogwildWorld' object has no attribute 'acts'
**Bug description**
When going through the ParlAI [quickstart](https://parl.ai/docs/tutorial_quick.html#install), I got the following error:

``` python
Traceback (most recent call last):
  File "examples/interactive.py", line 18, in <module>
    interactive(opt, print_parser=parser)
  File "/root/ParlAI/parlai/scripts/interactive.py", line 68, in interactive
    agent = create_agent(opt, requireModelExists=True)
  File "/root/ParlAI/parlai/core/agents.py", line 683, in create_agent
    model = load_agent_module(opt)
  File "/root/ParlAI/parlai/core/agents.py", line 548, in load_agent_module
    return model_class(new_opt)
  File "/root/ParlAI/parlai/agents/memnn/memnn.py", line 86, in __init__
    super().__init__(opt, shared)
  File "/root/ParlAI/parlai/core/torch_ranker_agent.py", line 135, in __init__
    super().__init__(opt, shared)
  File "/root/ParlAI/parlai/core/torch_agent.py", line 737, in __init__
    self.set_interactive_mode(opt['interactive_mode'], shared)
  File "/root/ParlAI/parlai/core/torch_ranker_agent.py", line 206, in set_interactive_mode
    path = self.get_task_candidates_path()
  File "/root/ParlAI/parlai/core/torch_ranker_agent.py", line 230, in get_task_candidates_path
    build_cands(opt)
  File "/root/ParlAI/parlai/scripts/build_candidates.py", line 47, in build_cands
    acts = world.get_acts()[0]
  File "/root/ParlAI/parlai/core/worlds.py", line 162, in get_acts
    return self.acts
AttributeError: 'HogwildWorld' object has no attribute 'acts'
```

**While running**
```python
python examples/interactive.py -mf /tmp/babi_memnn -ecands vocab
```

