Skip to content
This repository has been archived by the owner on Dec 1, 2022. It is now read-only.

Commit

Permalink
add_demo_restaurant_bot
Browse files Browse the repository at this point in the history
  • Loading branch information
currenjin committed Aug 27, 2020
1 parent 08cdcb9 commit f239379
Show file tree
Hide file tree
Showing 63 changed files with 399 additions and 3 deletions.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
Metadata-Version: 1.0
Name: python_programming_demo_app
Version: 0.0.1
Summary: UNKNOWN
Home-page: http://sakaijunsoccer.appspot.com
Author: jsakai
Author-email: [email protected]
License: MIT
Description-Content-Type: UNKNOWN
Description: Roboter
====

## Install

1. 以下のようにパーケージをインストールするか、もしくはroboterフォルダーを実行するディレクトリへ置いてください。
$ python setup.py develop

or

$ ls
roboter


## Requirement
pip install termcolor==1.1.0


## Usage

1. 以下のようにtalk_about_restaurant関数を呼び出すと実行可能です。

# vim main.py
import roboter.controller.conversation
roboter.controller.conversation.talk_about_restaurant()

2. 実行して下さい。
$ python main.py

(オプション: 保存するCSVやテンプレート先を変更する場合は、settings.pyに以下の値を入れる。)
# vim settings.py
CSV_FILE_PATH = '/tmp/test.csv'
TEMPLATE_PATH = '/tmp/templates/'

# settings.pyファイルを作成した場合は、変更しない場合のDefaultは以下に設定する
CSV_FILE_PATH = None
TEMPLATE_PATH = None


Platform: UNKNOWN
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
Roboter
====

## Install

1. 이하 패키지를 인스톨하거나, 실행하실 디렉토리에 roboter 폴더를 옮겨주시기 바랍니다.
$ python setup.py develop

or

$ ls
roboter


## Requirement
pip install termcolor==1.1.0


## Usage

1. 이하와 같이 talk_about_restaurant 함수를 불러오면 실행할 수 있습니다.

# vim main.py
import roboter.controller.conversation
roboter.controller.conversation.talk_about_restaurant()

2. 실행해주세요
$ python main.py

(옵션: 보존할 csv 나 템플릿을 변경할 경우는 settings.py 에 아래를 추가합니다)

# vim settings.py
CSV_FILE_PATH = '/tmp/test.csv'
TEMPLATE_PATH = '/tmp/templates/'

# settings.py 파일을 작성한 경우에는, 변경하지 않은 경우의 default 는 다음과 같이 설정합니다.
CSV_FILE_PATH = None
TEMPLATE_PATH = None

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import roboter.controller.conversation
roboter.controller.conversation.talk_about_restaurant()
Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
"""Controller for speaking with robot"""
from roboter.models import robot


def talk_about_restaurant():
"""Function to speak with robot"""
restaurant_robot = robot.RestaurantRobot()
restaurant_robot.hello()
restaurant_robot.recommend_restaurant()
restaurant_robot.ask_user_favorite()
restaurant_robot.thank_you()

Binary file not shown.
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
"""Generates ranking model to write to CSV
TODO (jsakai) Rewrite to DB instead of CSV
"""
import collections
import csv
import os
import pathlib


RANKING_COLUMN_NAME = 'NAME'
RANKING_COLUMN_COUNT = 'COUNT'
RANKING_CSV_FILE_PATH = 'ranking.csv'


class CsvModel(object):
"""Base csv model."""
def __init__(self, csv_file):
self.csv_file = csv_file
if not os.path.exists(csv_file):
pathlib.Path(csv_file).touch()


class RankingModel(CsvModel):
"""Definition of class that generates ranking model to write to CSV"""
def __init__(self, csv_file=None, *args, **kwargs):
if not csv_file:
csv_file = self.get_csv_file_path()
super().__init__(csv_file, *args, **kwargs)
self.column = [RANKING_COLUMN_NAME, RANKING_COLUMN_COUNT]
self.data = collections.defaultdict(int)
self.load_data()

def get_csv_file_path(self):
"""Set csv file path.
Use csv path if set in settings, otherwise use default
"""
csv_file_path = None
try:
import settings
if settings.CSV_FILE_PATH:
csv_file_path = settings.CSV_FILE_PATH
except ImportError:
pass

if not csv_file_path:
csv_file_path = RANKING_CSV_FILE_PATH
return csv_file_path

def load_data(self):
"""Load csv data.
Returns:
dict: Returns ranking data of dict type.
"""
with open(self.csv_file, 'r+') as csv_file:
reader = csv.DictReader(csv_file)
for row in reader:
self.data[row[RANKING_COLUMN_NAME]] = int(
row[RANKING_COLUMN_COUNT])
return self.data

def save(self):
"""Save data to csv file."""
# TODO (jsakai) Use locking mechanism for avoiding dead lock issue
with open(self.csv_file, 'w+') as csv_file:
writer = csv.DictWriter(csv_file, fieldnames=self.column)
writer.writeheader()

for name, count in self.data.items():
writer.writerow({
RANKING_COLUMN_NAME: name,
RANKING_COLUMN_COUNT: count
})

def get_most_popular(self, not_list=None):
"""Fetch the data of the top most ranking.
Args:
not_list (list): Excludes the name on the list.
Returns:
str: Returns the data of the top most ranking
"""
if not_list is None:
not_list = []

if not self.data:
return None

sorted_data = sorted(self.data, key=self.data.get, reverse=True)
for name in sorted_data:
if name in not_list:
continue
return name

def increment(self, name):
"""Increase rank for the give name."""
self.data[name.title()] += 1
self.save()
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
"""Defined a robot model """
from roboter.models import ranking
from roboter.views import console


DEFAULT_ROBOT_NAME = 'Roboko'


class Robot(object):
"""Base model for Robot."""

def __init__(self, name=DEFAULT_ROBOT_NAME, user_name='',
speak_color='green'):
self.name = name
self.user_name = user_name
self.speak_color = speak_color

def hello(self):
"""Returns words to the user that the robot speaks at the beginning."""
while True:
template = console.get_template('hello.txt', self.speak_color)
user_name = input(template.substitute({
'robot_name': self.name}))

if user_name:
self.user_name = user_name.title()
break


class RestaurantRobot(Robot):
"""Handle data model on restaurant."""

def __init__(self, name=DEFAULT_ROBOT_NAME):
super().__init__(name=name)
self.ranking_model = ranking.RankingModel()

def _hello_decorator(func):
"""Decorator to say a greeting if you are not greeting the user."""
def wrapper(self):
if not self.user_name:
self.hello()
return func(self)
return wrapper

@_hello_decorator
def recommend_restaurant(self):
"""Show restaurant recommended restaurant to the user."""
new_recommend_restaurant = self.ranking_model.get_most_popular()
if not new_recommend_restaurant:
return None

will_recommend_restaurants = [new_recommend_restaurant]
while True:
template = console.get_template('greeting.txt', self.speak_color)
is_yes = input(template.substitute({
'robot_name': self.name,
'user_name': self.user_name,
'restaurant': new_recommend_restaurant
}))

if is_yes.lower() == 'y' or is_yes.lower() == 'yes':
break

if is_yes.lower() == 'n' or is_yes.lower() == 'no':
new_recommend_restaurant = self.ranking_model.get_most_popular(
not_list=will_recommend_restaurants)
if not new_recommend_restaurant:
break
will_recommend_restaurants.append(new_recommend_restaurant)

@_hello_decorator
def ask_user_favorite(self):
"""Collect favorite restaurant information from users."""
while True:
template = console.get_template(
'which_restaurant.txt', self.speak_color)
restaurant = input(template.substitute({
'robot_name': self.name,
'user_name': self.user_name,
}))
if restaurant:
self.ranking_model.increment(restaurant)
break

@_hello_decorator
def thank_you(self):
"""Show words of appreciation to users."""
template = console.get_template('good_by.txt', self.speak_color)
print(template.substitute({
'robot_name': self.name,
'user_name': self.user_name,
}))
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
$robot_name: $user_name 씨 감사합니다.
$robot_name: Thank you so much, $user_name! 좋은 하루 되세요. 안녕히가세요
Have a good day!

Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
제가 추천하는 레스토랑은 $restaurant 입니다.
I recommend $restaurant restaurant. 이 레스토랑을 좋아하십니까? [Yes/No]
Do you like it? [y/n]
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
안녕하세요 저는 $robot_name 입니다. 당신의 이름은 무엇입니까?
Hello, I am $robot_name. What is your name?
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
$user_name 씨, 좋아하는 레스토랑은 어디인가요?
$user_name, which restaurants do you like?
Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""Utils to display to be returned to the user on the console."""
import os
import string

import termcolor


def get_template_dir_path():
"""Return the path of the template's directory.
Returns:
str: The template dir path.
"""
template_dir_path = None
try:
import settings
if settings.TEMPLATE_PATH:
template_dir_path = settings.TEMPLATE_PATH
except ImportError:
pass

if not template_dir_path:
base_dir = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
template_dir_path = os.path.join(base_dir, 'templates')

return template_dir_path


class NoTemplateError(Exception):
"""No Template Error"""


def find_template(temp_file):
"""Find for template file in the given location.
Returns:
str: The template file path
Raises:
NoTemplateError: If the file does not exists.
"""
template_dir_path = get_template_dir_path()
temp_file_path = os.path.join(template_dir_path, temp_file)
if not os.path.exists(temp_file_path):
raise NoTemplateError('Could not find {}'.format(temp_file))
return temp_file_path


def get_template(template_file_path, color=None):
"""Return the path of the template.
Args:
template_file_path (str): The template file path
color: (str): Color formatting for output in terminal
See in more details: https://pypi.python.org/pypi/termcolor
Returns:
string.Template: Return templates with characters in templates.
"""
template = find_template(template_file_path)
with open(template, 'r', encoding='utf-8') as template_file:
contents = template_file.read()
contents = contents.rstrip(os.linesep)
contents = '{splitter}{sep}{contents}{sep}{splitter}{sep}'.format(
contents=contents, splitter="=" * 60, sep=os.linesep)
contents = termcolor.colored(contents, color)
return string.Template(contents)
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[egg_info]
tag_build =
tag_date = 0

Loading

0 comments on commit f239379

Please sign in to comment.