diff --git a/Yasir Abdur Rohman/Project 1/.ipynb_checkpoints/Topic Modelling on Encrypted Twitter Dataset -checkpoint.ipynb b/Yasir Abdur Rohman/Project 1/.ipynb_checkpoints/Topic Modelling on Encrypted Twitter Dataset -checkpoint.ipynb new file mode 100644 index 00000000..7cb2f5af --- /dev/null +++ b/Yasir Abdur Rohman/Project 1/.ipynb_checkpoints/Topic Modelling on Encrypted Twitter Dataset -checkpoint.ipynb @@ -0,0 +1,2773 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Topic Modelling on Encrpyted Twitter Dataset\n", + "*Author: Yasir Abdur Rohman*\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Introduction\n", + "In this notebook, I will implement Topic Modelling with Latent Dirichlet on Encrypted Twitter Dataset. \n", + "\n", + "Twitter is one of the social media that has followed the GDPR rules to protect the privacy of each user. However, we can still access tweets from many users by using the Twitter API. Even though there is an agreement to use the Twitter API wisely, it will still damage the privacy of other users who don't want their tweets to be taken. Therefore, here we will implement Encrypted Twitter Dataset as a privacy protection from the user.\n", + "\n", + "And after we encrypt the Twitter dataset, we can still implement AI securely. Here, we will apply Topic Modeling to uncover abstract themes based on the underlying tweet documents and words in a corpus of text.\n", + "\n", + "The project consists of the following steps:\n", + "1. Crawling Twitter Dataset\n", + "2. Exploratory Data Analysis\n", + "3. Implement Encrypted Twitter Dataset\n", + "4. Topic Modelling" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Step 1: Crawling Twitter Dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + " \n", + " " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# import library\n", + "\n", + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import string\n", + "import time\n", + "\n", + "# import dotenv\n", + "import os\n", + "from dotenv import load_dotenv\n", + "\n", + "# import tweepy\n", + "import tweepy\n", + "\n", + "# datetime\n", + "from datetime import datetime, timedelta\n", + "\n", + "# plotly\n", + "from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot\n", + "import plotly as py\n", + "import plotly.graph_objs as go\n", + "\n", + "init_notebook_mode(connected=True) #do not miss this line\n", + "\n", + "# gensim\n", + "from gensim import corpora, models, similarities\n", + "\n", + "import warnings\n", + "warnings.filterwarnings(\"ignore\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We need Twitter API to crawl Twitter dataset. So, let's setting up for Twitter crawler first. " + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [], + "source": [ + "# load env file\n", + "load_dotenv(\".env\")\n", + "\n", + "# setting API Twitter\n", + "TWITTER_API_KEY = os.getenv('TWITTER_API_KEY')\n", + "TWITTER_API_SECRET_KEY = os.getenv('TWITTER_API_SECRET_KEY')\n", + "TWITTER_ACCESS_TOKEN = os.getenv('TWITTER_ACCESS_TOKEN')\n", + "TWITTER_ACCESS_TOKEN_SECRET = os.getenv('TWITTER_ACCESS_TOKEN_SECRET')\n", + "\n", + "auth = tweepy.OAuthHandler(TWITTER_API_KEY, TWITTER_API_SECRET_KEY)\n", + "auth.set_access_token(TWITTER_ACCESS_TOKEN, TWITTER_ACCESS_TOKEN_SECRET)\n", + "api = tweepy.API(auth, wait_on_rate_limit=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this project, we can setting up some parameters as follows:\n", + "- **maximum_days:** the age of the tweet document from the current time.\n", + "- **query:** keywords for searching tweet documents" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [], + "source": [ + "# initialize crawler parameters\n", + "\n", + "# date\n", + "maximum_days = 7 # 7 days, so we will get all of the tweet documents from 7 days before\n", + "today = datetime.today()\n", + "date_max = today - timedelta(days=maximum_days)\n", + "\n", + "# query\n", + "query = \"#Udacity OR #udacity OR Udacity OR udacity\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we will save the results of crawling the tweet document into the pandas dataframe .\n", + "\n", + "The fields from the tweet document that we will obtain are as follows:\n", + "- **username:** users\n", + "- **created_at:** the date when the tweet created\n", + "- **text:** text of the tweet" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [], + "source": [ + "# initialize dataframe\n", + "df_tweet = pd.DataFrame({'username': [], 'created_at': [], 'text': []})\n", + "\n", + "# crawling tweet documents\n", + "c = tweepy.Cursor(api.search, q=query, tweet_mode='extended').items()\n", + "while True:\n", + " try:\n", + " tweet = c.next()\n", + " \n", + " # get clean tweet without RT\n", + " if (not tweet.retweeted) and ('RT @' not in tweet.full_text):\n", + " username = tweet.user.screen_name\n", + " created = tweet.created_at\n", + " text = tweet.full_text.encode('utf-8', 'ignore').decode('utf-8', 'ignore')\n", + "\n", + " # get tweet documents before maximum_days\n", + " if tweet.created_at < date_max:\n", + " break\n", + " df_tweet = df_tweet.append({'username': username, 'created_at': created, \n", + " 'text': text}, ignore_index=True)\n", + " \n", + " except tweepy.TweepError as e:\n", + " print(e.reason)\n", + " time.sleep(15 * 60)\n", + " continue\n", + " except StopIteration:\n", + " break" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Step 2: Exploratory Data Analysis" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
usernamecreated_attext
0JustNowBulletin2019-08-20 14:20:11Udacity AWS DeepRacer Scholarship Challenge fo...
1sustaintrain2019-08-20 14:15:10A new Udacity Green IT training course has bee...
2Upwork2019-08-20 13:20:49Back to School Isn’t Just For Kids: 20 Courses...
3frengki_172019-08-20 13:17:23@onnowpurbo Belajar tensorflow yang di udacity...
4javaquantum2019-08-20 13:14:13@xsahil03x @GoogleIndia @udacity Congratulatio...
5RahulSi886620932019-08-20 13:08:38@anandjha_98 @kala83 @Google @udacity Please r...
6MaramAlroshoud2019-08-20 12:49:10وشو مسك يوداستي؟ — https://t.co/UC0Y4m9Foo htt...
7SafeScholarship2019-08-20 12:29:52Udacity AWS DeepRacer Scholarship Challenge fo...
80xAlsharif2019-08-20 12:29:09Networking for Web Developers. https://t.co/Hf...
90xAlsharif2019-08-20 12:19:33تحية وتقدير للمواقع والمصادر التعليمية اللي تج...
\n", + "
" + ], + "text/plain": [ + " username created_at \\\n", + "0 JustNowBulletin 2019-08-20 14:20:11 \n", + "1 sustaintrain 2019-08-20 14:15:10 \n", + "2 Upwork 2019-08-20 13:20:49 \n", + "3 frengki_17 2019-08-20 13:17:23 \n", + "4 javaquantum 2019-08-20 13:14:13 \n", + "5 RahulSi88662093 2019-08-20 13:08:38 \n", + "6 MaramAlroshoud 2019-08-20 12:49:10 \n", + "7 SafeScholarship 2019-08-20 12:29:52 \n", + "8 0xAlsharif 2019-08-20 12:29:09 \n", + "9 0xAlsharif 2019-08-20 12:19:33 \n", + "\n", + " text \n", + "0 Udacity AWS DeepRacer Scholarship Challenge fo... \n", + "1 A new Udacity Green IT training course has bee... \n", + "2 Back to School Isn’t Just For Kids: 20 Courses... \n", + "3 @onnowpurbo Belajar tensorflow yang di udacity... \n", + "4 @xsahil03x @GoogleIndia @udacity Congratulatio... \n", + "5 @anandjha_98 @kala83 @Google @udacity Please r... \n", + "6 وشو مسك يوداستي؟ — https://t.co/UC0Y4m9Foo htt... \n", + "7 Udacity AWS DeepRacer Scholarship Challenge fo... \n", + "8 Networking for Web Developers. https://t.co/Hf... \n", + "9 تحية وتقدير للمواقع والمصادر التعليمية اللي تج... " + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# let's see our twitter dataset\n", + "df_tweet.head(10)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The number of tweet documents: 493\n" + ] + } + ], + "source": [ + "# let's counting how many tweet documents that we got\n", + "print(\"The number of tweet documents:\", len(df_tweet['text']))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualizing The Number of Tweets for each day" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "linkText": "Export to plot.ly", + "plotlyServerURL": "https://plot.ly", + "showLink": false + }, + "data": [ + { + "marker": { + "color": "blue" + }, + "opacity": 0.75, + "type": "histogram", + "x": [ + "2019-08-20T14:20:11", + "2019-08-20T14:15:10", + "2019-08-20T13:20:49", + "2019-08-20T13:17:23", + "2019-08-20T13:14:13", + "2019-08-20T13:08:38", + "2019-08-20T12:49:10", + "2019-08-20T12:29:52", + "2019-08-20T12:29:09", + "2019-08-20T12:19:33", + "2019-08-20T11:56:06", + "2019-08-20T11:55:40", + "2019-08-20T11:47:58", + "2019-08-20T11:04:28", + "2019-08-20T09:09:11", + "2019-08-20T07:40:02", + "2019-08-20T07:23:02", + "2019-08-20T07:10:02", + "2019-08-20T06:47:44", + "2019-08-20T06:39:01", + "2019-08-20T05:56:57", + "2019-08-20T05:13:20", + "2019-08-20T04:36:32", + "2019-08-20T04:33:32", + "2019-08-20T04:03:08", + "2019-08-20T03:46:31", + "2019-08-20T03:44:14", + "2019-08-20T03:40:56", + "2019-08-20T03:28:33", + "2019-08-20T02:50:02", + "2019-08-20T02:28:57", + "2019-08-20T02:16:14", + "2019-08-20T02:14:38", + "2019-08-20T02:00:27", + "2019-08-20T02:00:02", + "2019-08-20T01:54:07", + "2019-08-20T01:34:01", + "2019-08-20T01:28:00", + "2019-08-20T01:13:03", + "2019-08-20T01:13:01", + "2019-08-20T01:05:33", + "2019-08-20T00:54:09", + "2019-08-20T00:47:07", + "2019-08-20T00:29:09", + "2019-08-19T23:50:59", + "2019-08-19T23:00:03", + "2019-08-19T22:35:19", + "2019-08-19T22:28:06", + "2019-08-19T22:19:16", + "2019-08-19T21:08:48", + "2019-08-19T21:00:08", + "2019-08-19T20:49:48", + "2019-08-19T19:57:24", + "2019-08-19T19:55:10", + "2019-08-19T19:41:41", + "2019-08-19T19:39:28", + "2019-08-19T19:32:50", + "2019-08-19T19:25:05", + "2019-08-19T19:15:09", + "2019-08-19T18:34:24", + "2019-08-19T18:34:16", + "2019-08-19T18:25:52", + "2019-08-19T18:18:12", + "2019-08-19T18:15:07", + "2019-08-19T18:08:12", + "2019-08-19T17:54:49", + "2019-08-19T17:43:33", + "2019-08-19T17:38:17", + "2019-08-19T17:35:44", + "2019-08-19T17:11:28", + "2019-08-19T17:06:26", + "2019-08-19T17:00:20", + "2019-08-19T16:44:14", + "2019-08-19T16:43:39", + "2019-08-19T16:32:27", + "2019-08-19T16:27:01", + "2019-08-19T16:22:32", + "2019-08-19T16:22:17", + "2019-08-19T16:16:12", + "2019-08-19T16:15:09", + "2019-08-19T16:12:52", + "2019-08-19T16:12:23", + "2019-08-19T16:09:00", + "2019-08-19T15:52:03", + "2019-08-19T15:46:59", + "2019-08-19T15:40:21", + "2019-08-19T15:26:17", + "2019-08-19T15:24:44", + "2019-08-19T15:23:28", + "2019-08-19T15:17:57", + "2019-08-19T15:16:48", + "2019-08-19T15:09:42", + "2019-08-19T14:58:38", + "2019-08-19T14:53:21", + "2019-08-19T14:38:42", + "2019-08-19T14:21:00", + "2019-08-19T14:18:34", + "2019-08-19T14:12:26", + "2019-08-19T13:53:37", + "2019-08-19T12:11:14", + "2019-08-19T12:00:01", + "2019-08-19T11:41:22", + "2019-08-19T11:40:36", + "2019-08-19T11:00:01", + "2019-08-19T10:35:54", + "2019-08-19T10:16:30", + "2019-08-19T09:03:41", + "2019-08-19T07:54:03", + "2019-08-19T07:02:35", + "2019-08-19T06:19:11", + "2019-08-19T06:09:27", + "2019-08-19T06:06:59", + "2019-08-19T05:03:21", + "2019-08-19T05:03:05", + "2019-08-19T03:55:35", + "2019-08-19T01:58:23", + "2019-08-19T01:53:31", + "2019-08-19T01:48:26", + "2019-08-19T01:45:51", + "2019-08-19T01:13:07", + "2019-08-19T00:31:08", + "2019-08-19T00:17:22", + "2019-08-18T23:22:21", + "2019-08-18T23:01:54", + "2019-08-18T22:54:33", + "2019-08-18T21:00:04", + "2019-08-18T20:51:24", + "2019-08-18T20:25:35", + "2019-08-18T19:44:01", + "2019-08-18T19:44:00", + "2019-08-18T19:09:04", + "2019-08-18T19:00:05", + "2019-08-18T18:21:12", + "2019-08-18T18:15:13", + "2019-08-18T18:15:07", + "2019-08-18T18:06:13", + "2019-08-18T18:00:09", + "2019-08-18T17:59:10", + "2019-08-18T17:56:21", + "2019-08-18T17:17:51", + "2019-08-18T17:12:10", + "2019-08-18T17:10:25", + "2019-08-18T17:03:21", + "2019-08-18T17:01:03", + "2019-08-18T17:01:01", + "2019-08-18T16:43:44", + "2019-08-18T16:37:03", + "2019-08-18T16:36:39", + "2019-08-18T16:15:07", + "2019-08-18T16:02:12", + "2019-08-18T15:52:10", + "2019-08-18T15:38:14", + "2019-08-18T15:09:45", + "2019-08-18T14:29:27", + "2019-08-18T14:29:18", + "2019-08-18T14:14:19", + "2019-08-18T14:11:49", + "2019-08-18T13:57:39", + "2019-08-18T13:24:20", + "2019-08-18T12:22:54", + "2019-08-18T12:05:02", + "2019-08-18T12:00:24", + "2019-08-18T11:41:30", + "2019-08-18T11:25:13", + "2019-08-18T11:25:12", + "2019-08-18T11:25:12", + "2019-08-18T10:34:30", + "2019-08-18T09:37:18", + "2019-08-18T09:33:28", + "2019-08-18T07:37:13", + "2019-08-18T06:33:47", + "2019-08-18T06:21:12", + "2019-08-18T05:04:38", + "2019-08-18T05:00:51", + "2019-08-18T03:42:11", + "2019-08-18T03:16:30", + "2019-08-18T02:19:28", + "2019-08-18T01:46:59", + "2019-08-18T01:12:38", + "2019-08-17T23:50:18", + "2019-08-17T23:42:23", + "2019-08-17T22:52:00", + "2019-08-17T21:12:06", + "2019-08-17T21:00:04", + "2019-08-17T20:49:02", + "2019-08-17T20:43:54", + "2019-08-17T20:28:26", + "2019-08-17T20:14:29", + "2019-08-17T19:34:52", + "2019-08-17T19:24:38", + "2019-08-17T19:00:11", + "2019-08-17T18:38:19", + "2019-08-17T18:37:04", + "2019-08-17T18:35:02", + "2019-08-17T18:15:08", + "2019-08-17T18:02:53", + "2019-08-17T17:57:56", + "2019-08-17T17:44:08", + "2019-08-17T17:32:34", + "2019-08-17T17:04:59", + "2019-08-17T17:03:41", + "2019-08-17T17:00:18", + "2019-08-17T16:58:30", + "2019-08-17T16:47:00", + "2019-08-17T16:37:49", + "2019-08-17T16:37:23", + "2019-08-17T16:16:15", + "2019-08-17T16:12:05", + "2019-08-17T15:51:38", + "2019-08-17T15:46:16", + "2019-08-17T15:34:20", + "2019-08-17T15:30:03", + "2019-08-17T15:12:05", + "2019-08-17T15:10:51", + "2019-08-17T15:00:23", + "2019-08-17T14:58:34", + "2019-08-17T14:30:54", + "2019-08-17T14:15:07", + "2019-08-17T14:12:23", + "2019-08-17T13:16:31", + "2019-08-17T13:06:25", + "2019-08-17T13:01:45", + "2019-08-17T12:56:46", + "2019-08-17T12:25:46", + "2019-08-17T12:04:54", + "2019-08-17T10:12:17", + "2019-08-17T10:09:07", + "2019-08-17T09:59:45", + "2019-08-17T09:33:00", + "2019-08-17T09:30:57", + "2019-08-17T08:34:19", + "2019-08-17T08:22:42", + "2019-08-17T07:57:47", + "2019-08-17T06:12:14", + "2019-08-17T06:11:53", + "2019-08-17T06:11:17", + "2019-08-17T06:11:16", + "2019-08-17T06:01:01", + "2019-08-17T05:34:13", + "2019-08-17T05:19:49", + "2019-08-17T03:30:56", + "2019-08-17T03:23:31", + "2019-08-17T02:11:48", + "2019-08-17T02:00:03", + "2019-08-17T01:22:07", + "2019-08-17T00:58:05", + "2019-08-17T00:09:37", + "2019-08-17T00:05:07", + "2019-08-17T00:04:42", + "2019-08-16T23:51:12", + "2019-08-16T23:01:49", + "2019-08-16T22:05:42", + "2019-08-16T22:05:01", + "2019-08-16T21:55:36", + "2019-08-16T21:44:07", + "2019-08-16T21:23:45", + "2019-08-16T21:00:08", + "2019-08-16T20:52:31", + "2019-08-16T20:35:02", + "2019-08-16T20:25:59", + "2019-08-16T20:10:49", + "2019-08-16T20:00:08", + "2019-08-16T19:48:30", + "2019-08-16T19:27:45", + "2019-08-16T19:12:09", + "2019-08-16T19:11:48", + "2019-08-16T19:03:49", + "2019-08-16T18:58:21", + "2019-08-16T18:47:23", + "2019-08-16T18:46:06", + "2019-08-16T18:34:12", + "2019-08-16T18:08:03", + "2019-08-16T18:05:23", + "2019-08-16T17:55:54", + "2019-08-16T17:48:06", + "2019-08-16T17:00:17", + "2019-08-16T16:55:16", + "2019-08-16T16:34:36", + "2019-08-16T16:32:38", + "2019-08-16T16:15:12", + "2019-08-16T15:34:40", + "2019-08-16T15:26:33", + "2019-08-16T15:25:53", + "2019-08-16T15:10:29", + "2019-08-16T15:00:22", + "2019-08-16T14:59:08", + "2019-08-16T14:15:12", + "2019-08-16T14:03:18", + "2019-08-16T13:24:25", + "2019-08-16T13:23:48", + "2019-08-16T13:16:54", + "2019-08-16T13:14:23", + "2019-08-16T11:55:51", + "2019-08-16T11:55:07", + "2019-08-16T10:25:08", + "2019-08-16T10:18:27", + "2019-08-16T09:17:12", + "2019-08-16T08:30:17", + "2019-08-16T08:05:16", + "2019-08-16T08:03:55", + "2019-08-16T08:01:30", + "2019-08-16T07:48:00", + "2019-08-16T07:30:08", + "2019-08-16T06:40:17", + "2019-08-16T05:51:06", + "2019-08-16T05:35:06", + "2019-08-16T05:27:20", + "2019-08-16T04:43:15", + "2019-08-16T04:17:25", + "2019-08-16T04:12:21", + "2019-08-16T03:38:04", + "2019-08-16T03:10:24", + "2019-08-16T02:33:51", + "2019-08-16T02:28:17", + "2019-08-16T02:10:35", + "2019-08-16T02:00:04", + "2019-08-16T01:52:37", + "2019-08-16T01:46:47", + "2019-08-16T01:39:01", + "2019-08-16T01:30:11", + "2019-08-15T23:53:45", + "2019-08-15T23:46:25", + "2019-08-15T23:13:34", + "2019-08-15T23:00:11", + "2019-08-15T22:47:27", + "2019-08-15T22:23:43", + "2019-08-15T21:44:22", + "2019-08-15T21:19:57", + "2019-08-15T21:15:12", + "2019-08-15T21:00:09", + "2019-08-15T20:19:44", + "2019-08-15T20:08:11", + "2019-08-15T20:02:17", + "2019-08-15T19:29:58", + "2019-08-15T19:00:18", + "2019-08-15T18:53:47", + "2019-08-15T18:18:56", + "2019-08-15T18:17:16", + "2019-08-15T18:15:13", + "2019-08-15T18:07:46", + "2019-08-15T18:01:48", + "2019-08-15T17:52:59", + "2019-08-15T17:50:17", + "2019-08-15T17:49:07", + "2019-08-15T17:46:13", + "2019-08-15T17:34:31", + "2019-08-15T17:28:59", + "2019-08-15T17:12:20", + "2019-08-15T17:08:09", + "2019-08-15T17:02:03", + "2019-08-15T17:01:07", + "2019-08-15T17:00:24", + "2019-08-15T16:53:47", + "2019-08-15T16:49:01", + "2019-08-15T16:18:15", + "2019-08-15T16:15:13", + "2019-08-15T16:01:27", + "2019-08-15T15:56:00", + "2019-08-15T15:43:56", + "2019-08-15T15:01:00", + "2019-08-15T15:00:17", + "2019-08-15T14:42:54", + "2019-08-15T14:20:28", + "2019-08-15T14:17:52", + "2019-08-15T13:57:03", + "2019-08-15T13:57:02", + "2019-08-15T13:49:41", + "2019-08-15T13:45:32", + "2019-08-15T13:44:25", + "2019-08-15T13:37:12", + "2019-08-15T13:28:45", + "2019-08-15T12:42:46", + "2019-08-15T11:03:20", + "2019-08-15T09:59:29", + "2019-08-15T09:59:06", + "2019-08-15T09:20:36", + "2019-08-15T09:17:42", + "2019-08-15T08:59:34", + "2019-08-15T07:04:33", + "2019-08-15T07:03:15", + "2019-08-15T06:52:19", + "2019-08-15T06:31:15", + "2019-08-15T06:30:41", + "2019-08-15T06:30:27", + "2019-08-15T06:29:53", + "2019-08-15T06:29:27", + "2019-08-15T06:28:27", + "2019-08-15T06:27:57", + "2019-08-15T06:27:17", + "2019-08-15T06:26:47", + "2019-08-15T06:26:03", + "2019-08-15T06:21:38", + "2019-08-15T06:21:05", + "2019-08-15T06:20:38", + "2019-08-15T04:25:18", + "2019-08-15T04:00:01", + "2019-08-15T03:59:07", + "2019-08-15T02:12:49", + "2019-08-15T02:07:37", + "2019-08-15T02:00:04", + "2019-08-15T01:52:58", + "2019-08-15T01:47:22", + "2019-08-15T00:42:53", + "2019-08-15T00:05:33", + "2019-08-14T23:14:11", + "2019-08-14T23:13:20", + "2019-08-14T23:12:55", + "2019-08-14T23:02:35", + "2019-08-14T23:00:06", + "2019-08-14T22:34:23", + "2019-08-14T22:11:12", + "2019-08-14T22:07:30", + "2019-08-14T21:54:54", + "2019-08-14T21:41:03", + "2019-08-14T21:00:08", + "2019-08-14T20:49:52", + "2019-08-14T20:42:58", + "2019-08-14T20:25:42", + "2019-08-14T20:22:35", + "2019-08-14T20:19:01", + "2019-08-14T20:15:11", + "2019-08-14T19:13:44", + "2019-08-14T18:53:05", + "2019-08-14T18:37:19", + "2019-08-14T18:36:47", + "2019-08-14T18:36:43", + "2019-08-14T18:26:49", + "2019-08-14T18:24:54", + "2019-08-14T18:21:47", + "2019-08-14T18:20:16", + "2019-08-14T18:18:41", + "2019-08-14T17:54:53", + "2019-08-14T17:52:50", + "2019-08-14T17:45:14", + "2019-08-14T17:44:30", + "2019-08-14T17:17:33", + "2019-08-14T17:00:20", + "2019-08-14T15:53:13", + "2019-08-14T15:47:51", + "2019-08-14T15:33:50", + "2019-08-14T15:31:57", + "2019-08-14T15:11:39", + "2019-08-14T15:00:20", + "2019-08-14T14:20:22", + "2019-08-14T14:15:11", + "2019-08-14T13:59:05", + "2019-08-14T13:55:48", + "2019-08-14T13:18:45", + "2019-08-14T12:58:26", + "2019-08-14T12:27:35", + "2019-08-14T12:01:21", + "2019-08-14T11:38:44", + "2019-08-14T11:34:58", + "2019-08-14T11:26:01", + "2019-08-14T11:24:26", + "2019-08-14T11:20:55", + "2019-08-14T11:20:37", + "2019-08-14T10:56:51", + "2019-08-14T10:56:17", + "2019-08-14T10:44:53", + "2019-08-14T10:24:14", + "2019-08-14T09:07:23", + "2019-08-14T08:30:57", + "2019-08-14T08:17:24", + "2019-08-14T07:34:59", + "2019-08-14T07:05:47", + "2019-08-14T07:04:10", + "2019-08-14T07:00:45", + "2019-08-14T06:19:43", + "2019-08-14T06:13:49", + "2019-08-14T05:54:41", + "2019-08-14T05:45:02", + "2019-08-14T05:15:32", + "2019-08-14T05:02:52", + "2019-08-14T04:40:41", + "2019-08-14T04:11:21", + "2019-08-14T03:15:10", + "2019-08-14T03:01:55", + "2019-08-14T02:09:27", + "2019-08-14T02:00:03", + "2019-08-14T01:56:07", + "2019-08-14T01:40:30", + "2019-08-14T01:19:53", + "2019-08-14T01:06:25", + "2019-08-14T01:03:37", + "2019-08-14T00:57:33", + "2019-08-14T00:25:22", + "2019-08-14T00:02:35", + "2019-08-13T23:54:24", + "2019-08-13T22:25:51", + "2019-08-13T22:17:48", + "2019-08-13T22:17:14", + "2019-08-13T22:14:52" + ] + } + ], + "layout": { + "bargap": 0.2, + "height": 450, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "scatter": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Tweet Activity" + }, + "width": 1000, + "xaxis": { + "title": { + "text": "Date" + } + }, + "yaxis": { + "title": { + "text": "Tweet Quantity" + } + } + } + }, + "text/html": [ + "
\n", + " \n", + " \n", + "
\n", + " \n", + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "tweetsT = df_tweet['created_at'] \n", + "\n", + "trace = go.Histogram(\n", + " x = tweetsT,\n", + " marker = dict(\n", + " color = 'blue'\n", + " ),\n", + " opacity = 0.75\n", + ")\n", + "\n", + "layout = go.Layout(\n", + " title = 'Tweet Activity',\n", + " height = 450,\n", + " width = 1000,\n", + " xaxis = dict(\n", + " title = 'Date'\n", + " ),\n", + " yaxis = dict(\n", + " title = 'Tweet Quantity'\n", + " ),\n", + " bargap = 0.2,\n", + ")\n", + "\n", + "data = [trace]\n", + "fig = go.Figure(data=data, layout=layout)\n", + "py.offline.iplot(fig)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Step 3: Implement Encrpyted Dataset" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, we create dictionaries to change for each character to index, and vice versa." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [], + "source": [ + "char2index = {}\n", + "index2char = {}\n", + "\n", + "for i, char in enumerate(' ' + string.ascii_lowercase + '0123456789' + string.punctuation):\n", + " char2index[char] = i\n", + " index2char[i] = char" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's build some functions to implement encrpyted dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [], + "source": [ + "def string2values(str_input, max_len=8):\n", + " \"\"\"Change string to value.\n", + " Args:\n", + " str_input(str): string input\n", + " max_len: maximum length of string\n", + " Returns:\n", + " tensor values\n", + " \"\"\"\n", + " str_input = str_input[:max_len].lower()\n", + " \n", + " # pad strings shorter than max len\n", + " if(len(str_input) < max_len):\n", + " str_input = str_input + \".\" * (max_len - len(str_input))\n", + " \n", + " values = list()\n", + " for char in str_input:\n", + " values.append(char2index[char])\n", + " \n", + " return th.tensor(values).long()\n", + "\n", + "def values2string(input_values):\n", + " \"\"\"Change value to string.\n", + " Args:\n", + " input_values: values input\n", + " Returns:\n", + " string\n", + " \"\"\"\n", + " s = \"\"\n", + " for value in input_values:\n", + " s += index2char[int(value)]\n", + " return s\n", + "\n", + "def one_hot(index, length):\n", + " \"\"\"Make one hot for each counted string on the index.\n", + " Args:\n", + " index\n", + " Returns:\n", + " one hot vector\n", + " \"\"\"\n", + " vect = th.zeros(length).long()\n", + " vect[index] = 1\n", + " return vect\n", + "\n", + "def string2one_hot_matrix(str_input, max_len=8):\n", + " \"\"\"Change string into one hot matrix\n", + " Args:\n", + " str_input(str): string input\n", + " max_len: maximum length of string\n", + " Returns:\n", + " one hot matrix\n", + " \"\"\"\n", + " str_input = str_input[:max_len].lower()\n", + " # pad strings shorter than max len\n", + " if(len(str_input) < max_len):\n", + " str_input = str_input + \".\" * (max_len - len(str_input))\n", + "\n", + " char_vectors = list()\n", + " for char in str_input:\n", + " char_v = one_hot(char2index[char], len(char2index)).unsqueeze(0)\n", + " char_vectors.append(char_v)\n", + " \n", + " return th.cat(char_vectors, dim=0)\n", + "\n", + "def strings_equal(str_a, str_b):\n", + " \"\"\"Comparing two string inputs\n", + " Args:\n", + " str_a(str): string input a\n", + " str_b(str): string input b\n", + " Returns:\n", + " tensor comparison result\n", + " \"\"\"\n", + " vect = (str_a * str_b).sum(1) # show overlapping\n", + "\n", + " x = vect[0]\n", + "\n", + " for i in range(vect.shape[0] - 1):\n", + " x = x * vect[i+1]\n", + "\n", + " return x" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we will make class EncrpytedDataset to encrypt Twitter dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [], + "source": [ + "class EncryptedDataset():\n", + " \n", + " def __init__(self, *owners, max_key_len=8, max_val_len=8):\n", + " self.max_key_len = max_key_len\n", + " self.max_val_len = max_val_len\n", + " \n", + " self.keys = list()\n", + " self.values = list()\n", + " self.owners = owners\n", + " \n", + " def add_entry(self, key, value):\n", + " key = string2one_hot_matrix(key)\n", + " key = key.share(*self.owners)\n", + " self.keys.append(key)\n", + " \n", + " value = string2values(value, max_len=self.max_val_len)\n", + " value = value.share(*self.owners)\n", + " self.values.append(value)\n", + " \n", + " def query(self, query_str):\n", + " query_matrix = string2one_hot_matrix(query_str)\n", + " \n", + " query_matrix = query_matrix.share(*self.owners)\n", + "\n", + " key_matches = list()\n", + " for key in self.keys:\n", + "\n", + " key_match = strings_equal(key, query_matrix)\n", + " key_matches.append(key_match)\n", + "\n", + " result = self.values[0] * key_matches[0]\n", + "\n", + " for i in range(len(self.values) - 1):\n", + " result += self.values[i+1] * key_matches[i+1]\n", + " \n", + " result = result.get()\n", + "\n", + " return values2string(result).replace(\".\",\"\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Make workers" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "W0820 22:11:36.020632 2788 hook.py:98] Torch was already hooked... skipping hooking process\n" + ] + } + ], + "source": [ + "import syft as sy\n", + "import torch as th\n", + "hook = sy.TorchHook(th)" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "W0820 22:34:05.893684 2788 base.py:628] Worker me already exists. Replacing old worker which could cause unexpected behavior\n", + "W0820 22:34:05.894680 2788 base.py:628] Worker me already exists. Replacing old worker which could cause unexpected behavior\n", + "W0820 22:34:05.895643 2788 base.py:628] Worker me already exists. Replacing old worker which could cause unexpected behavior\n" + ] + } + ], + "source": [ + "bob = sy.VirtualWorker(hook, id=\"bob\").add_worker(sy.local_worker)\n", + "alice = sy.VirtualWorker(hook, id=\"alice\").add_worker(sy.local_worker)\n", + "secure_worker = sy.VirtualWorker(hook, id=\"secure_worker\").add_worker(sy.local_worker)\n", + "\n", + "# clearing objects\n", + "bob = bob.clear_objects()\n", + "alice = alice.clear_objects()\n", + "secure_worker = secure_worker.clear_objects()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cleaning Dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[nltk_data] Downloading package stopwords to C:\\Users\\Yasir Abdur\n", + "[nltk_data] Rohman\\AppData\\Roaming\\nltk_data...\n", + "[nltk_data] Package stopwords is already up-to-date!\n" + ] + } + ], + "source": [ + "import nltk\n", + "nltk.download('stopwords')\n", + "from nltk.corpus import stopwords\n", + "from string import punctuation\n", + "import string\n", + "from unicodedata import normalize\n", + "import re\n", + "\n", + "def remove_url(tweet):\n", + " \"\"\"Remove URL link.\n", + " Args:\n", + " tweet(str): tweet\n", + " Returns:\n", + " modified tweet\n", + " \"\"\"\n", + " tweet = re.sub(r\"\\s—\\s\", \"\", tweet)\n", + " tweet = re.sub(r\"http\\S+\", \"\", tweet)\n", + " return tweet\n", + "\n", + "def remove_hashtag_mention(tweet):\n", + " \"\"\"Remove hastag and mention.\n", + " Args:\n", + " tweet(str): tweet\n", + " Returns:\n", + " modified tweet\n", + " \"\"\"\n", + " result = []\n", + " tweet = tweet.split(' ')\n", + " for t in tweet:\n", + " if t.startswith('#') or t.startswith('@'):\n", + " continue\n", + " else:\n", + " result.append(t)\n", + " return ' '.join(result)\n", + "\n", + "def remove_rt_fav(tweet):\n", + " \"\"\"Remove RT and FAV.\n", + " Args:\n", + " tweet(str): tweet\n", + " Returns:\n", + " modified tweet\n", + " \"\"\"\n", + " tweet = re.sub(r'^(RT|FAV)','', tweet)\n", + " return tweet\n", + "\n", + "def remove_punctuation(tweet):\n", + " \"\"\"Remove punctuation except '-'.\n", + " Args:\n", + " tweet(str): tweet\n", + " Returns:\n", + " modified tweet\n", + " \"\"\"\n", + " remove = string.punctuation\n", + " translator = str.maketrans(remove, ' '*len(remove))\n", + " return tweet.translate(translator)\n", + " \n", + "def remove_ascii_unicode(tweet):\n", + " \"\"\"Remove ASCII and Unicode.\n", + " Args:\n", + " tweet(str): tweet\n", + " Returns:\n", + " modified tweet\n", + " \"\"\"\n", + " tweet = normalize('NFKD', tweet)\n", + " tweet = tweet.encode('ascii', 'ignore').decode('utf-8')\n", + " return tweet\n", + "\n", + "def remove_newline(tweet):\n", + " \"\"\"Remove newline.\n", + " Args:\n", + " tweet(str): tweet\n", + " Returns:\n", + " modified tweet\n", + " \"\"\"\n", + " tweet = tweet.replace('\\n', ' ')\n", + " return tweet" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [], + "source": [ + "# cleaning tweet documents\n", + "\n", + "for index, row in df_tweet.iterrows():\n", + " clean_tweet = remove_ascii_unicode(row['text'])\n", + " clean_tweet = clean_tweet.lower()\n", + " clean_tweet = remove_rt_fav(clean_tweet)\n", + " clean_tweet = remove_newline(clean_tweet)\n", + " clean_tweet = remove_url(clean_tweet)\n", + " clean_tweet = remove_hashtag_mention(clean_tweet)\n", + " clean_tweet = remove_punctuation(clean_tweet)\n", + " \n", + " # update dataframe\n", + " df_tweet.at[index,'text'] = clean_tweet" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0 udacity aws deepracer scholarship challenge fo...\n", + "1 a new udacity green it training course has bee...\n", + "2 back to school isnt just for kids 20 courses ...\n", + "3 belajar tensorflow yang di udacity bagus gak pak \n", + "4 congratulations \n", + "5 please reach out at support udacity com\n", + "6 \n", + "7 udacity aws deepracer scholarship challenge fo...\n", + "8 networking for web developers \n", + "9 \n", + "Name: text, dtype: object" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# take a look at the results\n", + "df_tweet['text'].head(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Encrpyt the dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [], + "source": [ + "# initialize class EncrpytedDataset\n", + "db = EncryptedDataset(bob, alice, secure_worker, max_val_len=280)\n", + "\n", + "# add Twitter dataset into db\n", + "for index, row in df_tweet.iterrows():\n", + " # we can make the key combining index and username\n", + " key = str(index) + '@' + row['username']\n", + " values = row['text']\n", + " \n", + " db.add_entry(key, values)" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'udacity aws deepracer scholarship challenge for international students '" + ] + }, + "execution_count": 67, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# let's testing out our database\n", + "db.query(\"0@JustNowBulletin\")" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
usernamecreated_attext
0JustNowBulletin2019-08-20 14:20:11udacity aws deepracer scholarship challenge fo...
\n", + "
" + ], + "text/plain": [ + " username created_at \\\n", + "0 JustNowBulletin 2019-08-20 14:20:11 \n", + "\n", + " text \n", + "0 udacity aws deepracer scholarship challenge fo... " + ] + }, + "execution_count": 68, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# we get the same result\n", + "df_tweet.head(1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Step 4: Topic Modelling\n", + "Now, we will implementing Topic Modelling from our Encrpyted Dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "493" + ] + }, + "execution_count": 72, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# make list of keys\n", + "keys = list()\n", + "\n", + "for index, row in df_tweet.iterrows():\n", + " key = str(index) + '@' + row['username']\n", + " keys.append(key)\n", + "\n", + "len(keys)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Make a corpus\n", + "We will make corpus from Twitter Encrypted Dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": {}, + "outputs": [], + "source": [ + "corpus = list()\n", + "a = list()\n", + "\n", + "# for i in range(len(df_tweet['text'])):\n", + "# a = df_tweet['text'][i]\n", + "# corpus.append(a)\n", + "\n", + "for key in keys:\n", + " a = db.query(key)\n", + " corpus.append(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['udacity aws deepracer scholarship challenge for international students ',\n", + " 'a new udacity green it training course has been added to sustaintraina data engineer ',\n", + " 'back to school isnt just for kids 20 courses to update your skills from and ',\n", + " 'belajar tensorflow yang di udacity bagus gak pak ',\n", + " 'congratulations ']" + ] + }, + "execution_count": 79, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# let's see our corpus\n", + "corpus[0:5]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Make temporary folder for saving dictionary and corpus" + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Folder \"C:\\Users\\YASIRA~1\\AppData\\Local\\Temp\" will be used to save temporary dictionary and corpus.\n" + ] + } + ], + "source": [ + "import gensim\n", + "import logging\n", + "import tempfile\n", + "\n", + "TEMP_FOLDER = tempfile.gettempdir()\n", + "print('Folder \"{}\" will be used to save temporary dictionary and corpus.'.format(TEMP_FOLDER))\n", + "\n", + "from gensim import corpora\n", + "logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Remove common words and tokenize" + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "metadata": {}, + "outputs": [], + "source": [ + "# remove common words and tokenize\n", + "common_words = ['RT','rt', 'udacity']\n", + "stoplist = stopwords.words('english') + list(punctuation) + common_words\n", + "\n", + "texts = [[word for word in str(document).lower().split() if word not in stoplist] for document in corpus]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Convert corpus documents into a stream of vectors" + ] + }, + { + "cell_type": "code", + "execution_count": 82, + "metadata": {}, + "outputs": [], + "source": [ + "dictionary = corpora.Dictionary(texts)\n", + "dictionary.save(os.path.join(TEMP_FOLDER, 'tweet_documents.dict')) # store the dictionary, for future reference\n", + "# print(dictionary)\n", + "\n", + "corpus = [dictionary.doc2bow(text) for text in texts]\n", + "corpora.MmCorpus.serialize(os.path.join(TEMP_FOLDER, 'tweet_documents.mm'), corpus) # store to disk, for later use" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Transformation using Tfidf\n", + "TFIDF, short for term frequency–inverse document frequency, is a numerical statistic that is intended to reflect how important a word is to a document in a collection or corpus." + ] + }, + { + "cell_type": "code", + "execution_count": 83, + "metadata": {}, + "outputs": [], + "source": [ + "# initialize\n", + "tfidf = models.TfidfModel(corpus)" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "metadata": {}, + "outputs": [], + "source": [ + "# use the model to transform vectors\n", + "corpus_tfidf = tfidf[corpus]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Implement LDA\n", + "Latent Dirichlet allocation (LDA) is a generative statistical model that allows sets of observations to be explained by unobserved groups that explain why some parts of the data are similar. For example, if observations are words collected into documents, it posits that each document is a mixture of a small number of topics and that each word's presence is attributable to one of the document's topics. LDA is an example of a topic model." + ] + }, + { + "cell_type": "code", + "execution_count": 85, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "W0820 23:36:28.732566 2788 ldamodel.py:934] too few updates, training might not converge; consider increasing the number of passes or iterations to improve accuracy\n" + ] + } + ], + "source": [ + "num_of_topics = 4\n", + "\n", + "lda = models.LdaModel(corpus, id2word=dictionary, num_topics=num_of_topics)\n", + "corpus_lda = lda[corpus_tfidf]" + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[(0,\n", + " '0.014*\"course\" + 0.012*\"amp\" + 0.010*\"new\" + 0.007*\"training\" + 0.006*\"congratulations\"'),\n", + " (1,\n", + " '0.013*\"learning\" + 0.011*\"nanodegree\" + 0.010*\"day\" + 0.009*\"android\" + 0.008*\"data\"'),\n", + " (2,\n", + " '0.007*\"nanodegree\" + 0.007*\"thanks\" + 0.007*\"learning\" + 0.006*\"project\" + 0.006*\"amp\"'),\n", + " (3,\n", + " '0.018*\"course\" + 0.017*\"learning\" + 0.015*\"day\" + 0.010*\"nanodegree\" + 0.009*\"machine\"')]" + ] + }, + "execution_count": 89, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Show first n important word in the topics\n", + "lda.show_topics(num_of_topics, 5)" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(71, 4)\n", + "(4, 71)\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
123ableaddedaialsoampandroidbecome...timetrainingtwouudemyurviavoyagewebwork
00.0000000.0000000.0000000.0035330.0057340.0033790.0000000.0119320.0000000.000000...0.0000000.006630.003380.0000000.0000000.0000000.0000000.0045060.0000000.000000
10.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0035710.0088780.003672...0.0000000.000000.000000.0000000.0000000.0000000.0000000.0000000.0000000.003455
20.0000000.0000000.0000000.0000000.0000000.0000000.0035930.0058690.0000000.000000...0.0037560.000000.000000.0037020.0054440.0033320.0000000.0000000.0000000.000000
30.0076390.0090430.0080260.0000000.0000000.0041540.0000000.0000000.0000000.000000...0.0000000.000000.000000.0000000.0000000.0000000.0038510.0000000.0035430.000000
\n", + "

4 rows × 71 columns

\n", + "
" + ], + "text/plain": [ + " 1 2 3 able added ai also \\\n", + "0 0.000000 0.000000 0.000000 0.003533 0.005734 0.003379 0.000000 \n", + "1 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 \n", + "2 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.003593 \n", + "3 0.007639 0.009043 0.008026 0.000000 0.000000 0.004154 0.000000 \n", + "\n", + " amp android become ... time training two u \\\n", + "0 0.011932 0.000000 0.000000 ... 0.000000 0.00663 0.00338 0.000000 \n", + "1 0.003571 0.008878 0.003672 ... 0.000000 0.00000 0.00000 0.000000 \n", + "2 0.005869 0.000000 0.000000 ... 0.003756 0.00000 0.00000 0.003702 \n", + "3 0.000000 0.000000 0.000000 ... 0.000000 0.00000 0.00000 0.000000 \n", + "\n", + " udemy ur via voyage web work \n", + "0 0.000000 0.000000 0.000000 0.004506 0.000000 0.000000 \n", + "1 0.000000 0.000000 0.000000 0.000000 0.000000 0.003455 \n", + "2 0.005444 0.003332 0.000000 0.000000 0.000000 0.000000 \n", + "3 0.000000 0.000000 0.003851 0.000000 0.003543 0.000000 \n", + "\n", + "[4 rows x 71 columns]" + ] + }, + "execution_count": 90, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Show probability for each word in each topic\n", + "from collections import OrderedDict\n", + "\n", + "data_lda = {i: OrderedDict(lda.show_topic(i, 25)) for i in range(num_of_topics)}\n", + "\n", + "df_lda = pd.DataFrame(data_lda)\n", + "print(df_lda.shape)\n", + "df_lda = df_lda.fillna(0).T\n", + "print(df_lda.shape)\n", + "\n", + "df_lda.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualizing Clustermap LDA" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import seaborn as sns\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline\n", + "\n", + "g = sns.clustermap(df_lda.corr(), center=0, cmap=\"RdBu\", metric='cosine', linewidths=.75, figsize=(12, 12))\n", + "plt.setp(g.ax_heatmap.yaxis.get_majorticklabels(), rotation=0)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualizing with PyLDAvis" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import pyLDAvis.gensim\n", + "\n", + "pyLDAvis.enable_notebook()\n", + "panel = pyLDAvis.gensim.prepare(lda, corpus_lda, dictionary, mds='tsne')\n", + "panel" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Yasir Abdur Rohman/Project 1/README.md b/Yasir Abdur Rohman/Project 1/README.md new file mode 100644 index 00000000..e7f6ec22 --- /dev/null +++ b/Yasir Abdur Rohman/Project 1/README.md @@ -0,0 +1,38 @@ +# Topic Modelling on Encrpyted Twitter Dataset +Using Latent Dirichlet Allocation (LDA) for Topic Modelling on Encrypted Twitter Dataset + +# Step-by-step +## Step 1: Crawling Twitter Dataset +Getting tweet documents using Twitter API. The results are as follows. + +| | username | created_at | text | +|---|-----------------|---------------------|---------------------------------------------| +| 0 | JustNowBulletin | 2019-08-20 14:20:11 | Udacity AWS DeepRacer Scholarship Challenge | +| 1 | sustaintrain | 2019-08-20 14:15:10 | A new Udacity Green IT training course | +| 2 | Upwork | 2019-08-20 13:20:49 | Back to School Isn’t Just For Kids | + +## Step 2: Exploratory Data Analysis +We can visualizing the number of tweets for each day. +![EDA](https://github.com/yasirabd/SPAI/blob/master/Project%201/assets/eda.png "EDA") + +## Step 3: Implement Encrpyted Dataset +Encrypt our Twitter dataset. +```python +# initialize EncryptedDataset class +db = EncryptedDataset(bob, alice, secure_worker, max_val_len=280) + +# add Twitter dataset into db +for index, row in df_tweet.iterrows(): + # we can make the key combining index and username + key = str(index) + '@' + row['username'] + values = row['text'] + db.add_entry(key, values) + +# load encrypted dataset +db.query("0@JustNowBulletin") +# the result: 'udacity aws deepracer scholarship challenge for international students ' +``` + +## Step 4: Topic Modelling +Implementing Latent Dirichlet Allocation on Encrypted Twitter Dataset. The results are as follows. +![LDA](https://github.com/yasirabd/SPAI/blob/master/Project%201/assets/lda.PNG "LDA") diff --git a/Yasir Abdur Rohman/Project 1/Topic Modelling on Encrypted Twitter Dataset .html b/Yasir Abdur Rohman/Project 1/Topic Modelling on Encrypted Twitter Dataset .html new file mode 100644 index 00000000..1befbd8a --- /dev/null +++ b/Yasir Abdur Rohman/Project 1/Topic Modelling on Encrypted Twitter Dataset .html @@ -0,0 +1,14877 @@ + + + + +Topic Modelling on Encrypted Twitter Dataset + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+

Topic Modelling on Encrpyted Twitter Dataset

Author: Yasir Abdur Rohman

+
+
+
+
+
+
+
+

Introduction

In this notebook, I will implement Topic Modelling with Latent Dirichlet on Encrypted Twitter Dataset.

+

Twitter is one of the social media that has followed the GDPR rules to protect the privacy of each user. However, we can still access tweets from many users by using the Twitter API. Even though there is an agreement to use the Twitter API wisely, it will still damage the privacy of other users who don't want their tweets to be taken. Therefore, here we will implement Encrypted Twitter Dataset as a privacy protection from the user.

+

And after we encrypt the Twitter dataset, we can still implement AI securely. Here, we will apply Topic Modeling to uncover abstract themes based on the underlying tweet documents and words in a corpus of text.

+

The project consists of the following steps:

+
    +
  1. Crawling Twitter Dataset
  2. +
  3. Exploratory Data Analysis
  4. +
  5. Implement Encrypted Twitter Dataset
  6. +
  7. Topic Modelling
  8. +
+ +
+
+
+
+
+
+

Step 1: Crawling Twitter Dataset

+
+
+
+
+
+
In [34]:
+
+
+
# import library
+
+import pandas as pd
+import numpy as np
+import matplotlib.pyplot as plt
+import string
+import time
+
+# import dotenv
+import os
+from dotenv import load_dotenv
+
+# import tweepy
+import tweepy
+
+# datetime
+from datetime import datetime, timedelta
+
+# plotly
+from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
+import plotly as py
+import plotly.graph_objs as go
+
+init_notebook_mode(connected=True) #do not miss this line
+
+# gensim
+from gensim import corpora, models, similarities
+
+import warnings
+warnings.filterwarnings("ignore")
+
+ +
+
+
+ +
+
+ + +
+ +
+ + + +
+ + +
+ +
+ +
+
+ +
+
+
+
+

We need Twitter API to crawl Twitter dataset. So, let's setting up for Twitter crawler first.

+ +
+
+
+
+
+
In [35]:
+
+
+
# load env file
+load_dotenv(".env")
+
+# setting API Twitter
+TWITTER_API_KEY = os.getenv('TWITTER_API_KEY')
+TWITTER_API_SECRET_KEY = os.getenv('TWITTER_API_SECRET_KEY')
+TWITTER_ACCESS_TOKEN = os.getenv('TWITTER_ACCESS_TOKEN')
+TWITTER_ACCESS_TOKEN_SECRET = os.getenv('TWITTER_ACCESS_TOKEN_SECRET')
+
+auth = tweepy.OAuthHandler(TWITTER_API_KEY, TWITTER_API_SECRET_KEY)
+auth.set_access_token(TWITTER_ACCESS_TOKEN, TWITTER_ACCESS_TOKEN_SECRET)
+api = tweepy.API(auth, wait_on_rate_limit=True)
+
+ +
+
+
+ +
+
+
+
+

In this project, we can setting up some parameters as follows:

+
    +
  • maximum_days: the age of the tweet document from the current time.
  • +
  • query: keywords for searching tweet documents
  • +
+ +
+
+
+
+
+
In [36]:
+
+
+
# initialize crawler parameters
+
+# date
+maximum_days = 7 # 7 days, so we will get all of the tweet documents from 7 days before
+today = datetime.today()
+date_max = today - timedelta(days=maximum_days)
+
+# query
+query = "#Udacity OR #udacity OR Udacity OR udacity"
+
+ +
+
+
+ +
+
+
+
+

Next, we will save the results of crawling the tweet document into the pandas dataframe .

+

The fields from the tweet document that we will obtain are as follows:

+
    +
  • username: users
  • +
  • created_at: the date when the tweet created
  • +
  • text: text of the tweet
  • +
+ +
+
+
+
+
+
In [37]:
+
+
+
# initialize dataframe
+df_tweet = pd.DataFrame({'username': [], 'created_at': [], 'text': []})
+
+# crawling tweet documents
+c = tweepy.Cursor(api.search, q=query, tweet_mode='extended').items()
+while True:
+    try:
+        tweet = c.next()
+        
+        # get clean tweet without RT
+        if (not tweet.retweeted) and ('RT @' not in tweet.full_text):
+            username = tweet.user.screen_name
+            created = tweet.created_at
+            text = tweet.full_text.encode('utf-8', 'ignore').decode('utf-8', 'ignore')
+
+            # get tweet documents before maximum_days
+            if tweet.created_at < date_max:
+                break
+            df_tweet = df_tweet.append({'username': username, 'created_at': created, 
+                                        'text': text}, ignore_index=True)
+                       
+    except tweepy.TweepError as e:
+        print(e.reason)
+        time.sleep(15 * 60)
+        continue
+    except StopIteration:
+        break
+
+ +
+
+
+ +
+
+
+
+

Step 2: Exploratory Data Analysis

+
+
+
+
+
+
In [38]:
+
+
+
# let's see our twitter dataset
+df_tweet.head(10)
+
+ +
+
+
+ +
+
+ + +
+ +
Out[38]:
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
usernamecreated_attext
0JustNowBulletin2019-08-20 14:20:11Udacity AWS DeepRacer Scholarship Challenge fo...
1sustaintrain2019-08-20 14:15:10A new Udacity Green IT training course has bee...
2Upwork2019-08-20 13:20:49Back to School Isn’t Just For Kids: 20 Courses...
3frengki_172019-08-20 13:17:23@onnowpurbo Belajar tensorflow yang di udacity...
4javaquantum2019-08-20 13:14:13@xsahil03x @GoogleIndia @udacity Congratulatio...
5RahulSi886620932019-08-20 13:08:38@anandjha_98 @kala83 @Google @udacity Please r...
6MaramAlroshoud2019-08-20 12:49:10وشو مسك يوداستي؟ — https://t.co/UC0Y4m9Foo htt...
7SafeScholarship2019-08-20 12:29:52Udacity AWS DeepRacer Scholarship Challenge fo...
80xAlsharif2019-08-20 12:29:09Networking for Web Developers. https://t.co/Hf...
90xAlsharif2019-08-20 12:19:33تحية وتقدير للمواقع والمصادر التعليمية اللي تج...
+
+
+ +
+ +
+
+ +
+
+
+
In [39]:
+
+
+
# let's counting how many tweet documents that we got
+print("The number of tweet documents:", len(df_tweet['text']))
+
+ +
+
+
+ +
+
+ + +
+ +
+ + +
+
The number of tweet documents: 493
+
+
+
+ +
+
+ +
+
+
+
+

Visualizing The Number of Tweets for each day

+
+
+
+
+
+
In [40]:
+
+
+
tweetsT = df_tweet['created_at'] 
+
+trace = go.Histogram(
+    x = tweetsT,
+    marker = dict(
+        color = 'blue'
+    ),
+    opacity = 0.75
+)
+
+layout = go.Layout(
+    title = 'Tweet Activity',
+    height = 450,
+    width = 1000,
+    xaxis = dict(
+        title = 'Date'
+    ),
+    yaxis = dict(
+        title = 'Tweet Quantity'
+    ),
+    bargap = 0.2,
+)
+
+data = [trace]
+fig = go.Figure(data=data, layout=layout)
+py.offline.iplot(fig)
+
+ +
+
+
+ +
+
+ + +
+ +
+ + + +
+
+ + +
+ +
+
+ +
+ +
+
+ +
+
+
+
+

Step 3: Implement Encrpyted Dataset

+
+
+
+
+
+
+

First, we create dictionaries to change for each character to index, and vice versa.

+ +
+
+
+
+
+
In [41]:
+
+
+
char2index = {}
+index2char = {}
+
+for i, char in enumerate(' ' + string.ascii_lowercase + '0123456789' + string.punctuation):
+    char2index[char] = i
+    index2char[i] = char
+
+ +
+
+
+ +
+
+
+
+

Let's build some functions to implement encrpyted dataset.

+ +
+
+
+
+
+
In [42]:
+
+
+
def string2values(str_input, max_len=8):
+    """Change string to value.
+    Args:
+        str_input(str): string input
+        max_len: maximum length of string
+    Returns:
+        tensor values
+    """
+    str_input = str_input[:max_len].lower()
+    
+    # pad strings shorter than max len
+    if(len(str_input) < max_len):
+        str_input = str_input + "." * (max_len - len(str_input))
+    
+    values = list()
+    for char in str_input:
+        values.append(char2index[char])
+        
+    return th.tensor(values).long()
+
+def values2string(input_values):
+    """Change value to string.
+    Args:
+        input_values: values input
+    Returns:
+        string
+    """
+    s = ""
+    for value in input_values:
+        s += index2char[int(value)]
+    return s
+
+def one_hot(index, length):
+    """Make one hot for each counted string on the index.
+    Args:
+        index
+    Returns:
+        one hot vector
+    """
+    vect = th.zeros(length).long()
+    vect[index] = 1
+    return vect
+
+def string2one_hot_matrix(str_input, max_len=8):
+    """Change string into one hot matrix
+    Args:
+        str_input(str): string input
+        max_len: maximum length of string
+    Returns:
+        one hot matrix
+    """
+    str_input = str_input[:max_len].lower()
+    # pad strings shorter than max len
+    if(len(str_input) < max_len):
+        str_input = str_input + "." * (max_len - len(str_input))
+
+    char_vectors = list()
+    for char in str_input:
+        char_v = one_hot(char2index[char], len(char2index)).unsqueeze(0)
+        char_vectors.append(char_v)
+        
+    return th.cat(char_vectors, dim=0)
+
+def strings_equal(str_a, str_b):
+    """Comparing two string inputs
+    Args:
+        str_a(str): string input a
+        str_b(str): string input b
+    Returns:
+        tensor comparison result
+    """
+    vect = (str_a * str_b).sum(1) # show overlapping
+
+    x = vect[0]
+
+    for i in range(vect.shape[0] - 1):
+        x = x * vect[i+1]
+
+    return x
+
+ +
+
+
+ +
+
+
+
+

Now, we will make class EncrpytedDataset to encrypt Twitter dataset.

+ +
+
+
+
+
+
In [46]:
+
+
+
class EncryptedDataset():
+    
+    def __init__(self, *owners, max_key_len=8, max_val_len=8):
+        self.max_key_len = max_key_len
+        self.max_val_len = max_val_len
+        
+        self.keys = list()
+        self.values = list()
+        self.owners = owners
+        
+    def add_entry(self, key, value):
+        key = string2one_hot_matrix(key)
+        key = key.share(*self.owners)
+        self.keys.append(key)
+        
+        value = string2values(value, max_len=self.max_val_len)
+        value = value.share(*self.owners)
+        self.values.append(value)
+        
+    def query(self, query_str):
+        query_matrix = string2one_hot_matrix(query_str)
+        
+        query_matrix = query_matrix.share(*self.owners)
+
+        key_matches = list()
+        for key in self.keys:
+
+            key_match = strings_equal(key, query_matrix)
+            key_matches.append(key_match)
+
+        result = self.values[0] * key_matches[0]
+
+        for i in range(len(self.values) - 1):
+            result += self.values[i+1] * key_matches[i+1]
+            
+        result = result.get()
+
+        return values2string(result).replace(".","")
+
+ +
+
+
+ +
+
+
+
+

Make workers

+
+
+
+
+
+
In [44]:
+
+
+
import syft as sy
+import torch as th
+hook = sy.TorchHook(th)
+
+ +
+
+
+ +
+
+ + +
+ +
+ + +
+
W0820 22:11:36.020632  2788 hook.py:98] Torch was already hooked... skipping hooking process
+
+
+
+ +
+
+ +
+
+
+
In [63]:
+
+
+
bob = sy.VirtualWorker(hook, id="bob").add_worker(sy.local_worker)
+alice = sy.VirtualWorker(hook, id="alice").add_worker(sy.local_worker)
+secure_worker = sy.VirtualWorker(hook, id="secure_worker").add_worker(sy.local_worker)
+
+# clearing objects
+bob = bob.clear_objects()
+alice = alice.clear_objects()
+secure_worker = secure_worker.clear_objects()
+
+ +
+
+
+ +
+
+ + +
+ +
+ + +
+
W0820 22:34:05.893684  2788 base.py:628] Worker me already exists. Replacing old worker which could cause                     unexpected behavior
+W0820 22:34:05.894680  2788 base.py:628] Worker me already exists. Replacing old worker which could cause                     unexpected behavior
+W0820 22:34:05.895643  2788 base.py:628] Worker me already exists. Replacing old worker which could cause                     unexpected behavior
+
+
+
+ +
+
+ +
+
+
+
+

Cleaning Dataset

+
+
+
+
+
+
In [49]:
+
+
+
import nltk
+nltk.download('stopwords')
+from nltk.corpus import stopwords
+from string import punctuation
+import string
+from unicodedata import normalize
+import re
+
+def remove_url(tweet):
+    """Remove URL link.
+    Args:
+        tweet(str): tweet
+    Returns:
+        modified tweet
+    """
+    tweet = re.sub(r"\s—\s", "", tweet)
+    tweet = re.sub(r"http\S+", "", tweet)
+    return tweet
+
+def remove_hashtag_mention(tweet):
+    """Remove hastag and mention.
+    Args:
+        tweet(str): tweet
+    Returns:
+        modified tweet
+    """
+    result = []
+    tweet = tweet.split(' ')
+    for t in tweet:
+        if t.startswith('#') or t.startswith('@'):
+            continue
+        else:
+            result.append(t)
+    return ' '.join(result)
+
+def remove_rt_fav(tweet):
+    """Remove RT and FAV.
+    Args:
+        tweet(str): tweet
+    Returns:
+        modified tweet
+    """
+    tweet = re.sub(r'^(RT|FAV)','', tweet)
+    return tweet
+
+def remove_punctuation(tweet):
+    """Remove punctuation except '-'.
+    Args:
+        tweet(str): tweet
+    Returns:
+        modified tweet
+    """
+    remove = string.punctuation
+    translator = str.maketrans(remove, ' '*len(remove))
+    return tweet.translate(translator)
+    
+def remove_ascii_unicode(tweet):
+    """Remove ASCII and Unicode.
+    Args:
+        tweet(str): tweet
+    Returns:
+        modified tweet
+    """
+    tweet = normalize('NFKD', tweet)
+    tweet = tweet.encode('ascii', 'ignore').decode('utf-8')
+    return tweet
+
+def remove_newline(tweet):
+    """Remove newline.
+    Args:
+        tweet(str): tweet
+    Returns:
+        modified tweet
+    """
+    tweet = tweet.replace('\n', ' ')
+    return tweet
+
+ +
+
+
+ +
+
+ + +
+ +
+ + +
+
[nltk_data] Downloading package stopwords to C:\Users\Yasir Abdur
+[nltk_data]     Rohman\AppData\Roaming\nltk_data...
+[nltk_data]   Package stopwords is already up-to-date!
+
+
+
+ +
+
+ +
+
+
+
In [50]:
+
+
+
# cleaning tweet documents
+
+for index, row in df_tweet.iterrows():
+    clean_tweet = remove_ascii_unicode(row['text'])
+    clean_tweet = clean_tweet.lower()
+    clean_tweet = remove_rt_fav(clean_tweet)
+    clean_tweet = remove_newline(clean_tweet)
+    clean_tweet = remove_url(clean_tweet)
+    clean_tweet = remove_hashtag_mention(clean_tweet)
+    clean_tweet = remove_punctuation(clean_tweet)
+    
+    # update dataframe
+    df_tweet.at[index,'text'] = clean_tweet
+
+ +
+
+
+ +
+
+
+
In [52]:
+
+
+
# take a look at the results
+df_tweet['text'].head(10)
+
+ +
+
+
+ +
+
+ + +
+ +
Out[52]:
+ + + + +
+
0    udacity aws deepracer scholarship challenge fo...
+1    a new udacity green it training course has bee...
+2    back to school isnt just for kids  20 courses ...
+3    belajar tensorflow yang di udacity bagus gak pak 
+4                                    congratulations  
+5              please reach out at support udacity com
+6                                                     
+7    udacity aws deepracer scholarship challenge fo...
+8                     networking for web developers   
+9                                                     
+Name: text, dtype: object
+
+ +
+ +
+
+ +
+
+
+
+

Encrpyt the dataset

+
+
+
+
+
+
In [66]:
+
+
+
# initialize class EncrpytedDataset
+db = EncryptedDataset(bob, alice, secure_worker, max_val_len=280)
+
+# add Twitter dataset into db
+for index, row in df_tweet.iterrows():
+    # we can make the key combining index and username
+    key = str(index) + '@' + row['username']
+    values = row['text']
+    
+    db.add_entry(key, values)
+
+ +
+
+
+ +
+
+
+
In [67]:
+
+
+
# let's testing out our database
+db.query("0@JustNowBulletin")
+
+ +
+
+
+ +
+
+ + +
+ +
Out[67]:
+ + + + +
+
'udacity aws deepracer scholarship challenge for international students '
+
+ +
+ +
+
+ +
+
+
+
In [68]:
+
+
+
# we get the same result
+df_tweet.head(1)
+
+ +
+
+
+ +
+
+ + +
+ +
Out[68]:
+ + + +
+
+ + + + + + + + + + + + + + + + + + +
usernamecreated_attext
0JustNowBulletin2019-08-20 14:20:11udacity aws deepracer scholarship challenge fo...
+
+
+ +
+ +
+
+ +
+
+
+
+

Step 4: Topic Modelling

Now, we will implementing Topic Modelling from our Encrpyted Dataset.

+ +
+
+
+
+
+
In [72]:
+
+
+
# make list of keys
+keys = list()
+
+for index, row in df_tweet.iterrows():
+    key = str(index) + '@' + row['username']
+    keys.append(key)
+
+len(keys)
+
+ +
+
+
+ +
+
+ + +
+ +
Out[72]:
+ + + + +
+
493
+
+ +
+ +
+
+ +
+
+
+
+

Make a corpus

We will make corpus from Twitter Encrypted Dataset.

+ +
+
+
+
+
+
In [77]:
+
+
+
corpus = list()
+a = list()
+
+# for i in range(len(df_tweet['text'])):
+#     a = df_tweet['text'][i]
+#     corpus.append(a)
+
+for key in keys:
+    a = db.query(key)
+    corpus.append(a)
+
+ +
+
+
+ +
+
+
+
In [79]:
+
+
+
# let's see our corpus
+corpus[0:5]
+
+ +
+
+
+ +
+
+ + +
+ +
Out[79]:
+ + + + +
+
['udacity aws deepracer scholarship challenge for international students ',
+ 'a new udacity green it training course has been added to sustaintraina   data engineer     ',
+ 'back to school isnt just for kids  20 courses to update your skills from and   ',
+ 'belajar tensorflow yang di udacity bagus gak pak ',
+ 'congratulations  ']
+
+ +
+ +
+
+ +
+
+
+
+

Make temporary folder for saving dictionary and corpus

+
+
+
+
+
+
In [80]:
+
+
+
import gensim
+import logging
+import tempfile
+
+TEMP_FOLDER = tempfile.gettempdir()
+print('Folder "{}" will be used to save temporary dictionary and corpus.'.format(TEMP_FOLDER))
+
+from gensim import corpora
+logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)
+
+ +
+
+
+ +
+
+ + +
+ +
+ + +
+
Folder "C:\Users\YASIRA~1\AppData\Local\Temp" will be used to save temporary dictionary and corpus.
+
+
+
+ +
+
+ +
+
+
+
+

Remove common words and tokenize

+
+
+
+
+
+
In [81]:
+
+
+
# remove common words and tokenize
+common_words = ['RT','rt', 'udacity']
+stoplist = stopwords.words('english') + list(punctuation) + common_words
+
+texts = [[word for word in str(document).lower().split() if word not in stoplist] for document in corpus]
+
+ +
+
+
+ +
+
+
+
+

Convert corpus documents into a stream of vectors

+
+
+
+
+
+
In [82]:
+
+
+
dictionary = corpora.Dictionary(texts)
+dictionary.save(os.path.join(TEMP_FOLDER, 'tweet_documents.dict'))  # store the dictionary, for future reference
+# print(dictionary)
+
+corpus = [dictionary.doc2bow(text) for text in texts]
+corpora.MmCorpus.serialize(os.path.join(TEMP_FOLDER, 'tweet_documents.mm'), corpus)  # store to disk, for later use
+
+ +
+
+
+ +
+
+
+
+

Transformation using Tfidf

TFIDF, short for term frequency–inverse document frequency, is a numerical statistic that is intended to reflect how important a word is to a document in a collection or corpus.

+ +
+
+
+
+
+
In [83]:
+
+
+
# initialize
+tfidf = models.TfidfModel(corpus)
+
+ +
+
+
+ +
+
+
+
In [84]:
+
+
+
# use the model to transform vectors
+corpus_tfidf = tfidf[corpus]
+
+ +
+
+
+ +
+
+
+
+

Implement LDA

Latent Dirichlet allocation (LDA) is a generative statistical model that allows sets of observations to be explained by unobserved groups that explain why some parts of the data are similar. For example, if observations are words collected into documents, it posits that each document is a mixture of a small number of topics and that each word's presence is attributable to one of the document's topics. LDA is an example of a topic model.

+ +
+
+
+
+
+
In [85]:
+
+
+
num_of_topics = 4
+
+lda = models.LdaModel(corpus, id2word=dictionary, num_topics=num_of_topics)
+corpus_lda = lda[corpus_tfidf]
+
+ +
+
+
+ +
+
+ + +
+ +
+ + +
+
W0820 23:36:28.732566  2788 ldamodel.py:934] too few updates, training might not converge; consider increasing the number of passes or iterations to improve accuracy
+
+
+
+ +
+
+ +
+
+
+
In [89]:
+
+
+
# Show first n important word in the topics
+lda.show_topics(num_of_topics, 5)
+
+ +
+
+
+ +
+
+ + +
+ +
Out[89]:
+ + + + +
+
[(0,
+  '0.014*"course" + 0.012*"amp" + 0.010*"new" + 0.007*"training" + 0.006*"congratulations"'),
+ (1,
+  '0.013*"learning" + 0.011*"nanodegree" + 0.010*"day" + 0.009*"android" + 0.008*"data"'),
+ (2,
+  '0.007*"nanodegree" + 0.007*"thanks" + 0.007*"learning" + 0.006*"project" + 0.006*"amp"'),
+ (3,
+  '0.018*"course" + 0.017*"learning" + 0.015*"day" + 0.010*"nanodegree" + 0.009*"machine"')]
+
+ +
+ +
+
+ +
+
+
+
In [90]:
+
+
+
# Show probability for each word in each topic
+from collections import OrderedDict
+
+data_lda = {i: OrderedDict(lda.show_topic(i, 25)) for i in range(num_of_topics)}
+
+df_lda = pd.DataFrame(data_lda)
+print(df_lda.shape)
+df_lda = df_lda.fillna(0).T
+print(df_lda.shape)
+
+df_lda.head()
+
+ +
+
+
+ +
+
+ + +
+ +
+ + +
+
(71, 4)
+(4, 71)
+
+
+
+ +
+ +
Out[90]:
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
123ableaddedaialsoampandroidbecome...timetrainingtwouudemyurviavoyagewebwork
00.0000000.0000000.0000000.0035330.0057340.0033790.0000000.0119320.0000000.000000...0.0000000.006630.003380.0000000.0000000.0000000.0000000.0045060.0000000.000000
10.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0035710.0088780.003672...0.0000000.000000.000000.0000000.0000000.0000000.0000000.0000000.0000000.003455
20.0000000.0000000.0000000.0000000.0000000.0000000.0035930.0058690.0000000.000000...0.0037560.000000.000000.0037020.0054440.0033320.0000000.0000000.0000000.000000
30.0076390.0090430.0080260.0000000.0000000.0041540.0000000.0000000.0000000.000000...0.0000000.000000.000000.0000000.0000000.0000000.0038510.0000000.0035430.000000
+

4 rows × 71 columns

+
+
+ +
+ +
+
+ +
+
+
+
+

Visualizing Clustermap LDA

+
+
+
+
+
+
In [91]:
+
+
+
import seaborn as sns
+import matplotlib.pyplot as plt
+%matplotlib inline
+
+g = sns.clustermap(df_lda.corr(), center=0, cmap="RdBu", metric='cosine', linewidths=.75, figsize=(12, 12))
+plt.setp(g.ax_heatmap.yaxis.get_majorticklabels(), rotation=0)
+plt.show()
+
+ +
+
+
+ +
+
+ + +
+ +
+ + + + +
+ +
+ +
+ +
+
+ +
+
+
+
+

Visualizing with PyLDAvis

+
+
+
+
+
+
In [92]:
+
+
+
import pyLDAvis.gensim
+
+pyLDAvis.enable_notebook()
+panel = pyLDAvis.gensim.prepare(lda, corpus_lda, dictionary, mds='tsne')
+panel
+
+ +
+
+
+ +
+
+ + +
+ +
Out[92]:
+ + + +
+ + + + +
+ +
+ +
+ +
+
+ +
+
+
+
In [ ]:
+
+
+
 
+
+ +
+
+
+ +
+
+
+
In [ ]:
+
+
+
 
+
+ +
+
+
+ +
+
+
+ + + + + + diff --git a/Yasir Abdur Rohman/Project 1/Topic Modelling on Encrypted Twitter Dataset .ipynb b/Yasir Abdur Rohman/Project 1/Topic Modelling on Encrypted Twitter Dataset .ipynb new file mode 100644 index 00000000..e8439e09 --- /dev/null +++ b/Yasir Abdur Rohman/Project 1/Topic Modelling on Encrypted Twitter Dataset .ipynb @@ -0,0 +1,2972 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Topic Modelling on Encrpyted Twitter Dataset\n", + "*Author: Yasir Abdur Rohman*\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Introduction\n", + "In this notebook, I will implement Topic Modelling with Latent Dirichlet on Encrypted Twitter Dataset. \n", + "\n", + "Twitter is one of the social media that has followed the GDPR rules to protect the privacy of each user. However, we can still access tweets from many users by using the Twitter API. Even though there is an agreement to use the Twitter API wisely, it will still damage the privacy of other users who don't want their tweets to be taken. Therefore, here we will implement Encrypted Twitter Dataset as a privacy protection from the user.\n", + "\n", + "And after we encrypt the Twitter dataset, we can still implement AI securely. Here, we will apply Topic Modeling to uncover abstract themes based on the underlying tweet documents and words in a corpus of text.\n", + "\n", + "The project consists of the following steps:\n", + "1. Crawling Twitter Dataset\n", + "2. Exploratory Data Analysis\n", + "3. Implement Encrypted Twitter Dataset\n", + "4. Topic Modelling" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Step 1: Crawling Twitter Dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + " \n", + " " + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "# import library\n", + "\n", + "import pandas as pd\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import string\n", + "import time\n", + "\n", + "# import dotenv\n", + "import os\n", + "from dotenv import load_dotenv\n", + "\n", + "# import tweepy\n", + "import tweepy\n", + "\n", + "# datetime\n", + "from datetime import datetime, timedelta\n", + "\n", + "# plotly\n", + "from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot\n", + "import plotly as py\n", + "import plotly.graph_objs as go\n", + "\n", + "init_notebook_mode(connected=True) #do not miss this line\n", + "\n", + "# gensim\n", + "from gensim import corpora, models, similarities\n", + "\n", + "import warnings\n", + "warnings.filterwarnings(\"ignore\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We need Twitter API to crawl Twitter dataset. So, let's setting up for Twitter crawler first. " + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": {}, + "outputs": [], + "source": [ + "# load env file\n", + "load_dotenv(\".env\")\n", + "\n", + "# setting API Twitter\n", + "TWITTER_API_KEY = os.getenv('TWITTER_API_KEY')\n", + "TWITTER_API_SECRET_KEY = os.getenv('TWITTER_API_SECRET_KEY')\n", + "TWITTER_ACCESS_TOKEN = os.getenv('TWITTER_ACCESS_TOKEN')\n", + "TWITTER_ACCESS_TOKEN_SECRET = os.getenv('TWITTER_ACCESS_TOKEN_SECRET')\n", + "\n", + "auth = tweepy.OAuthHandler(TWITTER_API_KEY, TWITTER_API_SECRET_KEY)\n", + "auth.set_access_token(TWITTER_ACCESS_TOKEN, TWITTER_ACCESS_TOKEN_SECRET)\n", + "api = tweepy.API(auth, wait_on_rate_limit=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this project, we can setting up some parameters as follows:\n", + "- **maximum_days:** the age of the tweet document from the current time.\n", + "- **query:** keywords for searching tweet documents" + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": {}, + "outputs": [], + "source": [ + "# initialize crawler parameters\n", + "\n", + "# date\n", + "maximum_days = 7 # 7 days, so we will get all of the tweet documents from 7 days before\n", + "today = datetime.today()\n", + "date_max = today - timedelta(days=maximum_days)\n", + "\n", + "# query\n", + "query = \"#Udacity OR #udacity OR Udacity OR udacity\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we will save the results of crawling the tweet document into the pandas dataframe .\n", + "\n", + "The fields from the tweet document that we will obtain are as follows:\n", + "- **username:** users\n", + "- **created_at:** the date when the tweet created\n", + "- **text:** text of the tweet" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": {}, + "outputs": [], + "source": [ + "# initialize dataframe\n", + "df_tweet = pd.DataFrame({'username': [], 'created_at': [], 'text': []})\n", + "\n", + "# crawling tweet documents\n", + "c = tweepy.Cursor(api.search, q=query, tweet_mode='extended').items()\n", + "while True:\n", + " try:\n", + " tweet = c.next()\n", + " \n", + " # get clean tweet without RT\n", + " if (not tweet.retweeted) and ('RT @' not in tweet.full_text):\n", + " username = tweet.user.screen_name\n", + " created = tweet.created_at\n", + " text = tweet.full_text.encode('utf-8', 'ignore').decode('utf-8', 'ignore')\n", + "\n", + " # get tweet documents before maximum_days\n", + " if tweet.created_at < date_max:\n", + " break\n", + " df_tweet = df_tweet.append({'username': username, 'created_at': created, \n", + " 'text': text}, ignore_index=True)\n", + " \n", + " except tweepy.TweepError as e:\n", + " print(e.reason)\n", + " time.sleep(15 * 60)\n", + " continue\n", + " except StopIteration:\n", + " break" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Step 2: Exploratory Data Analysis" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
usernamecreated_attext
0JustNowBulletin2019-08-20 14:20:11Udacity AWS DeepRacer Scholarship Challenge fo...
1sustaintrain2019-08-20 14:15:10A new Udacity Green IT training course has bee...
2Upwork2019-08-20 13:20:49Back to School Isn’t Just For Kids: 20 Courses...
3frengki_172019-08-20 13:17:23@onnowpurbo Belajar tensorflow yang di udacity...
4javaquantum2019-08-20 13:14:13@xsahil03x @GoogleIndia @udacity Congratulatio...
5RahulSi886620932019-08-20 13:08:38@anandjha_98 @kala83 @Google @udacity Please r...
6MaramAlroshoud2019-08-20 12:49:10وشو مسك يوداستي؟ — https://t.co/UC0Y4m9Foo htt...
7SafeScholarship2019-08-20 12:29:52Udacity AWS DeepRacer Scholarship Challenge fo...
80xAlsharif2019-08-20 12:29:09Networking for Web Developers. https://t.co/Hf...
90xAlsharif2019-08-20 12:19:33تحية وتقدير للمواقع والمصادر التعليمية اللي تج...
\n", + "
" + ], + "text/plain": [ + " username created_at \\\n", + "0 JustNowBulletin 2019-08-20 14:20:11 \n", + "1 sustaintrain 2019-08-20 14:15:10 \n", + "2 Upwork 2019-08-20 13:20:49 \n", + "3 frengki_17 2019-08-20 13:17:23 \n", + "4 javaquantum 2019-08-20 13:14:13 \n", + "5 RahulSi88662093 2019-08-20 13:08:38 \n", + "6 MaramAlroshoud 2019-08-20 12:49:10 \n", + "7 SafeScholarship 2019-08-20 12:29:52 \n", + "8 0xAlsharif 2019-08-20 12:29:09 \n", + "9 0xAlsharif 2019-08-20 12:19:33 \n", + "\n", + " text \n", + "0 Udacity AWS DeepRacer Scholarship Challenge fo... \n", + "1 A new Udacity Green IT training course has bee... \n", + "2 Back to School Isn’t Just For Kids: 20 Courses... \n", + "3 @onnowpurbo Belajar tensorflow yang di udacity... \n", + "4 @xsahil03x @GoogleIndia @udacity Congratulatio... \n", + "5 @anandjha_98 @kala83 @Google @udacity Please r... \n", + "6 وشو مسك يوداستي؟ — https://t.co/UC0Y4m9Foo htt... \n", + "7 Udacity AWS DeepRacer Scholarship Challenge fo... \n", + "8 Networking for Web Developers. https://t.co/Hf... \n", + "9 تحية وتقدير للمواقع والمصادر التعليمية اللي تج... " + ] + }, + "execution_count": 38, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# let's see our twitter dataset\n", + "df_tweet.head(10)" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The number of tweet documents: 493\n" + ] + } + ], + "source": [ + "# let's counting how many tweet documents that we got\n", + "print(\"The number of tweet documents:\", len(df_tweet['text']))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualizing The Number of Tweets for each day" + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "linkText": "Export to plot.ly", + "plotlyServerURL": "https://plot.ly", + "showLink": false + }, + "data": [ + { + "marker": { + "color": "blue" + }, + "opacity": 0.75, + "type": "histogram", + "x": [ + "2019-08-20T14:20:11", + "2019-08-20T14:15:10", + "2019-08-20T13:20:49", + "2019-08-20T13:17:23", + "2019-08-20T13:14:13", + "2019-08-20T13:08:38", + "2019-08-20T12:49:10", + "2019-08-20T12:29:52", + "2019-08-20T12:29:09", + "2019-08-20T12:19:33", + "2019-08-20T11:56:06", + "2019-08-20T11:55:40", + "2019-08-20T11:47:58", + "2019-08-20T11:04:28", + "2019-08-20T09:09:11", + "2019-08-20T07:40:02", + "2019-08-20T07:23:02", + "2019-08-20T07:10:02", + "2019-08-20T06:47:44", + "2019-08-20T06:39:01", + "2019-08-20T05:56:57", + "2019-08-20T05:13:20", + "2019-08-20T04:36:32", + "2019-08-20T04:33:32", + "2019-08-20T04:03:08", + "2019-08-20T03:46:31", + "2019-08-20T03:44:14", + "2019-08-20T03:40:56", + "2019-08-20T03:28:33", + "2019-08-20T02:50:02", + "2019-08-20T02:28:57", + "2019-08-20T02:16:14", + "2019-08-20T02:14:38", + "2019-08-20T02:00:27", + "2019-08-20T02:00:02", + "2019-08-20T01:54:07", + "2019-08-20T01:34:01", + "2019-08-20T01:28:00", + "2019-08-20T01:13:03", + "2019-08-20T01:13:01", + "2019-08-20T01:05:33", + "2019-08-20T00:54:09", + "2019-08-20T00:47:07", + "2019-08-20T00:29:09", + "2019-08-19T23:50:59", + "2019-08-19T23:00:03", + "2019-08-19T22:35:19", + "2019-08-19T22:28:06", + "2019-08-19T22:19:16", + "2019-08-19T21:08:48", + "2019-08-19T21:00:08", + "2019-08-19T20:49:48", + "2019-08-19T19:57:24", + "2019-08-19T19:55:10", + "2019-08-19T19:41:41", + "2019-08-19T19:39:28", + "2019-08-19T19:32:50", + "2019-08-19T19:25:05", + "2019-08-19T19:15:09", + "2019-08-19T18:34:24", + "2019-08-19T18:34:16", + "2019-08-19T18:25:52", + "2019-08-19T18:18:12", + "2019-08-19T18:15:07", + "2019-08-19T18:08:12", + "2019-08-19T17:54:49", + "2019-08-19T17:43:33", + "2019-08-19T17:38:17", + "2019-08-19T17:35:44", + "2019-08-19T17:11:28", + "2019-08-19T17:06:26", + "2019-08-19T17:00:20", + "2019-08-19T16:44:14", + "2019-08-19T16:43:39", + "2019-08-19T16:32:27", + "2019-08-19T16:27:01", + "2019-08-19T16:22:32", + "2019-08-19T16:22:17", + "2019-08-19T16:16:12", + "2019-08-19T16:15:09", + "2019-08-19T16:12:52", + "2019-08-19T16:12:23", + "2019-08-19T16:09:00", + "2019-08-19T15:52:03", + "2019-08-19T15:46:59", + "2019-08-19T15:40:21", + "2019-08-19T15:26:17", + "2019-08-19T15:24:44", + "2019-08-19T15:23:28", + "2019-08-19T15:17:57", + "2019-08-19T15:16:48", + "2019-08-19T15:09:42", + "2019-08-19T14:58:38", + "2019-08-19T14:53:21", + "2019-08-19T14:38:42", + "2019-08-19T14:21:00", + "2019-08-19T14:18:34", + "2019-08-19T14:12:26", + "2019-08-19T13:53:37", + "2019-08-19T12:11:14", + "2019-08-19T12:00:01", + "2019-08-19T11:41:22", + "2019-08-19T11:40:36", + "2019-08-19T11:00:01", + "2019-08-19T10:35:54", + "2019-08-19T10:16:30", + "2019-08-19T09:03:41", + "2019-08-19T07:54:03", + "2019-08-19T07:02:35", + "2019-08-19T06:19:11", + "2019-08-19T06:09:27", + "2019-08-19T06:06:59", + "2019-08-19T05:03:21", + "2019-08-19T05:03:05", + "2019-08-19T03:55:35", + "2019-08-19T01:58:23", + "2019-08-19T01:53:31", + "2019-08-19T01:48:26", + "2019-08-19T01:45:51", + "2019-08-19T01:13:07", + "2019-08-19T00:31:08", + "2019-08-19T00:17:22", + "2019-08-18T23:22:21", + "2019-08-18T23:01:54", + "2019-08-18T22:54:33", + "2019-08-18T21:00:04", + "2019-08-18T20:51:24", + "2019-08-18T20:25:35", + "2019-08-18T19:44:01", + "2019-08-18T19:44:00", + "2019-08-18T19:09:04", + "2019-08-18T19:00:05", + "2019-08-18T18:21:12", + "2019-08-18T18:15:13", + "2019-08-18T18:15:07", + "2019-08-18T18:06:13", + "2019-08-18T18:00:09", + "2019-08-18T17:59:10", + "2019-08-18T17:56:21", + "2019-08-18T17:17:51", + "2019-08-18T17:12:10", + "2019-08-18T17:10:25", + "2019-08-18T17:03:21", + "2019-08-18T17:01:03", + "2019-08-18T17:01:01", + "2019-08-18T16:43:44", + "2019-08-18T16:37:03", + "2019-08-18T16:36:39", + "2019-08-18T16:15:07", + "2019-08-18T16:02:12", + "2019-08-18T15:52:10", + "2019-08-18T15:38:14", + "2019-08-18T15:09:45", + "2019-08-18T14:29:27", + "2019-08-18T14:29:18", + "2019-08-18T14:14:19", + "2019-08-18T14:11:49", + "2019-08-18T13:57:39", + "2019-08-18T13:24:20", + "2019-08-18T12:22:54", + "2019-08-18T12:05:02", + "2019-08-18T12:00:24", + "2019-08-18T11:41:30", + "2019-08-18T11:25:13", + "2019-08-18T11:25:12", + "2019-08-18T11:25:12", + "2019-08-18T10:34:30", + "2019-08-18T09:37:18", + "2019-08-18T09:33:28", + "2019-08-18T07:37:13", + "2019-08-18T06:33:47", + "2019-08-18T06:21:12", + "2019-08-18T05:04:38", + "2019-08-18T05:00:51", + "2019-08-18T03:42:11", + "2019-08-18T03:16:30", + "2019-08-18T02:19:28", + "2019-08-18T01:46:59", + "2019-08-18T01:12:38", + "2019-08-17T23:50:18", + "2019-08-17T23:42:23", + "2019-08-17T22:52:00", + "2019-08-17T21:12:06", + "2019-08-17T21:00:04", + "2019-08-17T20:49:02", + "2019-08-17T20:43:54", + "2019-08-17T20:28:26", + "2019-08-17T20:14:29", + "2019-08-17T19:34:52", + "2019-08-17T19:24:38", + "2019-08-17T19:00:11", + "2019-08-17T18:38:19", + "2019-08-17T18:37:04", + "2019-08-17T18:35:02", + "2019-08-17T18:15:08", + "2019-08-17T18:02:53", + "2019-08-17T17:57:56", + "2019-08-17T17:44:08", + "2019-08-17T17:32:34", + "2019-08-17T17:04:59", + "2019-08-17T17:03:41", + "2019-08-17T17:00:18", + "2019-08-17T16:58:30", + "2019-08-17T16:47:00", + "2019-08-17T16:37:49", + "2019-08-17T16:37:23", + "2019-08-17T16:16:15", + "2019-08-17T16:12:05", + "2019-08-17T15:51:38", + "2019-08-17T15:46:16", + "2019-08-17T15:34:20", + "2019-08-17T15:30:03", + "2019-08-17T15:12:05", + "2019-08-17T15:10:51", + "2019-08-17T15:00:23", + "2019-08-17T14:58:34", + "2019-08-17T14:30:54", + "2019-08-17T14:15:07", + "2019-08-17T14:12:23", + "2019-08-17T13:16:31", + "2019-08-17T13:06:25", + "2019-08-17T13:01:45", + "2019-08-17T12:56:46", + "2019-08-17T12:25:46", + "2019-08-17T12:04:54", + "2019-08-17T10:12:17", + "2019-08-17T10:09:07", + "2019-08-17T09:59:45", + "2019-08-17T09:33:00", + "2019-08-17T09:30:57", + "2019-08-17T08:34:19", + "2019-08-17T08:22:42", + "2019-08-17T07:57:47", + "2019-08-17T06:12:14", + "2019-08-17T06:11:53", + "2019-08-17T06:11:17", + "2019-08-17T06:11:16", + "2019-08-17T06:01:01", + "2019-08-17T05:34:13", + "2019-08-17T05:19:49", + "2019-08-17T03:30:56", + "2019-08-17T03:23:31", + "2019-08-17T02:11:48", + "2019-08-17T02:00:03", + "2019-08-17T01:22:07", + "2019-08-17T00:58:05", + "2019-08-17T00:09:37", + "2019-08-17T00:05:07", + "2019-08-17T00:04:42", + "2019-08-16T23:51:12", + "2019-08-16T23:01:49", + "2019-08-16T22:05:42", + "2019-08-16T22:05:01", + "2019-08-16T21:55:36", + "2019-08-16T21:44:07", + "2019-08-16T21:23:45", + "2019-08-16T21:00:08", + "2019-08-16T20:52:31", + "2019-08-16T20:35:02", + "2019-08-16T20:25:59", + "2019-08-16T20:10:49", + "2019-08-16T20:00:08", + "2019-08-16T19:48:30", + "2019-08-16T19:27:45", + "2019-08-16T19:12:09", + "2019-08-16T19:11:48", + "2019-08-16T19:03:49", + "2019-08-16T18:58:21", + "2019-08-16T18:47:23", + "2019-08-16T18:46:06", + "2019-08-16T18:34:12", + "2019-08-16T18:08:03", + "2019-08-16T18:05:23", + "2019-08-16T17:55:54", + "2019-08-16T17:48:06", + "2019-08-16T17:00:17", + "2019-08-16T16:55:16", + "2019-08-16T16:34:36", + "2019-08-16T16:32:38", + "2019-08-16T16:15:12", + "2019-08-16T15:34:40", + "2019-08-16T15:26:33", + "2019-08-16T15:25:53", + "2019-08-16T15:10:29", + "2019-08-16T15:00:22", + "2019-08-16T14:59:08", + "2019-08-16T14:15:12", + "2019-08-16T14:03:18", + "2019-08-16T13:24:25", + "2019-08-16T13:23:48", + "2019-08-16T13:16:54", + "2019-08-16T13:14:23", + "2019-08-16T11:55:51", + "2019-08-16T11:55:07", + "2019-08-16T10:25:08", + "2019-08-16T10:18:27", + "2019-08-16T09:17:12", + "2019-08-16T08:30:17", + "2019-08-16T08:05:16", + "2019-08-16T08:03:55", + "2019-08-16T08:01:30", + "2019-08-16T07:48:00", + "2019-08-16T07:30:08", + "2019-08-16T06:40:17", + "2019-08-16T05:51:06", + "2019-08-16T05:35:06", + "2019-08-16T05:27:20", + "2019-08-16T04:43:15", + "2019-08-16T04:17:25", + "2019-08-16T04:12:21", + "2019-08-16T03:38:04", + "2019-08-16T03:10:24", + "2019-08-16T02:33:51", + "2019-08-16T02:28:17", + "2019-08-16T02:10:35", + "2019-08-16T02:00:04", + "2019-08-16T01:52:37", + "2019-08-16T01:46:47", + "2019-08-16T01:39:01", + "2019-08-16T01:30:11", + "2019-08-15T23:53:45", + "2019-08-15T23:46:25", + "2019-08-15T23:13:34", + "2019-08-15T23:00:11", + "2019-08-15T22:47:27", + "2019-08-15T22:23:43", + "2019-08-15T21:44:22", + "2019-08-15T21:19:57", + "2019-08-15T21:15:12", + "2019-08-15T21:00:09", + "2019-08-15T20:19:44", + "2019-08-15T20:08:11", + "2019-08-15T20:02:17", + "2019-08-15T19:29:58", + "2019-08-15T19:00:18", + "2019-08-15T18:53:47", + "2019-08-15T18:18:56", + "2019-08-15T18:17:16", + "2019-08-15T18:15:13", + "2019-08-15T18:07:46", + "2019-08-15T18:01:48", + "2019-08-15T17:52:59", + "2019-08-15T17:50:17", + "2019-08-15T17:49:07", + "2019-08-15T17:46:13", + "2019-08-15T17:34:31", + "2019-08-15T17:28:59", + "2019-08-15T17:12:20", + "2019-08-15T17:08:09", + "2019-08-15T17:02:03", + "2019-08-15T17:01:07", + "2019-08-15T17:00:24", + "2019-08-15T16:53:47", + "2019-08-15T16:49:01", + "2019-08-15T16:18:15", + "2019-08-15T16:15:13", + "2019-08-15T16:01:27", + "2019-08-15T15:56:00", + "2019-08-15T15:43:56", + "2019-08-15T15:01:00", + "2019-08-15T15:00:17", + "2019-08-15T14:42:54", + "2019-08-15T14:20:28", + "2019-08-15T14:17:52", + "2019-08-15T13:57:03", + "2019-08-15T13:57:02", + "2019-08-15T13:49:41", + "2019-08-15T13:45:32", + "2019-08-15T13:44:25", + "2019-08-15T13:37:12", + "2019-08-15T13:28:45", + "2019-08-15T12:42:46", + "2019-08-15T11:03:20", + "2019-08-15T09:59:29", + "2019-08-15T09:59:06", + "2019-08-15T09:20:36", + "2019-08-15T09:17:42", + "2019-08-15T08:59:34", + "2019-08-15T07:04:33", + "2019-08-15T07:03:15", + "2019-08-15T06:52:19", + "2019-08-15T06:31:15", + "2019-08-15T06:30:41", + "2019-08-15T06:30:27", + "2019-08-15T06:29:53", + "2019-08-15T06:29:27", + "2019-08-15T06:28:27", + "2019-08-15T06:27:57", + "2019-08-15T06:27:17", + "2019-08-15T06:26:47", + "2019-08-15T06:26:03", + "2019-08-15T06:21:38", + "2019-08-15T06:21:05", + "2019-08-15T06:20:38", + "2019-08-15T04:25:18", + "2019-08-15T04:00:01", + "2019-08-15T03:59:07", + "2019-08-15T02:12:49", + "2019-08-15T02:07:37", + "2019-08-15T02:00:04", + "2019-08-15T01:52:58", + "2019-08-15T01:47:22", + "2019-08-15T00:42:53", + "2019-08-15T00:05:33", + "2019-08-14T23:14:11", + "2019-08-14T23:13:20", + "2019-08-14T23:12:55", + "2019-08-14T23:02:35", + "2019-08-14T23:00:06", + "2019-08-14T22:34:23", + "2019-08-14T22:11:12", + "2019-08-14T22:07:30", + "2019-08-14T21:54:54", + "2019-08-14T21:41:03", + "2019-08-14T21:00:08", + "2019-08-14T20:49:52", + "2019-08-14T20:42:58", + "2019-08-14T20:25:42", + "2019-08-14T20:22:35", + "2019-08-14T20:19:01", + "2019-08-14T20:15:11", + "2019-08-14T19:13:44", + "2019-08-14T18:53:05", + "2019-08-14T18:37:19", + "2019-08-14T18:36:47", + "2019-08-14T18:36:43", + "2019-08-14T18:26:49", + "2019-08-14T18:24:54", + "2019-08-14T18:21:47", + "2019-08-14T18:20:16", + "2019-08-14T18:18:41", + "2019-08-14T17:54:53", + "2019-08-14T17:52:50", + "2019-08-14T17:45:14", + "2019-08-14T17:44:30", + "2019-08-14T17:17:33", + "2019-08-14T17:00:20", + "2019-08-14T15:53:13", + "2019-08-14T15:47:51", + "2019-08-14T15:33:50", + "2019-08-14T15:31:57", + "2019-08-14T15:11:39", + "2019-08-14T15:00:20", + "2019-08-14T14:20:22", + "2019-08-14T14:15:11", + "2019-08-14T13:59:05", + "2019-08-14T13:55:48", + "2019-08-14T13:18:45", + "2019-08-14T12:58:26", + "2019-08-14T12:27:35", + "2019-08-14T12:01:21", + "2019-08-14T11:38:44", + "2019-08-14T11:34:58", + "2019-08-14T11:26:01", + "2019-08-14T11:24:26", + "2019-08-14T11:20:55", + "2019-08-14T11:20:37", + "2019-08-14T10:56:51", + "2019-08-14T10:56:17", + "2019-08-14T10:44:53", + "2019-08-14T10:24:14", + "2019-08-14T09:07:23", + "2019-08-14T08:30:57", + "2019-08-14T08:17:24", + "2019-08-14T07:34:59", + "2019-08-14T07:05:47", + "2019-08-14T07:04:10", + "2019-08-14T07:00:45", + "2019-08-14T06:19:43", + "2019-08-14T06:13:49", + "2019-08-14T05:54:41", + "2019-08-14T05:45:02", + "2019-08-14T05:15:32", + "2019-08-14T05:02:52", + "2019-08-14T04:40:41", + "2019-08-14T04:11:21", + "2019-08-14T03:15:10", + "2019-08-14T03:01:55", + "2019-08-14T02:09:27", + "2019-08-14T02:00:03", + "2019-08-14T01:56:07", + "2019-08-14T01:40:30", + "2019-08-14T01:19:53", + "2019-08-14T01:06:25", + "2019-08-14T01:03:37", + "2019-08-14T00:57:33", + "2019-08-14T00:25:22", + "2019-08-14T00:02:35", + "2019-08-13T23:54:24", + "2019-08-13T22:25:51", + "2019-08-13T22:17:48", + "2019-08-13T22:17:14", + "2019-08-13T22:14:52" + ] + } + ], + "layout": { + "bargap": 0.2, + "height": 450, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "scatter": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "title": { + "text": "Tweet Activity" + }, + "width": 1000, + "xaxis": { + "title": { + "text": "Date" + } + }, + "yaxis": { + "title": { + "text": "Tweet Quantity" + } + } + } + }, + "text/html": [ + "
\n", + " \n", + " \n", + "
\n", + " \n", + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "tweetsT = df_tweet['created_at'] \n", + "\n", + "trace = go.Histogram(\n", + " x = tweetsT,\n", + " marker = dict(\n", + " color = 'blue'\n", + " ),\n", + " opacity = 0.75\n", + ")\n", + "\n", + "layout = go.Layout(\n", + " title = 'Tweet Activity',\n", + " height = 450,\n", + " width = 1000,\n", + " xaxis = dict(\n", + " title = 'Date'\n", + " ),\n", + " yaxis = dict(\n", + " title = 'Tweet Quantity'\n", + " ),\n", + " bargap = 0.2,\n", + ")\n", + "\n", + "data = [trace]\n", + "fig = go.Figure(data=data, layout=layout)\n", + "py.offline.iplot(fig)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Step 3: Implement Encrpyted Dataset" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, we create dictionaries to change for each character to index, and vice versa." + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [], + "source": [ + "char2index = {}\n", + "index2char = {}\n", + "\n", + "for i, char in enumerate(' ' + string.ascii_lowercase + '0123456789' + string.punctuation):\n", + " char2index[char] = i\n", + " index2char[i] = char" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's build some functions to implement encrpyted dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [], + "source": [ + "def string2values(str_input, max_len=8):\n", + " \"\"\"Change string to value.\n", + " Args:\n", + " str_input(str): string input\n", + " max_len: maximum length of string\n", + " Returns:\n", + " tensor values\n", + " \"\"\"\n", + " str_input = str_input[:max_len].lower()\n", + " \n", + " # pad strings shorter than max len\n", + " if(len(str_input) < max_len):\n", + " str_input = str_input + \".\" * (max_len - len(str_input))\n", + " \n", + " values = list()\n", + " for char in str_input:\n", + " values.append(char2index[char])\n", + " \n", + " return th.tensor(values).long()\n", + "\n", + "def values2string(input_values):\n", + " \"\"\"Change value to string.\n", + " Args:\n", + " input_values: values input\n", + " Returns:\n", + " string\n", + " \"\"\"\n", + " s = \"\"\n", + " for value in input_values:\n", + " s += index2char[int(value)]\n", + " return s\n", + "\n", + "def one_hot(index, length):\n", + " \"\"\"Make one hot for each counted string on the index.\n", + " Args:\n", + " index\n", + " Returns:\n", + " one hot vector\n", + " \"\"\"\n", + " vect = th.zeros(length).long()\n", + " vect[index] = 1\n", + " return vect\n", + "\n", + "def string2one_hot_matrix(str_input, max_len=8):\n", + " \"\"\"Change string into one hot matrix\n", + " Args:\n", + " str_input(str): string input\n", + " max_len: maximum length of string\n", + " Returns:\n", + " one hot matrix\n", + " \"\"\"\n", + " str_input = str_input[:max_len].lower()\n", + " # pad strings shorter than max len\n", + " if(len(str_input) < max_len):\n", + " str_input = str_input + \".\" * (max_len - len(str_input))\n", + "\n", + " char_vectors = list()\n", + " for char in str_input:\n", + " char_v = one_hot(char2index[char], len(char2index)).unsqueeze(0)\n", + " char_vectors.append(char_v)\n", + " \n", + " return th.cat(char_vectors, dim=0)\n", + "\n", + "def strings_equal(str_a, str_b):\n", + " \"\"\"Comparing two string inputs\n", + " Args:\n", + " str_a(str): string input a\n", + " str_b(str): string input b\n", + " Returns:\n", + " tensor comparison result\n", + " \"\"\"\n", + " vect = (str_a * str_b).sum(1) # show overlapping\n", + "\n", + " x = vect[0]\n", + "\n", + " for i in range(vect.shape[0] - 1):\n", + " x = x * vect[i+1]\n", + "\n", + " return x" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, we will make class EncrpytedDataset to encrypt Twitter dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "metadata": {}, + "outputs": [], + "source": [ + "class EncryptedDataset():\n", + " \n", + " def __init__(self, *owners, max_key_len=8, max_val_len=8):\n", + " self.max_key_len = max_key_len\n", + " self.max_val_len = max_val_len\n", + " \n", + " self.keys = list()\n", + " self.values = list()\n", + " self.owners = owners\n", + " \n", + " def add_entry(self, key, value):\n", + " key = string2one_hot_matrix(key)\n", + " key = key.share(*self.owners)\n", + " self.keys.append(key)\n", + " \n", + " value = string2values(value, max_len=self.max_val_len)\n", + " value = value.share(*self.owners)\n", + " self.values.append(value)\n", + " \n", + " def query(self, query_str):\n", + " query_matrix = string2one_hot_matrix(query_str)\n", + " \n", + " query_matrix = query_matrix.share(*self.owners)\n", + "\n", + " key_matches = list()\n", + " for key in self.keys:\n", + "\n", + " key_match = strings_equal(key, query_matrix)\n", + " key_matches.append(key_match)\n", + "\n", + " result = self.values[0] * key_matches[0]\n", + "\n", + " for i in range(len(self.values) - 1):\n", + " result += self.values[i+1] * key_matches[i+1]\n", + " \n", + " result = result.get()\n", + "\n", + " return values2string(result).replace(\".\",\"\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Make workers" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "W0820 22:11:36.020632 2788 hook.py:98] Torch was already hooked... skipping hooking process\n" + ] + } + ], + "source": [ + "import syft as sy\n", + "import torch as th\n", + "hook = sy.TorchHook(th)" + ] + }, + { + "cell_type": "code", + "execution_count": 63, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "W0820 22:34:05.893684 2788 base.py:628] Worker me already exists. Replacing old worker which could cause unexpected behavior\n", + "W0820 22:34:05.894680 2788 base.py:628] Worker me already exists. Replacing old worker which could cause unexpected behavior\n", + "W0820 22:34:05.895643 2788 base.py:628] Worker me already exists. Replacing old worker which could cause unexpected behavior\n" + ] + } + ], + "source": [ + "bob = sy.VirtualWorker(hook, id=\"bob\").add_worker(sy.local_worker)\n", + "alice = sy.VirtualWorker(hook, id=\"alice\").add_worker(sy.local_worker)\n", + "secure_worker = sy.VirtualWorker(hook, id=\"secure_worker\").add_worker(sy.local_worker)\n", + "\n", + "# clearing objects\n", + "bob = bob.clear_objects()\n", + "alice = alice.clear_objects()\n", + "secure_worker = secure_worker.clear_objects()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cleaning Dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "[nltk_data] Downloading package stopwords to C:\\Users\\Yasir Abdur\n", + "[nltk_data] Rohman\\AppData\\Roaming\\nltk_data...\n", + "[nltk_data] Package stopwords is already up-to-date!\n" + ] + } + ], + "source": [ + "import nltk\n", + "nltk.download('stopwords')\n", + "from nltk.corpus import stopwords\n", + "from string import punctuation\n", + "import string\n", + "from unicodedata import normalize\n", + "import re\n", + "\n", + "def remove_url(tweet):\n", + " \"\"\"Remove URL link.\n", + " Args:\n", + " tweet(str): tweet\n", + " Returns:\n", + " modified tweet\n", + " \"\"\"\n", + " tweet = re.sub(r\"\\s—\\s\", \"\", tweet)\n", + " tweet = re.sub(r\"http\\S+\", \"\", tweet)\n", + " return tweet\n", + "\n", + "def remove_hashtag_mention(tweet):\n", + " \"\"\"Remove hastag and mention.\n", + " Args:\n", + " tweet(str): tweet\n", + " Returns:\n", + " modified tweet\n", + " \"\"\"\n", + " result = []\n", + " tweet = tweet.split(' ')\n", + " for t in tweet:\n", + " if t.startswith('#') or t.startswith('@'):\n", + " continue\n", + " else:\n", + " result.append(t)\n", + " return ' '.join(result)\n", + "\n", + "def remove_rt_fav(tweet):\n", + " \"\"\"Remove RT and FAV.\n", + " Args:\n", + " tweet(str): tweet\n", + " Returns:\n", + " modified tweet\n", + " \"\"\"\n", + " tweet = re.sub(r'^(RT|FAV)','', tweet)\n", + " return tweet\n", + "\n", + "def remove_punctuation(tweet):\n", + " \"\"\"Remove punctuation except '-'.\n", + " Args:\n", + " tweet(str): tweet\n", + " Returns:\n", + " modified tweet\n", + " \"\"\"\n", + " remove = string.punctuation\n", + " translator = str.maketrans(remove, ' '*len(remove))\n", + " return tweet.translate(translator)\n", + " \n", + "def remove_ascii_unicode(tweet):\n", + " \"\"\"Remove ASCII and Unicode.\n", + " Args:\n", + " tweet(str): tweet\n", + " Returns:\n", + " modified tweet\n", + " \"\"\"\n", + " tweet = normalize('NFKD', tweet)\n", + " tweet = tweet.encode('ascii', 'ignore').decode('utf-8')\n", + " return tweet\n", + "\n", + "def remove_newline(tweet):\n", + " \"\"\"Remove newline.\n", + " Args:\n", + " tweet(str): tweet\n", + " Returns:\n", + " modified tweet\n", + " \"\"\"\n", + " tweet = tweet.replace('\\n', ' ')\n", + " return tweet" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "metadata": {}, + "outputs": [], + "source": [ + "# cleaning tweet documents\n", + "\n", + "for index, row in df_tweet.iterrows():\n", + " clean_tweet = remove_ascii_unicode(row['text'])\n", + " clean_tweet = clean_tweet.lower()\n", + " clean_tweet = remove_rt_fav(clean_tweet)\n", + " clean_tweet = remove_newline(clean_tweet)\n", + " clean_tweet = remove_url(clean_tweet)\n", + " clean_tweet = remove_hashtag_mention(clean_tweet)\n", + " clean_tweet = remove_punctuation(clean_tweet)\n", + " \n", + " # update dataframe\n", + " df_tweet.at[index,'text'] = clean_tweet" + ] + }, + { + "cell_type": "code", + "execution_count": 52, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "0 udacity aws deepracer scholarship challenge fo...\n", + "1 a new udacity green it training course has bee...\n", + "2 back to school isnt just for kids 20 courses ...\n", + "3 belajar tensorflow yang di udacity bagus gak pak \n", + "4 congratulations \n", + "5 please reach out at support udacity com\n", + "6 \n", + "7 udacity aws deepracer scholarship challenge fo...\n", + "8 networking for web developers \n", + "9 \n", + "Name: text, dtype: object" + ] + }, + "execution_count": 52, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# take a look at the results\n", + "df_tweet['text'].head(10)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Encrpyt the dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 66, + "metadata": {}, + "outputs": [], + "source": [ + "# initialize class EncrpytedDataset\n", + "db = EncryptedDataset(bob, alice, secure_worker, max_val_len=280)\n", + "\n", + "# add Twitter dataset into db\n", + "for index, row in df_tweet.iterrows():\n", + " # we can make the key combining index and username\n", + " key = str(index) + '@' + row['username']\n", + " values = row['text']\n", + " \n", + " db.add_entry(key, values)" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'udacity aws deepracer scholarship challenge for international students '" + ] + }, + "execution_count": 67, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# let's testing out our database\n", + "db.query(\"0@JustNowBulletin\")" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
usernamecreated_attext
0JustNowBulletin2019-08-20 14:20:11udacity aws deepracer scholarship challenge fo...
\n", + "
" + ], + "text/plain": [ + " username created_at \\\n", + "0 JustNowBulletin 2019-08-20 14:20:11 \n", + "\n", + " text \n", + "0 udacity aws deepracer scholarship challenge fo... " + ] + }, + "execution_count": 68, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# we get the same result\n", + "df_tweet.head(1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Step 4: Topic Modelling\n", + "Now, we will implementing Topic Modelling from our Encrpyted Dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 72, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "493" + ] + }, + "execution_count": 72, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# make list of keys\n", + "keys = list()\n", + "\n", + "for index, row in df_tweet.iterrows():\n", + " key = str(index) + '@' + row['username']\n", + " keys.append(key)\n", + "\n", + "len(keys)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Make a corpus\n", + "We will make corpus from Twitter Encrypted Dataset." + ] + }, + { + "cell_type": "code", + "execution_count": 77, + "metadata": {}, + "outputs": [], + "source": [ + "corpus = list()\n", + "a = list()\n", + "\n", + "# for i in range(len(df_tweet['text'])):\n", + "# a = df_tweet['text'][i]\n", + "# corpus.append(a)\n", + "\n", + "for key in keys:\n", + " a = db.query(key)\n", + " corpus.append(a)" + ] + }, + { + "cell_type": "code", + "execution_count": 79, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "['udacity aws deepracer scholarship challenge for international students ',\n", + " 'a new udacity green it training course has been added to sustaintraina data engineer ',\n", + " 'back to school isnt just for kids 20 courses to update your skills from and ',\n", + " 'belajar tensorflow yang di udacity bagus gak pak ',\n", + " 'congratulations ']" + ] + }, + "execution_count": 79, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# let's see our corpus\n", + "corpus[0:5]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Make temporary folder for saving dictionary and corpus" + ] + }, + { + "cell_type": "code", + "execution_count": 80, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Folder \"C:\\Users\\YASIRA~1\\AppData\\Local\\Temp\" will be used to save temporary dictionary and corpus.\n" + ] + } + ], + "source": [ + "import gensim\n", + "import logging\n", + "import tempfile\n", + "\n", + "TEMP_FOLDER = tempfile.gettempdir()\n", + "print('Folder \"{}\" will be used to save temporary dictionary and corpus.'.format(TEMP_FOLDER))\n", + "\n", + "from gensim import corpora\n", + "logging.basicConfig(format='%(asctime)s : %(levelname)s : %(message)s', level=logging.INFO)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Remove common words and tokenize" + ] + }, + { + "cell_type": "code", + "execution_count": 81, + "metadata": {}, + "outputs": [], + "source": [ + "# remove common words and tokenize\n", + "common_words = ['RT','rt', 'udacity']\n", + "stoplist = stopwords.words('english') + list(punctuation) + common_words\n", + "\n", + "texts = [[word for word in str(document).lower().split() if word not in stoplist] for document in corpus]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Convert corpus documents into a stream of vectors" + ] + }, + { + "cell_type": "code", + "execution_count": 82, + "metadata": {}, + "outputs": [], + "source": [ + "dictionary = corpora.Dictionary(texts)\n", + "dictionary.save(os.path.join(TEMP_FOLDER, 'tweet_documents.dict')) # store the dictionary, for future reference\n", + "# print(dictionary)\n", + "\n", + "corpus = [dictionary.doc2bow(text) for text in texts]\n", + "corpora.MmCorpus.serialize(os.path.join(TEMP_FOLDER, 'tweet_documents.mm'), corpus) # store to disk, for later use" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Transformation using Tfidf\n", + "TFIDF, short for term frequency–inverse document frequency, is a numerical statistic that is intended to reflect how important a word is to a document in a collection or corpus." + ] + }, + { + "cell_type": "code", + "execution_count": 83, + "metadata": {}, + "outputs": [], + "source": [ + "# initialize\n", + "tfidf = models.TfidfModel(corpus)" + ] + }, + { + "cell_type": "code", + "execution_count": 84, + "metadata": {}, + "outputs": [], + "source": [ + "# use the model to transform vectors\n", + "corpus_tfidf = tfidf[corpus]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Implement LDA\n", + "Latent Dirichlet allocation (LDA) is a generative statistical model that allows sets of observations to be explained by unobserved groups that explain why some parts of the data are similar. For example, if observations are words collected into documents, it posits that each document is a mixture of a small number of topics and that each word's presence is attributable to one of the document's topics. LDA is an example of a topic model." + ] + }, + { + "cell_type": "code", + "execution_count": 85, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "W0820 23:36:28.732566 2788 ldamodel.py:934] too few updates, training might not converge; consider increasing the number of passes or iterations to improve accuracy\n" + ] + } + ], + "source": [ + "num_of_topics = 4\n", + "\n", + "lda = models.LdaModel(corpus, id2word=dictionary, num_topics=num_of_topics)\n", + "corpus_lda = lda[corpus_tfidf]" + ] + }, + { + "cell_type": "code", + "execution_count": 89, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[(0,\n", + " '0.014*\"course\" + 0.012*\"amp\" + 0.010*\"new\" + 0.007*\"training\" + 0.006*\"congratulations\"'),\n", + " (1,\n", + " '0.013*\"learning\" + 0.011*\"nanodegree\" + 0.010*\"day\" + 0.009*\"android\" + 0.008*\"data\"'),\n", + " (2,\n", + " '0.007*\"nanodegree\" + 0.007*\"thanks\" + 0.007*\"learning\" + 0.006*\"project\" + 0.006*\"amp\"'),\n", + " (3,\n", + " '0.018*\"course\" + 0.017*\"learning\" + 0.015*\"day\" + 0.010*\"nanodegree\" + 0.009*\"machine\"')]" + ] + }, + "execution_count": 89, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Show first n important word in the topics\n", + "lda.show_topics(num_of_topics, 5)" + ] + }, + { + "cell_type": "code", + "execution_count": 90, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "(71, 4)\n", + "(4, 71)\n" + ] + }, + { + "data": { + "text/html": [ + "
\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "
123ableaddedaialsoampandroidbecome...timetrainingtwouudemyurviavoyagewebwork
00.0000000.0000000.0000000.0035330.0057340.0033790.0000000.0119320.0000000.000000...0.0000000.006630.003380.0000000.0000000.0000000.0000000.0045060.0000000.000000
10.0000000.0000000.0000000.0000000.0000000.0000000.0000000.0035710.0088780.003672...0.0000000.000000.000000.0000000.0000000.0000000.0000000.0000000.0000000.003455
20.0000000.0000000.0000000.0000000.0000000.0000000.0035930.0058690.0000000.000000...0.0037560.000000.000000.0037020.0054440.0033320.0000000.0000000.0000000.000000
30.0076390.0090430.0080260.0000000.0000000.0041540.0000000.0000000.0000000.000000...0.0000000.000000.000000.0000000.0000000.0000000.0038510.0000000.0035430.000000
\n", + "

4 rows × 71 columns

\n", + "
" + ], + "text/plain": [ + " 1 2 3 able added ai also \\\n", + "0 0.000000 0.000000 0.000000 0.003533 0.005734 0.003379 0.000000 \n", + "1 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 \n", + "2 0.000000 0.000000 0.000000 0.000000 0.000000 0.000000 0.003593 \n", + "3 0.007639 0.009043 0.008026 0.000000 0.000000 0.004154 0.000000 \n", + "\n", + " amp android become ... time training two u \\\n", + "0 0.011932 0.000000 0.000000 ... 0.000000 0.00663 0.00338 0.000000 \n", + "1 0.003571 0.008878 0.003672 ... 0.000000 0.00000 0.00000 0.000000 \n", + "2 0.005869 0.000000 0.000000 ... 0.003756 0.00000 0.00000 0.003702 \n", + "3 0.000000 0.000000 0.000000 ... 0.000000 0.00000 0.00000 0.000000 \n", + "\n", + " udemy ur via voyage web work \n", + "0 0.000000 0.000000 0.000000 0.004506 0.000000 0.000000 \n", + "1 0.000000 0.000000 0.000000 0.000000 0.000000 0.003455 \n", + "2 0.005444 0.003332 0.000000 0.000000 0.000000 0.000000 \n", + "3 0.000000 0.000000 0.003851 0.000000 0.003543 0.000000 \n", + "\n", + "[4 rows x 71 columns]" + ] + }, + "execution_count": 90, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Show probability for each word in each topic\n", + "from collections import OrderedDict\n", + "\n", + "data_lda = {i: OrderedDict(lda.show_topic(i, 25)) for i in range(num_of_topics)}\n", + "\n", + "df_lda = pd.DataFrame(data_lda)\n", + "print(df_lda.shape)\n", + "df_lda = df_lda.fillna(0).T\n", + "print(df_lda.shape)\n", + "\n", + "df_lda.head()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualizing Clustermap LDA" + ] + }, + { + "cell_type": "code", + "execution_count": 91, + "metadata": {}, + "outputs": [ + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "import seaborn as sns\n", + "import matplotlib.pyplot as plt\n", + "%matplotlib inline\n", + "\n", + "g = sns.clustermap(df_lda.corr(), center=0, cmap=\"RdBu\", metric='cosine', linewidths=.75, figsize=(12, 12))\n", + "plt.setp(g.ax_heatmap.yaxis.get_majorticklabels(), rotation=0)\n", + "plt.show()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualizing with PyLDAvis" + ] + }, + { + "cell_type": "code", + "execution_count": 92, + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "\n", + "\n", + "\n", + "\n", + "
\n", + "" + ], + "text/plain": [ + "PreparedData(topic_coordinates= x y topics cluster Freq\n", + "topic \n", + "3 717.098206 -274.787933 1 1 61.212318\n", + "0 -497.595306 -238.658997 2 1 12.996777\n", + "2 91.696190 -863.767029 3 1 12.954168\n", + "1 127.807060 350.324554 4 1 12.836737, topic_info= Category Freq Term Total loglift logprob\n", + "384 Default 1.000000 amp 1.000000 30.0000 30.0000\n", + "11 Default 1.000000 new 1.000000 29.0000 29.0000\n", + "163 Default 4.000000 nanodegree 4.000000 28.0000 28.0000\n", + "8 Default 1.000000 data 1.000000 27.0000 27.0000\n", + "7 Default 6.000000 course 6.000000 26.0000 26.0000\n", + "131 Default 0.000000 android 0.000000 25.0000 25.0000\n", + "121 Default 6.000000 learning 6.000000 24.0000 24.0000\n", + "177 Default 1.000000 thanks 1.000000 23.0000 23.0000\n", + "29 Default 0.000000 congratulations 0.000000 22.0000 22.0000\n", + "13 Default 1.000000 training 1.000000 21.0000 21.0000\n", + "12 Default 0.000000 sustaintraina 0.000000 20.0000 20.0000\n", + "166 Default 0.000000 science 0.000000 19.0000 19.0000\n", + "379 Default 1.000000 developer 1.000000 18.0000 18.0000\n", + "10 Default 0.000000 green 0.000000 17.0000 17.0000\n", + "6 Default 0.000000 added 0.000000 16.0000 16.0000\n", + "150 Default 1.000000 project 1.000000 15.0000 15.0000\n", + "147 Default 5.000000 day 5.000000 14.0000 14.0000\n", + "51 Default 1.000000 program 1.000000 13.0000 13.0000\n", + "162 Default 1.000000 completed 1.000000 12.0000 12.0000\n", + "127 Default 1.000000 udemy 1.000000 11.0000 11.0000\n", + "900 Default 0.000000 de 0.000000 10.0000 10.0000\n", + "16 Default 1.000000 courses 1.000000 9.0000 9.0000\n", + "689 Default 0.000000 help 0.000000 8.0000 8.0000\n", + "580 Default 0.000000 end 0.000000 7.0000 7.0000\n", + "245 Default 0.000000 build 0.000000 6.0000 6.0000\n", + "671 Default 0.000000 voyage 0.000000 5.0000 5.0000\n", + "620 Default 1.000000 self 1.000000 4.0000 4.0000\n", + "645 Default 1.000000 learn 1.000000 3.0000 3.0000\n", + "640 Default 0.000000 become 0.000000 2.0000 2.0000\n", + "617 Default 1.000000 driving 1.000000 1.0000 1.0000\n", + ".. ... ... ... ... ... ...\n", + "533 Topic4 0.188341 could 0.372085 1.3720 -5.8172\n", + "166 Topic4 0.375340 science 0.784598 1.3155 -5.1276\n", + "819 Topic4 0.202087 gb 0.419389 1.3228 -5.7467\n", + "165 Topic4 0.246269 programming 0.571765 1.2106 -5.5490\n", + "8 Topic4 0.527921 data 1.718537 0.8726 -4.7865\n", + "245 Topic4 0.300216 build 0.800375 1.0723 -5.3509\n", + "754 Topic4 0.199724 front 0.482997 1.1698 -5.7585\n", + "379 Topic4 0.369394 developer 1.165598 0.9037 -5.1435\n", + "217 Topic4 0.218626 work 0.551821 1.1270 -5.6680\n", + "854 Topic4 0.127035 explore 0.255990 1.3522 -6.2109\n", + "467 Topic4 0.239285 need 0.692042 0.9909 -5.5777\n", + "850 Topic4 0.189130 artificial 0.491826 1.0972 -5.8130\n", + "163 Topic4 0.710112 nanodegree 4.463806 0.2145 -4.4900\n", + "851 Topic4 0.162263 autonomous 0.413281 1.1179 -5.9662\n", + "162 Topic4 0.335191 completed 1.386456 0.6331 -5.2407\n", + "121 Topic4 0.832880 learning 6.782568 -0.0444 -4.3305\n", + "147 Topic4 0.660560 day 5.637958 -0.0913 -4.5623\n", + "16 Topic4 0.329677 courses 1.519501 0.5248 -5.2573\n", + "51 Topic4 0.330654 program 1.834227 0.3396 -5.2543\n", + "11 Topic4 0.305914 new 1.579808 0.4111 -5.3321\n", + "645 Topic4 0.298989 learn 1.537540 0.4153 -5.3550\n", + "177 Topic4 0.268187 thanks 1.217927 0.5396 -5.4637\n", + "122 Topic4 0.246624 like 1.295200 0.3943 -5.5475\n", + "408 Topic4 0.211589 google 0.832637 0.6829 -5.7008\n", + "235 Topic4 0.282597 thank 3.263640 -0.3937 -5.4114\n", + "7 Topic4 0.309832 course 6.947092 -1.0572 -5.3194\n", + "384 Topic4 0.225995 amp 1.896308 -0.0743 -5.6349\n", + "168 Topic4 0.204323 coding 1.197109 0.2849 -5.7357\n", + "173 Topic4 0.200624 great 1.101611 0.3498 -5.7540\n", + "267 Topic4 0.200957 machine 3.204221 -0.7163 -5.7523\n", + "\n", + "[280 rows x 6 columns], token_table= Topic Freq Term\n", + "term \n", + "87 1 0.784676 1\n", + "145 1 1.003142 2\n", + "244 1 0.718488 3\n", + "218 1 0.895239 4\n", + "1215 1 1.028093 49\n", + "195 1 1.171668 6\n", + "977 1 1.355159 9\n", + "53 1 0.582997 ai\n", + "384 1 0.527341 amp\n", + "384 2 0.527341 amp\n", + "131 4 1.048993 android\n", + "73 1 1.005416 app\n", + "196 1 1.870341 beginning\n", + "625 1 0.863184 car\n", + "168 1 0.835346 coding\n", + "162 1 0.721263 completed\n", + "401 1 1.208927 continue\n", + "222 1 1.015573 continuing\n", + "7 1 0.719726 course\n", + "7 2 0.143945 course\n", + "16 1 0.658111 courses\n", + "1085 1 1.165815 create\n", + "8 1 0.581890 data\n", + "8 4 0.581890 data\n", + "147 1 0.709477 day\n", + "147 4 0.177369 day\n", + "148 1 0.888986 discussion\n", + "617 1 0.830102 driving\n", + "1013 1 1.590379 drlnd\n", + "1164 1 1.428462 embedded\n", + "... ... ... ...\n", + "1443 1 1.845314 movie\n", + "163 1 0.672072 nanodegree\n", + "163 4 0.224024 nanodegree\n", + "1444 1 1.848279 netflix\n", + "11 2 0.632989 new\n", + "719 1 0.609141 online\n", + "149 1 0.651882 participated\n", + "31 1 0.901349 please\n", + "630 1 0.985107 prepared\n", + "329 1 1.847007 product\n", + "51 1 0.545189 program\n", + "150 1 0.703423 project\n", + "631 1 0.629519 projects\n", + "1445 1 1.844630 recommendation\n", + "1018 1 1.574677 reviewing\n", + "1166 1 1.428593 roles\n", + "4 1 0.611216 scholarship\n", + "620 1 0.770427 self\n", + "151 1 0.729788 showcase\n", + "20 1 0.573691 skills\n", + "152 1 0.882125 slack\n", + "1168 1 1.428715 society\n", + "347 1 0.957356 studying\n", + "52 1 0.813581 tech\n", + "235 1 0.919219 thank\n", + "614 1 0.724789 time\n", + "127 1 0.754704 udemy\n", + "326 1 0.668864 via\n", + "36 1 0.817077 web\n", + "203 1 0.937495 years\n", + "\n", + "[76 rows x 3 columns], R=30, lambda_step=0.01, plot_opts={'xlab': 'PC1', 'ylab': 'PC2'}, topic_order=[4, 1, 3, 2])" + ] + }, + "execution_count": 92, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import pyLDAvis.gensim\n", + "\n", + "pyLDAvis.enable_notebook()\n", + "panel = pyLDAvis.gensim.prepare(lda, corpus_lda, dictionary, mds='tsne')\n", + "panel" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Yasir Abdur Rohman/Project 1/assets/eda.png b/Yasir Abdur Rohman/Project 1/assets/eda.png new file mode 100644 index 00000000..676b128c Binary files /dev/null and b/Yasir Abdur Rohman/Project 1/assets/eda.png differ diff --git a/Yasir Abdur Rohman/Project 1/assets/lda.PNG b/Yasir Abdur Rohman/Project 1/assets/lda.PNG new file mode 100644 index 00000000..8197d81b Binary files /dev/null and b/Yasir Abdur Rohman/Project 1/assets/lda.PNG differ diff --git a/Yasir Abdur Rohman/Project 2/.ipynb_checkpoints/Federated Learning on Fashion MNIST using CNN-checkpoint.ipynb b/Yasir Abdur Rohman/Project 2/.ipynb_checkpoints/Federated Learning on Fashion MNIST using CNN-checkpoint.ipynb new file mode 100644 index 00000000..293f173b --- /dev/null +++ b/Yasir Abdur Rohman/Project 2/.ipynb_checkpoints/Federated Learning on Fashion MNIST using CNN-checkpoint.ipynb @@ -0,0 +1,441 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Federated Learning on Fashion MNIST using CNN\n", + "*Author: Yasir Abdur Rohman*\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Introduction\n", + "In this project, we will implement federated learning on Fashion MNIST dataset using CNN. Federated Learning is a machine learning setting where the goal is to train a high-quality centralized model with training data distributed over a large number of clients each with unreliable and relatively slow network connections. This project inspired by an example from Pysyft tutorial on [Federated CIFAR10](https://github.com/OpenMined/PySyft/blob/dev/examples/tutorials/advanced/Federated%20CIFAR10.ipynb).\n", + "\n", + "For the better model performance, we will use transfer learning from a pre-trained model.\n", + "\n", + "The project consists of the following steps:\n", + "1. Import and model Specification\n", + "2. Load data\n", + "3. Convolutional Neural Network\n", + "4. Training" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Step 1: Import and model specification" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING: Logging before flag parsing goes to stderr.\n", + "W0821 06:06:49.046733 22572 secure_random.py:26] Falling back to insecure randomness since the required custom op could not be found for the installed version of TensorFlow. Fix this by compiling custom ops. Missing file was 'D:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\tf_encrypted/operations/secure_random/secure_random_module_tf_1.14.0.so'\n", + "W0821 06:06:49.058670 22572 deprecation_wrapper.py:119] From D:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\tf_encrypted\\session.py:26: The name tf.Session is deprecated. Please use tf.compat.v1.Session instead.\n", + "\n" + ] + } + ], + "source": [ + "import torch\n", + "import torch.nn as nn\n", + "import torch.nn.functional as F\n", + "import torch.optim as optim\n", + "from torchvision import datasets, models, transforms\n", + "\n", + "# pysyft\n", + "import syft as sy\n", + "\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setting hyperparameters" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "class Arguments():\n", + " def __init__(self):\n", + " self.batch_size = 64\n", + " self.test_batch_size = 1000\n", + " self.epochs = 25\n", + " self.lr = 0.001\n", + " self.momentum = 0.5\n", + " self.no_cuda = True\n", + " self.seed = 1\n", + " self.log_interval = 30\n", + " self.save_model = False\n", + "\n", + "args = Arguments()\n", + "\n", + "use_cuda = not args.no_cuda and torch.cuda.is_available()\n", + "\n", + "torch.manual_seed(args.seed)\n", + "\n", + "device = torch.device(\"cuda\" if use_cuda else \"cpu\")\n", + "\n", + "kwargs = {'num_workers': 1, 'pin_memory': True} if use_cuda else {}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Initialize workers" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "hook = sy.TorchHook(torch)\n", + "bob = sy.VirtualWorker(hook, id=\"bob\")\n", + "alice = sy.VirtualWorker(hook, id=\"alice\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Step 2: Load Data" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "def load_data():\n", + " \n", + " '''Load Fashion MNIST dataset from torch vision module distribute to workers using PySyft's Federated Data loader'''\n", + " \n", + "\n", + " federated_train_loader = sy.FederatedDataLoader(\n", + " datasets.FashionMNIST('../data', train=True, download=True,\n", + " transform=transforms.Compose([\n", + " transforms.ToTensor(),\n", + " transforms.Normalize((0.5,), (0.5,))\n", + " ]))\n", + " .federate((bob, alice)),\n", + " batch_size=args.batch_size, shuffle=True, **kwargs)\n", + "\n", + " test_loader = torch.utils.data.DataLoader(\n", + " datasets.FashionMNIST('../data', train=False, transform=transforms.Compose([\n", + " transforms.ToTensor(),\n", + " transforms.Normalize((0.5,), (0.5,))\n", + " ])),\n", + " batch_size=args.test_batch_size, shuffle=True, **kwargs)\n", + "\n", + " return federated_train_loader,test_loader" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "federated_train_loader, test_loader = load_data()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualize some dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAPsAAAD4CAYAAAAq5pAIAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAALEgAACxIB0t1+/AAAADh0RVh0U29mdHdhcmUAbWF0cGxvdGxpYiB2ZXJzaW9uMy4xLjAsIGh0dHA6Ly9tYXRwbG90bGliLm9yZy+17YcXAAAQEklEQVR4nO3df4yVVX7H8c9XQOSHg4zISJAALsRoNIpBbMLaWA2IxgRXsw38UW2KYRNXs8bGlmxj1qRpQtpuG//ahM2axbp13ShmCTa6E7Kp7T8GJBZxh10oUhkZmSDoDj8EB779Yx7aUef5nvE+997nruf9SiZ35n7n3Hu4mQ/Pc+95zjnm7gLw9XdR3R0A0B6EHcgEYQcyQdiBTBB2IBMT2/lkZsZH/0CLubuNdX+lI7uZrTKz35rZfjPbUOWxALSWNTrObmYTJP1O0gpJ/ZJ2SFrr7r8J2nBkB1qsFUf2ZZL2u/sBdz8r6eeSVld4PAAtVCXscyUdGvVzf3Hf55jZejPbaWY7KzwXgIqqfEA31qnCl07T3X2TpE0Sp/FAnaoc2fslzRv181WSDlfrDoBWqRL2HZIWm9lCM7tY0hpJW5vTLQDN1vBpvLsPm9mjkl6XNEHSs+7+btN6BqCpGh56a+jJeM8OtFxLLqoB8IeDsAOZIOxAJgg7kAnCDmSCsAOZIOxAJgg7kAnCDmSCsAOZIOxAJgg7kAnCDmSCsAOZIOxAJgg7kAnCDmSCsAOZIOxAJgg7kAnCDmSCsAOZIOxAJgg7kAnCDmSCsAOZIOxAJgg7kAnCDmSi4S2bgU530UWNH8tSuxu3cvfj6667LqzPmjWrtLZr167SWqWwm9lBSUOSzkkadvelVR4PQOs048j+J+5+tAmPA6CFeM8OZKJq2F3Sr8zsLTNbP9YvmNl6M9tpZjsrPheACqqexi9398NmNltSr5ntdfc3Rv+Cu2+StEmSzKx1n2oACFU6srv74eJ2UNIrkpY1o1MAmq/hsJvZNDO79ML3klZK2tOsjgForiqn8T2SXjGzC4/zr+7+WlN6hY6RGqs+f/58WF+zZk1p7d577w3bPv/882H9tdfiP7dU31pp0qRJYf22224rrU2ZMiVse/jw4dLauXPnSmsNh93dD0i6sdH2ANqLoTcgE4QdyARhBzJB2IFMEHYgE0xxzVzVobWU66+/vrTW09MTtr3//vvD+g033BDWjx07VlpL/bvPnj0b1k+dOhXWoyFHKe57X19f2Hb16tVhvQxHdiAThB3IBGEHMkHYgUwQdiAThB3IBGEHMsE4e+aqjrNHyxpLUldXV2lt69atYdsZM2aE9Q0bNoT1aKz89OnTYdtLLrkkrE+cGEent7c3rO/du7e09txzz4VtG8WRHcgEYQcyQdiBTBB2IBOEHcgEYQcyQdiBTDDOnrnh4eFK7e+8886wHo1Hp8aylyxZEtaj+eqSdOLEidLatGnTwrapcfhDhw6F9U8//TSs33zzzaW17du3h20bxZEdyARhBzJB2IFMEHYgE4QdyARhBzJB2IFMMM7+NVdsqV3K3Ss9/qJFi8J6NM7e3d0dtp0/f35Ynzp1aliP5uqnxvhTWy6ntlVOjdN//PHHDdWqSB7ZzexZMxs0sz2j7us2s14z21fczmxJ7wA0zXhO438qadUX7tsgabu7L5a0vfgZQAdLht3d35D0xesSV0vaXHy/WdJ9Te4XgCZr9D17j7sPSJK7D5jZ7LJfNLP1ktY3+DwAmqTlH9C5+yZJmyTJzKp9GgSgYY0OvR0xszmSVNwONq9LAFqh0bBvlfRQ8f1Dkn7ZnO4AaJXkabyZvSDpdkmzzKxf0g8kbZT0CzNbJ+l9Sd9uZSfRuKrj7HfddVdYX7BgQVifPbv04xwNDsYnhKk16Y8fPx7WL7744tLaZ599FrZNSc1XT63HPzQ0VOn5G5EMu7uvLSnFqxYA6ChcLgtkgrADmSDsQCYIO5AJwg5kgimuHaDq8NiECRNKa+fOnQvbpqZ63nHHHWE9Nfy1f//+0lpqCmuqb6mpoJdeemlp7cyZM2HbyZMnh/Xp06eH9ZR58+Y1/NjREtkRjuxAJgg7kAnCDmSCsAOZIOxAJgg7kAnCDmSi7ePsqTHlSNVljztV6t+VWta4ynTNhx9+OKynxulTY90DAwOltQcffDBsm5oGmnpdotc19e9KST13f39/WJ8xY0Zpbfny5WHb119/PayX4cgOZIKwA5kg7EAmCDuQCcIOZIKwA5kg7EAm2j7O/oc6Vh5dH5BaNrjqv7nKOPojjzwS1hcuXBjWU+PFJ0+eDOvXXHNNaS21VPSRI0fCemqsO5IaZ4/WCJCkrq6usH7+/PmwHv1NrFixImzLODuAEGEHMkHYgUwQdiAThB3IBGEHMkHYgUx01Hz21Hh1VK+6BW+Vtdurzo1OSa2f/sQTT5TWDh06FLZ98cUXw3pqy+bTp0+H9QceeKDhthMnxn+e0ZbMKdFW0pI0derUsL53796wnrp+Ifq33XjjjWHbRiWP7Gb2rJkNmtmeUfc9bWYfmNnbxdc9LekdgKYZz2n8TyWtGuP+f3b3m4qvf2tutwA0WzLs7v6GpGNt6AuAFqryAd2jZra7OM2fWfZLZrbezHaa2c4KzwWgokbD/iNJ35B0k6QBST8s+0V33+TuS919aYPPBaAJGgq7ux9x93Pufl7SjyUta263ADRbQ2E3szmjfvyWpD1lvwugMyTH2c3sBUm3S5plZv2SfiDpdjO7SZJLOijpO+N9wirj1a0cz64y5zzaB1ySlixZEtYXLVoU1pcujd8Bvfrqqw3VpPTc6dRYd6o+ODhYWps5s/SjHknS8PBwWK/y95KaK7979+6wnrquY9WqsQaw/t8nn3xSWrvyyivDto1Kht3d145x909a0BcALcTlskAmCDuQCcIOZIKwA5kg7EAmrJ1LO5tZ+GSXXXZZ2D7a4nffvn1h29S0wdTWw9FwyPz588O27733XlhPTZd88803w3o0jPTkk0+Gba+++uqwnpoKGm3JLMVTbK+44oqw7dy5c8N6d3d3WD9z5kxpLTU9NjUsmHpdUn9P0VLV0bCcJN1yyy1h3d3HnK/NkR3IBGEHMkHYgUwQdiAThB3IBGEHMkHYgUx01Dh7b29v2P6qq64qrT3zzDNh2x07doT11HhzNFZ+4MCBsO2UKVPC+rXXXhvWU1NkV65cWVpLbYt89OjRsJ5qn1qCOxozjqa/StLkyZPDemqJ7Wjb5NRjz5s3L6ynpjWfOnUqrE+bNq20lhpnX7x4cVhnnB3IHGEHMkHYgUwQdiAThB3IBGEHMkHYgUy0dcvmrq4uLV++vLSemhceLVv81FNPhW1TSwcfP348rB88eLC0lprT3dPTE9ZTc6tT4/Sp8eZIarw4mhMuSWfPng3r0Xj2smXx3iKpMf7Uvzu6hiR1fUk0Ri9JJ0+eDOvROLok7d+/v7QW/a1VwZEdyARhBzJB2IFMEHYgE4QdyARhBzJB2IFMdNR89tTa7uvWrSutpdbSTm2DG63jLcVjuqm50SmpsewqY8Kpx06ZPn16WJ80aVJY7+rqKq2lrk/o6+sL6++//37D7YeGhsK2H330UVhP9T11DUB0bUXquoqXXnoprDc8n93M5pnZr82sz8zeNbPvFfd3m1mvme0rbuNV9QHUajyn8cOS/tLdr5X0R5K+a2bXSdogabu7L5a0vfgZQIdKht3dB9x9V/H9kKQ+SXMlrZa0ufi1zZLua1UnAVT3la6NN7MFkpZIelNSj7sPSCP/IZjZmJtfmdl6SeurdRNAVeMOu5lNl/SypMfd/fephQYvcPdNkjYVj9G+TwMBfM64ht7MbJJGgv4zd99S3H3EzOYU9TmS4qVCAdQqOfRmI4fwzZKOufvjo+7/B0kfuftGM9sgqdvd/yrxWC07sqeGgO6+++6wnlqu+dZbby2tzZkzJ2ybmkZ6+vTpsJ7aHvjEiROltdSSxh9++GFY37ZtW1jfsmVLWI+2bK7qscceC+uXX355ae2ii+LjXGroLDU8lsrV8PBwaS21xPbGjRtTzz3mafd4TuOXS/ozSe+Y2dvFfd+XtFHSL8xsnaT3JX17HI8FoCbJsLv7f0oqe4N+Z3O7A6BVuFwWyARhBzJB2IFMEHYgE4QdyERHTXHNVXd3d1hPjcOn6l9X0bLkUjw994MPPgjbprZNrrrUdDTOnro2IvXcbNkMZI6wA5kg7EAmCDuQCcIOZIKwA5kg7EAmGGcHvmYYZwcyR9iBTBB2IBOEHcgEYQcyQdiBTBB2IBOEHcgEYQcyQdiBTBB2IBOEHcgEYQcyQdiBTBB2IBPJsJvZPDP7tZn1mdm7Zva94v6nzewDM3u7+Lqn9d0F0Kjk4hVmNkfSHHffZWaXSnpL0n2S/lTSCXf/x3E/GYtXAC1XtnjFePZnH5A0UHw/ZGZ9kuY2t3sAWu0rvWc3swWSlkh6s7jrUTPbbWbPmtnMkjbrzWynme2s1FMAlYx7DTozmy7p3yX9nbtvMbMeSUcluaS/1cip/l8kHoPTeKDFyk7jxxV2M5skaZuk1939n8aoL5C0zd2vTzwOYQdarOEFJ83MJP1EUt/ooBcf3F3wLUl7qnYSQOuM59P4b0r6D0nvSLqwV+z3Ja2VdJNGTuMPSvpO8WFe9Fgc2YEWq3Qa3yyEHWg91o0HMkfYgUwQdiAThB3IBGEHMkHYgUwQdiAThB3IBGEHMkHYgUwQdiAThB3IBGEHMkHYgUwkF5xssqOS/mfUz7OK+zpRp/atU/sl0bdGNbNv88sKbZ3P/qUnN9vp7ktr60CgU/vWqf2S6Fuj2tU3TuOBTBB2IBN1h31Tzc8f6dS+dWq/JPrWqLb0rdb37ADap+4jO4A2IexAJmoJu5mtMrPfmtl+M9tQRx/KmNlBM3un2Ia61v3pij30Bs1sz6j7us2s18z2Fbdj7rFXU986YhvvYJvxWl+7urc/b/t7djObIOl3klZI6pe0Q9Jad/9NWztSwswOSlrq7rVfgGFmfyzphKTnLmytZWZ/L+mYu28s/qOc6e5/3SF9e1pfcRvvFvWtbJvxP1eNr10ztz9vRB1H9mWS9rv7AXc/K+nnklbX0I+O5+5vSDr2hbtXS9pcfL9ZI38sbVfSt47g7gPuvqv4fkjShW3Ga33tgn61RR1hnyvp0Kif+9VZ+727pF+Z2Vtmtr7uzoyh58I2W8Xt7Jr780XJbbzb6QvbjHfMa9fI9udV1RH2sbam6aTxv+XufrOkuyV9tzhdxfj8SNI3NLIH4ICkH9bZmWKb8ZclPe7uv6+zL6ON0a+2vG51hL1f0rxRP18l6XAN/RiTux8ubgclvaKRtx2d5MiFHXSL28Ga+/N/3P2Iu59z9/OSfqwaX7tim/GXJf3M3bcUd9f+2o3Vr3a9bnWEfYekxWa20MwulrRG0tYa+vElZjat+OBEZjZN0kp13lbUWyU9VHz/kKRf1tiXz+mUbbzLthlXza9d7dufu3vbvyTdo5FP5P9b0t/U0YeSfl0t6b+Kr3fr7pukFzRyWveZRs6I1km6XNJ2SfuK2+4O6tu/aGRr790aCdacmvr2TY28Ndwt6e3i6566X7ugX2153bhcFsgEV9ABmSDsQCYIO5AJwg5kgrADmSDsQCYIO5CJ/wUYJUU41W/TVgAAAABJRU5ErkJggg==\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# obtain one batch of training images\n", + "dataiter = iter(test_loader)\n", + "images, labels = dataiter.next()\n", + "images = images.numpy() # convert images to numpy for display\n", + "\n", + "plt.imshow(images[1].squeeze(), cmap='Greys_r')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Step 3: Convolutional Neural Network\n", + "**Note:** Since BatchNorm is still not compatible in Federated Learning as issued in [#2132](https://github.com/OpenMined/PySyft/issues/2132), we cannot using transfer learning from pre-trained model such as Resnet18, VGG16. So for the solution we will make CNN layer manually as follows." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "# download resnet 18 model\n", + "# resnet18 = models.resnet18(pretrained=True)\n", + "\n", + "# Freeze training for all \"features\" layers\n", + "# for param in resnet18.parameters():\n", + "# param.requires_grad = False\n", + " \n", + "# num_ftrs = resnet18.fc.in_features\n", + "\n", + "# resnet18.fc = nn.Sequential(nn.Linear(num_ftrs, 256),\n", + "# nn.Dropout(0.3),\n", + "# nn.Linear(256, 128),\n", + "# nn.Dropout(0.3),\n", + "# nn.Linear(128, 64),\n", + "# nn.Dropout(0.3),\n", + "# nn.Linear(64, 10),\n", + "# nn.LogSoftmax(dim=1))\n", + "# architecture resnet18 modified\n", + "# resnet18" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "class CNN(nn.Module):\n", + " def __init__(self,num_classes=10):\n", + " super(CNN, self).__init__()\n", + " self.conv1 = nn.Conv2d(1, 20, 5, 1)\n", + " self.conv2 = nn.Conv2d(20, 50, 5, 1)\n", + " self.fc1 = nn.Linear(4*4*50, 500)\n", + " self.fc2 = nn.Linear(500, 10)\n", + " \n", + " def forward(self, x):\n", + " x = F.relu(self.conv1(x))\n", + " x = F.max_pool2d(x, 2, 2)\n", + " x = F.relu(self.conv2(x))\n", + " x = F.max_pool2d(x, 2, 2)\n", + " x = x.view(-1, 4*4*50)\n", + " x = F.relu(self.fc1(x))\n", + " x = self.fc2(x)\n", + " return F.log_softmax(x, dim=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Train Function" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "def train(args, model, device, train_loader, optimizer, epoch):\n", + " model.train()\n", + " for batch_idx, (data, target) in enumerate(federated_train_loader):\n", + " model.send(data.location)\n", + " data, target = data.to(device), target.to(device)\n", + " optimizer.zero_grad()\n", + " output = model(data)\n", + " loss = F.nll_loss(output, target)\n", + " loss.backward()\n", + " optimizer.step()\n", + " model.get()\n", + " if batch_idx % args.log_interval == 0:\n", + " loss = loss.get()\n", + " print('Train Epoch: {} [{}/{} ({:.0f}%)]\\tLoss: {:.6f}'.format(\n", + " epoch, batch_idx * args.batch_size, len(train_loader) * args.batch_size, #batch_idx * len(data), len(train_loader.dataset),\n", + " 100. * batch_idx / len(train_loader), loss.item()))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test Function" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "def test(args, model, device, test_loader):\n", + " model.eval()\n", + " test_loss = 0\n", + " correct = 0\n", + " with torch.no_grad():\n", + " for data, target in test_loader:\n", + " data, target = data.to(device), target.to(device)\n", + " output = model(data)\n", + " test_loss += F.nll_loss(output, target, reduction='sum').item() # sum up batch loss\n", + " pred = output.argmax(1, keepdim=True) # get the index of the max log-probability \n", + " correct += pred.eq(target.view_as(pred)).sum().item()\n", + "\n", + " test_loss /= len(test_loader.dataset)\n", + "\n", + " print('\\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\\n'.format(\n", + " test_loss, correct, len(test_loader.dataset),\n", + " 100. * correct / len(test_loader.dataset)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Step 4: Training Neural Network" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Epoch: 1 [0/60032 (0%)]\tLoss: 2.305633\n", + "Train Epoch: 1 [1920/60032 (3%)]\tLoss: 0.740293\n", + "Train Epoch: 1 [3840/60032 (6%)]\tLoss: 0.725667\n", + "Train Epoch: 1 [5760/60032 (10%)]\tLoss: 0.552224\n", + "Train Epoch: 1 [7680/60032 (13%)]\tLoss: 0.808906\n", + "Train Epoch: 1 [9600/60032 (16%)]\tLoss: 0.540031\n", + "Train Epoch: 1 [11520/60032 (19%)]\tLoss: 0.476487\n", + "Train Epoch: 1 [13440/60032 (22%)]\tLoss: 0.433211\n", + "Train Epoch: 1 [15360/60032 (26%)]\tLoss: 0.367201\n", + "Train Epoch: 1 [17280/60032 (29%)]\tLoss: 0.437580\n", + "Train Epoch: 1 [19200/60032 (32%)]\tLoss: 0.465955\n", + "Train Epoch: 1 [21120/60032 (35%)]\tLoss: 0.478523\n", + "Train Epoch: 1 [23040/60032 (38%)]\tLoss: 0.569970\n", + "Train Epoch: 1 [24960/60032 (42%)]\tLoss: 0.323152\n", + "Train Epoch: 1 [26880/60032 (45%)]\tLoss: 0.535027\n", + "Train Epoch: 1 [28800/60032 (48%)]\tLoss: 0.366544\n" + ] + }, + { + "ename": "TypeError", + "evalue": "add_() takes 1 positional argument but 2 were given", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[1;31m# Train Neural network and validate with test set after completion of training every epoch\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 6\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mepoch\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0margs\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mepochs\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 7\u001b[1;33m \u001b[0mtrain\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcnn\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdevice\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfederated_train_loader\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0moptimizer\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mepoch\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 8\u001b[0m \u001b[0mtest\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcnn\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdevice\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtest_loader\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 9\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32m\u001b[0m in \u001b[0;36mtrain\u001b[1;34m(args, model, device, train_loader, optimizer, epoch)\u001b[0m\n\u001b[0;32m 8\u001b[0m \u001b[0mloss\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mF\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mnll_loss\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0moutput\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtarget\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 9\u001b[0m \u001b[0mloss\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mbackward\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 10\u001b[1;33m \u001b[0moptimizer\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstep\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 11\u001b[0m \u001b[0mmodel\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 12\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mbatch_idx\u001b[0m \u001b[1;33m%\u001b[0m \u001b[0margs\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlog_interval\u001b[0m \u001b[1;33m==\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\torch\\optim\\adam.py\u001b[0m in \u001b[0;36mstep\u001b[1;34m(self, closure)\u001b[0m\n\u001b[0;32m 91\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 92\u001b[0m \u001b[1;31m# Decay the first and second moment running average coefficient\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 93\u001b[1;33m \u001b[0mexp_avg\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmul_\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mbeta1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0madd_\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m \u001b[1;33m-\u001b[0m \u001b[0mbeta1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mgrad\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 94\u001b[0m \u001b[0mexp_avg_sq\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmul_\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mbeta2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0maddcmul_\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m \u001b[1;33m-\u001b[0m \u001b[0mbeta2\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mgrad\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mgrad\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 95\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mamsgrad\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\syft\\frameworks\\torch\\hook\\hook.py\u001b[0m in \u001b[0;36moverloaded_native_method\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 675\u001b[0m \u001b[1;31m# Send the new command to the appropriate class and get the response\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 676\u001b[0m \u001b[0mmethod\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mgetattr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnew_self\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmethod_name\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 677\u001b[1;33m \u001b[0mresponse\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mmethod\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0mnew_args\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mnew_kwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 678\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 679\u001b[0m \u001b[1;31m# For inplace methods, just directly return self\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\syft\\frameworks\\torch\\hook\\hook.py\u001b[0m in \u001b[0;36moverloaded_pointer_method\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 511\u001b[0m \u001b[0mcommand\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0mattr\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 512\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 513\u001b[1;33m \u001b[0mresponse\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mowner\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msend_command\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlocation\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcommand\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 514\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 515\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mresponse\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\syft\\workers\\base.py\u001b[0m in \u001b[0;36msend_command\u001b[1;34m(self, recipient, message, return_ids)\u001b[0m\n\u001b[0;32m 425\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 426\u001b[0m \u001b[1;32mtry\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 427\u001b[1;33m \u001b[0mret_val\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msend_msg\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcodes\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mMSGTYPE\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mCMD\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmessage\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mlocation\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mrecipient\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 428\u001b[0m \u001b[1;32mexcept\u001b[0m \u001b[0mResponseSignatureError\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 429\u001b[0m \u001b[0mret_val\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\syft\\workers\\base.py\u001b[0m in \u001b[0;36msend_msg\u001b[1;34m(self, msg_type, message, location)\u001b[0m\n\u001b[0;32m 221\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 222\u001b[0m \u001b[1;31m# Step 2: send the message and wait for a response\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 223\u001b[1;33m \u001b[0mbin_response\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_send_msg\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mbin_message\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mlocation\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 224\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 225\u001b[0m \u001b[1;31m# Step 3: deserialize the response\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\syft\\workers\\virtual.py\u001b[0m in \u001b[0;36m_send_msg\u001b[1;34m(self, message, location)\u001b[0m\n\u001b[0;32m 8\u001b[0m \u001b[1;32mclass\u001b[0m \u001b[0mVirtualWorker\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mBaseWorker\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mFederatedClient\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 9\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0m_send_msg\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmessage\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mbin\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mlocation\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mBaseWorker\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m->\u001b[0m \u001b[0mbin\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 10\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mlocation\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_recv_msg\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmessage\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 11\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 12\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0m_recv_msg\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmessage\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mbin\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m->\u001b[0m \u001b[0mbin\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\syft\\workers\\virtual.py\u001b[0m in \u001b[0;36m_recv_msg\u001b[1;34m(self, message)\u001b[0m\n\u001b[0;32m 11\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 12\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0m_recv_msg\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmessage\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mbin\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m->\u001b[0m \u001b[0mbin\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 13\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrecv_msg\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmessage\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 14\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 15\u001b[0m \u001b[1;33m@\u001b[0m\u001b[0mstaticmethod\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\syft\\workers\\base.py\u001b[0m in \u001b[0;36mrecv_msg\u001b[1;34m(self, bin_message)\u001b[0m\n\u001b[0;32m 252\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34mf\"worker {self} received {sy.codes.code2MSGTYPE[msg_type]} {contents}\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 253\u001b[0m \u001b[1;31m# Step 1: route message to appropriate function\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 254\u001b[1;33m \u001b[0mresponse\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_message_router\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mmsg_type\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcontents\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 255\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 256\u001b[0m \u001b[1;31m# Step 2: Serialize the message to simple python objects\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\syft\\workers\\base.py\u001b[0m in \u001b[0;36mexecute_command\u001b[1;34m(self, message)\u001b[0m\n\u001b[0;32m 359\u001b[0m \u001b[0m_self\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 360\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0msy\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtorch\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mis_inplace_method\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcommand_name\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 361\u001b[1;33m \u001b[0mgetattr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0m_self\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcommand_name\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 362\u001b[0m \u001b[1;32mreturn\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 363\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\syft\\frameworks\\torch\\hook\\hook.py\u001b[0m in \u001b[0;36moverloaded_native_method\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 661\u001b[0m \u001b[1;32mexcept\u001b[0m \u001b[0mBaseException\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 662\u001b[0m \u001b[1;31m# we can make some errors more descriptive with this method\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 663\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0mroute_method_exception\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0me\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 664\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 665\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m \u001b[1;31m# means that there is a wrapper to remove\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\syft\\frameworks\\torch\\hook\\hook.py\u001b[0m in \u001b[0;36moverloaded_native_method\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 655\u001b[0m \u001b[1;32mtry\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 656\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtuple\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 657\u001b[1;33m \u001b[0mresponse\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mmethod\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 658\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 659\u001b[0m \u001b[0mresponse\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mmethod\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;31mTypeError\u001b[0m: add_() takes 1 positional argument but 2 were given" + ] + } + ], + "source": [ + "# resnet18 = resnet18.to(device)\n", + "cnn = CNN().to(device)\n", + "optimizer = optim.Adam(cnn.parameters(), lr=args.lr)\n", + "\n", + "# Train Neural network and validate with test set after completion of training every epoch\n", + "for epoch in range(1, args.epochs + 1):\n", + " train(args, cnn, device, federated_train_loader, optimizer, epoch)\n", + " test(args, cnn, device, test_loader)\n", + "\n", + "if (args.save_model):\n", + " torch.save(cnn.state_dict(), \"FashionMNIST_cnn.pt\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## My Notes\n", + "For some reason, when the model is training suddenly stopped at 48%. I don't know if this is a bug or my code has an error. But, so far we already implementing Federated Learning on Fashion MNIST using CNN. For the future, I hope we can doing transfer learning on Federated Learning." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Yasir Abdur Rohman/Project 2/Federated Learning on Fashion MNIST using CNN.html b/Yasir Abdur Rohman/Project 2/Federated Learning on Fashion MNIST using CNN.html new file mode 100644 index 00000000..3710b63f --- /dev/null +++ b/Yasir Abdur Rohman/Project 2/Federated Learning on Fashion MNIST using CNN.html @@ -0,0 +1,13701 @@ + + + + +Federated Learning on Fashion MNIST using CNN + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+

Federated Learning on Fashion MNIST using CNN

Author: Yasir Abdur Rohman

+
+
+
+
+
+
+
+

Introduction

In this project, we will implement federated learning on Fashion MNIST dataset using CNN. Federated Learning is a machine learning setting where the goal is to train a high-quality centralized model with training data distributed over a large number of clients each with unreliable and relatively slow network connections. This project inspired by an example from Pysyft tutorial on Federated CIFAR10.

+

For the better model performance, we will use transfer learning from a pre-trained model.

+

The project consists of the following steps:

+
    +
  1. Import and model Specification
  2. +
  3. Load data
  4. +
  5. Convolutional Neural Network
  6. +
  7. Training
  8. +
+ +
+
+
+
+
+
+

Step 1: Import and model specification

+
+
+
+
+
+
In [1]:
+
+
+
import torch
+import torch.nn as nn
+import torch.nn.functional as F
+import torch.optim as optim
+from torchvision import datasets, models, transforms
+
+# pysyft
+import syft as sy
+
+import numpy as np
+import matplotlib.pyplot as plt
+
+ +
+
+
+ +
+
+ + +
+ +
+ + +
+
WARNING: Logging before flag parsing goes to stderr.
+W0821 06:06:49.046733 22572 secure_random.py:26] Falling back to insecure randomness since the required custom op could not be found for the installed version of TensorFlow. Fix this by compiling custom ops. Missing file was 'D:\Anaconda3\envs\pysyft\lib\site-packages\tf_encrypted/operations/secure_random/secure_random_module_tf_1.14.0.so'
+W0821 06:06:49.058670 22572 deprecation_wrapper.py:119] From D:\Anaconda3\envs\pysyft\lib\site-packages\tf_encrypted\session.py:26: The name tf.Session is deprecated. Please use tf.compat.v1.Session instead.
+
+
+
+
+ +
+
+ +
+
+
+
+

Setting hyperparameters

+
+
+
+
+
+
In [2]:
+
+
+
class Arguments():
+    def __init__(self):
+        self.batch_size = 64
+        self.test_batch_size = 1000
+        self.epochs = 25
+        self.lr = 0.001
+        self.momentum = 0.5
+        self.no_cuda = True
+        self.seed = 1
+        self.log_interval = 30
+        self.save_model = False
+
+args = Arguments()
+
+use_cuda = not args.no_cuda and torch.cuda.is_available()
+
+torch.manual_seed(args.seed)
+
+device = torch.device("cuda" if use_cuda else "cpu")
+
+kwargs = {'num_workers': 1, 'pin_memory': True} if use_cuda else {}
+
+ +
+
+
+ +
+
+
+
+

Initialize workers

+
+
+
+
+
+
In [3]:
+
+
+
hook = sy.TorchHook(torch)
+bob = sy.VirtualWorker(hook, id="bob")
+alice = sy.VirtualWorker(hook, id="alice")
+
+ +
+
+
+ +
+
+
+
+

Step 2: Load Data

+
+
+
+
+
+
In [8]:
+
+
+
def load_data():
+    
+    '''Load Fashion MNIST dataset from torch vision module distribute to workers using PySyft's Federated Data loader'''
+    
+
+    federated_train_loader = sy.FederatedDataLoader(
+        datasets.FashionMNIST('../data', train=True, download=True,
+                       transform=transforms.Compose([
+                           transforms.ToTensor(),
+                           transforms.Normalize((0.5,), (0.5,))
+                       ]))
+        .federate((bob, alice)),
+        batch_size=args.batch_size, shuffle=True, **kwargs)
+
+    test_loader = torch.utils.data.DataLoader(
+        datasets.FashionMNIST('../data', train=False, transform=transforms.Compose([
+                           transforms.ToTensor(),
+                           transforms.Normalize((0.5,), (0.5,))
+                       ])),
+        batch_size=args.test_batch_size, shuffle=True, **kwargs)
+
+    return federated_train_loader,test_loader
+
+ +
+
+
+ +
+
+
+
In [9]:
+
+
+
federated_train_loader, test_loader = load_data()
+
+ +
+
+
+ +
+
+
+
+

Visualize some dataset

+
+
+
+
+
+
In [10]:
+
+
+
# obtain one batch of training images
+dataiter = iter(test_loader)
+images, labels = dataiter.next()
+images = images.numpy() # convert images to numpy for display
+
+plt.imshow(images[1].squeeze(), cmap='Greys_r')
+
+ +
+
+
+ +
+
+ + +
+ +
Out[10]:
+ + + + +
+
<matplotlib.image.AxesImage at 0x1570f4a2588>
+
+ +
+ +
+ +
+ + + + +
+ +
+ +
+ +
+
+ +
+
+
+
+

Step 3: Convolutional Neural Network

Note: Since BatchNorm is still not compatible in Federated Learning as issued in #2132, we cannot using transfer learning from pre-trained model such as Resnet18, VGG16. So for the solution we will make CNN layer manually as follows.

+ +
+
+
+
+
+
In [11]:
+
+
+
# download resnet 18 model
+# resnet18 = models.resnet18(pretrained=True)
+
+# Freeze training for all "features" layers
+# for param in resnet18.parameters():
+#     param.requires_grad = False
+    
+# num_ftrs = resnet18.fc.in_features
+
+# resnet18.fc = nn.Sequential(nn.Linear(num_ftrs, 256),
+#                             nn.Dropout(0.3),
+#                             nn.Linear(256, 128),
+#                             nn.Dropout(0.3),
+#                             nn.Linear(128, 64),
+#                             nn.Dropout(0.3),
+#                             nn.Linear(64, 10),
+#                             nn.LogSoftmax(dim=1))
+# architecture resnet18 modified
+# resnet18
+
+ +
+
+
+ +
+
+
+
In [12]:
+
+
+
class CNN(nn.Module):
+    def __init__(self,num_classes=10):
+        super(CNN, self).__init__()
+        self.conv1 = nn.Conv2d(1, 20, 5, 1)
+        self.conv2 = nn.Conv2d(20, 50, 5, 1)
+        self.fc1 = nn.Linear(4*4*50, 500)
+        self.fc2 = nn.Linear(500, 10)
+        
+    def forward(self, x):
+        x = F.relu(self.conv1(x))
+        x = F.max_pool2d(x, 2, 2)
+        x = F.relu(self.conv2(x))
+        x = F.max_pool2d(x, 2, 2)
+        x = x.view(-1, 4*4*50)
+        x = F.relu(self.fc1(x))
+        x = self.fc2(x)
+        return F.log_softmax(x, dim=1)
+
+ +
+
+
+ +
+
+
+
+

Train Function

+
+
+
+
+
+
In [13]:
+
+
+
def train(args, model, device, train_loader, optimizer, epoch):
+    model.train()
+    for batch_idx, (data, target) in enumerate(federated_train_loader):
+        model.send(data.location)
+        data, target = data.to(device), target.to(device)
+        optimizer.zero_grad()
+        output = model(data)
+        loss = F.nll_loss(output, target)
+        loss.backward()
+        optimizer.step()
+        model.get()
+        if batch_idx % args.log_interval == 0:
+            loss = loss.get()
+            print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
+                epoch, batch_idx * args.batch_size, len(train_loader) * args.batch_size, #batch_idx * len(data), len(train_loader.dataset),
+                100. * batch_idx / len(train_loader), loss.item()))
+
+ +
+
+
+ +
+
+
+
+

Test Function

+
+
+
+
+
+
In [14]:
+
+
+
def test(args, model, device, test_loader):
+    model.eval()
+    test_loss = 0
+    correct = 0
+    with torch.no_grad():
+        for data, target in test_loader:
+            data, target = data.to(device), target.to(device)
+            output = model(data)
+            test_loss += F.nll_loss(output, target, reduction='sum').item() # sum up batch loss
+            pred = output.argmax(1, keepdim=True) # get the index of the max log-probability 
+            correct += pred.eq(target.view_as(pred)).sum().item()
+
+    test_loss /= len(test_loader.dataset)
+
+    print('\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\n'.format(
+        test_loss, correct, len(test_loader.dataset),
+        100. * correct / len(test_loader.dataset)))
+
+ +
+
+
+ +
+
+
+
+

Step 4: Training Neural Network

+
+
+
+
+
+
In [15]:
+
+
+
# resnet18 = resnet18.to(device)
+cnn = CNN().to(device)
+optimizer = optim.Adam(cnn.parameters(), lr=args.lr)
+
+# Train Neural network and validate with test set after completion of training every epoch
+for epoch in range(1, args.epochs + 1):
+    train(args, cnn, device, federated_train_loader, optimizer, epoch)
+    test(args, cnn, device, test_loader)
+
+if (args.save_model):
+    torch.save(cnn.state_dict(), "FashionMNIST_cnn.pt")
+
+ +
+
+
+ +
+
+ + +
+ +
+ + +
+
Train Epoch: 1 [0/60032 (0%)]	Loss: 2.305633
+Train Epoch: 1 [1920/60032 (3%)]	Loss: 0.740293
+Train Epoch: 1 [3840/60032 (6%)]	Loss: 0.725667
+Train Epoch: 1 [5760/60032 (10%)]	Loss: 0.552224
+Train Epoch: 1 [7680/60032 (13%)]	Loss: 0.808906
+Train Epoch: 1 [9600/60032 (16%)]	Loss: 0.540031
+Train Epoch: 1 [11520/60032 (19%)]	Loss: 0.476487
+Train Epoch: 1 [13440/60032 (22%)]	Loss: 0.433211
+Train Epoch: 1 [15360/60032 (26%)]	Loss: 0.367201
+Train Epoch: 1 [17280/60032 (29%)]	Loss: 0.437580
+Train Epoch: 1 [19200/60032 (32%)]	Loss: 0.465955
+Train Epoch: 1 [21120/60032 (35%)]	Loss: 0.478523
+Train Epoch: 1 [23040/60032 (38%)]	Loss: 0.569970
+Train Epoch: 1 [24960/60032 (42%)]	Loss: 0.323152
+Train Epoch: 1 [26880/60032 (45%)]	Loss: 0.535027
+Train Epoch: 1 [28800/60032 (48%)]	Loss: 0.366544
+
+
+
+ +
+ +
+ + +
+
+---------------------------------------------------------------------------
+TypeError                                 Traceback (most recent call last)
+<ipython-input-15-924dd6cf9117> in <module>
+      5 # Train Neural network and validate with test set after completion of training every epoch
+      6 for epoch in range(1, args.epochs + 1):
+----> 7     train(args, cnn, device, federated_train_loader, optimizer, epoch)
+      8     test(args, cnn, device, test_loader)
+      9 
+
+<ipython-input-13-9ae35a15d1b3> in train(args, model, device, train_loader, optimizer, epoch)
+      8         loss = F.nll_loss(output, target)
+      9         loss.backward()
+---> 10         optimizer.step()
+     11         model.get()
+     12         if batch_idx % args.log_interval == 0:
+
+D:\Anaconda3\envs\pysyft\lib\site-packages\torch\optim\adam.py in step(self, closure)
+     91 
+     92                 # Decay the first and second moment running average coefficient
+---> 93                 exp_avg.mul_(beta1).add_(1 - beta1, grad)
+     94                 exp_avg_sq.mul_(beta2).addcmul_(1 - beta2, grad, grad)
+     95                 if amsgrad:
+
+D:\Anaconda3\envs\pysyft\lib\site-packages\syft\frameworks\torch\hook\hook.py in overloaded_native_method(self, *args, **kwargs)
+    675                 # Send the new command to the appropriate class and get the response
+    676                 method = getattr(new_self, method_name)
+--> 677                 response = method(*new_args, **new_kwargs)
+    678 
+    679                 # For inplace methods, just directly return self
+
+D:\Anaconda3\envs\pysyft\lib\site-packages\syft\frameworks\torch\hook\hook.py in overloaded_pointer_method(self, *args, **kwargs)
+    511             command = (attr, self, args, kwargs)
+    512 
+--> 513             response = owner.send_command(location, command)
+    514 
+    515             return response
+
+D:\Anaconda3\envs\pysyft\lib\site-packages\syft\workers\base.py in send_command(self, recipient, message, return_ids)
+    425 
+    426         try:
+--> 427             ret_val = self.send_msg(codes.MSGTYPE.CMD, message, location=recipient)
+    428         except ResponseSignatureError as e:
+    429             ret_val = None
+
+D:\Anaconda3\envs\pysyft\lib\site-packages\syft\workers\base.py in send_msg(self, msg_type, message, location)
+    221 
+    222         # Step 2: send the message and wait for a response
+--> 223         bin_response = self._send_msg(bin_message, location)
+    224 
+    225         # Step 3: deserialize the response
+
+D:\Anaconda3\envs\pysyft\lib\site-packages\syft\workers\virtual.py in _send_msg(self, message, location)
+      8 class VirtualWorker(BaseWorker, FederatedClient):
+      9     def _send_msg(self, message: bin, location: BaseWorker) -> bin:
+---> 10         return location._recv_msg(message)
+     11 
+     12     def _recv_msg(self, message: bin) -> bin:
+
+D:\Anaconda3\envs\pysyft\lib\site-packages\syft\workers\virtual.py in _recv_msg(self, message)
+     11 
+     12     def _recv_msg(self, message: bin) -> bin:
+---> 13         return self.recv_msg(message)
+     14 
+     15     @staticmethod
+
+D:\Anaconda3\envs\pysyft\lib\site-packages\syft\workers\base.py in recv_msg(self, bin_message)
+    252             print(f"worker {self} received {sy.codes.code2MSGTYPE[msg_type]} {contents}")
+    253         # Step 1: route message to appropriate function
+--> 254         response = self._message_router[msg_type](contents)
+    255 
+    256         # Step 2: Serialize the message to simple python objects
+
+D:\Anaconda3\envs\pysyft\lib\site-packages\syft\workers\base.py in execute_command(self, message)
+    359                 _self = self
+    360             if sy.torch.is_inplace_method(command_name):
+--> 361                 getattr(_self, command_name)(*args, **kwargs)
+    362                 return
+    363             else:
+
+D:\Anaconda3\envs\pysyft\lib\site-packages\syft\frameworks\torch\hook\hook.py in overloaded_native_method(self, *args, **kwargs)
+    661                 except BaseException as e:
+    662                     # we can make some errors more descriptive with this method
+--> 663                     raise route_method_exception(e, self, args, kwargs)
+    664 
+    665             else:  # means that there is a wrapper to remove
+
+D:\Anaconda3\envs\pysyft\lib\site-packages\syft\frameworks\torch\hook\hook.py in overloaded_native_method(self, *args, **kwargs)
+    655                 try:
+    656                     if isinstance(args, tuple):
+--> 657                         response = method(*args, **kwargs)
+    658                     else:
+    659                         response = method(args, **kwargs)
+
+TypeError: add_() takes 1 positional argument but 2 were given
+
+
+ +
+
+ +
+
+
+
+

My Notes

For some reason, when the model is training suddenly stopped at 48%. I don't know if this is a bug or my code has an error. But, so far we already implementing Federated Learning on Fashion MNIST using CNN. For the future, I hope we can doing transfer learning on Federated Learning.

+ +
+
+
+
+
+
In [ ]:
+
+
+
 
+
+ +
+
+
+ +
+
+
+ + + + + + diff --git a/Yasir Abdur Rohman/Project 2/Federated Learning on Fashion MNIST using CNN.ipynb b/Yasir Abdur Rohman/Project 2/Federated Learning on Fashion MNIST using CNN.ipynb new file mode 100644 index 00000000..293f173b --- /dev/null +++ b/Yasir Abdur Rohman/Project 2/Federated Learning on Fashion MNIST using CNN.ipynb @@ -0,0 +1,441 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Federated Learning on Fashion MNIST using CNN\n", + "*Author: Yasir Abdur Rohman*\n", + "
" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Introduction\n", + "In this project, we will implement federated learning on Fashion MNIST dataset using CNN. Federated Learning is a machine learning setting where the goal is to train a high-quality centralized model with training data distributed over a large number of clients each with unreliable and relatively slow network connections. This project inspired by an example from Pysyft tutorial on [Federated CIFAR10](https://github.com/OpenMined/PySyft/blob/dev/examples/tutorials/advanced/Federated%20CIFAR10.ipynb).\n", + "\n", + "For the better model performance, we will use transfer learning from a pre-trained model.\n", + "\n", + "The project consists of the following steps:\n", + "1. Import and model Specification\n", + "2. Load data\n", + "3. Convolutional Neural Network\n", + "4. Training" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Step 1: Import and model specification" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING: Logging before flag parsing goes to stderr.\n", + "W0821 06:06:49.046733 22572 secure_random.py:26] Falling back to insecure randomness since the required custom op could not be found for the installed version of TensorFlow. Fix this by compiling custom ops. Missing file was 'D:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\tf_encrypted/operations/secure_random/secure_random_module_tf_1.14.0.so'\n", + "W0821 06:06:49.058670 22572 deprecation_wrapper.py:119] From D:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\tf_encrypted\\session.py:26: The name tf.Session is deprecated. Please use tf.compat.v1.Session instead.\n", + "\n" + ] + } + ], + "source": [ + "import torch\n", + "import torch.nn as nn\n", + "import torch.nn.functional as F\n", + "import torch.optim as optim\n", + "from torchvision import datasets, models, transforms\n", + "\n", + "# pysyft\n", + "import syft as sy\n", + "\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Setting hyperparameters" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "class Arguments():\n", + " def __init__(self):\n", + " self.batch_size = 64\n", + " self.test_batch_size = 1000\n", + " self.epochs = 25\n", + " self.lr = 0.001\n", + " self.momentum = 0.5\n", + " self.no_cuda = True\n", + " self.seed = 1\n", + " self.log_interval = 30\n", + " self.save_model = False\n", + "\n", + "args = Arguments()\n", + "\n", + "use_cuda = not args.no_cuda and torch.cuda.is_available()\n", + "\n", + "torch.manual_seed(args.seed)\n", + "\n", + "device = torch.device(\"cuda\" if use_cuda else \"cpu\")\n", + "\n", + "kwargs = {'num_workers': 1, 'pin_memory': True} if use_cuda else {}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Initialize workers" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "hook = sy.TorchHook(torch)\n", + "bob = sy.VirtualWorker(hook, id=\"bob\")\n", + "alice = sy.VirtualWorker(hook, id=\"alice\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Step 2: Load Data" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "def load_data():\n", + " \n", + " '''Load Fashion MNIST dataset from torch vision module distribute to workers using PySyft's Federated Data loader'''\n", + " \n", + "\n", + " federated_train_loader = sy.FederatedDataLoader(\n", + " datasets.FashionMNIST('../data', train=True, download=True,\n", + " transform=transforms.Compose([\n", + " transforms.ToTensor(),\n", + " transforms.Normalize((0.5,), (0.5,))\n", + " ]))\n", + " .federate((bob, alice)),\n", + " batch_size=args.batch_size, shuffle=True, **kwargs)\n", + "\n", + " test_loader = torch.utils.data.DataLoader(\n", + " datasets.FashionMNIST('../data', train=False, transform=transforms.Compose([\n", + " transforms.ToTensor(),\n", + " transforms.Normalize((0.5,), (0.5,))\n", + " ])),\n", + " batch_size=args.test_batch_size, shuffle=True, **kwargs)\n", + "\n", + " return federated_train_loader,test_loader" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "federated_train_loader, test_loader = load_data()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Visualize some dataset" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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\n", + "text/plain": [ + "
" + ] + }, + "metadata": { + "needs_background": "light" + }, + "output_type": "display_data" + } + ], + "source": [ + "# obtain one batch of training images\n", + "dataiter = iter(test_loader)\n", + "images, labels = dataiter.next()\n", + "images = images.numpy() # convert images to numpy for display\n", + "\n", + "plt.imshow(images[1].squeeze(), cmap='Greys_r')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Step 3: Convolutional Neural Network\n", + "**Note:** Since BatchNorm is still not compatible in Federated Learning as issued in [#2132](https://github.com/OpenMined/PySyft/issues/2132), we cannot using transfer learning from pre-trained model such as Resnet18, VGG16. So for the solution we will make CNN layer manually as follows." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "# download resnet 18 model\n", + "# resnet18 = models.resnet18(pretrained=True)\n", + "\n", + "# Freeze training for all \"features\" layers\n", + "# for param in resnet18.parameters():\n", + "# param.requires_grad = False\n", + " \n", + "# num_ftrs = resnet18.fc.in_features\n", + "\n", + "# resnet18.fc = nn.Sequential(nn.Linear(num_ftrs, 256),\n", + "# nn.Dropout(0.3),\n", + "# nn.Linear(256, 128),\n", + "# nn.Dropout(0.3),\n", + "# nn.Linear(128, 64),\n", + "# nn.Dropout(0.3),\n", + "# nn.Linear(64, 10),\n", + "# nn.LogSoftmax(dim=1))\n", + "# architecture resnet18 modified\n", + "# resnet18" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "class CNN(nn.Module):\n", + " def __init__(self,num_classes=10):\n", + " super(CNN, self).__init__()\n", + " self.conv1 = nn.Conv2d(1, 20, 5, 1)\n", + " self.conv2 = nn.Conv2d(20, 50, 5, 1)\n", + " self.fc1 = nn.Linear(4*4*50, 500)\n", + " self.fc2 = nn.Linear(500, 10)\n", + " \n", + " def forward(self, x):\n", + " x = F.relu(self.conv1(x))\n", + " x = F.max_pool2d(x, 2, 2)\n", + " x = F.relu(self.conv2(x))\n", + " x = F.max_pool2d(x, 2, 2)\n", + " x = x.view(-1, 4*4*50)\n", + " x = F.relu(self.fc1(x))\n", + " x = self.fc2(x)\n", + " return F.log_softmax(x, dim=1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Train Function" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "def train(args, model, device, train_loader, optimizer, epoch):\n", + " model.train()\n", + " for batch_idx, (data, target) in enumerate(federated_train_loader):\n", + " model.send(data.location)\n", + " data, target = data.to(device), target.to(device)\n", + " optimizer.zero_grad()\n", + " output = model(data)\n", + " loss = F.nll_loss(output, target)\n", + " loss.backward()\n", + " optimizer.step()\n", + " model.get()\n", + " if batch_idx % args.log_interval == 0:\n", + " loss = loss.get()\n", + " print('Train Epoch: {} [{}/{} ({:.0f}%)]\\tLoss: {:.6f}'.format(\n", + " epoch, batch_idx * args.batch_size, len(train_loader) * args.batch_size, #batch_idx * len(data), len(train_loader.dataset),\n", + " 100. * batch_idx / len(train_loader), loss.item()))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Test Function" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "def test(args, model, device, test_loader):\n", + " model.eval()\n", + " test_loss = 0\n", + " correct = 0\n", + " with torch.no_grad():\n", + " for data, target in test_loader:\n", + " data, target = data.to(device), target.to(device)\n", + " output = model(data)\n", + " test_loss += F.nll_loss(output, target, reduction='sum').item() # sum up batch loss\n", + " pred = output.argmax(1, keepdim=True) # get the index of the max log-probability \n", + " correct += pred.eq(target.view_as(pred)).sum().item()\n", + "\n", + " test_loss /= len(test_loader.dataset)\n", + "\n", + " print('\\nTest set: Average loss: {:.4f}, Accuracy: {}/{} ({:.0f}%)\\n'.format(\n", + " test_loss, correct, len(test_loader.dataset),\n", + " 100. * correct / len(test_loader.dataset)))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Step 4: Training Neural Network" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Train Epoch: 1 [0/60032 (0%)]\tLoss: 2.305633\n", + "Train Epoch: 1 [1920/60032 (3%)]\tLoss: 0.740293\n", + "Train Epoch: 1 [3840/60032 (6%)]\tLoss: 0.725667\n", + "Train Epoch: 1 [5760/60032 (10%)]\tLoss: 0.552224\n", + "Train Epoch: 1 [7680/60032 (13%)]\tLoss: 0.808906\n", + "Train Epoch: 1 [9600/60032 (16%)]\tLoss: 0.540031\n", + "Train Epoch: 1 [11520/60032 (19%)]\tLoss: 0.476487\n", + "Train Epoch: 1 [13440/60032 (22%)]\tLoss: 0.433211\n", + "Train Epoch: 1 [15360/60032 (26%)]\tLoss: 0.367201\n", + "Train Epoch: 1 [17280/60032 (29%)]\tLoss: 0.437580\n", + "Train Epoch: 1 [19200/60032 (32%)]\tLoss: 0.465955\n", + "Train Epoch: 1 [21120/60032 (35%)]\tLoss: 0.478523\n", + "Train Epoch: 1 [23040/60032 (38%)]\tLoss: 0.569970\n", + "Train Epoch: 1 [24960/60032 (42%)]\tLoss: 0.323152\n", + "Train Epoch: 1 [26880/60032 (45%)]\tLoss: 0.535027\n", + "Train Epoch: 1 [28800/60032 (48%)]\tLoss: 0.366544\n" + ] + }, + { + "ename": "TypeError", + "evalue": "add_() takes 1 positional argument but 2 were given", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mTypeError\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 5\u001b[0m \u001b[1;31m# Train Neural network and validate with test set after completion of training every epoch\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 6\u001b[0m \u001b[1;32mfor\u001b[0m \u001b[0mepoch\u001b[0m \u001b[1;32min\u001b[0m \u001b[0mrange\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0margs\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mepochs\u001b[0m \u001b[1;33m+\u001b[0m \u001b[1;36m1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 7\u001b[1;33m \u001b[0mtrain\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcnn\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdevice\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mfederated_train_loader\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0moptimizer\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mepoch\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 8\u001b[0m \u001b[0mtest\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcnn\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdevice\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtest_loader\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 9\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32m\u001b[0m in \u001b[0;36mtrain\u001b[1;34m(args, model, device, train_loader, optimizer, epoch)\u001b[0m\n\u001b[0;32m 8\u001b[0m \u001b[0mloss\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mF\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mnll_loss\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0moutput\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtarget\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 9\u001b[0m \u001b[0mloss\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mbackward\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 10\u001b[1;33m \u001b[0moptimizer\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstep\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 11\u001b[0m \u001b[0mmodel\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mget\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 12\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mbatch_idx\u001b[0m \u001b[1;33m%\u001b[0m \u001b[0margs\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mlog_interval\u001b[0m \u001b[1;33m==\u001b[0m \u001b[1;36m0\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\torch\\optim\\adam.py\u001b[0m in \u001b[0;36mstep\u001b[1;34m(self, closure)\u001b[0m\n\u001b[0;32m 91\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 92\u001b[0m \u001b[1;31m# Decay the first and second moment running average coefficient\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 93\u001b[1;33m \u001b[0mexp_avg\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmul_\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mbeta1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0madd_\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m \u001b[1;33m-\u001b[0m \u001b[0mbeta1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mgrad\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 94\u001b[0m \u001b[0mexp_avg_sq\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mmul_\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mbeta2\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0maddcmul_\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;36m1\u001b[0m \u001b[1;33m-\u001b[0m \u001b[0mbeta2\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mgrad\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mgrad\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 95\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0mamsgrad\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\syft\\frameworks\\torch\\hook\\hook.py\u001b[0m in \u001b[0;36moverloaded_native_method\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 675\u001b[0m \u001b[1;31m# Send the new command to the appropriate class and get the response\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 676\u001b[0m \u001b[0mmethod\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mgetattr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mnew_self\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmethod_name\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 677\u001b[1;33m \u001b[0mresponse\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mmethod\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0mnew_args\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mnew_kwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 678\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 679\u001b[0m \u001b[1;31m# For inplace methods, just directly return self\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\syft\\frameworks\\torch\\hook\\hook.py\u001b[0m in \u001b[0;36moverloaded_pointer_method\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 511\u001b[0m \u001b[0mcommand\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;33m(\u001b[0m\u001b[0mattr\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 512\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 513\u001b[1;33m \u001b[0mresponse\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mowner\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msend_command\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mlocation\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcommand\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 514\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 515\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mresponse\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\syft\\workers\\base.py\u001b[0m in \u001b[0;36msend_command\u001b[1;34m(self, recipient, message, return_ids)\u001b[0m\n\u001b[0;32m 425\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 426\u001b[0m \u001b[1;32mtry\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 427\u001b[1;33m \u001b[0mret_val\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0msend_msg\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcodes\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mMSGTYPE\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mCMD\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmessage\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mlocation\u001b[0m\u001b[1;33m=\u001b[0m\u001b[0mrecipient\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 428\u001b[0m \u001b[1;32mexcept\u001b[0m \u001b[0mResponseSignatureError\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 429\u001b[0m \u001b[0mret_val\u001b[0m \u001b[1;33m=\u001b[0m \u001b[1;32mNone\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\syft\\workers\\base.py\u001b[0m in \u001b[0;36msend_msg\u001b[1;34m(self, msg_type, message, location)\u001b[0m\n\u001b[0;32m 221\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 222\u001b[0m \u001b[1;31m# Step 2: send the message and wait for a response\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 223\u001b[1;33m \u001b[0mbin_response\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_send_msg\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mbin_message\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mlocation\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 224\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 225\u001b[0m \u001b[1;31m# Step 3: deserialize the response\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\syft\\workers\\virtual.py\u001b[0m in \u001b[0;36m_send_msg\u001b[1;34m(self, message, location)\u001b[0m\n\u001b[0;32m 8\u001b[0m \u001b[1;32mclass\u001b[0m \u001b[0mVirtualWorker\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mBaseWorker\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mFederatedClient\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 9\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0m_send_msg\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmessage\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mbin\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mlocation\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mBaseWorker\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m->\u001b[0m \u001b[0mbin\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 10\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mlocation\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_recv_msg\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmessage\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 11\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 12\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0m_recv_msg\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmessage\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mbin\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m->\u001b[0m \u001b[0mbin\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\syft\\workers\\virtual.py\u001b[0m in \u001b[0;36m_recv_msg\u001b[1;34m(self, message)\u001b[0m\n\u001b[0;32m 11\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 12\u001b[0m \u001b[1;32mdef\u001b[0m \u001b[0m_recv_msg\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mmessage\u001b[0m\u001b[1;33m:\u001b[0m \u001b[0mbin\u001b[0m\u001b[1;33m)\u001b[0m \u001b[1;33m->\u001b[0m \u001b[0mbin\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 13\u001b[1;33m \u001b[1;32mreturn\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mrecv_msg\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mmessage\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 14\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 15\u001b[0m \u001b[1;33m@\u001b[0m\u001b[0mstaticmethod\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\syft\\workers\\base.py\u001b[0m in \u001b[0;36mrecv_msg\u001b[1;34m(self, bin_message)\u001b[0m\n\u001b[0;32m 252\u001b[0m \u001b[0mprint\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;34mf\"worker {self} received {sy.codes.code2MSGTYPE[msg_type]} {contents}\"\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 253\u001b[0m \u001b[1;31m# Step 1: route message to appropriate function\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 254\u001b[1;33m \u001b[0mresponse\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0m_message_router\u001b[0m\u001b[1;33m[\u001b[0m\u001b[0mmsg_type\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcontents\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 255\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 256\u001b[0m \u001b[1;31m# Step 2: Serialize the message to simple python objects\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\syft\\workers\\base.py\u001b[0m in \u001b[0;36mexecute_command\u001b[1;34m(self, message)\u001b[0m\n\u001b[0;32m 359\u001b[0m \u001b[0m_self\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 360\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0msy\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mtorch\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mis_inplace_method\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mcommand_name\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 361\u001b[1;33m \u001b[0mgetattr\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0m_self\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mcommand_name\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 362\u001b[0m \u001b[1;32mreturn\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 363\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\syft\\frameworks\\torch\\hook\\hook.py\u001b[0m in \u001b[0;36moverloaded_native_method\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 661\u001b[0m \u001b[1;32mexcept\u001b[0m \u001b[0mBaseException\u001b[0m \u001b[1;32mas\u001b[0m \u001b[0me\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 662\u001b[0m \u001b[1;31m# we can make some errors more descriptive with this method\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 663\u001b[1;33m \u001b[1;32mraise\u001b[0m \u001b[0mroute_method_exception\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0me\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mself\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 664\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 665\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m \u001b[1;31m# means that there is a wrapper to remove\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\syft\\frameworks\\torch\\hook\\hook.py\u001b[0m in \u001b[0;36moverloaded_native_method\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 655\u001b[0m \u001b[1;32mtry\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 656\u001b[0m \u001b[1;32mif\u001b[0m \u001b[0misinstance\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mtuple\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 657\u001b[1;33m \u001b[0mresponse\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mmethod\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m*\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 658\u001b[0m \u001b[1;32melse\u001b[0m\u001b[1;33m:\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 659\u001b[0m \u001b[0mresponse\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mmethod\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0margs\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;33m**\u001b[0m\u001b[0mkwargs\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;31mTypeError\u001b[0m: add_() takes 1 positional argument but 2 were given" + ] + } + ], + "source": [ + "# resnet18 = resnet18.to(device)\n", + "cnn = CNN().to(device)\n", + "optimizer = optim.Adam(cnn.parameters(), lr=args.lr)\n", + "\n", + "# Train Neural network and validate with test set after completion of training every epoch\n", + "for epoch in range(1, args.epochs + 1):\n", + " train(args, cnn, device, federated_train_loader, optimizer, epoch)\n", + " test(args, cnn, device, test_loader)\n", + "\n", + "if (args.save_model):\n", + " torch.save(cnn.state_dict(), \"FashionMNIST_cnn.pt\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## My Notes\n", + "For some reason, when the model is training suddenly stopped at 48%. I don't know if this is a bug or my code has an error. But, so far we already implementing Federated Learning on Fashion MNIST using CNN. For the future, I hope we can doing transfer learning on Federated Learning." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Yasir Abdur Rohman/Project 2/README.md b/Yasir Abdur Rohman/Project 2/README.md new file mode 100644 index 00000000..9217115c --- /dev/null +++ b/Yasir Abdur Rohman/Project 2/README.md @@ -0,0 +1,45 @@ +# Federated Learning on Fashion MNIST using CNN +Implement federated learning on Fashion MNIST dataset. + +# Step-by-step +## Step 1: Import and model specification +- Initialize CNN hyperparameters such as learning rate, batch size, numpy seed. +- Create 2 workers Alice and Bob + +## Step 2: Load data +- Load Fashion MNIST dataset using torchvision.datasets. +![FashionMNIST](https://github.com/yasirabd/SPAI/blob/master/Project%202/assets/fashion-mnist.png "FashionMNIST") +- Create federated_train_loader using FederatedDataLoader. Don't forget to transform dataset! +- Create test_loader using torch.utils.DataLoader. Don't forget to transform dataset! +- Visualize one data + +![Shoes](https://github.com/yasirabd/SPAI/blob/master/Project%202/assets/shoes.png "Shoes") + +## Step 3: Convolutional Neural Network +- Create architecture Class CNN. +```python +class CNN(nn.Module): + def __init__(self,num_classes=10): + super(CNN, self).__init__() + self.conv1 = nn.Conv2d(1, 20, 5, 1) + self.conv2 = nn.Conv2d(20, 50, 5, 1) + self.fc1 = nn.Linear(4*4*50, 500) + self.fc2 = nn.Linear(500, 10) + + def forward(self, x): + x = F.relu(self.conv1(x)) + x = F.max_pool2d(x, 2, 2) + x = F.relu(self.conv2(x)) + x = F.max_pool2d(x, 2, 2) + x = x.view(-1, 4*4*50) + x = F.relu(self.fc1(x)) + x = self.fc2(x) + return F.log_softmax(x, dim=1) +``` + +## Step 4: Training +- Train Neural network and validate with test set after completion of training every epoch + +## My Notes +- BatchNorm is still not compatible on Federated Learning. So, it is still imposible using pre-trained model such as resnet, VGG, etc. +- For some reason, the training suddenly stopped at 48%. I don't know if this is a bug or my code has an error. But, so far we already implementing Federated Learning on Fashion MNIST using CNN. diff --git a/Yasir Abdur Rohman/Project 2/assets/fashion-mnist.png b/Yasir Abdur Rohman/Project 2/assets/fashion-mnist.png new file mode 100644 index 00000000..1ecde6f1 Binary files /dev/null and b/Yasir Abdur Rohman/Project 2/assets/fashion-mnist.png differ diff --git a/Yasir Abdur Rohman/Project 2/assets/shoes.png b/Yasir Abdur Rohman/Project 2/assets/shoes.png new file mode 100644 index 00000000..93d760c5 Binary files /dev/null and b/Yasir Abdur Rohman/Project 2/assets/shoes.png differ diff --git a/Yasir Abdur Rohman/Project 3/.ipynb_checkpoints/Machine Translation with a Sequence to Sequence Network and Attention (English - Indonesian)-checkpoint.ipynb b/Yasir Abdur Rohman/Project 3/.ipynb_checkpoints/Machine Translation with a Sequence to Sequence Network and Attention (English - Indonesian)-checkpoint.ipynb new file mode 100644 index 00000000..6b3f9039 --- /dev/null +++ b/Yasir Abdur Rohman/Project 3/.ipynb_checkpoints/Machine Translation with a Sequence to Sequence Network and Attention (English - Indonesian)-checkpoint.ipynb @@ -0,0 +1,804 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Machine Translation with a Sequence to Sequence Network and Attention (English - Indonesian)\n", + "
\n", + "\n", + "- *Author: Yasir Abdur Rohman*\n", + "- *Slack Name: Yasir Abdur Rohman*\n", + "\n", + "
\n", + "\n", + "In this project we will implement a neural network to translate from English to Indonesian in a federated way.\n", + "\n", + "We will train two models residing on two remote workers based on **Tatoeba dataset**. You can download the dataset from [Opus Corpus](http://opus.nlpl.eu/).\n", + "\n", + "This idea inspired by [tutorial seq2seq translation](https://pytorch.org/tutorials/intermediate/seq2seq_translation_tutorial.html). The idea of [sequence to sequence network](https://arxiv.org/abs/1409.3215) is having two Recurrent Neural Network works together to transform one sequence to another. An encoder network condenses an input sequence into a vector, and a decoder network unfolds that vector into a new sequence.\n", + "\n", + "To improve the model, we will use an [attention mechanism](https://arxiv.org/abs/1409.0473), which lets the decoder learn to focus over a specific range of the input sequence." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 1. Step: Requirements" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING: Logging before flag parsing goes to stderr.\n", + "W0821 07:08:45.595940 21596 secure_random.py:26] Falling back to insecure randomness since the required custom op could not be found for the installed version of TensorFlow. Fix this by compiling custom ops. Missing file was 'D:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\tf_encrypted/operations/secure_random/secure_random_module_tf_1.14.0.so'\n", + "W0821 07:08:45.699662 21596 deprecation_wrapper.py:119] From D:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\tf_encrypted\\session.py:26: The name tf.Session is deprecated. Please use tf.compat.v1.Session instead.\n", + "\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cuda\n" + ] + } + ], + "source": [ + "from __future__ import unicode_literals, print_function, division\n", + "from io import open\n", + "import unicodedata\n", + "import string\n", + "import re\n", + "import random\n", + "import glob\n", + "import os\n", + "import numpy as np\n", + "import time\n", + "import math\n", + "import pandas as pd\n", + "\n", + "import torch\n", + "import torch.nn as nn\n", + "from torch import optim\n", + "import torch.nn.functional as F\n", + "from torch.utils.data import Dataset\n", + "\n", + "import syft as sy\n", + "from syft.frameworks.torch.federated import utils\n", + "from syft.workers import WebsocketClientWorker\n", + "\n", + "import matplotlib.pyplot as plt\n", + "import matplotlib.ticker as ticker\n", + "\n", + "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n", + "print(device)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 2. Step: Loading Data Files\n", + "We will representing each word in a language as one-hot vector. We also need a unique index per word to use as the inputs and targets of the network. To keep track of all this we will use a helper class called Lang which has word → index (word2index) and index → word (index2word) dictionaries, as well as a count of each word word2count to use to later replace rare words." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "SOS_token = 0\n", + "EOS_token = 1\n", + "\n", + "\n", + "class Lang:\n", + " def __init__(self, name):\n", + " self.name = name\n", + " self.word2index = {}\n", + " self.word2count = {}\n", + " self.index2word = {0: \"SOS\", 1: \"EOS\"}\n", + " self.n_words = 2 # Count SOS and EOS\n", + "\n", + " def addSentence(self, sentence):\n", + " for word in sentence.split(' '):\n", + " self.addWord(word)\n", + "\n", + " def addWord(self, word):\n", + " if word not in self.word2index:\n", + " self.word2index[word] = self.n_words\n", + " self.word2count[word] = 1\n", + " self.index2word[self.n_words] = word\n", + " self.n_words += 1\n", + " else:\n", + " self.word2count[word] += 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Preprocessing:\n", + "- convert unicode characters to ascii\n", + "- lowercase\n", + "- trim punctuation" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# Turn a Unicode string to plain ASCII, thanks to\n", + "# https://stackoverflow.com/a/518232/2809427\n", + "def unicodeToAscii(s):\n", + " return ''.join(\n", + " c for c in unicodedata.normalize('NFD', s)\n", + " if unicodedata.category(c) != 'Mn'\n", + " )\n", + "\n", + "# Lowercase, trim, and remove non-letter characters\n", + "\n", + "\n", + "def normalizeString(s):\n", + " s = unicodeToAscii(s.lower().strip())\n", + " s = re.sub(r\"([.!?])\", r\" \\1\", s)\n", + " s = re.sub(r\"[^a-zA-Z.!?]+\", r\" \", s)\n", + " return s" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "we will split the file into lines, and then split lines into pairs. The files are all English → Other Language, so if we want to translate from Other Language → English I added the reverse flag to reverse the pairs." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "def readLangs(lang1, lang2, reverse=False):\n", + " print(\"Reading lines...\")\n", + "\n", + " # Read the file and split into lines\n", + " lines = open('data/%s-%s.txt' % (lang1, lang2), encoding='utf-8').\\\n", + " read().strip().split('\\n')\n", + "\n", + " # Split every line into pairs and normalize\n", + " pairs = [[normalizeString(s) for s in l.split('\\t')] for l in lines]\n", + "\n", + " # Reverse pairs, make Lang instances\n", + " if reverse:\n", + " pairs = [list(reversed(p)) for p in pairs]\n", + " input_lang = Lang(lang2)\n", + " output_lang = Lang(lang1)\n", + " else:\n", + " input_lang = Lang(lang1)\n", + " output_lang = Lang(lang2)\n", + "\n", + " return input_lang, output_lang, pairs" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "MAX_LENGTH = 10\n", + "\n", + "eng_prefixes = (\n", + " \"i am \", \"i m \",\n", + " \"he is\", \"he s \",\n", + " \"she is\", \"she s \",\n", + " \"you are\", \"you re \",\n", + " \"we are\", \"we re \",\n", + " \"they are\", \"they re \"\n", + ")\n", + "\n", + "\n", + "def filterPair(p):\n", + " return len(p[0].split(' ')) < MAX_LENGTH and \\\n", + " len(p[1].split(' ')) < MAX_LENGTH and \\\n", + " p[1].startswith(eng_prefixes)\n", + "\n", + "\n", + "def filterPairs(pairs):\n", + " return [pair for pair in pairs if filterPair(pair)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The full process for preparing the data is:\n", + "\n", + "- Read text file and split into lines, split lines into pairs\n", + "- Normalize text, filter by length and content\n", + "- Make word lists from sentences in pairs" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "def prepareData(lang1, lang2, reverse=False):\n", + " input_lang, output_lang, pairs = readLangs(lang1, lang2, reverse)\n", + " print(\"Read %s sentence pairs\" % len(pairs))\n", + " pairs = filterPairs(pairs)\n", + " print(\"Trimmed to %s sentence pairs\" % len(pairs))\n", + " print(\"Counting words...\")\n", + " for pair in pairs:\n", + " input_lang.addSentence(pair[0])\n", + " output_lang.addSentence(pair[1])\n", + " print(\"Counted words:\")\n", + " print(input_lang.name, input_lang.n_words)\n", + " print(output_lang.name, output_lang.n_words)\n", + " return input_lang, output_lang, pairs" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Reading lines...\n", + "Read 7124 sentence pairs\n", + "Trimmed to 474 sentence pairs\n", + "Counting words...\n", + "Counted words:\n", + "ind 554\n", + "eng 517\n", + "['kau agresif .', 'you re aggressive .']\n" + ] + } + ], + "source": [ + "input_lang, output_lang, pairs = prepareData('eng', 'ind', True)\n", + "print(random.choice(pairs))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# The Seq2Seq Model\n", + "It consisting two RNN such as encoder and decoder network. The encoder reads an input sequence and outputs a single vector, and the decoder reads that vector to produce an output sequence. With a seq2seq model the encoder creates a single vector which, in the ideal case, encodes the “meaning” of the input sequence into a single vector — a single point in some N dimensional space of sentences" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## The Encoder\n", + "The encoder of a seq2seq network is a RNN that outputs some value for every word from the input sentence. For every input word the encoder outputs a vector and a hidden state, and uses the hidden state for the next input word" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "class EncoderRNN(nn.Module):\n", + " def __init__(self, input_size, hidden_size):\n", + " super(EncoderRNN, self).__init__()\n", + " self.hidden_size = hidden_size\n", + "\n", + " self.embedding = nn.Embedding(input_size, hidden_size)\n", + " self.gru = nn.GRU(hidden_size, hidden_size)\n", + "\n", + " def forward(self, input, hidden):\n", + " embedded = self.embedding(input).view(1, 1, -1)\n", + " output = embedded\n", + " output, hidden = self.gru(output, hidden)\n", + " return output, hidden\n", + "\n", + " def initHidden(self):\n", + " return torch.zeros(1, 1, self.hidden_size, device=device)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## The Decoder\n", + "The decoder is another RNN that takes the encoder output vector(s) and outputs a sequence of words to create the translation" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "class DecoderRNN(nn.Module):\n", + " def __init__(self, hidden_size, output_size):\n", + " super(DecoderRNN, self).__init__()\n", + " self.hidden_size = hidden_size\n", + "\n", + " self.embedding = nn.Embedding(output_size, hidden_size)\n", + " self.gru = nn.GRU(hidden_size, hidden_size)\n", + " self.out = nn.Linear(hidden_size, output_size)\n", + " self.softmax = nn.LogSoftmax(dim=1)\n", + "\n", + " def forward(self, input, hidden):\n", + " output = self.embedding(input).view(1, 1, -1)\n", + " output = F.relu(output)\n", + " output, hidden = self.gru(output, hidden)\n", + " output = self.softmax(self.out(output[0]))\n", + " return output, hidden\n", + "\n", + " def initHidden(self):\n", + " return torch.zeros(1, 1, self.hidden_size, device=device)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The Attention Decoder\n", + "Attention allows the decoder network to “focus” on a different part of the encoder’s outputs for every step of the decoder’s own outputs. First we calculate a set of attention weights. These will be multiplied by the encoder output vectors to create a weighted combination. The result (called attn_applied in the code) should contain information about that specific part of the input sequence, and thus help the decoder choose the right output words.\n", + "\n", + "Calculating the attention weights is done with another feed-forward layer attn, using the decoder’s input and hidden state as inputs. Because there are sentences of all sizes in the training data, to actually create and train this layer we have to choose a maximum sentence length (input length, for encoder outputs) that it can apply to. Sentences of the maximum length will use all the attention weights, while shorter sentences will only use the first few." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "class AttnDecoderRNN(nn.Module):\n", + " def __init__(self, hidden_size, output_size, dropout_p=0.1, max_length=MAX_LENGTH):\n", + " super(AttnDecoderRNN, self).__init__()\n", + " self.hidden_size = hidden_size\n", + " self.output_size = output_size\n", + " self.dropout_p = dropout_p\n", + " self.max_length = max_length\n", + "\n", + " self.embedding = nn.Embedding(self.output_size, self.hidden_size)\n", + " self.attn = nn.Linear(self.hidden_size * 2, self.max_length)\n", + " self.attn_combine = nn.Linear(self.hidden_size * 2, self.hidden_size)\n", + " self.dropout = nn.Dropout(self.dropout_p)\n", + " self.gru = nn.GRU(self.hidden_size, self.hidden_size)\n", + " self.out = nn.Linear(self.hidden_size, self.output_size)\n", + "\n", + " def forward(self, input, hidden, encoder_outputs):\n", + " embedded = self.embedding(input).view(1, 1, -1)\n", + " embedded = self.dropout(embedded)\n", + "\n", + " attn_weights = F.softmax(\n", + " self.attn(torch.cat((embedded[0], hidden[0]), 1)), dim=1)\n", + " attn_applied = torch.bmm(attn_weights.unsqueeze(0),\n", + " encoder_outputs.unsqueeze(0))\n", + "\n", + " output = torch.cat((embedded[0], attn_applied[0]), 1)\n", + " output = self.attn_combine(output).unsqueeze(0)\n", + "\n", + " output = F.relu(output)\n", + " output, hidden = self.gru(output, hidden)\n", + "\n", + " output = F.log_softmax(self.out(output[0]), dim=1)\n", + " return output, hidden, attn_weights\n", + "\n", + " def initHidden(self):\n", + " return torch.zeros(1, 1, self.hidden_size, device=device)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Training" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Preparing Training Data\n", + "To train, for each pair we will need an input tensor (indexes of the words in the input sentence) and target tensor (indexes of the words in the target sentence). While creating these vectors we will append the EOS token to both sequences." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "def indexesFromSentence(lang, sentence):\n", + " return [lang.word2index[word] for word in sentence.split(' ')]\n", + "\n", + "\n", + "def tensorFromSentence(lang, sentence):\n", + " indexes = indexesFromSentence(lang, sentence)\n", + " indexes.append(EOS_token)\n", + " return torch.tensor(indexes, dtype=torch.long, device=device).view(-1, 1)\n", + "\n", + "\n", + "def tensorsFromPair(pair):\n", + " input_tensor = tensorFromSentence(input_lang, pair[0])\n", + " target_tensor = tensorFromSentence(output_lang, pair[1])\n", + " return (input_tensor, target_tensor)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Training The Model\n", + "To train we run the input sentence through the encoder, and keep track of every output and the latest hidden state. Then the decoder is given the token as its first input, and the last hidden state of the encoder as its first hidden state.\n", + " \n", + "Because of the freedom PyTorch’s autograd gives us, we can randomly choose to use teacher forcing or not with a simple if statement. Turn teacher_forcing_ratio up to use more of it." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "teacher_forcing_ratio = 0.5\n", + "\n", + "\n", + "def train(input_tensor, target_tensor, encoder, decoder, encoder_optimizer, decoder_optimizer, criterion, max_length=MAX_LENGTH):\n", + " encoder_hidden = encoder.initHidden()\n", + "\n", + " encoder_optimizer.zero_grad()\n", + " decoder_optimizer.zero_grad()\n", + "\n", + " input_length = input_tensor.size(0)\n", + " target_length = target_tensor.size(0)\n", + "\n", + " encoder_outputs = torch.zeros(max_length, encoder.hidden_size, device=device)\n", + "\n", + " loss = 0\n", + "\n", + " for ei in range(input_length):\n", + " encoder_output, encoder_hidden = encoder(\n", + " input_tensor[ei], encoder_hidden)\n", + " encoder_outputs[ei] = encoder_output[0, 0]\n", + "\n", + " decoder_input = torch.tensor([[SOS_token]], device=device)\n", + "\n", + " decoder_hidden = encoder_hidden\n", + "\n", + " use_teacher_forcing = True if random.random() < teacher_forcing_ratio else False\n", + "\n", + " if use_teacher_forcing:\n", + " # Teacher forcing: Feed the target as the next input\n", + " for di in range(target_length):\n", + " decoder_output, decoder_hidden, decoder_attention = decoder(\n", + " decoder_input, decoder_hidden, encoder_outputs)\n", + " loss += criterion(decoder_output, target_tensor[di])\n", + " decoder_input = target_tensor[di] # Teacher forcing\n", + "\n", + " else:\n", + " # Without teacher forcing: use its own predictions as the next input\n", + " for di in range(target_length):\n", + " decoder_output, decoder_hidden, decoder_attention = decoder(\n", + " decoder_input, decoder_hidden, encoder_outputs)\n", + " topv, topi = decoder_output.topk(1)\n", + " decoder_input = topi.squeeze().detach() # detach from history as input\n", + "\n", + " loss += criterion(decoder_output, target_tensor[di])\n", + " if decoder_input.item() == EOS_token:\n", + " break\n", + "\n", + " loss.backward()\n", + "\n", + " encoder_optimizer.step()\n", + " decoder_optimizer.step()\n", + "\n", + " return loss.item() / target_length" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Helper Function" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "import math\n", + "\n", + "\n", + "def asMinutes(s):\n", + " m = math.floor(s / 60)\n", + " s -= m * 60\n", + " return '%dm %ds' % (m, s)\n", + "\n", + "\n", + "def timeSince(since, percent):\n", + " now = time.time()\n", + " s = now - since\n", + " es = s / (percent)\n", + " rs = es - s\n", + " return '%s (- %s)' % (asMinutes(s), asMinutes(rs))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The whole training process looks like this:\n", + "\n", + "- Start a timer\n", + "- Initialize optimizers and criterion\n", + "- Create set of training pairs\n", + "- Start empty losses array for plotting" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "def trainIters(encoder, decoder, n_iters, print_every=1000, plot_every=100, learning_rate=0.01):\n", + " start = time.time()\n", + " plot_losses = []\n", + " print_loss_total = 0 # Reset every print_every\n", + " plot_loss_total = 0 # Reset every plot_every\n", + "\n", + " encoder_optimizer = optim.SGD(encoder.parameters(), lr=learning_rate)\n", + " decoder_optimizer = optim.SGD(decoder.parameters(), lr=learning_rate)\n", + " training_pairs = [tensorsFromPair(random.choice(pairs))\n", + " for i in range(n_iters)]\n", + " criterion = nn.NLLLoss()\n", + "\n", + " for iter in range(1, n_iters + 1):\n", + " training_pair = training_pairs[iter - 1]\n", + " input_tensor = training_pair[0]\n", + " target_tensor = training_pair[1]\n", + "\n", + " loss = train(input_tensor, target_tensor, encoder,\n", + " decoder, encoder_optimizer, decoder_optimizer, criterion)\n", + " print_loss_total += loss\n", + " plot_loss_total += loss\n", + "\n", + " if iter % print_every == 0:\n", + " print_loss_avg = print_loss_total / print_every\n", + " print_loss_total = 0\n", + " print('%s (%d %d%%) %.4f' % (timeSince(start, iter / n_iters),\n", + " iter, iter / n_iters * 100, print_loss_avg))\n", + "\n", + " if iter % plot_every == 0:\n", + " plot_loss_avg = plot_loss_total / plot_every\n", + " plot_losses.append(plot_loss_avg)\n", + " plot_loss_total = 0\n", + "\n", + " showPlot(plot_losses)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plotting Result" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "def showPlot(points):\n", + " plt.figure()\n", + " fig, ax = plt.subplots()\n", + " # this locator puts ticks at regular intervals\n", + " loc = ticker.MultipleLocator(base=0.2)\n", + " ax.yaxis.set_major_locator(loc)\n", + " plt.plot(points)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Evaluation\n", + "Evaluation is mostly the same as training, but there are no targets so we simply feed the decoder’s predictions back to itself for each step. Every time it predicts a word we add it to the output string, and if it predicts the EOS token we stop there. We also store the decoder’s attention outputs for display later." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "def evaluate(encoder, decoder, sentence, max_length=MAX_LENGTH):\n", + " with torch.no_grad():\n", + " input_tensor = tensorFromSentence(input_lang, sentence)\n", + " input_length = input_tensor.size()[0]\n", + " encoder_hidden = encoder.initHidden()\n", + "\n", + " encoder_outputs = torch.zeros(max_length, encoder.hidden_size, device=device)\n", + "\n", + " for ei in range(input_length):\n", + " encoder_output, encoder_hidden = encoder(input_tensor[ei],\n", + " encoder_hidden)\n", + " encoder_outputs[ei] += encoder_output[0, 0]\n", + "\n", + " decoder_input = torch.tensor([[SOS_token]], device=device) # SOS\n", + "\n", + " decoder_hidden = encoder_hidden\n", + "\n", + " decoded_words = []\n", + " decoder_attentions = torch.zeros(max_length, max_length)\n", + "\n", + " for di in range(max_length):\n", + " decoder_output, decoder_hidden, decoder_attention = decoder(\n", + " decoder_input, decoder_hidden, encoder_outputs)\n", + " decoder_attentions[di] = decoder_attention.data\n", + " topv, topi = decoder_output.data.topk(1)\n", + " if topi.item() == EOS_token:\n", + " decoded_words.append('')\n", + " break\n", + " else:\n", + " decoded_words.append(output_lang.index2word[topi.item()])\n", + "\n", + " decoder_input = topi.squeeze().detach()\n", + "\n", + " return decoded_words, decoder_attentions[:di + 1]" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "# we can evaluate randomly\n", + "def evaluateRandomly(encoder, decoder, n=10):\n", + " for i in range(n):\n", + " pair = random.choice(pairs)\n", + " print('>', pair[0])\n", + " print('=', pair[1])\n", + " output_words, attentions = evaluate(encoder, decoder, pair[0])\n", + " output_sentence = ' '.join(output_words)\n", + " print('<', output_sentence)\n", + " print('')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Training And Evaluating" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3m 46s (- 52m 54s) (5000 6%) 2.0429\n", + "7m 18s (- 47m 28s) (10000 13%) 0.4685\n", + "10m 49s (- 43m 16s) (15000 20%) 0.1562\n", + "14m 20s (- 39m 26s) (20000 26%) 0.1273\n", + "17m 50s (- 35m 40s) (25000 33%) 0.1147\n", + "21m 25s (- 32m 7s) (30000 40%) 0.1110\n", + "24m 57s (- 28m 31s) (35000 46%) 0.1143\n", + "28m 32s (- 24m 58s) (40000 53%) 0.1023\n", + "32m 6s (- 21m 24s) (45000 60%) 0.0996\n" + ] + }, + { + "ename": "KeyboardInterrupt", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[0mattn_decoder1\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mAttnDecoderRNN\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mhidden_size\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0moutput_lang\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mn_words\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdropout_p\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m0.1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mto\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdevice\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 5\u001b[1;33m \u001b[0mtrainIters\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mencoder1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mattn_decoder1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m75000\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mprint_every\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m5000\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[1;32m\u001b[0m in \u001b[0;36mtrainIters\u001b[1;34m(encoder, decoder, n_iters, print_every, plot_every, learning_rate)\u001b[0m\n\u001b[0;32m 17\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 18\u001b[0m loss = train(input_tensor, target_tensor, encoder,\n\u001b[1;32m---> 19\u001b[1;33m decoder, encoder_optimizer, decoder_optimizer, criterion)\n\u001b[0m\u001b[0;32m 20\u001b[0m \u001b[0mprint_loss_total\u001b[0m \u001b[1;33m+=\u001b[0m \u001b[0mloss\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 21\u001b[0m \u001b[0mplot_loss_total\u001b[0m \u001b[1;33m+=\u001b[0m \u001b[0mloss\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32m\u001b[0m in \u001b[0;36mtrain\u001b[1;34m(input_tensor, target_tensor, encoder, decoder, encoder_optimizer, decoder_optimizer, criterion, max_length)\u001b[0m\n\u001b[0;32m 48\u001b[0m \u001b[0mloss\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mbackward\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 49\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 50\u001b[1;33m \u001b[0mencoder_optimizer\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstep\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 51\u001b[0m \u001b[0mdecoder_optimizer\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstep\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 52\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\torch\\optim\\sgd.py\u001b[0m in \u001b[0;36mstep\u001b[1;34m(self, closure)\u001b[0m\n\u001b[0;32m 104\u001b[0m \u001b[0md_p\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mbuf\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 105\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 106\u001b[1;33m \u001b[0mp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0madd_\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m-\u001b[0m\u001b[0mgroup\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'lr'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0md_p\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 107\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 108\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mloss\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;31mKeyboardInterrupt\u001b[0m: " + ] + } + ], + "source": [ + "hidden_size = 256\n", + "encoder1 = EncoderRNN(input_lang.n_words, hidden_size).to(device)\n", + "attn_decoder1 = AttnDecoderRNN(hidden_size, output_lang.n_words, dropout_p=0.1).to(device)\n", + "\n", + "trainIters(encoder1, attn_decoder1, 75000, print_every=5000)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def showAttention(input_sentence, output_words, attentions):\n", + " # Set up figure with colorbar\n", + " fig = plt.figure()\n", + " ax = fig.add_subplot(111)\n", + " cax = ax.matshow(attentions.numpy(), cmap='bone')\n", + " fig.colorbar(cax)\n", + "\n", + " # Set up axes\n", + " ax.set_xticklabels([''] + input_sentence.split(' ') +\n", + " [''], rotation=90)\n", + " ax.set_yticklabels([''] + output_words)\n", + "\n", + " # Show label at every tick\n", + " ax.xaxis.set_major_locator(ticker.MultipleLocator(1))\n", + " ax.yaxis.set_major_locator(ticker.MultipleLocator(1))\n", + "\n", + " plt.show()\n", + "\n", + "\n", + "def evaluateAndShowAttention(input_sentence):\n", + " output_words, attentions = evaluate(\n", + " encoder1, attn_decoder1, input_sentence)\n", + " print('input =', input_sentence)\n", + " print('output =', ' '.join(output_words))\n", + " showAttention(input_sentence, output_words, attentions)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "evaluateAndShowAttention(\"saya sangat lapar .\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Yasir Abdur Rohman/Project 3/Machine Translation with a Sequence to Sequence Network and Attention (English - Indonesian).ipynb b/Yasir Abdur Rohman/Project 3/Machine Translation with a Sequence to Sequence Network and Attention (English - Indonesian).ipynb new file mode 100644 index 00000000..6b3f9039 --- /dev/null +++ b/Yasir Abdur Rohman/Project 3/Machine Translation with a Sequence to Sequence Network and Attention (English - Indonesian).ipynb @@ -0,0 +1,804 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Machine Translation with a Sequence to Sequence Network and Attention (English - Indonesian)\n", + "
\n", + "\n", + "- *Author: Yasir Abdur Rohman*\n", + "- *Slack Name: Yasir Abdur Rohman*\n", + "\n", + "
\n", + "\n", + "In this project we will implement a neural network to translate from English to Indonesian in a federated way.\n", + "\n", + "We will train two models residing on two remote workers based on **Tatoeba dataset**. You can download the dataset from [Opus Corpus](http://opus.nlpl.eu/).\n", + "\n", + "This idea inspired by [tutorial seq2seq translation](https://pytorch.org/tutorials/intermediate/seq2seq_translation_tutorial.html). The idea of [sequence to sequence network](https://arxiv.org/abs/1409.3215) is having two Recurrent Neural Network works together to transform one sequence to another. An encoder network condenses an input sequence into a vector, and a decoder network unfolds that vector into a new sequence.\n", + "\n", + "To improve the model, we will use an [attention mechanism](https://arxiv.org/abs/1409.0473), which lets the decoder learn to focus over a specific range of the input sequence." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 1. Step: Requirements" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING: Logging before flag parsing goes to stderr.\n", + "W0821 07:08:45.595940 21596 secure_random.py:26] Falling back to insecure randomness since the required custom op could not be found for the installed version of TensorFlow. Fix this by compiling custom ops. Missing file was 'D:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\tf_encrypted/operations/secure_random/secure_random_module_tf_1.14.0.so'\n", + "W0821 07:08:45.699662 21596 deprecation_wrapper.py:119] From D:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\tf_encrypted\\session.py:26: The name tf.Session is deprecated. Please use tf.compat.v1.Session instead.\n", + "\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "cuda\n" + ] + } + ], + "source": [ + "from __future__ import unicode_literals, print_function, division\n", + "from io import open\n", + "import unicodedata\n", + "import string\n", + "import re\n", + "import random\n", + "import glob\n", + "import os\n", + "import numpy as np\n", + "import time\n", + "import math\n", + "import pandas as pd\n", + "\n", + "import torch\n", + "import torch.nn as nn\n", + "from torch import optim\n", + "import torch.nn.functional as F\n", + "from torch.utils.data import Dataset\n", + "\n", + "import syft as sy\n", + "from syft.frameworks.torch.federated import utils\n", + "from syft.workers import WebsocketClientWorker\n", + "\n", + "import matplotlib.pyplot as plt\n", + "import matplotlib.ticker as ticker\n", + "\n", + "device = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\n", + "print(device)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 2. Step: Loading Data Files\n", + "We will representing each word in a language as one-hot vector. We also need a unique index per word to use as the inputs and targets of the network. To keep track of all this we will use a helper class called Lang which has word → index (word2index) and index → word (index2word) dictionaries, as well as a count of each word word2count to use to later replace rare words." + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "SOS_token = 0\n", + "EOS_token = 1\n", + "\n", + "\n", + "class Lang:\n", + " def __init__(self, name):\n", + " self.name = name\n", + " self.word2index = {}\n", + " self.word2count = {}\n", + " self.index2word = {0: \"SOS\", 1: \"EOS\"}\n", + " self.n_words = 2 # Count SOS and EOS\n", + "\n", + " def addSentence(self, sentence):\n", + " for word in sentence.split(' '):\n", + " self.addWord(word)\n", + "\n", + " def addWord(self, word):\n", + " if word not in self.word2index:\n", + " self.word2index[word] = self.n_words\n", + " self.word2count[word] = 1\n", + " self.index2word[self.n_words] = word\n", + " self.n_words += 1\n", + " else:\n", + " self.word2count[word] += 1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Preprocessing:\n", + "- convert unicode characters to ascii\n", + "- lowercase\n", + "- trim punctuation" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "# Turn a Unicode string to plain ASCII, thanks to\n", + "# https://stackoverflow.com/a/518232/2809427\n", + "def unicodeToAscii(s):\n", + " return ''.join(\n", + " c for c in unicodedata.normalize('NFD', s)\n", + " if unicodedata.category(c) != 'Mn'\n", + " )\n", + "\n", + "# Lowercase, trim, and remove non-letter characters\n", + "\n", + "\n", + "def normalizeString(s):\n", + " s = unicodeToAscii(s.lower().strip())\n", + " s = re.sub(r\"([.!?])\", r\" \\1\", s)\n", + " s = re.sub(r\"[^a-zA-Z.!?]+\", r\" \", s)\n", + " return s" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "we will split the file into lines, and then split lines into pairs. The files are all English → Other Language, so if we want to translate from Other Language → English I added the reverse flag to reverse the pairs." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "def readLangs(lang1, lang2, reverse=False):\n", + " print(\"Reading lines...\")\n", + "\n", + " # Read the file and split into lines\n", + " lines = open('data/%s-%s.txt' % (lang1, lang2), encoding='utf-8').\\\n", + " read().strip().split('\\n')\n", + "\n", + " # Split every line into pairs and normalize\n", + " pairs = [[normalizeString(s) for s in l.split('\\t')] for l in lines]\n", + "\n", + " # Reverse pairs, make Lang instances\n", + " if reverse:\n", + " pairs = [list(reversed(p)) for p in pairs]\n", + " input_lang = Lang(lang2)\n", + " output_lang = Lang(lang1)\n", + " else:\n", + " input_lang = Lang(lang1)\n", + " output_lang = Lang(lang2)\n", + "\n", + " return input_lang, output_lang, pairs" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "MAX_LENGTH = 10\n", + "\n", + "eng_prefixes = (\n", + " \"i am \", \"i m \",\n", + " \"he is\", \"he s \",\n", + " \"she is\", \"she s \",\n", + " \"you are\", \"you re \",\n", + " \"we are\", \"we re \",\n", + " \"they are\", \"they re \"\n", + ")\n", + "\n", + "\n", + "def filterPair(p):\n", + " return len(p[0].split(' ')) < MAX_LENGTH and \\\n", + " len(p[1].split(' ')) < MAX_LENGTH and \\\n", + " p[1].startswith(eng_prefixes)\n", + "\n", + "\n", + "def filterPairs(pairs):\n", + " return [pair for pair in pairs if filterPair(pair)]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The full process for preparing the data is:\n", + "\n", + "- Read text file and split into lines, split lines into pairs\n", + "- Normalize text, filter by length and content\n", + "- Make word lists from sentences in pairs" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "def prepareData(lang1, lang2, reverse=False):\n", + " input_lang, output_lang, pairs = readLangs(lang1, lang2, reverse)\n", + " print(\"Read %s sentence pairs\" % len(pairs))\n", + " pairs = filterPairs(pairs)\n", + " print(\"Trimmed to %s sentence pairs\" % len(pairs))\n", + " print(\"Counting words...\")\n", + " for pair in pairs:\n", + " input_lang.addSentence(pair[0])\n", + " output_lang.addSentence(pair[1])\n", + " print(\"Counted words:\")\n", + " print(input_lang.name, input_lang.n_words)\n", + " print(output_lang.name, output_lang.n_words)\n", + " return input_lang, output_lang, pairs" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Reading lines...\n", + "Read 7124 sentence pairs\n", + "Trimmed to 474 sentence pairs\n", + "Counting words...\n", + "Counted words:\n", + "ind 554\n", + "eng 517\n", + "['kau agresif .', 'you re aggressive .']\n" + ] + } + ], + "source": [ + "input_lang, output_lang, pairs = prepareData('eng', 'ind', True)\n", + "print(random.choice(pairs))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# The Seq2Seq Model\n", + "It consisting two RNN such as encoder and decoder network. The encoder reads an input sequence and outputs a single vector, and the decoder reads that vector to produce an output sequence. With a seq2seq model the encoder creates a single vector which, in the ideal case, encodes the “meaning” of the input sequence into a single vector — a single point in some N dimensional space of sentences" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## The Encoder\n", + "The encoder of a seq2seq network is a RNN that outputs some value for every word from the input sentence. For every input word the encoder outputs a vector and a hidden state, and uses the hidden state for the next input word" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "class EncoderRNN(nn.Module):\n", + " def __init__(self, input_size, hidden_size):\n", + " super(EncoderRNN, self).__init__()\n", + " self.hidden_size = hidden_size\n", + "\n", + " self.embedding = nn.Embedding(input_size, hidden_size)\n", + " self.gru = nn.GRU(hidden_size, hidden_size)\n", + "\n", + " def forward(self, input, hidden):\n", + " embedded = self.embedding(input).view(1, 1, -1)\n", + " output = embedded\n", + " output, hidden = self.gru(output, hidden)\n", + " return output, hidden\n", + "\n", + " def initHidden(self):\n", + " return torch.zeros(1, 1, self.hidden_size, device=device)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## The Decoder\n", + "The decoder is another RNN that takes the encoder output vector(s) and outputs a sequence of words to create the translation" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "class DecoderRNN(nn.Module):\n", + " def __init__(self, hidden_size, output_size):\n", + " super(DecoderRNN, self).__init__()\n", + " self.hidden_size = hidden_size\n", + "\n", + " self.embedding = nn.Embedding(output_size, hidden_size)\n", + " self.gru = nn.GRU(hidden_size, hidden_size)\n", + " self.out = nn.Linear(hidden_size, output_size)\n", + " self.softmax = nn.LogSoftmax(dim=1)\n", + "\n", + " def forward(self, input, hidden):\n", + " output = self.embedding(input).view(1, 1, -1)\n", + " output = F.relu(output)\n", + " output, hidden = self.gru(output, hidden)\n", + " output = self.softmax(self.out(output[0]))\n", + " return output, hidden\n", + "\n", + " def initHidden(self):\n", + " return torch.zeros(1, 1, self.hidden_size, device=device)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### The Attention Decoder\n", + "Attention allows the decoder network to “focus” on a different part of the encoder’s outputs for every step of the decoder’s own outputs. First we calculate a set of attention weights. These will be multiplied by the encoder output vectors to create a weighted combination. The result (called attn_applied in the code) should contain information about that specific part of the input sequence, and thus help the decoder choose the right output words.\n", + "\n", + "Calculating the attention weights is done with another feed-forward layer attn, using the decoder’s input and hidden state as inputs. Because there are sentences of all sizes in the training data, to actually create and train this layer we have to choose a maximum sentence length (input length, for encoder outputs) that it can apply to. Sentences of the maximum length will use all the attention weights, while shorter sentences will only use the first few." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "class AttnDecoderRNN(nn.Module):\n", + " def __init__(self, hidden_size, output_size, dropout_p=0.1, max_length=MAX_LENGTH):\n", + " super(AttnDecoderRNN, self).__init__()\n", + " self.hidden_size = hidden_size\n", + " self.output_size = output_size\n", + " self.dropout_p = dropout_p\n", + " self.max_length = max_length\n", + "\n", + " self.embedding = nn.Embedding(self.output_size, self.hidden_size)\n", + " self.attn = nn.Linear(self.hidden_size * 2, self.max_length)\n", + " self.attn_combine = nn.Linear(self.hidden_size * 2, self.hidden_size)\n", + " self.dropout = nn.Dropout(self.dropout_p)\n", + " self.gru = nn.GRU(self.hidden_size, self.hidden_size)\n", + " self.out = nn.Linear(self.hidden_size, self.output_size)\n", + "\n", + " def forward(self, input, hidden, encoder_outputs):\n", + " embedded = self.embedding(input).view(1, 1, -1)\n", + " embedded = self.dropout(embedded)\n", + "\n", + " attn_weights = F.softmax(\n", + " self.attn(torch.cat((embedded[0], hidden[0]), 1)), dim=1)\n", + " attn_applied = torch.bmm(attn_weights.unsqueeze(0),\n", + " encoder_outputs.unsqueeze(0))\n", + "\n", + " output = torch.cat((embedded[0], attn_applied[0]), 1)\n", + " output = self.attn_combine(output).unsqueeze(0)\n", + "\n", + " output = F.relu(output)\n", + " output, hidden = self.gru(output, hidden)\n", + "\n", + " output = F.log_softmax(self.out(output[0]), dim=1)\n", + " return output, hidden, attn_weights\n", + "\n", + " def initHidden(self):\n", + " return torch.zeros(1, 1, self.hidden_size, device=device)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Training" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Preparing Training Data\n", + "To train, for each pair we will need an input tensor (indexes of the words in the input sentence) and target tensor (indexes of the words in the target sentence). While creating these vectors we will append the EOS token to both sequences." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [], + "source": [ + "def indexesFromSentence(lang, sentence):\n", + " return [lang.word2index[word] for word in sentence.split(' ')]\n", + "\n", + "\n", + "def tensorFromSentence(lang, sentence):\n", + " indexes = indexesFromSentence(lang, sentence)\n", + " indexes.append(EOS_token)\n", + " return torch.tensor(indexes, dtype=torch.long, device=device).view(-1, 1)\n", + "\n", + "\n", + "def tensorsFromPair(pair):\n", + " input_tensor = tensorFromSentence(input_lang, pair[0])\n", + " target_tensor = tensorFromSentence(output_lang, pair[1])\n", + " return (input_tensor, target_tensor)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Training The Model\n", + "To train we run the input sentence through the encoder, and keep track of every output and the latest hidden state. Then the decoder is given the token as its first input, and the last hidden state of the encoder as its first hidden state.\n", + " \n", + "Because of the freedom PyTorch’s autograd gives us, we can randomly choose to use teacher forcing or not with a simple if statement. Turn teacher_forcing_ratio up to use more of it." + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "metadata": {}, + "outputs": [], + "source": [ + "teacher_forcing_ratio = 0.5\n", + "\n", + "\n", + "def train(input_tensor, target_tensor, encoder, decoder, encoder_optimizer, decoder_optimizer, criterion, max_length=MAX_LENGTH):\n", + " encoder_hidden = encoder.initHidden()\n", + "\n", + " encoder_optimizer.zero_grad()\n", + " decoder_optimizer.zero_grad()\n", + "\n", + " input_length = input_tensor.size(0)\n", + " target_length = target_tensor.size(0)\n", + "\n", + " encoder_outputs = torch.zeros(max_length, encoder.hidden_size, device=device)\n", + "\n", + " loss = 0\n", + "\n", + " for ei in range(input_length):\n", + " encoder_output, encoder_hidden = encoder(\n", + " input_tensor[ei], encoder_hidden)\n", + " encoder_outputs[ei] = encoder_output[0, 0]\n", + "\n", + " decoder_input = torch.tensor([[SOS_token]], device=device)\n", + "\n", + " decoder_hidden = encoder_hidden\n", + "\n", + " use_teacher_forcing = True if random.random() < teacher_forcing_ratio else False\n", + "\n", + " if use_teacher_forcing:\n", + " # Teacher forcing: Feed the target as the next input\n", + " for di in range(target_length):\n", + " decoder_output, decoder_hidden, decoder_attention = decoder(\n", + " decoder_input, decoder_hidden, encoder_outputs)\n", + " loss += criterion(decoder_output, target_tensor[di])\n", + " decoder_input = target_tensor[di] # Teacher forcing\n", + "\n", + " else:\n", + " # Without teacher forcing: use its own predictions as the next input\n", + " for di in range(target_length):\n", + " decoder_output, decoder_hidden, decoder_attention = decoder(\n", + " decoder_input, decoder_hidden, encoder_outputs)\n", + " topv, topi = decoder_output.topk(1)\n", + " decoder_input = topi.squeeze().detach() # detach from history as input\n", + "\n", + " loss += criterion(decoder_output, target_tensor[di])\n", + " if decoder_input.item() == EOS_token:\n", + " break\n", + "\n", + " loss.backward()\n", + "\n", + " encoder_optimizer.step()\n", + " decoder_optimizer.step()\n", + "\n", + " return loss.item() / target_length" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Helper Function" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "metadata": {}, + "outputs": [], + "source": [ + "import time\n", + "import math\n", + "\n", + "\n", + "def asMinutes(s):\n", + " m = math.floor(s / 60)\n", + " s -= m * 60\n", + " return '%dm %ds' % (m, s)\n", + "\n", + "\n", + "def timeSince(since, percent):\n", + " now = time.time()\n", + " s = now - since\n", + " es = s / (percent)\n", + " rs = es - s\n", + " return '%s (- %s)' % (asMinutes(s), asMinutes(rs))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The whole training process looks like this:\n", + "\n", + "- Start a timer\n", + "- Initialize optimizers and criterion\n", + "- Create set of training pairs\n", + "- Start empty losses array for plotting" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": {}, + "outputs": [], + "source": [ + "def trainIters(encoder, decoder, n_iters, print_every=1000, plot_every=100, learning_rate=0.01):\n", + " start = time.time()\n", + " plot_losses = []\n", + " print_loss_total = 0 # Reset every print_every\n", + " plot_loss_total = 0 # Reset every plot_every\n", + "\n", + " encoder_optimizer = optim.SGD(encoder.parameters(), lr=learning_rate)\n", + " decoder_optimizer = optim.SGD(decoder.parameters(), lr=learning_rate)\n", + " training_pairs = [tensorsFromPair(random.choice(pairs))\n", + " for i in range(n_iters)]\n", + " criterion = nn.NLLLoss()\n", + "\n", + " for iter in range(1, n_iters + 1):\n", + " training_pair = training_pairs[iter - 1]\n", + " input_tensor = training_pair[0]\n", + " target_tensor = training_pair[1]\n", + "\n", + " loss = train(input_tensor, target_tensor, encoder,\n", + " decoder, encoder_optimizer, decoder_optimizer, criterion)\n", + " print_loss_total += loss\n", + " plot_loss_total += loss\n", + "\n", + " if iter % print_every == 0:\n", + " print_loss_avg = print_loss_total / print_every\n", + " print_loss_total = 0\n", + " print('%s (%d %d%%) %.4f' % (timeSince(start, iter / n_iters),\n", + " iter, iter / n_iters * 100, print_loss_avg))\n", + "\n", + " if iter % plot_every == 0:\n", + " plot_loss_avg = plot_loss_total / plot_every\n", + " plot_losses.append(plot_loss_avg)\n", + " plot_loss_total = 0\n", + "\n", + " showPlot(plot_losses)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Plotting Result" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [], + "source": [ + "def showPlot(points):\n", + " plt.figure()\n", + " fig, ax = plt.subplots()\n", + " # this locator puts ticks at regular intervals\n", + " loc = ticker.MultipleLocator(base=0.2)\n", + " ax.yaxis.set_major_locator(loc)\n", + " plt.plot(points)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Evaluation\n", + "Evaluation is mostly the same as training, but there are no targets so we simply feed the decoder’s predictions back to itself for each step. Every time it predicts a word we add it to the output string, and if it predicts the EOS token we stop there. We also store the decoder’s attention outputs for display later." + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "metadata": {}, + "outputs": [], + "source": [ + "def evaluate(encoder, decoder, sentence, max_length=MAX_LENGTH):\n", + " with torch.no_grad():\n", + " input_tensor = tensorFromSentence(input_lang, sentence)\n", + " input_length = input_tensor.size()[0]\n", + " encoder_hidden = encoder.initHidden()\n", + "\n", + " encoder_outputs = torch.zeros(max_length, encoder.hidden_size, device=device)\n", + "\n", + " for ei in range(input_length):\n", + " encoder_output, encoder_hidden = encoder(input_tensor[ei],\n", + " encoder_hidden)\n", + " encoder_outputs[ei] += encoder_output[0, 0]\n", + "\n", + " decoder_input = torch.tensor([[SOS_token]], device=device) # SOS\n", + "\n", + " decoder_hidden = encoder_hidden\n", + "\n", + " decoded_words = []\n", + " decoder_attentions = torch.zeros(max_length, max_length)\n", + "\n", + " for di in range(max_length):\n", + " decoder_output, decoder_hidden, decoder_attention = decoder(\n", + " decoder_input, decoder_hidden, encoder_outputs)\n", + " decoder_attentions[di] = decoder_attention.data\n", + " topv, topi = decoder_output.data.topk(1)\n", + " if topi.item() == EOS_token:\n", + " decoded_words.append('')\n", + " break\n", + " else:\n", + " decoded_words.append(output_lang.index2word[topi.item()])\n", + "\n", + " decoder_input = topi.squeeze().detach()\n", + "\n", + " return decoded_words, decoder_attentions[:di + 1]" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": {}, + "outputs": [], + "source": [ + "# we can evaluate randomly\n", + "def evaluateRandomly(encoder, decoder, n=10):\n", + " for i in range(n):\n", + " pair = random.choice(pairs)\n", + " print('>', pair[0])\n", + " print('=', pair[1])\n", + " output_words, attentions = evaluate(encoder, decoder, pair[0])\n", + " output_sentence = ' '.join(output_words)\n", + " print('<', output_sentence)\n", + " print('')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Training And Evaluating" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "3m 46s (- 52m 54s) (5000 6%) 2.0429\n", + "7m 18s (- 47m 28s) (10000 13%) 0.4685\n", + "10m 49s (- 43m 16s) (15000 20%) 0.1562\n", + "14m 20s (- 39m 26s) (20000 26%) 0.1273\n", + "17m 50s (- 35m 40s) (25000 33%) 0.1147\n", + "21m 25s (- 32m 7s) (30000 40%) 0.1110\n", + "24m 57s (- 28m 31s) (35000 46%) 0.1143\n", + "28m 32s (- 24m 58s) (40000 53%) 0.1023\n", + "32m 6s (- 21m 24s) (45000 60%) 0.0996\n" + ] + }, + { + "ename": "KeyboardInterrupt", + "evalue": "", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mKeyboardInterrupt\u001b[0m Traceback (most recent call last)", + "\u001b[1;32m\u001b[0m in \u001b[0;36m\u001b[1;34m\u001b[0m\n\u001b[0;32m 3\u001b[0m \u001b[0mattn_decoder1\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mAttnDecoderRNN\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mhidden_size\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0moutput_lang\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mn_words\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mdropout_p\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m0.1\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mto\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mdevice\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 4\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m----> 5\u001b[1;33m \u001b[0mtrainIters\u001b[0m\u001b[1;33m(\u001b[0m\u001b[0mencoder1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mattn_decoder1\u001b[0m\u001b[1;33m,\u001b[0m \u001b[1;36m75000\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0mprint_every\u001b[0m\u001b[1;33m=\u001b[0m\u001b[1;36m5000\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[1;32m\u001b[0m in \u001b[0;36mtrainIters\u001b[1;34m(encoder, decoder, n_iters, print_every, plot_every, learning_rate)\u001b[0m\n\u001b[0;32m 17\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 18\u001b[0m loss = train(input_tensor, target_tensor, encoder,\n\u001b[1;32m---> 19\u001b[1;33m decoder, encoder_optimizer, decoder_optimizer, criterion)\n\u001b[0m\u001b[0;32m 20\u001b[0m \u001b[0mprint_loss_total\u001b[0m \u001b[1;33m+=\u001b[0m \u001b[0mloss\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 21\u001b[0m \u001b[0mplot_loss_total\u001b[0m \u001b[1;33m+=\u001b[0m \u001b[0mloss\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32m\u001b[0m in \u001b[0;36mtrain\u001b[1;34m(input_tensor, target_tensor, encoder, decoder, encoder_optimizer, decoder_optimizer, criterion, max_length)\u001b[0m\n\u001b[0;32m 48\u001b[0m \u001b[0mloss\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mbackward\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 49\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m---> 50\u001b[1;33m \u001b[0mencoder_optimizer\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstep\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 51\u001b[0m \u001b[0mdecoder_optimizer\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mstep\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 52\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;32mD:\\Anaconda3\\envs\\pysyft\\lib\\site-packages\\torch\\optim\\sgd.py\u001b[0m in \u001b[0;36mstep\u001b[1;34m(self, closure)\u001b[0m\n\u001b[0;32m 104\u001b[0m \u001b[0md_p\u001b[0m \u001b[1;33m=\u001b[0m \u001b[0mbuf\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 105\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[1;32m--> 106\u001b[1;33m \u001b[0mp\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0mdata\u001b[0m\u001b[1;33m.\u001b[0m\u001b[0madd_\u001b[0m\u001b[1;33m(\u001b[0m\u001b[1;33m-\u001b[0m\u001b[0mgroup\u001b[0m\u001b[1;33m[\u001b[0m\u001b[1;34m'lr'\u001b[0m\u001b[1;33m]\u001b[0m\u001b[1;33m,\u001b[0m \u001b[0md_p\u001b[0m\u001b[1;33m)\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0m\u001b[0;32m 107\u001b[0m \u001b[1;33m\u001b[0m\u001b[0m\n\u001b[0;32m 108\u001b[0m \u001b[1;32mreturn\u001b[0m \u001b[0mloss\u001b[0m\u001b[1;33m\u001b[0m\u001b[1;33m\u001b[0m\u001b[0m\n", + "\u001b[1;31mKeyboardInterrupt\u001b[0m: " + ] + } + ], + "source": [ + "hidden_size = 256\n", + "encoder1 = EncoderRNN(input_lang.n_words, hidden_size).to(device)\n", + "attn_decoder1 = AttnDecoderRNN(hidden_size, output_lang.n_words, dropout_p=0.1).to(device)\n", + "\n", + "trainIters(encoder1, attn_decoder1, 75000, print_every=5000)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def showAttention(input_sentence, output_words, attentions):\n", + " # Set up figure with colorbar\n", + " fig = plt.figure()\n", + " ax = fig.add_subplot(111)\n", + " cax = ax.matshow(attentions.numpy(), cmap='bone')\n", + " fig.colorbar(cax)\n", + "\n", + " # Set up axes\n", + " ax.set_xticklabels([''] + input_sentence.split(' ') +\n", + " [''], rotation=90)\n", + " ax.set_yticklabels([''] + output_words)\n", + "\n", + " # Show label at every tick\n", + " ax.xaxis.set_major_locator(ticker.MultipleLocator(1))\n", + " ax.yaxis.set_major_locator(ticker.MultipleLocator(1))\n", + "\n", + " plt.show()\n", + "\n", + "\n", + "def evaluateAndShowAttention(input_sentence):\n", + " output_words, attentions = evaluate(\n", + " encoder1, attn_decoder1, input_sentence)\n", + " print('input =', input_sentence)\n", + " print('output =', ' '.join(output_words))\n", + " showAttention(input_sentence, output_words, attentions)\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "evaluateAndShowAttention(\"saya sangat lapar .\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.7.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/Yasir Abdur Rohman/Project 3/README.md b/Yasir Abdur Rohman/Project 3/README.md new file mode 100644 index 00000000..0b08518a --- /dev/null +++ b/Yasir Abdur Rohman/Project 3/README.md @@ -0,0 +1,82 @@ +# Machine Translation with a Sequence to Sequence Network and Attention (English - Indonesian) +Create machine translation from English to Indonesian + +# Step-by-step +## Step 1: Install requirements +- Installing Pytorch and Syft. + +## Step 2: Loading Data Files +- Download Tatoeba dataset eng->Indonesian. +- Do preprocessing: + - Read text file and split into lines, split lines into pairs + - Normalize text, filter by length and content + - Make word lists from sentences in pairs +- Transform dataset into input_lang for encoder, output_lang for decoder, and pairs for training model. + + +## Step 3: The Seq2Seq Model +- Create EncoderRNN: The encoder of a seq2seq network is a RNN that outputs some value for every word from the input sentence. For every input word the encoder outputs a vector and a hidden state, and uses the hidden state for the next input word. + +![EncoderRNN](https://github.com/yasirabd/SPAI/blob/master/Project%203/assets/encoder-network.png "EncoderRNN") + +- Create DecoderRNN: The decoder is another RNN that takes the encoder output vector(s) and outputs a sequence of words to create the translation + +![DecoderRNN](https://github.com/yasirabd/SPAI/blob/master/Project%203/assets/decoder-network.png "DecoderRNN") + +- Create Attention Decoder: Attention allows the decoder network to “focus” on a different part of the encoder’s outputs for every step of the decoder’s own outputs. + +![DecoderAttn](https://github.com/yasirabd/SPAI/blob/master/Project%203/assets/attention-decoder-network.png "DecoderAttn") + +## Step 4: Training +- To train we run the input sentence through the encoder, and keep track of every output and the latest hidden state. Then the decoder is given the token as its first input, and the last hidden state of the encoder as its first hidden state. + +## Step 5: Evaluation +- Evaluation is mostly the same as training, but there are no targets so we simply feed the decoder’s predictions back to itself for each step. +- The result such as follows: +``` +> saya malu telah melakukan hal tersebut . += i am ashamed of having done so . +< i am ashamed of having done so . + +> saya senang bisa membantu . += i m glad i could help out . +< i m glad i could help . + +> dia pintar . += he s smart . +< he s intelligent . + +> aku minta maaf sudah mengecewakanmu . += i m sorry i let you down . +< i m sorry i let you down + +> aku lebih pendek ketimbang kamu . += i am shorter than you . +< i m shorter than you . + +> saya cukup nyaman di ruangan ini . += i am quite comfortable in this room . +< i am quite comfortable in this room . + +> aku orang yang rasional . += i m reasonable . +< i m reasonable . + +> saya senang bisa membantu . += i m glad i could help out . +< i m glad i could help . + +> dia takut kucing . += she is afraid of cats . +< she is afraid of cats . + +> aku tidak sedang bercanda . += i am not kidding . +< i m not kidding . +``` +- Evaluate and showing Attention +```python +evaluateAndShowAttention("saya sangat lapar .") +> input = saya sangat lapar . +> output = i am terribly hungry . +``` diff --git a/Yasir Abdur Rohman/Project 3/assets/attention-decoder-network.png b/Yasir Abdur Rohman/Project 3/assets/attention-decoder-network.png new file mode 100644 index 00000000..243f87c6 Binary files /dev/null and b/Yasir Abdur Rohman/Project 3/assets/attention-decoder-network.png differ diff --git a/Yasir Abdur Rohman/Project 3/assets/decoder-network.png b/Yasir Abdur Rohman/Project 3/assets/decoder-network.png new file mode 100644 index 00000000..54931fcd Binary files /dev/null and b/Yasir Abdur Rohman/Project 3/assets/decoder-network.png differ diff --git a/Yasir Abdur Rohman/Project 3/assets/encoder-network.png b/Yasir Abdur Rohman/Project 3/assets/encoder-network.png new file mode 100644 index 00000000..1525f1bf Binary files /dev/null and b/Yasir Abdur Rohman/Project 3/assets/encoder-network.png differ diff --git a/Yasir Abdur Rohman/Project 3/assets/seq2seq.png b/Yasir Abdur Rohman/Project 3/assets/seq2seq.png new file mode 100644 index 00000000..af09c74a Binary files /dev/null and b/Yasir Abdur Rohman/Project 3/assets/seq2seq.png differ diff --git a/Yasir Abdur Rohman/Project 3/data/eng-ind.txt b/Yasir Abdur Rohman/Project 3/data/eng-ind.txt new file mode 100644 index 00000000..b708c95c --- /dev/null +++ b/Yasir Abdur Rohman/Project 3/data/eng-ind.txt @@ -0,0 +1,7124 @@ +Run! Lari! +Who? Siapa? +Wow! Wow! +Help! Tolong! +Jump! Lompat! +Jump. Loncat. +Stop! Berhenti! +Wait! Tunggu! +Wait. Tunggu. +Hurry! Cepatlah! +Hurry! Cepat! +Hurry! Buruan! +I see. Begitu rupanya. +Smile. Senyum. +Attack! Serang! +Cheers! Bersulang! +Freeze! Jangan bergerak! +Get up. Bangunlah. +Got it! Aku mengerti! +Got it? Mengerti? +Listen. Dengar. +No way! Tak bisa! +No way! Tidak mungkin! +Really? Benarkah? +Really? Beneran? +Thanks. Terima kasih. +Thanks. Makasih. +We try. Kami mencoba. +Why me? Kenapa harus saya? +Awesome! Mengagumkan! +Come on! Ayo! +Get out! Keluar! +Goodbye! Sampai jumpa! +Hold it! Tahan! +I agree. Aku setuju. +I'm sad. Saya sedih. +It's OK. Tidak apa-apa. +It's me! Ini aku! +It's me. Ini aku. +Me, too. Aku juga. +Perfect! Sempurna! +See you! Sampai jumpa! +Show me. Perlihatkan padaku. +Show me. Perlihatin. +Shut up! Diam! +So long. Sampai jumpa. +Tom won. Tom menang. +Wake up! Bangun! +Wake up! Bangunlah! +Wake up. Bangunlah. +Welcome. Selamat datang. +Be still. Jangan bergerak. +Good job! Kerja yang bagus! +Good job! Kerja bagus! +Grab Tom. Tangkap Tom. +Hi, guys. Hai, kawan-kawan. +I failed. Aku gagal. +I get it. Aku mengerti. +I got it. Aku mengerti. +I refuse. Aku menolak. +I stayed. Aku tetap tinggal. +I'm okay. Aku baik-baik saja. +It's odd. Itu aneh. +It's odd. Ini aneh. +Look out! Awas! +Sit down! Duduklah! +Sit down. Duduklah. +Stand up! Berdiri! +Stand up. Berdirilah. +Terrific! Hebat! +They won. Mereka menang. +Trust me. Percaya padaku. +We tried. Kami sudah mencoba. +What for? Untuk apa? +Who's he? Dia siapa? +Be seated. Duduklah. +Bless you. Terberkatilah dirimu. +Calm down. Tenanglah. +Chill out. Tenanglah. +Come here. Kemari. +Come soon. Datanglah segera. +Cool down. Tenanglah. +Don't cry. Jangan menangis. +Don't die. Jangan mati. +Fantastic! Fantastis! +Forget it. Lupakan. +He's a DJ. Dia adalah seorang DJ. +I can ski. Saya bisa bermain ski. +I hit Tom. Aku memukul Tom. +I mean it! Aku serius! +I mean it. Aku serius. +I promise. Aku janji. +I'm a man. Aku laki-laki. +I'm bored. Saya bosan. +I'm bored. Aku bosan. +I'm drunk. Aku mabuk. +I'm first. Aku yang pertama. +I'm naked. Aku telanjang. +I'm tired. Aku lelah. +It's cold. Dingin. +It's food. Ini adalah makanan. +Let's try! Mari kita coba! +Let's try. Mari kita coba. +Of course! Tentu saja! +Pipe down! Harap tenang! +See below. Lihat di bawah ini. +Seriously? Masa? +Seriously? Serius? +Seriously? Beneran? +Stop that! Hentikan itu! +Stop that. Hentikan itu. +Thank you. Terima kasih. +Then what? Terus kenapa? +Tom cried. Tom menangis. +Try again. Coba lagi. +Turn left. Belok kiri. +Watch out! Awas! +Well done! Kerja yang bagus! +Well done! Kerja bagus! +What else? Apa lagi? +What's up? Ada apa? +Who is he? Dia siapa? +Who's Tom? Tom itu siapa? +Wonderful! Luar biasa! +Are you OK? Kamu tidak apa-apa? +Be careful! Hati-hati! +Be careful. Hati-hati. +Cut it out! Sudah hentikan! +Cut it out. Sudah hentikan. +Don't move! Jangan bergerak! +Don't move. Jangan bergerak. +Don't talk! Jangan berbicara! +Duty calls. Panggilan tugas. +Eat slowly. Makan pelan-pelan. +Forget him. Lupakan dirinya. +He coughed. Dia batuk. +He is a DJ. Dia adalah seorang DJ. +He's smart. Dia pintar. +Hello, Tom. Halo, Tom! +How boring! Membosankan sekali! +I am a man. Aku laki-laki. +I am bored. Saya bosan. +I am bored. Aku bosan. +I am going. Saya pergi. +I am tired. Aku lelah. +I just ate. Aku baru makan. +I like him. Aku suka dia. +I love you. Aku cinta kamu. +I love you. aku mencintaimu +I miss you. Aku merindukanmu. +I miss you. Aku rindu kamu. +I'm hiding. Aku sedang sembunyi. +I'm hungry! Aku lapar! +I'm hungry. Saya lapar. +I'm hungry. Aku lapar. +I'm joking. Aku bercanda. +I'm pooped. Aku sangat capek. +I'm sleepy! Aku ngantuk! +I'm sleepy. Aku ngantuk. +Is Tom ill? Apa Tom sakit? +Is it love? Apakah ini cinta? +Is it true? Apa itu benar? +Is that so? Apa benar begitu? +It is cold. Dingin. +It'll burn. Itu akan terbakar +It's night. Sekarang malam. +It's weird. Itu aneh. +It's weird. Ini aneh. +Let me see. Coba saya lihat. +Look at me. Lihat saya. +No kidding? Beneran? +No problem! Tidak masalah! +No problem. Tidak masalah. +Oh, really? Oh, benarkah? +Please sit. Silakan duduk. +Step on it! Cepatlah! +Step on it! Cepat! +That's odd. Itu aneh. +Tom did it. Tom melakukannya. +Tom is fun. Tom menyenangkan +Tom was OK. Tom dalam keadaan baik. +Tom's home. Tom di rumah. +Turn right. Belok kanan. +Was he Tom? Apakah dia Tom? +Who is Tom? Tom itu siapa? +Are you cut? Apa kau melakukan khitan? +Are you new? Kamu orang baru? +Can you see? Kamu masih belum mengerti? +Do you bowl? Apa kau bermain boling? +Don't smoke. Jangan merokok. +Don't worry. Jangan khawatir +Go to sleep. Pergilah tidur. +Grab a seat. Duduklah. +Have a seat. Duduklah. +He has wine. Dia memiliki anggur. +He is alone. Dia sendirian. +He is eight. Dia delapan tahun. +He's crying. Dia sedang menangis. +How are you? Apa kabar? +How are you? Bagaimana kabar Anda? +I also went. Saya juga pergi. +I am joking. Aku bercanda. +I felt dumb. Aku merasa bodoh. +I got tired. Aku lelah. +I like blue. Aku suka biru. +I like cats. Aku suka kucing. +I like this. Aku suka ini. +I need cash. Aku perlu uang. +I thank you. Aku berterima kasih. +I trust him. Saya mempercayainya. +I want mine. Aku mau punyaku. +I was tired. Aku lelah. +I went, too. Saya juga pergi. +I'm kidding. Aku bercanda. +I'm not shy. Saya tidak malu. +I'm serious. Aku serius. +I'm starved. Aku kelaparan. +I'm thirsty. Aku haus. +I'm too fat. Aku terlalu gemuk. +I've failed. Aku sudah gagal. +I've failed. Aku telah gagal. +Is Tom sick? Apa Tom sakit? +Is Tom well? Apa Tom sehat? +It can't be! Tidak mungkin! +It may rain. Mungkin akan turun hujan. +It's a fake. Itu palsu. +It's a joke. Bercanda. +Let's do it! Mari kita melakukannya! +Let's do it! Mari kita lakukan! +Let's do it. Mari kita lakukan. +Let's do it. Mari kita melakukannya. +Let's party. Mari berpesta. +Look at Tom. Lihatlah ke arah Tom. +Many thanks. Terima kasih banyak. +Many thanks. Makasih banyak. +Please stop! Tolong berhenti! +Please stop. Tolong berhenti. +Say goodbye. Ucapkan selamat tinggal. +She blushed. Ia tersipu malu. +Stand still! Diam di situ! +Take a seat. Duduklah. +That's life. Begitulah hidup. +This is Tom. Ini Tom. +This is big. Ini besar. +This is odd. Ini aneh. +Tom fainted. Tom pingsan. +Tom is rude. Tom adalah seorang yang kasar. +Tom's flaky. Tom itu suka berpangku tangan. +Turn on CNN. Nyalakan CNN. +We help Tom. Kami membantu Tom. +We know him. Kami mengenalnya. +We'll fight. Kita akan bertarung. +What a bore! Membosankan sekali! +What a pity! Sayang sekali! +What's that? Itu apa? +What's this? Ini apa? +Who drew it? Siapa yang menggambar itu? +Whose is it? Itu punya siapa? +You're thin. Kamu kurus. +Are you sure? Apakah kamu yakin? +Are you sure? Apakah Anda yakin? +Are you sure? Apa kau yakin? +Cut that out! Hentikan itu! +Don't ask me. Jangan tanya aku. +Don't go yet. Jangan pergi dulu. +Don't kid me! Jangan mempermainkanku! +Good morning. Selamat pagi. +Has Tom gone? Sudahkah Tom pergi? +How horrible! Mengerikan sekali! +I am injured. Aku terluka. +I don't care. Saya tidak peduli. +I don't know. Saya tidak tahu. +I feel tired. Aku merasa capek. +I must study. Aku harus belajar. +I understand. Aku mengerti. +I want to go. Saya ingin pergi. +I'm famished. Aku sangat lapar. +I'm not dumb. Aku tidak dungu. +I'm not here. Aku tidak berada di sini. +I'm not sure. Aku tidak yakin. +I'm so sorry. Saya sangat menyesal. +I'm starving! Aku kelaparan! +I'm starving. Aku kelaparan. +I'm the best. Saya yang terbaik. +I'm worn out. Aku kelelahan. +Is that true? Apa itu benar? +Is this true? Apa ini benar? +Is this true? Apakah ini benar? +It is my cat. Ini kucing saya. +It was a lie. Itu bohong. +It was clear. Tadi itu jelas. +It's my ship. Ini kapalku. +It's no joke. Ini bukan lelucon. +It's raining. Sedang turun hujan. +It's strange. Itu aneh. +It's strange. Ini aneh. +Keep driving. Teruslah mengemudi. +Keep reading. Teruslah membaca. +Knock it off. Sudah hentikan. +Let's try it. Mari kita mencobanya. +No one cares. Tidak ada satupun yang peduli. +Please hurry! Cepatlah! +Set Tom free. Bebaskan Tom. +She is eight. Dia delapan tahun. +Show me that. Perlihatkan itu padaku. +Stop the car. Hentikan mobilnya. +Sweet dreams! Mimpi indah! +Thanks a lot. Terima kasih banyak. +Thanks a lot. Makasih banyak. +That's great! Itu bagus! +That's right! Tepat sekali! +That's weird. Itu aneh. +This is easy. ini gampang +This is food. Ini adalah makanan. +Tom hates me. Tom membenciku. +Tom insisted. Tom memaksa. +Tom is tense. Tom tidak tenang. +Tom needs it. Tom membutuhkannya. +Tom saw them. Tom melihat mereka. +Tom stutters. Tom berbicara dengan gagap. +Tom was fine. Tom dalam keadaan baik. +Tom was good. Tom dalam keadaan baik. +Tom's polite. Tom itu ramah. +Tom's strict. Tom itu keras. +Try and swim! Cobalah berenang! +Wait and see. Lihat saja nanti! +We apologize. Kami mohon maaf. +We'll fix it. Kami akan memperbaikinya. +We're trying. Kami sedang mencoba. +What is this? Ini apa? +You're fools. Kamu bodoh. +You're young. Kamu muda. +Any questions? Ada pertanyaan? +Anything else? Ada lagi? +Are you happy? Apa kamu senang? +Are you happy? Apa Anda bahagia? +Are you tired? Kamu capek? +Check, please. Tolong bonnya. +Come back now. Kembalilah sekarang. +Do you get it? Apa kamu paham? +Do you see it? Apa kamu melihatnya? +Don't go away. Jangan pergi. +Don't mock me. Jangan mengejekku. +Eat something. Makanlah sesuatu. +Feed the bird! Beri makan burungnya! +Feed the bird. Beri makan burungnya. +Get over here. Kemari. +Get your gear. Ambil perlengkapanmu. +Give it to me. Berikan padaku. +God bless you! Tuhan memberkatimu! +He seems sick. Dia nampaknya sedang sakit. +He shot at me. Dia menembak ke arahku. +Hold the rope. Pegang tali itu. +How do you do? Apa kabar? +How do you do? Bagaimana kabar Anda? +I can do that. Aku bisa melakukannya. +I can see Tom. Aku bisa melihat Tom. +I can't do it. Aku tidak bisa melakukannya. +I feel hungry. Aku merasa lapar. +I hate Boston. Aku benci Boston. +I have a home. Aku punya tempat tinggal. +I have a twin. Aku punya saudara kembar. +I have failed. Aku sudah gagal. +I have failed. Aku telah gagal. +I kid you not. Aku tidak bercanda. +I looked away. Aku memalingkan wajahku. +I must refuse. Aku harus menolak. +I tricked you. Aku menipumu. +I use Twitter. Saya menggunakan Twitter. +I want to die. Aku ingin mati. +I went inside. Saya masuk ke dalam. +I'm exhausted. Aku kelelahan. +I'm not blind. Saya tidak buta. +I'm on a diet. Aku sedang melakukan diet. +I'm satisfied. Aku puas. +I'm so hungry. Aku sangat lapar. +Is it raining? Apa sedang hujan? +Is that right? Apa itu benar? +Is that wrong? Apa itu salah? +It is raining. Sedang turun hujan. +It was a hoax. Itu cerita bohong. +It's for sale. Ini dijual. +It's for sale. Ini untuk dijual. +It's upstairs. Ada di lantai atas. +Just trust me. Sudah percaya saja padaku. +Let go of Tom. Lepaskan Tom! +Let go of Tom. Lepaskan Tom. +Let me see it. Biarkan aku melihatnya. +Let me try it. Biarkan aku mencobanya. +Let's do that. Mari kita melakukannya. +Let's go back. Ayo kembali. +Love is crazy. Cinta itu gila. +No one saw us. Tidak ada yang melihat kita. +Quiet, please. Harap tenang. +She went home. Dia pulang. +She went home. Ia pulang. +Show it to me. Perlihatkan itu padaku. +Stop dreaming. Berhentilah bermimpi. +That was fast. Tadi itu cepat. +That was good. Itu tadi enak. +That was good. Itu enak. +That's a fake. Itu palsu. +That's a joke. Bercanda. +That's absurd. Itu konyol. +That's enough. Itu cukup. +They will die. Mereka akan mati. +This is Italy. Inilah Italia. +This is a pen. Ini pulpen. +This is silly. Ini bodoh. +This is weird. Ini aneh. +This was good. Ini enak. +Time is money. Waktu adalah uang. +Tom blames us. Tom menyalahkan kami. +Tom is cranky. Tom bete. +Tom is immune. Tom kebal. +Tom is polite. Tom itu ramah. +Tom looks bad. Tom terlihat buruk. +Tom was fired. Tom dipecat. +Tom was happy. Tom merasa bahagia. +Tom was lucky. Tom beruntung. +We helped Tom. Kami membantu Tom. +We need rules. Kita membutuhkan aturan-aturan. +We will fight. Kita akan bertarung. +We're leaving. Kami berangkat. +What did I do? Apa yang sudah kulakukan? +What happened? Apa yang terjadi? +What is a UFO? Apa itu UFO? +Which is mine? Yang mana punyaku? +You all right? Kamu tidak apa-apa? +You're sleepy. Kamu ngantuk. +Are you asleep? Kamu sudah tidur? +Are you hungry? Apa kau lapar? +Are you hungry? Apa kamu lapar? +Are you joking? Apa kau bercanda? +Can I help you? Bisa saya bantu? +Can you see it? Kamu masih belum mengerti? +Can you see it? Kamu masih belum memahaminya? +Change is good. Perubahan itu bagus. +Come back home. Kembali ke rumah. +Come back soon. Segeralah kembali. +Do you hate me? Apa kamu benci aku? +Don't say that. Jangan katakan itu! +Don't tease me. Jangan menggodaku. +Don't you know? Apa kamu tidak tahu? +Get out of bed! Turun dari kasur! +Get out of bed! Bangun dari tempat tidur! +Get out of bed. Bangunlah dari tempat tidur. +Good afternoon. Selamat siang. +Grab your gear. Ambil perlengkapanmu. +Happy birthday! Selamat ulang tahun! +He came by bus. Dia datang dengan bus. +He is a doctor. Dia adalah seorang dokter. +He is an actor. Dia adalah seorang aktor. +He looks young. Dia terlihat muda. +He was perfect. Dia sempurna. +How late is it? Sudah terlambat berapa lamakah? +How late is it? Sudah telat berapa lamakah? +How late is it? Sudah telat berapa lama? +How much is it? Berapa harganya? +I am a student. Saya adalah seorang siswa. +I am exhausted. Aku kelelahan. +I am in London. Aku ada di London. +I dislike eggs. Aku tidak suka telur. +I go to school. Saya pergi ke sekolah. +I hate dancing. Aku benci menari. +I have a fever. Saya demam. +I have a house. Saya punya rumah. +I have no clue. Aku tidak tahu sama sekali. +I have no time. Saya tidak punya waktu. +I like lasagna. Aku suka lasagna. +I love dessert. Saya suka makanan penutup. +I love lasagna. Aku suka lasagna. +I must decline. Aku harus menolak. +I need a stamp. Aku butuh perangko. +I need friends. Saya butuh teman. +I want a puppy. Aku ingin seekor anak anjing. +I wear glasses. Saya memakai kacamata. +I'll need help. Aku akan membutuhkan bantuan. +I'm a free man. Aku adalah lelaki yang bebas. +I'm not a baby. Saya bukan bayi. +I'm not joking. Aku tidak bercanda. +I'm not joking. Aku tidak sedang bercanda. +I'm not stupid. Saya tidak bodoh. +I'm reasonable. Aku orang yang rasional. +I'm sick of it. Aku muak dengan hal itu. +I'm very tired. Aku sangat capek. +I've moved out. Aku sudah pindah. +It must be Tom. Itu pasti Tom. +It's up to you. Terserah padamu. +Keep Tom quiet. Jaga agar Tom tetap diam. +Leave it to me. Serahkan semuanya padaku. +Leave me alone! Tinggalkan aku sendiri! +Leave me alone. Tinggalkan aku sendiri. +Lying is wrong. Berbohong adalah perbuatan yang salah. +Please stop it. Tolong hentikan itu. +Rise and shine. Bangunlah. +She is running. Dia sedang lari +She looked ill. Dia tampak sakit. +She swims well. Dia jago renang. +She's a beauty. Dia seorang yang cantik. +So let's do it. Jadi mari kita lakukan. +Stop screaming. Berhenti berteriak. +Take your time. Santai saja. +Thanks a bunch. Terima kasih banyak. +Thanks a bunch. Makasih banyak. +Thanks so much. Terima kasih banyak. +Thanks so much. Makasih banyak. +That felt good. Itu tadi enak. +That was a lie. Itu bohong. +That was close. Tadi itu hampir saja. +That's curious. Itu aneh. +That's cyanide. Itu sianida. +That's my line. Harusnya aku yang bilang begitu. +That's strange. Itu aneh. +That's strange. Anehnya. +That's unlucky. Sayang sekali. +There is a cat. Ada seekor kucing. +There is a cat. Ada kucing. +This is a joke. Bercanda. +This is absurd. Ini konyol. +This is my cat. Ini kucing saya. +This is so sad. Ini sangat menyedihkan. +This isn't fun. Ini tidak menyenangkan. +Time to get up. Waktunya bangun. +Tom can't swim. Tom tidak bisa berenang. +Tom ignored me. Tom mengabaikanku. +Tom is at home. Tom ada di rumah. +Tom is jittery. Tom gelisah. +Tom is nervous. Tom gugup. +Tom isn't weak. Tom tidak lemah. +Tom passed out. Tom pingsan. +Tom was crying. Tom menangis. +Tom was eating. Tom sedang makan tadi. +Tom works hard. Tom bekerja dengan keras. +Tom's not weak. Tom tidak lemah. +We made a deal. Kami membuat sebuah kesepakatan. +We'll be happy. Kami akan senang. +We're credible. Kami dapat dipercaya. +We're sociable. Kami seorang yang mudah bergaul. +What's so hard? Apa susahnya, sih? +Where were you? Tadi kamu di mana? +Where were you? Kamu di mana? +Where were you? Tadi kau ada di mana? +Where's Boston? Boston itu di mana? +Where's my car? Mobilku mana? +Whose are they? Itu punya siapa? +You have to go. Kamu harus pergi. +Are these yours? Apa ini milikmu? +Are we done yet? Apa kita masih belum selesai? +Are you certain? Apakah kamu yakin? +Are you certain? Apakah Anda yakin? +Are you certain? Apa kau yakin? +Are you in love? Apa kamu sedang jatuh cinta? +Are you kidding? Apa kau bercanda? +Are you serious? Apa kau serius? +Call my husband. Panggil suamiku. +Can I bring Tom? Boleh aku mengajak Tom? +Can it be fixed? Apa bisa dibetulkan? +Close that door. Tutup pintu itu. +Congratulations! Selamat! +Do you have one? Apa kamu punya satu? +Do you see that? Apa kamu melihatnya? +Do you see this? Apa kamu melihat ini? +Do you think so? Apa kamu pikir begitu? +Don't be afraid. Jangan takut. +Don't be scared. Jangan takut. +Don't bother me. Jangan ganggu aku. +Don't get angry. Jangan marah. +Don't get drunk. Jangan mabuk! +Don't stay here. Jangan menetap di sini. +Enjoy your food. Nikmati makananmu. +Enjoy your meal! Nikmati makananmu! +Enjoy your meal. Nikmati makananmu. +Get your things. Ambil barang-barangmu. +Grab your stuff. Ambil barangmu! +He has two cats. Dia punya dua kucing. +He likes tigers. Dia suka macan. +He looks gloomy. Dia terlihat suram. +He seems hungry. Dia sepertinya sedang lapar. +He was cheating. Dia berselingkuh. +He's helping me. Dia menolongku. +He's my brother. Dia kakak laki-lakiku. +He's my brother. Dia kakakku. +He's my brother. Dia adikku. +He's not in yet. Dia masih belum ada. +Hi! How are you? Hai! Bagaimana kabarmu? +Hi! How are you? Hai! Apa kabar? +Hi. How are you? Hai. Bagaimana kabarmu? +His name is Tom. Namanya Tom. +Hold on, please. Tolong tunggu sebentar. +Hold the candle. Pegang lilinnya! +How is it going? Apa kabar? +I agree totally. Saya sepenuhnya setuju. +I am from Spain. Saya berasal dari Spanyol. +I am very tired. Aku sangat capek. +I appreciate it. Aku mengapresiasinya. +I do understand. Aku mengerti. +I don't see Tom. Aku tidak melihat Tom. +I get the point. Aku mengerti maksudmu. +I have to study. Aku harus belajar. +I have two cars. Aku memiliki dua buah mobil. +I have two cats. Saya punya dua ekor kucing. +I haven't slept. Saya belum tidur. +I heard yelling. Aku mendengar suara teriakan. +I know the girl. Aku tahu perempuan itu. +I like your car. Aku suka mobilmu. +I love eggplant. Aku suka terung. +I need to study. Aku perlu belajar. +I owe you a lot. Aku berutang banyak padamu. +I surprised Tom. Aku mengangetkan Tom. +I totally agree. Saya sepenuhnya setuju. +I'll be at home. Aku akan di rumah. +I'll destroy it. Aku akan menghancurkannya. +I'm almost done. Aku hampir selesai. +I'm going to go. Aku akan pergi. +I'm going to go. Saya akan pergi. +I'm just joking. Aku cuma bercanda. +I'm not kidding. Aku tidak bercanda. +I'm not kidding. Aku tidak sedang bercanda. +I'm only joking. Aku cuma bercanda. +I'm tired of it. Aku lelah dengan hal itu. +I'm very hungry. Aku sangat lapar. +I'm your friend. Aku temanmu. +I've had enough. Aku sudah muak. +Is it important? Itu penting? +Is this correct? Apa ini benar? +Is this correct? Apakah ini benar? +It is up to you. Terserah padamu. +It isn't enough. Ini tidak cukup. +It isn't enough. Itu tidak cukup. +It looked cheap. Kelihatannya itu murah. +It was a thrill. Tadi itu seru sekali. +It wasn't funny. Ini tidak lucu. +It won't be fun. Itu tidak akan menyenangkan. +It's no problem. Tidak masalah. +It's not a joke. Ini bukan lelucon. +It's not broken. Ini tidak rusak. +It's not enough. Ini tidak cukup. +It's not enough. Itu tidak cukup. +It's ridiculous. Ini konyol. +It's ridiculous. Itu konyol. +It's time to go. Sudah waktunya untuk pergi. +Let me check it. Biarkan aku memeriksanya. +Let me see that. Biarkan aku melihatnya. +Let's come back. Ayo kembali. +Let's do it now. Mari kita lakukan sekarang. +Let's turn back. Ayo kembali. +Mistakes happen. Kesalahan bisa terjadi. +Mom, I'm hungry. Mama, aku lapar. +My house is big. Rumahku besar. +Nature is cruel. Alam itu kejam. +Never forget it. Jangan lupakan itu! +Never tell lies. Jangan pernah berbohong. +Now you're safe. Sekarang Anda sudah aman. +Please fix that. Tolong betulkan itu. +Please fix this. Tolong betulkan ini. +Please sit down. Silakan duduk. +Raise your hand. Angkat tanganmu. +Read this first. Baca ini dulu. +Rejection hurts. Penolakan itu menyakitkan. +She is a beauty. Dia seorang yang cantik. +She married him. Ia menikahinya. +She took it off. Dia menanggalkannya. +She's assertive. Ia tegas. +She's assertive. Dia tegas. +She's beautiful. Dia cantik. +Sorry, I forgot. Maaf, saya melupakannya. +Thanks for this. Terima kasih untuk ini. +That dog jumped. Anjing itu lompat. +That isn't fair. Itu tidak adil. +That's nonsense. Itu omong kosong. +That's peculiar. Itu aneh. +The book is red. Buku itu berwarna merah. +The room is hot. Ruangannya panas. +They are actors. Mereka adalah aktor. +They feared you. Mereka takut padamu. +They left early. Mereka pulang lebih awal. +They left early. Mereka pergi lebih awal. +This is awkward. Ini aneh. +This is my room. Ini adalah kamarku. +This is my wife. ini istriku. +This is natural. Ini alami. +This is no joke. Ini bukan lelucon. +This is on sale. Ini dijual. +This is strange. Ini aneh. +Tom blacked out. Tom pingsan. +Tom is home now. Tom sedang di rumah sekarang. +Tom is my buddy. Tom adalah temanku. +Tom is very old. Tom sangat tua. +Tom isn't happy. Tom tidak senang. +Tom kept eating. Tom terus makan. +Tom lied to you. Tom berbohong padamu. +Tom looks upset. Tom terlihat sedih. +Tom needs a cab. Tom butuh taksi. +Tom needs water. Tom butuh air. +Tom quit school. Tom berhenti sekolah. +Tom seems upset. Tom sepertinya sedih. +Tom was injured. Tom telah terluka. +Tom was singing. Tom sedang bernyanyi tadi. +Tom's concerned. Tom khawatir. +Tom's dangerous. Tom itu berbahaya. +Tom's my friend. Tom itu temanku. +Wasn't it awful? Bukankah itu mengerikan? +We captured Tom. Kita menangkap Tom. +We did our best. Kami melakukan yang terbaik. +We felt at home. Kami merasa seperti di rumah. +We never forget. Kami tidak pernah lupa. +We never forget. Kita tidak pernah lupa. +We're ambitious. Kami ambisius. +What is pottery? Apa itu tembikar? +What's going on? Ada apa? +What's happened? Apa yang terjadi? +What's your job? Apa pekerjaanmu? +What've you got? Kalian punya apa? +What've you got? Kalian dapat apa? +When can we eat? Kapan kita bisa makan? +Where did he go? Dia pergi ke mana? +Where did it go? Ke mana perginya? +Where is my car? Mobilku mana? +Where is my pen? Di mana pulpenku? +Where were they? Di mana mereka? +Where were they? Di manakah mereka? +Who contributed? Siapa yang berkontribusi? +Who is that boy? Siapa anak itu? +Why did you ask? Mengapa kamu bertanya? +Why is she here? Kenapa dia ada di sini? +You let me down. Kamu membuatku kecewa. +You let me down. Kamu mengecewakanku. +You look unsure. Kamu terlihat tidak yakin. +Your time is up. Waktumu sudah habis. +Anyone can do it. Siapapun bisa melakukannya. +Are we all ready? Apakah kita siap? +Are you for real? Apa kau serius? +Are you positive? Apa kamu sudah positif? +Are you sleeping? Kamu lagi tidur? +Can anyone drive? Apakah ada orang yang bisa mengemudi? +Can you ski well? Apa kamu bisa berski dengan baik? +Control yourself! Kendalikan dirimu! +Control yourself. Kendalikan dirimu. +Did Tom go alone? Tom pergi sendiri? +Did she say that? Dia tadi bilang begitu? +Did you have fun? Apa kau bersenang-senang? +Did you have fun? Apa kamu senang? +Do you cry often? Apakah kamu sering menangis? +Do you feel sick? Apa kamu merasa sakit? +Do you live here? Apakah kamu tinggal di sini? +Do you live here? Apakah Anda tinggal di sini? +Don't mention it. Tidak apa-apa. +Don't you get it? Apa kamu tidak mengerti? +Enough is enough. Cukup cukup. +He can swim fast. Dia dapat berenang dengan cepat. +He had few teeth. Dia punya sedikit gigi. +He has a bicycle. Dia memiliki sebuah sepeda. +He is in trouble. Dia dalam masalah. +He is my brother. Dia adalah adikku. +He is my brother. Dia adalah kakakku. +He is still here. Dia masih di sini. +He left just now. Dia baru saja pergi. +He ran into debt. Dia mengambil pinjaman uang. +He was acquitted. Dia dinyatakan tidak bersalah. +He's intelligent. Dia pintar. +He's still young. Dia masih muda. +Here is your bag. Ini dia tasmu. +Hold on a second. Tunggu sebentar. +How about a bite? Mau coba satu gigitan? +How could I know? Bagaimana aku bisa mengetahuinya? +How does it look? Bagaimana kelihatannya? +How tall are you? Seberapa tinggi kamu? +How will it work? Bagaimana cara kerjanya? +How would I know? Bagaimana aku bisa mengetahuinya? +How're you doing? Apa kabar? +I agree with you. Aku setuju denganmu. +I also like cake. Aku juga suka kue. +I am not kidding. Aku tidak bercanda. +I am not kidding. Aku tidak sedang bercanda. +I am only joking. Saya hanya bergurau. +I am only joking. Aku cuma bercanda. +I am very hungry. Aku sangat lapar. +I believe in you. Aku percaya padamu. +I came yesterday. Aku datang kemarin. +I can't say that. Aku tidak bisa mengatakan itu. +I caught the flu. Aku terkena flu. +I don't think so. Aku rasa tidak. +I found the keys. Kuncinya ketemu. +I had a bad cold. Aku kena flu berat. +I hope I survive. Aku harap aku akan bertahan hidup. +I know only this. Aku hanya tahu ini. +I know your name. Aku tahu namamu. +I like chocolate. Saya suka coklat. +I like red roses. Aku suka mawar merah. +I like your hair. Aku suka rambutmu. +I love chocolate. Saya suka coklat. +I love this song. Aku sangat suka lagu ini. +I love your hair. Aku sangat suka rambutmu. +I made it myself. Aku membuatnya sendiri. +I must leave now. Saya harus pergi sekarang. +I play in a band. Aku tergabung dalam sebuah kelompok musik. +I read the label. Aku membaca labelnya. +I want to see it. Aku ingin melihatnya. +I want you to go. Aku ingin kamu pergi. +I was frightened. Aku ketakutan. +I'll be with Tom. Aku dengan Tom. +I'll go upstairs. Aku akan naik ke lantai atas. +I'll go with you. Aku akan pergi denganmu. +I'll take my car. Aku akan mengambil mobilku. +I'm 18 years old. Saya berusia 18 tahun. +I'm Tom's driver. Saya supir Tom. +I'm a bookkeeper. Aku seorang penata buku. +I'm an alcoholic. Saya kecanduan alkohol. +I'm disappointed. Aku kecewa. +I'm done working. Aku sudah selesai bekerja. +I'm just kidding. Aku cuma bercanda. +I'm not a doctor. Aku bukan dokter. +I'm not an idiot. Saya bukan idiot. +I'm not bluffing. Aku tidak sedang menggertakmu. +I'm proud of you. Aku bangga padamu. +I'm really tired. Aku sangat capek. +I'm sick of this. Aku muak dengan hal ini. +I'm still sleepy. Aku masih ngantuk. +I'm super hungry. Aku sangat lapar. +I've got a fever. Saya demam. +Is everything OK? Apa semuanya baik-baik saja? +Is that your car? Apakah itu mobilmu? +Is this accurate? Apakah ini tepat? +It's a nice town. Ini kota yang bagus. +It's not a trick. Ini bukan tipuan. +It's on the sofa. Itu ada di atas sofa. +It's very boring. Ini sangat membosankan. +Let's cross here. Mari menyeberang di sini. +Let's go back in. Ayo masuk kembali ke dalam. +Let's have a try. Mari kita coba. +Let's just do it. Sudah ayo kita lakukan saja. +Let's live it up! Mari bersenang-senang! +Let's run for it. Ayo lari. +Listen carefully. Dengarkan baik-baik. +Mary is graceful. Mary adalah seorang yang anggun. +My dog likes you. Anjingku menyukaimu. +My pulse is fast. Denyut nadiku cepat. +My rifle's empty. Senapanku kosong. +My stomach hurts. Perutku sakit. +Nice to meet you. Senang bertemu denganmu. +No one asked you. Tidak ada yang bertanya padamu. +No one's perfect. Tidak ada orang yang sempurna. +Nobody asked you. Tidak ada yang bertanya padamu. +Nobody must know. Tidak ada yang harus tahu. +Nobody's perfect. Tidak ada orang yang sempurna. +Nothing happened. Tak ada yang terjadi. +Please be seated. Silakan duduk. +Please don't cry. Janganlah menangis. +Please don't die! Tolong jangan mati! +Please don't die. Tolong jangan mati. +Please stop that. Tolong hentikan itu. +Put on your coat. Pakai jasmu. +Raise your hands! Angkat tanganmu! +Raise your hands. Angkat tanganmu. +Shall we go home? Mau pulang? +She has dry hair. Dia memiliki rambut yang kering. +She is a student. Dia seorang siswa. +She is beautiful. Dia cantik. +She is mad at me. Dia marah padaku. +She is not young. Dia tidak muda. +She's helping me. Dia menolongku. +She's not a liar. Dia bukan seorang pembohong. +Sit down, please. Silakan duduk. +Sit down, please. Tolong duduklah. +Stop daydreaming. Berhentilah melamun. +Thank you kindly. Terima kasih banyak. +Thanks a million. Terima kasih banyak. +Thanks a million. Makasih banyak. +Thanks very much. Terima kasih banyak. +Thanks very much. Makasih banyak. +That's wonderful. Itu luar biasa. +The bill, please. Tolong bonnya. +The box is empty. Kotak itu kosong. +There's no proof. Tidak ada bukti. +They both agreed. Mereka berdua setuju. +They won the day. Mereka menang. +This is nonsense. Ini omong kosong. +This is puzzling. Ini membingungkan. +Time is valuable. Waktu itu berharga. +Tom became blind. Tom menjadi buta. +Tom has a butler. Tom punya kepala pelayan. +Tom helped a lot. Tom membantu banyak. +Tom hurt his leg. Kaki Tom terluka. +Tom is a student. Tom adalah seorang siswa. +Tom is courteous. Tom itu ramah. +Tom is easygoing. Tom itu santai. +Tom is forgetful. Tom itu pelupa. +Tom is my friend. Tom adalah temanku. +Tom isn't famous. Tom tidak terkenal. +Tom kept talking. Tom terus berbicara. +Tom lost his hat. Tom kehilangan topinya. +Tom lost his job. Tom kehilangan pekerjaannya. +Tom sounds upset. Tom sepertinya sedih. +Tom studies hard. Tom belajar dengan tekun. +Tom walks slowly. Tom berjalan dengan pelan. +Tom was divorced. Tom diceraikan. +Tom was poisoned. Tom keracunan. +Tom was worn out. Tom kelelahan. +Tom will improve. Tom akan berkembang. +Tom's quite good. Tom lumayan bagus. +Turn to the left. Belok ke kiri. +Walk ahead of me. Berjalanlah di depanku. +We won this time. Kali ini kita menang. +We'll be rescued. Kita akan diselamatkan. +We're nonsmokers. Kami bukan perokok. +What could I say? Apa yang dapat saya katakan? +What did you buy? Apa yang kamu beli? +What did you buy? Beli apa? +What did you eat? Apa yang kau makan? +What do you have? Kalian punya apa? +What do you have? Anda punya apa? +What do you want? Apa maumu? +What do you want? Apa yang kamu inginkan? +What do you want? Apa yang Anda inginkan? +What does it say? Apa yang dikatakannya? +What have I done? Apa yang sudah kulakukan? +What is going on? Ada apa? +What woke you up? Apa yang membuatmu terbangun? +What'll you have? Kamu mau yang mana? +What's your name? Siapa namamu? +Where did you go? Ke mana kamu pergi? +Where is Customs? Di mana Bea dan Cukai? +Where will we go? Ke mana kita akan pergi? +Where's the exit? Di mana pintu keluarnya? +Whose plan is it? Rencana siapakah ini? +Why did you stop? Kenapa kau berhenti? +Why should I pay? Mengapa saya harus membayar? +Will you risk it? Apa kamu mau mengambil risiko? +You don't listen. Kamu tidak mendengar. +You don't own me. Kamu tidak memilikiku. +You look worried. Kamu terlihat khawatir. +You may be right. Mungkin kamu benar. +You may go there. Kamu boleh pergi ke sana. +You need therapy. Kamu butuh terapi. +You should sleep. Kamu harus tidur. +You're too young. Kamu itu masih bau kencur. +Your face is red. Mukamu merah. +Are you all ready? Apa kalian semua sudah siap? +Are you all right? Kamu tidak apa-apa? +Can I have a bite? Boleh aku mencoba satu gigitan? +Can we talk later? Bisakah kita berbicara nanti? +Did they fire you? Apakah mereka memecatmu? +Didn't I warn you? Bukankah saya sudah memperingatkanmu? +Do you have a pen? Apa kau punya pulpen? +Does she know you? Apa dia mengenalmu? +Don't let me down. Jangan buat aku kecewa. +Don't let me down. Jangan mengecewakanku. +Don't pull my leg! Jangan mempermainkanku! +Don't you feel it? Apa kamu merasakannya? +Don't you hear it? Apa kamu mendengarnya? +Don't you see Tom? Apakah kamu melihat Tom? +Everybody laughed. Semuanya tertawa. +Get up out of bed. Bangunlah dari tempat tidur. +Goodnight, ladies. Selamat malam nona-nona. +He can be trusted. Dia bisa dipercaya. +He is a quiet man. Dia orangnya pendiam. +He is from France. Dia dari Perancis. +He is intelligent. Dia pintar. +He is still alive. Dia masih hidup. +He is still angry. Dia masih marah. +He is still young. Dia masih muda. +He isn't here yet. Dia masih belum di sini. +He kept on crying. Dia terus menangis. +He will come soon. Ia akan segera datang. +He's not here yet. Dia masih belum di sini. +His room's a mess. Kamarnya sangat berantakan. +How about a drink? Bagaimana kalau minuman? +How are you doing? Bagaimana kabar Anda? +I admit I'm wrong. Aku akui aku salah. +I am disappointed. Aku kecewa. +I am not a doctor. Saya bukan dokter. +I appreciate that. Aku mengapresiasinya. +I appreciate this. Aku menghargai ini. +I can't trust him. Aku tidak bisa mempercayai dia. +I cannot help you. Saya tidak dapat membantumu. +I cried all night. Aku menangis sepanjang malam. +I don't blame you. Aku tidak menyalahkanmu. +I don't like eggs. Aku tidak suka telur. +I don't trust you. Aku tidak mempercayaimu. +I don't trust you. Aku tidak percaya padamu. +I doubt his story. Saya meragukan ceritanya. +I feel good today. Aku merasa baik hari ini. +I have a headache. Aku sakit kepala. +I like this store. Aku suka toko ini. +I like watermelon. Aku suka semangka. +I liked this film. Dulu aku suka film ini. +I met Tom tonight. Aku bertemu Tom malam ini. +I missed my train. Aku ketinggalan keretaku. +I need some money. Aku membutuhkan uang. +I need some paper. Aku perlu kertas. +I saw Tom earlier. Barusan aku melihat Tom. +I want a lot more. Aku mau lebih banyak. +I want some paper. Aku ingin kertas. +I want to see him. Aku ingin bertemu dengannya. +I was just joking. Saya hanya bergurau. +I was just joking. Aku cuma bercanda. +I was very hungry. Aku sangat lapar. +I wish I was dead. Aku harap aku mati. +I won't be silent. Aku tidak akan diam. +I worry about him. Aku mengkhawatirkan dia. +I'll be in my car. Aku ada di dalam mobil. +I'll give it back. Aku akan mengembalikannya. +I'll never forget. Aku tidak akan pernah lupa. +I'll pay the bill. Aku akan membayar tagihannya. +I'll send it back. Aku akan mengirimnya kembali. +I'm a human being. Aku adalah manusia. +I'm an accountant. Aku seorang akuntan. +I'm awfully tired. Aku benar-benar capek. +I'm feeling tired. Aku merasa capek. +I'm not a student. Aku bukan pelajar. +I'm not a student. Aku bukan siswa. +I'm not a student. Saya bukan siswa. +I'm not into that. Aku tidak begitu suka dengan hal semacam itu. +I'm really hungry. Aku sangat lapar. +I'm tired of this. Aku lelah dengan hal ini. +I've got to study. Aku harus belajar. +Is Tom still sick? Apakah Tom masih sakit? +Is that important? Itu penting? +It doesn't matter. Tidak masalah. +It isn't optional. Ini tidak fakultatif. +It should be fine. Semuanya akan baik-baik saja. +It was no trouble. Tidak ada masalah. +It's all my fault. Ini semua salahku. +It's confidential. Ini rahasia. +It's my only hope. Ini satu-satunya harapan saya. +It's not my fault. Itu bukan salahku. +It's pretty weird. Itu sangat aneh. +It's starting now. Sudah dimulai sekarang. +Keep away from me. Menjauhlah dariku. +Keep your chin up. Tetaplah semangat. +Leave me in peace! Tinggalkan aku sendiri! +Let's do it again. Mari kita melakukannya lagi. +Let's do it again. Mari kita lakukan lagi. +Let's do this now. Mari kita melakukannya sekarang. +Let's go to sleep. Mari kita tidur. +Let's go to sleep. Mari kita pergi tidur. +Let's have a look. Mari kita coba lihat. +Let's take a look. Mari kita coba lihat. +May I take a rest? Bolehkah saya istirahat? +May I try this on? Bolehkah saya mencoba mengenakan ini? +My bag was stolen. Tasku dicuri. +My hobby is music. Hobiku musik. +My house is dirty. Rumahku kotor. +No one is perfect. Tidak ada orang yang sempurna. +Nobody is perfect. Tidak ada orang yang sempurna. +Please turn right. Tolong belok kanan. +Put on some music. Putarlah musik. +Put your hands up! Angkat tanganmu! +Put your hands up! Angkat kedua tanganmu! +Put your hands up. Angkat tanganmu. +See you next week! Sampai jumpa minggu depan! +She is aggressive. Dia agresif. +Should I help you? Mau saya bantu? +Stop following me. Berhenti mengikutiku. +Tell me the story. Ceritakan padaku. +Tell me the truth. Katakan padaku yang sebenarnya. +That house is big. Rumah itu besar. +That isn't enough. Itu tidak cukup. +That was our home. Itu dulunya rumah kami. +That was our home. Itu dulunya rumah kita. +That won't happen. Itu tidak akan terjadi. +That won't happen. Itu tak 'kan terjadi. +That's all I have. Ini semua yang saya punya. +That's my brother. Itu kakakku. +That's my brother. Itu adikku. +That's not enough. Itu tidak cukup. +The check, please. Tolong bonnya. +The train is here. Keretanya di sini. +These are my boys. Mereka ini adalah anak-anak laki-lakiku. +They'll try again. Mereka akan mencobanya lagi. +This is ludicrous. Ini menggelikan. +This is my sister. Ini adikku. +This is very cool. Ini sangat keren. +This isn't a joke. Ini bukan lelucon. +This isn't enough. Ini tidak cukup. +Today is Thursday. Hari ini hari Kamis. +Tom broke the law. Tom melanggar hukum. +Tom gave me a pen. Tom memberiku sebuah pena. +Tom has been good. Tom selalu dalam keadaan baik. +Tom has big hands. Tom punya tangan yang besar. +Tom has lost hope. Tom telah kehilangan harapan. +Tom is a bit pale. Tom agak pucat. +Tom is a bookworm. Tom itu kutu buku. +Tom is a good guy. Tom adalah pria yang baik. +Tom is a good man. Tom adalah pria yang baik. +Tom is a murderer. Tom seorang pembunuh. +Tom is distressed. Tom tertekan. +Tom is having fun. Tom sedang bersenang-senang. +Tom is in the car. Tom sedang berada di dalam mobil. +Tom is not famous. Tom tidak terkenal. +Tom is quite good. Tom lumayan bagus. +Tom is stuttering. Tom berbicara dengan gagap. +Tom is unemployed. Tom adalah seorang penganggur. +Tom is very funny. Tom sangat lucu. +Tom isn't thirsty. Tom tidak haus. +Tom looks baffled. Tom terlihat kebingungan. +Tom looks puzzled. Tom terlihat kebingungan. +Tom looks shocked. Tom terlihat syok. +Tom misses Boston. Tom merindukan Boston. +Tom seems puzzled. Tom sepertinya kebingungan. +Tom seems shocked. Tom sepertinya syok. +Tom seems stunned. Tom sepertinya terkejut. +Tom set the table. Tom mengatur meja. +Tom shut his eyes. Tom memejamkan mata. +Tom staggered out. Tom terhuyung-huyung keluar. +Tom stood in line. Tom berjajar dalam barisan. +Tom tried to help. Tom coba membantu. +Tom used to smoke. Tom dulunya merokok. +Tom was delighted. Tom merasa gembira. +Tom was exhausted. Tom kelelahan. +Tom was fortunate. Tom beruntung. +Tom, are you okay? Tom, kamu gak apa-apa? +Tomorrow's payday. Besok hari gajian. +Turn on the radio. Nyalakan radionya. +Turn on your back. Balikkan badanmu. +Turn to the right. Belok ke kanan. +We got up at dawn. Kami bangun saat subuh. +We tried our best. Kami telah mencoba yang terbaik. +We want our money. Kami ingin uang kami. +We're helping Tom. Kami sedang membantu Tom. +We've been trying. Kami mencoba. +What did you make? Apa yang kau buat? +What did you make? Kamu bikin apa? +What do they know? Apa yang mereka tahu? +What do you think? Bagaimana menurutmu? +What does it cost? Berapa harganya? +What have you got? Kalian dapat apa? +What is the price? Berapa harganya? +What is your name? Siapa nama Anda? +What is your name? Siapa namamu? +What'll you drink? Kamu mau minum apa? +What's the matter? Ada apa? +What's the matter? Ada masalah apa? +What's the matter? Ada masalah? +What's your major? Jurusanmu apa? +What's your score? Berapa nilaimu? +When did Tom call? Kapan Tom menelepon? +Where did they go? Ke mana mereka pergi? +Where did you eat? Kamu makan di mana? +Where is my watch? Di mana jamku? +Where is the exit? Di mana pintu keluarnya? +Where's Tom today? Di mana Tom hari ini? +Where's your coat? Mana jasmu? +Where've you been? Dari mana kamu? +Where've you been? Ke mana saja kamu? +Whose car is this? Mobil siapa ini? +Why did you do it? Kenapa kau melakukannya? +Why not try it on? Kenapa tidak dicoba? +Why should I quit? Kenapa saya harus keluar? +Why should I wait? Mengapa saya harus menunggu? +You are in my way. Kau berada di jalanku. +You don't need it. Kau tidak memerlukannya. +You make me happy. Kamu membuatku bahagia. +You must be tired. Kamu pasti lelah. +You talk too much. Kau terlalu banyak bicara. +You work too hard. Kamu bekerja terlalu keras. +You're a murderer. Kau seorang pembunuh. +You're aggressive. Kau agresif. +A cat has two ears. Kucing punya dua telinga. +A cat is not human. Kucing bukan manusia. +Anyone can do that. Siapapun bisa melakukan itu. +Are you down there? Apakah kamu di sana? +Are you down there? Apakah kamu di situ? +Are you in a hurry? Apa kamu sedang terburu-buru? +Are you kidding me? Apa kau bercanda? +Are you quite sure? Apa kau sudah cukup yakin? +Are you sure of it? Apa kau yakin dengan hal itu? +Are you vegetarian? Apa kau nabatiwan? +Bring me the flute. Bawakan aku serulingnya. +Can I borrow those? Bolehkah saya meminjam itu? +Can it be repaired? Bisakah diperbaiki? +Cats are not human. Kucing bukan manusia. +Did you sleep well? Apakah kamu tidur nyenyak? +Do you feel guilty? Apa kamu merasa bersalah? +Do you feel guilty? Apa Anda merasa bersalah? +Do you feel guilty? Apakah kamu merasa bersalah? +Do you feel guilty? Apakah Anda merasa bersalah? +Do you have a plan? Apa kau memiliki sebuah rencana? +Do you like it all? Apa kamu suka semuanya? +Do you need a hand? Apa kamu butuh bantuan? +Do you remember us? Apa kau mengingat kami? +Do you want to try? Anda ingin mencoba? +Does Tom work here? Apakah Tom bekerja di sini? +Does it hurt a lot? Apakah ini sangat sakit? +Don't give me that. Jangan berikan itu padaku! +Don't say his name. Jangan sebut namanya. +Don't throw stones. Jangan melempar batu. +Don't touch my car. Jangan sentuh mobilku. +Get me up at eight. Bangunkan aku jam delapan. +Give me your money. Berikan uangmu. +Go brush your hair. Pergi dan sikat rambutmu. +Have we met before? Apakah kita pernah bertemu sebelumnya? +Have we met before? Apa kita pernah bertemu sebelumnya? +He doesn't like us. Dia tidak suka dengan kita. +He hasn't come yet. Dia belum datang. +He took a week off. Dia mengambil libur selama seminggu. +He works in a bank. Dia bekerja di sebuah bank. +Hello, how are you? Halo, apa kabar? +Hello, how are you? Halo, bagaimana kabarmu? +Hi, how's it going? Hai, bagaimana kabarmu? +Hold on one second. Tunggu sebentar. +How can I help you? Ada yang bisa saya bantu? +How did you get it? Bagaimana kamu bisa mendapatkannya? +How is your family? Bagaimana kabar keluargamu? +How's your brother? Bagaimana keadaan saudaramu? +I agree completely. Saya sepenuhnya setuju. +I am not a student. Aku bukan pelajar. +I am not a student. Aku bukan siswa. +I am not a student. Saya bukan siswa. +I am sorry for you. Saya turut berduka. +I broke Tom's nose. Aku melukai hidung Tom. +I can't live alone. Aku tidak bisa hidup seorang diri. +I can't sleep well. Saya tidak dapat tidur nyenyak. +I completely agree. Saya sepenuhnya setuju. +I did it like this. Aku melakukannya seperti ini. +I don't have a car. Saya tidak memiliki mobil. +I don't know where. Saya tak tahu di mana. +I have a white cat. Saya mempunyai kucing putih. +I have to get home. Aku harus pulang. +I hope you like it. Aku harap kau menyukainya. +I know what I feel. Aku tahu apa yang aku rasakan. +I know what I felt. Aku tahu apa yang aku rasakan. +I know your father. Aku tahu ayahmu. +I missed the train. Aku ketinggalan keretanya. +I need information. Aku butuh informasi. +I saw him run away. Aku melihatnya melarikan diri. +I swim once a week. Aku berenang seminggu sekali. +I think he is sick. Saya pikir dia sakit. +I told Tom to stop. Aku menyuruh Tom untuk berhenti. +I want to die soon. Aku ingin cepat mati. +I wanted red shoes. Aku ingin sepatu merah. +I was quite hungry. Aku sangat lapar. +I wish I were dead. Aku harap aku mati. +I wish I were rich. Aku harap aku kaya. +I'll accompany you. Aku akan menemanimu. +I'll bring it back. Aku akan membawanya kembali. +I'll come by later. Saya akan datang nanti. +I'll come with you. Aku akan ikut denganmu. +I'll do what I can. Akan kulakukan yang kubisa. +I'm afraid of cats. Aku takut kucing. +I'm from Singapore. Saya dari Singapura. +I'm getting hungry. Aku mulai lapar. +I'm giving it back. Aku mengembalikannya. +I'm going downtown. Aku mau pergi ke pusat kota. +I'm going with you. Aku akan pergi denganmu. +I'm holding a book. Aku menggenggam sebuah buku. +I'm not going back. Aku tidak akan kembali. +I'm scared of cats. Aku takut kucing. +Is Tom left-handed? Apakah Tom kidal? +Is everything okay? Apa semuanya baik-baik saja? +Is this book yours? Buku ini milikmu? +Is your room quiet? Apa kamarmu sunyi? +It is almost three. Sekarang hampir jam tiga. +It was really nice. Itu bagus sekali. +It wasn't my fault. Itu bukan salahku. +It's already seven. Ini sudah jam tujuh. +It's already seven. Sudah jam tujuh. +It's very relaxing. Ini sangat menenangkan. +Just open the door. Sudah buka saja pintunya. +Just wait a second. Tunggu sebentar. +Keep your promises. Tepati janjimu. +Leave me alone now. Tinggalkan aku sendiri sekarang. +Let me have a look. Coba saya lihat. +Let's do it my way. Mari kita lakukan dengan caraku. +Let's stay married. Mari kita pertahankan pernikahan kita. +May I run with you? Bolehkah aku berlari bersamamu? +May I speak to Tom? Bisakah saya berbicara dengan Tom? +Mistakes do happen. Kesalahan bisa terjadi. +My father is frank. Ayahku adalah seorang yang suka berterus terang. +My hobby is skiing. Hobi saya bermain ski. +My legs still hurt. Kakiku masih sakit. +Please call a taxi. Tolong panggilkan taksi. +Please go get help. Tolong pergi dan panggil bantuan. +Please have a seat. Silakan duduk. +Please repair this. Tolong perbaiki ini. +Please take a seat. Silakan duduk. +She looked excited. Dia terlihat bersemangat. +She looks confused. Dia nampak bingung. +She looks familiar. Ia terlihat tidak asing. +She will come soon. Ia akan segera datang. +She's from Somalia. Dia dari Somalia +Some of us hate it. Beberapa dari kami membencinya. +Something happened. Sesuatu telah terjadi. +Take off your coat. Lepaskan jasmu. +Tell me everything. Beritahukan semuanya kepada saya. +Tell me what to do. Katakan padaku apa yang harus aku lakukan. +Thank you for this. Terima kasih untuk ini. +That doll is scary. Boneka itu seram. +That doll is scary. Boneka itu menyeramkan. +That guy's amazing. Orang itu menakjubkan. +That will be funny. Itu akan jadi menggelikan. +That's pretty cool. Itu sangat keren. +That's unfortunate. Sayang sekali. +The apples are big. Apel-apel itu besar. +The barn was empty. Lumbungnya kosong. +The boy is jumping. Anak laki-laki itu melompat. +The car hit a tree. Mobil itu menabrak pohon. +The dog is jumping. Anjing itu lompat. +The earth is round. Bumi itu bulat. +The lock is broken. Kuncinya rusak. +The stamp came off. Perangkonya lepas. +The sun is setting. Mataharinya mulai terbenam. +The waves are high. Ombaknya tinggi. +They were all busy. Mereka semua sedang sibuk. +This book is yours. Buku ini milikmu. +This has been good. Ini selalu enak. +This is good sushi. Ini adalah sushi yang enak. +This is my brother. Ini adikku. +This is not a joke. Ini bukan lelucon. +This is not enough. Ini tidak cukup. +This is ridiculous! Konyol! +This is ridiculous. Ini konyol. +This is surprising. Ini mengejutkan. +Tom broke that one. Tom merusakkan yang satu itu. +Tom didn't mean it. Tom tidak bermaksud demikian. +Tom has a headache. Tom sakit kepala. +Tom has been awful. Tom sedang tidak bahagia. +Tom has passed out. Tom pingsan. +Tom is Mary's boss. Tom adalah bos dari Mary. +Tom is a bartender. Tom adalah seorang pelayan bar. +Tom is a good cook. Tom adalah seorang yang pandai memasak. +Tom is at home now. Tom sedang di rumah sekarang. +Tom is on the dock. Tom ada di dok. +Tom is pretty good. Tom sangat bagus. +Tom is probably OK. Tom mungkin baik-baik saja. +Tom looked at Mary. Tom melihat kepada Mary. +Tom looked puzzled. Tom terlihat kebingungan. +Tom looks confused. Tom terlihat kebingungan. +Tom must be asleep. Tom pasti tertidur. +Tom must be lonely. Tom pasti kesepian. +Tom needs a friend. Tom membutuhkan seorang teman. +Tom seems confused. Tom sepertinya kebingungan. +Tom should be here. Tom seharusnya ada di sini. +Tom won't hurt you. Tom tidak akan menyakitimu. +Tom works too much. Tom terlalu banyak bekerja. +Tom, you're a liar. Tom, kamu pembohong. +Tomorrow is payday. Besok hari gajian. +Turn the volume up. Naikkan volume suaranya. +Washing is my work. Pekerjaan saya mencuci. +We don't get along. Kami tidak akrab. +We don't have much. Kami tidak punya banyak. +We have many goals. Kita punya banyak tujuan. +We were doing fine. Kami baik-baik saja. +We're closed today. Hari ini kami tutup. +We're out of money. Uang kami habis. +What I say is true. Apa yang aku katakan itu benar. +What a stupid joke! Dasar lelucon bego! +What are you doing? Kamu lagi ngapain? +What did Tom think? Apa yang telah Tom pikirkan? +What happened here? Apa yang terjadi di sini? +What is my purpose? Apa tujuan yang ingin aku capai? +What should I wear? Baju mana yang mesti aku pakai? +What's the problem? Ada masalah apa? +What's the problem? Ada masalah? +What's this called? Disebut apa ini? +When did you start? Kapan kamu mulai? +When will it begin? Akan dimulai jam berapa? +Where did you stay? Di mana Anda menginap? +Where has she gone? Ke mana perginya dia? +Where is your coat? Di mana jasmu? +Where is your room? Kamarmu yang mana? +Where was he going? Dia pergi ke mana? +Where will we meet? Di mana kita akan bertemu. +Where're you going? Kamu mau ke mana? +Where're you going? Mau ke mana? +Which is your book? Bukumu yang mana? +Who are those guys? Siapa orang-orang itu? +Who wrote the book? Siapa yang menulis buku itu? +Who's your teacher? Siapa gurumu? +Whose book is this? Buku siapa ini? +Why are they angry? Kenapa mereka marah? +Why can't you come? Kenapa kamu tidak bisa datang? +Why did you go out? Mengapa kamu pergi keluar? +Why do you need it? Kenapa kau membutuhkannya? +Wish you were here. Berharap kau di sini. +You are very brave. Kamu berani sekali. +You can study here. Kamu bisa belajar di sini. +You look very pale. Kamu terlihat sangat pucat. +You were too young. Kamu itu masih bau kencur. +You're a good cook. Kamu koki yang terampil. +You're interfering. Kau menghalangi. +You're quite right. Kau memang benar. +You're still green. Kamu itu masih muda. +You're still green. Kamu itu masih bau kencur. +You're still young. Kamu itu masih muda. +You've made my day. Kau membuatku merasa sangat bahagia. +Your time has come. Waktumu sudah tiba. +Anybody can do that. Siapa pun bisa melakukan itu. +Anybody can do this. Siapapun bisa melakukan ini. +Are you guys hungry? Apa kalian lapar? +Are you on Facebook? Apa kau punya Facebook? +Breakfast is served. Makan pagi telah dipesan. +Did anybody come by? Adakah orang yang mampir? +Did you leave a tip? Apa kau meninggalkan tip? +Divide this in half. Bagilah ini menjadi dua. +Do not go near them. Jangan mendekati mereka. +Do you have any CDs? Apa kau memiliki CD? +Do you keep a diary? Apa kamu menulis buku harian? +Do you like bowling? Apakah kamu suka bowling? +Do you travel a lot? Apakah Anda banyak melakukan perjalanan? +Don't disappoint me. Jangan mengecewakanku. +Don't even go there. Jangan pernah pergi ke sana. +Don't make me laugh! Jangan buat aku tertawa! +Don't make me laugh! Jangan konyol! +Don't make me laugh. Jangan membuatku tertawa. +Don't work too hard! Jangan bekerja terlalu keras! +Don't work too hard. Jangan bekerja terlalu keras. +Don't you feel cold? Apakah kamu tidak merasa dingin. +Every day is a gift. Setiap hari adalah hadiah. +Everyone has faults. Semua orang punya kekurangan. +Everything is great. Semuanya bagus. +Have you had dinner? Kamu sudah makan malam? +Have you had dinner? Apa kau sudah makan malam? +He became a pianist. Ia menjadi seorang pianis. +He gave me the salt. Dia memberiku garam. +He got rich quickly. Dia kaya dengan cepat. +He has a good brain. Dia punya otak yang cerdas. +He should have come. Dia seharusnya datang. +He was sound asleep. Dia tertidur lelap. +He went to the shop. Dia pergi ke toko. +Her face turned red. Wajahnya memerah. +Here is your change. Ini kembalian Anda. +His eyesight is bad. Penglihatannya sangat buruk. +How I've missed you! Aku sangat rindu padamu! +I am about your age. Aku hampir seusia denganmu. +I am fed up with it. Aku sudah jenuh akan hal itu. +I am going with you. Aku akan pergi denganmu. +I am short of money. Aku kekurangan uang. +I believe in ghosts. Aku percaya akan adanya hantu. +I can't do that yet. Saya belum sanggup melakukannya. +I can't give up now. Aku tidak boleh menyerah sekarang. +I can't wait to die. Aku sudah tidak sabar untuk mati. +I cleared the table. Aku membersihkan mejanya. +I did not know this. Aku tidak tahu tentang hal ini. +I don't believe you. Aku tidak mempercayaimu. +I don't believe you. Aku tidak percaya padamu. +I feel really tired. Aku merasa sangat lelah. +I get paid tomorrow. Aku dapat gaji besok. +I grew up in Boston. Aku besar di Boston. +I have a dictionary. Aku punya kamus. +I have to visit Tom. Aku harus mengunjungi Tom. +I know what Tom saw. Aku tahu apa yang Tom lihat. +I met him yesterday. Kemarin saya bertemu dia. +I only speak French. Saya hanya berbicara bahasa Prancis. +I only speak French. Aku hanya berbicara bahasa Prancis. +I shower once a day. Saya mandi sehari sekali. +I study art history. Saya belajar tentang sejarah seni. +I think I'll go now. Aku pikir aku akan pergi sekarang. +I think I've got it. Kurasa aku paham. +I think they saw us. Aku pikir mereka melihat kita. +I think we'll be OK. Aku pikir kita akan baik-baik saja. +I want orange juice. Saya ingin jus jeruk. +I want to go abroad. Aku ingin ke luar negeri. +I want to visit you. Saya ingin menjumpai kamu. +I want your opinion. Aku ingin mendengar pendapatmu. +I will be back soon. Aku akan segera kembali. +I will miss you all. Aku akan merindukan kalian semua. +I wish I could swim. Aku harap aku bisa berenang. +I'd like to go, too. Aku ingin ikut pergi juga. +I'd like to see her. Aku ingin bertemu dengannya. +I'll call him later. Aku akan menghubunginya nanti. +I'll call you later. Aku akan menghubungimu nanti. +I'll join you later. Aku akan menyusul kalian nanti. +I'll lend it to you. Aku akan meminjamkannya padamu. +I'll make you happy. Aku akan membuatmu bahagia. +I'll stick with Tom. Aku dengan Tom. +I'm a lousy swimmer. Aku perenang yang payah. +I'm counting on you. Aku mengandalkanmu. +I'm extremely tired. Aku benar-benar capek. +I'm fine, thank you. Saya baik-baik saja, terima kasih. +I'm grateful to you. Aku berterima kasih padamu. +I'm still not ready. Saya belum siap. +I'm tracking a buck. Saya sedang memburu seekor rusa jantan. +I'm waiting for him. Aku sedang menunggunya. +I've been very busy. Aku sedang sibuk sekali. +I've just come back. Aku baru kembali. +I've lost my ticket. Aku kehilangan tiketku. +I've lost my ticket. Aku menghilangkan tiketku. +Is everybody hungry? Apa kalian lapar? +Is it far from here? Apakah jauh dari sini? +Is that about right? Apa itu kurang lebih benar? +Is that really true? Apa itu memang benar? +Is this permissible? Apa ini diizinkan? +It isn't hard to do. Ini tidak sulit untuk dilakukan. +It was a nice party. Tadi itu pesta yang menyenangkan. +It was really cheap. Itu sangat murah. +It's an old picture. Itu adalah lukisan yang tua. +It's not my problem. Ini bukan masalahku. +It's rather curious. Ini agak aneh. +It's time to get up. Sudah waktunya bangun. +Keep your eyes open. Tetap buka matamu. +Let Tom come aboard. Biarkan Tom naik. +Let me look into it. Biarkan aku melihat ke dalamnya. +Let's do it for Tom. Mari kita melakukannya untuk Tom. +Let's do it tonight. Mari kita lakukan malam ini. +Let's do that again. Mari kita melakukannya lagi. +Let's do this again. Mari kita melakukannya lagi. +Let's give it a try. Mari kita mencobanya. +Let's let Tom do it. Mari kita biarkan Tom yang melakukannya. +Let's start working. Mari kita mulai bekerja. +Let's try something. Mari kita coba sesuatu. +More coffee, please. Tolong tambah kopinya. +My back still hurts. Punggungku masih sakit. +My dad will kill me. Ayah akan membunuhku. +My hobby is fishing. Hobiku memancing ikan. +My house is haunted. Rumah saya berhantu. +My mom will kill me. Ibuku akan membunuhku. +Pleased to meet you. Senang bertemu denganmu. +Prepare to evacuate. Bersiap siap untuk evakuasi. +Quit fooling around. Jangan bertingkah bodoh. +She has 2,000 books. Dia punya 2.000 buku. +She hasn't come yet. Dia masih belum datang. +She is not here yet. Dia masih belum di sini. +She's still a minor. Dia masih di bawah umur. +Take a seat, please. Silakan duduk. +Take off your socks. Lepas kaus kakimu. +Thank you very much. Terima kasih banyak. +That door is locked. Pintu itu terkunci. +That should suffice. Itu cukup. +That won't help you. Itu tidak akan membantumu. +That's an imitation. Itu imitasi. +That's it, isn't it? Yang itu, kan? +That's preposterous. Itu gila. +The girl is jumping. Anak perempuan itu melompat. +The office is empty. Kantornya kosong. +The scar is healing. Bekas lukanya sembuh +There's no evidence. Tidak ada bukti. +They're kind of fun. Mereka lumayan menyenangkan. +They're not illegal. Mereka bukan pendatang gelap. +They're still young. Mereka masih muda. +Things have changed. Sesuatu telah berubah. +This is a pay phone. Ini telepon umum. +This is her handbag. Ini tasnya. +This is magnificent. Ini luar biasa indah. +This is my computer. Ini adalah komputerku. +This is really cool. Ini sangat keren. +This novel bores me. Novel ini membuatku bosan. +Those are my orders. Itu pesananku. +Tom abused my trust. Tom menyalahgunakan kepercayaan yang aku berikan. +Tom appears stunned. Tom kelihatannya terkejut. +Tom bought me roses. Tom membelikanku bunga mawar. +Tom came here alone. Tom datang kemari sendirian. +Tom closed his eyes. Tom memejamkan mata. +Tom disappointed me. Tom mengecewakanku. +Tom doesn't know me. Tom tidak mengetahui saya. +Tom drives too fast. Tom mengemudi terlalu cepat. +Tom found me a taxi. Tom mencarikanku sebuah taksi. +Tom has lied to you. Tom sudah berbohong padamu. +Tom is Mary's uncle. Tom adalah paman Mary. +Tom is a politician. Tom adalah seorang politikus. +Tom is all business. Tom terlalu serius. +Tom is having lunch. Tom sedang makan siang. +Tom is ignoring you. Tom mengabaikanmu. +Tom is in the house. Tom ada di dalam rumah. +Tom is still crying. Tom masih menangis. +Tom kept on talking. Tom terus berbicara. +Tom looked confused. Tom terlihat kebingungan. +Tom looks perplexed. Tom terlihat kebingungan. +Tom must be stopped. Tom harus dihentikan. +Tom needed training. Tom membutuhkan pelatihan. +Tom remains puzzled. Tom masih bingung. +Tom says he'll come. Tom bilang ia akan datang. +Tom shut the drawer. Tom menutup lacinya. +Tom started to sing. Tom mulai bernyanyi. +Tom was very scared. Tom sangat ketakutan. +Tom went home alone. Tom pulang ke rumah sendirian. +Tom went on talking. Tom lanjut berbicara. +Tom's eyes are blue. Mata Tom biru. +Tom's eyes are blue. Tom matanya biru. +Tom's face was pale. Muka tom pucat +Wake me up at eight. Bangunkan aku jam delapan. +We can count on Tom. Kami dapat mempercayai Tom. +We're eating apples. Kami sedang makan apel. +Were they convinced? Apakah mereka telah yakin? +What are you eating? Apa yang sedang kamu makan? +What did he look up? Apa yang dia cari? +What does Tom think? Apa yang Tom pikirkan? +What is on the desk? Di atas meja ada apa? +What should I bring? Saya harus bawa apa? +What was the result? Bagaimana hasilnya? +What were you doing? Sedang apa kau tadi? +What's your problem? Apa masalahmu? +When did you get up? Kapan kamu bangun? +When will you leave? Kapan kamu akan pergi? +When will you leave? Kamu kapan akan pergi? +When will you leave? Kapan kamu berangkat? +Where are you bound? Kamu menuju ke mana? +Where are you going? Kau mau pergi ke mana? +Where are you going? Anda akan pergi ke mana? +Where are you going? Kamu mau ke mana? +Where are you going? Mau ke mana? +Where have you been? Dari mana kamu? +Where have you been? Kamu dari mana saja? +Where have you been? Ke mana saja kamu? +Where have you been? Dari mana saja Anda? +Where have you gone? Ke mana kamu pergi? +Where is the toilet? Di manakah toilet? +Where is the toilet? Di mana toiletnya? +Where's the airport? Ada di mana bandaranya? +Where's the station? Stasiunnya di mana? +Where's your jacket? Mana jaketmu? +Who is your teacher? Siapa gurumu? +Why did you give up? Kenapa kau menyerah? +Why didn't you come? Kenapa kau tidak datang? +Why do you say that? Mengapa kamu mengatakan itu? +Why do you think so? Kenapa kau berpikir begitu? +You are a good cook. Kamu koki yang terampil. +You can rely on him. Kau bisa mengandalkannya. +You disappointed me. Kamu mengecewakanku. +You don't need that. Kau tidak memerlukan itu. +You don't need this. Kau tidak memerlukan ini. +You have to go back. Kamu harus kembali. +You look very tired. Kamu terlihat sangat lelah. +You must stay awake. Kau harus tetap terjaga. +You still have time. Kamu masih punya waktu. +You tore your pants. Kau merobekkan celanamu. +You won't need that. Kamu tidak akan memerlukan itu. +You'd better not go. Sebaiknya kamu tidak pergi. +You're going to die. Kau akan mati. +Your father is tall. Ayahmu tinggi besar. +Your shoes are here. Sepatumu ada di sini. +Am I being too vague? Apa aku kurang jelas? +Are you a vegetarian? Apa kau nabatiwan? +Are you a vegetarian? Apa kau seorang nabatiwan? +Are you conservative? Apa kau konservatif? +Are you sure of that? Apa kau yakin dengan hal itu? +Are your hands clean? Apakah tanganmu sudah bersih? +Birds fly in the sky. Burung-burung terbang di langit. +Bring me a dry towel. Bawakan aku sebuah handuk kering. +Button up your shirt. Kancingkan bajumu. +Can I take a day off? Bisakah aku mengambil hari libur? +Can I turn on the TV? Bolehkah saya nyalakan TV-nya? +Can he speak English? Dapatkah dia berbicara bahasa Inggris? +Can you ride a horse? Dapatkah kamu menunggang kuda? +Can you speak French? Apakah Anda bisa berbahasa Prancis? +Come on, let's do it. Ayolah, mari kita lakukan. +Did you see a doctor? Apa kau sudah pergi ke dokter? +Did you see anything? Kamu melihat sesuatu? +Didn't I tell you so? Tidakkah aku berkata begitu padamu? +Do whatever it takes. Lakukan apapun yang diperlukan. +Do you have any pets? Apakah Anda memiliki peliharaan? +Do you speak English? Apa Anda menggunakan bahasa Inggris? +Don't make fun of me. Jangan mempermainkanku. +Don't worry about me. Jangan khawatirkan aku. +Everybody was silent. Semua orang terdiam. +Go back to your seat. Kembali ke tempat dudukmu! +Have you been abroad? Kamu pernah ke luar negeri? +He began to feel ill. Dia mulai merasa sakit. +He didn't fear death. Dia tidak takut pada kematian. +He easily gets angry. Dia mudah marah. +He gave a short talk. Dia berbicara singkat. +He got bored quickly. Dia mudah bosan. +He has a sweet voice. Dia memiliki suara yang merdu. +He isn't here, is he? Dia tidak ada di sini, kan? +He left home at 8:00. Dia meninggalkan rumah pukul 8:00. +He wanted to succeed. Dia ingin berhasil. +He went deer hunting. Ia pergi berburu rusa. +He's eating an apple. Dia sedang memakan sebuah apel. +He's eight years old. Dia berumur 8 tahun. +He's under the chair. Dia ada di bawah kursi. +How are your parents? Bagaimana kabar orang tuamu? +How did you get hurt? Bagaimana kamu bisa terluka? +How many people died? Berapa banyak orang yang mati? +How much is this tie? Berapa harga dasi ini? +I agree to this plan. Saya setuju pada rencana ini. +I am afraid of dying. Saya takut mati. +I am counting on you. Aku mengandalkanmu. +I am eating an apple. Saya sedang makan sebuah apel. +I am terribly hungry. Aku sangat lapar. +I can't stop smoking. Aku tidak bisa berhenti merokok. +I don't know exactly. Aku tidak tahu tepatnya. +I felt like an idiot. Aku merasa seperti orang bodoh. +I guess you're right. Aku rasa kamu benar. +I have a new red car. Aku punya mobil baru warna merah. +I have a stepbrother. Saya punya kakak tiri. +I have a stepbrother. Saya punya adik tiri. +I have a stomachache. Perutku sakit. +I have a twin sister. Aku punya saudara kembar adik perempuan. +I have a twin sister. Aku punya saudara kembar kakak perempuan. +I have no more ideas. Aku kehabisan ide. +I have three cameras. Aku memiliki tiga buah kamera. +I hope I can do this. Aku harap aku bisa melakukan ini. +I know what you mean. Aku tahu apa maksudmu. +I left the door open. Aku membiarkan pintunya terbuka. +I like how it sounds. Aku suka dengan bunyinya. +I like your optimism. Aku suka dengan sifat optimismu. +I look forward to it. Aku menantikannya. +I met Mary yesterday. Aku bertemu Mary kemarin. +I owe my life to Tom. Aku berhutang nyawa kepada Tom. +I paid $200 in taxes. Aku membayar $200 untuk pajak. +I saw them yesterday. Aku melihat mereka kemarin. +I showed her my room. Aku menunjukkan kamarku padanya. +I tell you the truth. Aku mengatakan padamu yang sebenarnya. +I think I understand. Aku pikir aku paham. +I think you're crazy. Saya pikir kamu gila. +I think you're right. Aku pikir kamu benar. +I walked up the hill. Aku menapaki bukit. +I want an MP3 player! Aku ingin sebuah pemutar MP3! +I wanted to go there. Aku ingin pergi ke sana. +I will come with you. Aku akan ikut denganmu. +I'd like to see that. Aku ingin melihatnya. +I'll be glad to come. Dengan senang hati saya akan datang. +I'll buy you a drink. Aku akan membelikanmu minuman. +I'll phone you later. Aku akan meneleponmu nanti. +I'm glad to meet you. Senang bertemu denganmu. +I'm happy to be here. Saya senang berada disini. +I'm not busy anymore. Aku tidak lagi sibuk. +I'm not feeling well. Aku merasa tidak enak badan. +I'm shorter than you. Aku lebih pendek ketimbang kamu. +I'm usually punctual. Saya terbiasa tepat waktu. +I'm washing my hands. Saya mencuci tangan. +I've already retired. Aku sudah pensiun. +I've got a toothache. Saya sakit gigi. +I've only just begun. Aku baru saja memulainya. +I've read both books. Aku sudah membaca kedua buku itu. +Is my answer correct? Apakah jawaban saya tepat? +Is this your bicycle? Apakah ini sepedamu? +It could've been Tom. Itu mungkin Tom. +It is already eleven. Sudah jam sebelas. +It is time to get up. Sudah waktunya bangun. +It must've been love. Ini pasti cinta. +It was kind of funny. Itu agak menggelikan. +It's a good question. Ini pertanyaan yang bagus +It's time to wake up. Sudah waktunya bangun. +Just watch and learn. Lihat dan pelajarilah. +Let me see that list. Coba saya lihat daftar itu. +Let me take a gander. Biarkan aku melihatnya. +Let's do it this way. Mari kita lakukan dengan cara ini. +Let's do it your way. Mari kita lakukan dengan caramu. +Let's give it a shot. Mari kita mencobanya. +Let's just do it now. Sudah mari kita lakukan saja sekarang. +Let's try once again. Ayo coba sekali lagi. +Look at that big dog. Lihatlah anjing besar itu. +May I ask a question? Bolehkah saya mengajukan sebuah pertanyaan? +May I go out to play? Bolehkah aku pergi bermain? +May I hold your hand? Boleh aku pegang tangan kamu? +May I play the piano? Bolehkah aku memainkan pianonya? +May I use your phone? Boleh pinjam ponselmu? +May I use your phone? Apakah saya boleh menggunakan ponsel Anda? +May I use your phone? Bolehkah saya meminjam telepon Anda? +My house was on fire. Rumahku kebakaran. +My watch is accurate. Jam saya akurat. +OK, let's just do it. OK, mari kita lakukan saja. +Please shut the door. Tolong tutup pintunya. +She felt like crying. Dia merasa ingin menangis. +She has ten children. Dia mempunyai sepuluh anak. +She opens the window. Dia membuka jendela. +She tends to be late. Dia suka terlambat. +Should I cut my hair? Haruskah aku memotong rambutku? +Should I go with you? Apa perlu aku temani? +Stay out of the rain. Jangan sampai kehujanan. +Take this table away. Singkirkan meja ini. +That'll never change. Itu tak akan pernah berubah. +That's my best guess. Kurang lebih seperti itu. +That's not an answer. Itu bukan suatu jawaban. +That's probably wise. Mungkin sebaiknya begitu. +The TV won't turn on. Televisinya tidak mau menyala. +The horse is jumping. Kudanya melompat. +The house is haunted. Rumah tersebut berhantu. +The ink is still wet. Tintanya masih basah. +The voting continued. Pemungutan suaranya dilanjutkan. +These are all I have. Ini semua yang saya punya. +They live in a house. Mereka tinggal di sebuah rumah. +They were all guilty. Mereka semua bersalah. +They'll be safe here. Mereka akan aman di sini. +They're all the same. Semuanya sama. +This bed looks solid. Ranjang ini tampak kokoh. +This is a true story. Ini cerita yang sebenarnya. +This is all my fault. Ini semua adalah salahku. +This is homemade jam. Ini adalah selai buatan rumah. +This is insufficient. Ini tidak cukup. +This is preposterous. Ini gila. +This novel is boring. Novel ini membosankan. +This room is cramped. Ruangannya sempit. +Tom appears confused. Tom terlihat kebingungan. +Tom became irritated. Tom merasa jengkel. +Tom doesn't trust us. Tom tidak mempercayai kita. +Tom finally met Mary. Tom akhirnya bertemu dengan Mary. +Tom has good manners. Tom punya sopan santun. +Tom ironed his shirt. Tom menyetrika bajunya. +Tom is a Red Sox fan. Tom adalah penggemar dari Red Sox. +Tom is a good person. Tom adalah orang yang baik. +Tom is a good worker. Tom adalah pekerja yang baik. +Tom is a nice person. Tom adalah orang yang baik. +Tom is conscientious. Tom adalah seorang yang teliti. +Tom is older than me. Tom lebih tua ketimbang aku. +Tom is the strongest. Tomlah yang terkuat. +Tom looks bewildered. Tom terlihat bimbang. +Tom looks nonplussed. Tom tampak tercengang. +Tom never backs down. Tom tidak pernah mundur. +Tom resumed speaking. Tom lanjut berbicara. +Tom seems bewildered. Tom sepertinya bimbang. +Tom speaks very fast. Tom berbicara sangat cepat. +Tom speaks very fast. Tom berbicara dengan sangat cepat. +Tom told me about it. Tom memberitahuku tentang hal itu. +Tom used to be happy. Tom dulu bahagia. +Tom was all worn out. Tom benar-benar kelelahan. +Tom was good at that. Tom sangat baik dalam hal itu. +Tom was lying to you. Tom sudah berbohong padamu. +Tom went on speaking. Tom lanjut berbicara. +Tom won't let you go. Tom tidak akan membiarkanmu pergi. +Turtles are reptiles. Kura-kura adalah reptil. +We did what we could. Kami melakukan yang kami bisa. +We finished the work. Kami menyelesaikan pekerjaannya. +We had to let Tom go. Kita harus membiarkan Tom pergi. +We have two children. Kami punya dua orang anak. +We met along the way. Kami bertemu di tengah perjalanan. +We must do something. Kita harus melakukan sesuatu. +We ran down the hill. Kami berlari menuruni bukit. +We were all laughing. Kami semua tertawa. +We'll need more time. Kita akan membutuhkan waktu lebih. +We're going to fight. Kita akan bertarung. +We're really married. Kami berdua benar-benar sudah menikah. +Were you intoxicated? Apa kau mabuk? +What did you do then? Lalu apa yang kau lakukan? +What grade is Tom in? Kelas berapa Tom? +What grade is Tom in? Tom kelas berapa? +What're you drinking? Kamu minum apa? +What's our situation? Bagaimana situasi kita? +When are you leaving? Kapan kamu akan pergi? +When are you leaving? Kamu kapan akan pergi? +When are you leaving? Kapan kamu berangkat? +When did you come in? Kapan kamu masuk? +When is Tom arriving? Kapan Tom akan tiba? +When will you return? Kapan kamu akan kembali? +When's your birthday? Kapan ulang tahunmu? +Where are the knives? Ada di mana pisau-pisaunya? +Where are you headed? Kamu menuju ke mana? +Where are you off to? Kau mau pergi ke mana? +Where are you off to? Anda akan pergi ke mana? +Where have they gone? Ke mana mereka pergi? +Where is the station? Ada di mana stasiunnya? +Where is the station? Stasiunnya di mana? +Where is your jacket? Di mana jaketmu? +Where were you going? Ke mana kamu pergi? +Where's the restroom? Di mana kamar kecilnya? +Who are these people? Siapa orang-orang ini? +Who are these people? Mereka ini siapa? +Who deleted the file? Siapa yang menghapus berkasnya? +Who do you live with? Dengan siapa kamu tinggal? +Who invited you guys? Siapa yang mengundang kalian? +Whose pencil is this? Pensil siapa ini? +Why do you need this? Kenapa kau membutuhkan ini? +Why do you work here? Kenapa kau bekerja di sini? +Yesterday was Monday. Kemarin adalah hari Senin. +You are new students. Kalian adalah para siswa baru. +You are the only one. Kaulah satu-satunya. +You just made my day. Kau baru saja membuatku merasa sangat bahagia. +You look happy today. Kamu terlihat bahagia hari ini. +You may use this car. Kamu boleh menggunakan mobil ini. +You're not ready yet. Kamu belum siap. +You're totally right. Kau memang benar. +Your answer is right. Jawabanmu benar. +Your answer is wrong. Jawabanmu salah. +Am I imagining things? Apa aku sedang berhalusinasi? +Any child can do that. Semua anak bisa melakukan itu. +Are they all the same? Apakah mereka semua sama? +Are you being serious? Apa kau serius? +Are you in a bad mood? Apa suasana hatimu sedang buruk? +Are you talking to me? Apakah kau sedang bicara padaku? +Are you ten years old? Apa umurmu 10 tahun? +Call me at the office. Hubungi aku melalui kantor. +Can I ask you a favor? Boleh minta tolong? +Can I buy you a drink? Mau aku traktir minum? +Can I use your pencil? Bolehkah aku menggunakan pensilmu? +Can you get a day off? Bisakah aku mendapatkan hari libur? +Can you keep a secret? Bisakah kau menjaga rahasia? +Can you speak English? Apa Anda bisa berbahasa Inggris? +Cats don't like water. Kucing tidak suka air. +Did you see something? Kamu melihat sesuatu? +Dinner's getting cold. Makan malamnya mendingin. +Do you have a bicycle? Apakah kamu punya sepeda? +Do you have a bicycle? Apakah Anda punya sepeda? +Do you have a lighter? Apa kau punya korek api? +Do you have a vacancy? Apa ada kamar yang kosong? +Do you have some milk? Apa kau punya susu? +Do you like surprises? Apakah kamu menyukai kejutan? +Do you understand her? Apa kamu mengerti dia? +Does Tom like to swim? Apakah Tom suka berenang? +Don't make me hit you. Jangan sampai aku memukulmu. +Don't point at others. Jangan menuduh orang lain. +Don't touch my camera. Jangan sentuh kameraku. +Everyone stared at me. Semua orang menatap padaku. +Everything's so cheap. Semuanya sangat murah. +Get a picture of this. Coba pahami ini. +Has Tom said anything? Apakah Tom mengatakan sesuatu? +Have you eaten dinner? Kamu sudah makan malam? +Have you eaten dinner? Apa kau sudah makan malam? +Haven't we met before? Bukankah kita pernah bertemu sebelumnya? +He crossed the street. Dia menyeberang jalan. +He got a lot of money. Dia punya banyak uang. +He has a lot of money. Dia punya banyak uang. +He has an eye for art. Dia punya selera seni yang tinggi. +He has gone to London. Dia telah berangkat ke London. +He is mad about music. Dia tergila-gila soal musik. +He lived a happy life. Dia hidup dengan bahagia. +He often plays guitar. Dia sering bermain gitar. +He's eating lunch now. Dia sedang makan siang sekarang. +He's my older brother. Dia kakakku. +He's very intelligent. Dia sangat pintar. +Hello, how's business? Halo, bagaimana bisnismu? +Hi. How are you doing? Hai. Bagaimana kabarmu? +His dad calls him Tom. Ayahnya memanggilnya Tom. +How high can you jump? Seberapa tinggi kamu dapat melompat? +How long did you stay? Berapa lama kamu menginap? +How long does it take? Butuh waktu berapa lama? +How long does it take? Akan memakan waktu berapa lama? +How long will it take? Berapa lama waktu yang dibutuhkan? +How many do they need? Berapa banyak yang mereka butuhkan? +How much does it cost? Berapa harganya? +How was your vacation? Bagaimana liburan Anda? +I admire your courage. Aku memuji keberanianmu. +I am glad to meet you. Senang bertemu denganmu. +I am shorter than you. Aku lebih pendek ketimbang kamu. +I can't take any more. Aku tidak tahan lagi. +I can't take any more. Aku sudah tak mampu menahannya lagi. +I can't take any more. Aku sudah tidak tahan lagi. +I come from Australia. Saya datang dari Australia. +I do not know exactly. Aku tidak tahu tepatnya. +I don't care for eggs. Aku tidak suka telur. +I don't know for sure. Aku tidak tahu pastinya. +I don't like this one. Saya tidak suka yang ini. +I don't need anything. Saya tidak butuh apapun. +I don't need your job. Saya tidak butuh pekerjaanmu. +I don't often eat out. Saya jarang makan diluar. +I don't want any more. Saya tidak mau lagi. +I feel so happy today. Aku merasa sangat bahagia hari ini. +I go to bed about ten. Aku pergi tidur sekitar jam 10. +I had my watch stolen. Arloji saya dicuri. +I had to go back home. Aku harus pulang. +I have a bad headache. Saya menderita sakit kepala yang parah. +I have a few theories. Aku punya beberapa teori. +I have a half brother. Saya punya kakak tiri. +I have a half brother. Saya punya adik tiri. +I have a twin brother. Aku punya saudara kembar kakak laki-laki. +I have a twin brother. Aku punya saudara kembar adik laki-laki. +I have life insurance. Saya punya asuransi jiwa. +I have lost my wallet. Dompetku hilang. +I have to go to sleep. Aku harus pergi tidur. +I love French culture. Aku sangat suka budaya Prancis. +I met her an hour ago. Aku bertemu dengannya sejam yang lalu. +I met her by accident. Aku tidak sengaja bertemu dengannya. +I must hurry to class. Aku harus segera pergi ke kelas. +I need to get a stamp. Aku butuh perangko. +I no longer want that. Aku tidak lagi menginginkan itu. +I owe you ten dollars. Aku berhutang 10 dolar padamu. +I ran a race with him. Aku berbalapan lari dengannya. +I said that as a joke. Itu tadi bercanda. +I saw Tom in the hall. Aku melihat Tom di aula. +I saw Tom in the hall. Aku melihat Tom di lorong. +I thought he was sick. Kukira dia sakit. +I thought it was true. Aku kira itu benar adanya. +I usually eat outside. Aku biasanya makan di luar. +I want to go with you. Saya ingin pergi dengan anda. +I want to sing a song. Aku ingin menyanyikan sebuah lagu. +I want you to take it. Aku mau kamu mengambilnya. +I was at my wit's end. Aku kehabisan akal. +I was kind of nervous. Aku agak gugup. +I went out for a walk. saya pergi keluar untuk jalan-jalan. +I'd like to buy a map. Saya ingin membeli sebuah peta. +I'd like to check out. Aku mau memeriksa. +I'll call again later. Saya hubungi lagi nanti. +I'll get some glasses. Aku akan mengambil beberapa gelas. +I'll stay if it rains. Aku akan tinggal jika hujan. +I'm a college student. Aku adalah mahasiswa. +I'm afraid to go home. Aku takut pulang ke rumah. +I'm glad I could help. Saya senang bisa membantu. +I'm glad you liked it. Aku senang kamu menyukainya. +I'm going to kill you. Aku akan membunuhmu. +I'm here as a tourist. Aku di sini sebagai seorang turis. +I'm playing a TV game. Aku memainkan sebuah permainan di televisi. +I'm still not certain. Aku masih belum yakin. +I've been to the bank. Aku baru saja pergi ke bank. +Is everything OK here? Apakah semuanya oke di sini? +Is that clock working? Apakah jam itu bekerja? +Is there a difference? Apakah ada perbedaan? +Is there life on Mars? Apakah ada kehidupan di Mars? +Is this a coincidence? Apakah ini sebuah kebetulan? +Is your home far away? Apakah rumahmu jauh? +Is your watch correct? Apakah jam Anda waktunya tepat? +It can be frustrating. Hal ini bisa membuatmu frustrasi. +It is under the chair. Itu ada di bawah kursi. +It seemed to be cheap. Sepertinya itu murah. +It seems well written. Ini kelihatan ditulis dengan rapi. +It will probably rain. Kemungkinan hujan akan turun. +It's really happening. Itu benar-benar terjadi. +Keep your hands clean. Jaga tanganmu tetap bersih. +Let me drive you home. Biarkan aku mengantarmu pulang. +Let's do it ourselves. Mari kita lakukan sendiri. +Let's do it right now. Mari kita lakukan sekarang juga. +Let's get back inside. Ayo masuk kedalam kembali. +Let's give it a whirl. Mari kita mencobanya. +Let's go to the beach. Mari kita pergi ke pantai. +Let's have a go at it. Mari kita mencobanya. +Like father, like son. Seperti ayah, seperti anak. +Like father, like son. Anak laki-laki mirip dengan ayahnya. +Mary is a lovely girl. Mary adalah gadis yang menawan. +Mary is a pretty girl. Mary adalah gadis yang cantik. +My bicycle was stolen. Sepedaku dicuri. +My brother swims well. Adikku berenang dengan baik. +My brother swims well. Kakakku berenang dengan baik. +My life was in danger. Hidupku dalam bahaya. +My mother is a lawyer. Ibuku adalah seorang pengacara. +My right hand is numb. Tangan kananku mati rasa. +My shoes are worn out. Sepatuku sudah usang. +No one knew who I was. Tidak ada yang tahu siapa dulunya aku. +Nobody understands me. Tidak ada yang mengerti aku. +Not all birds can fly. Tidak semua burung bisa terbang. +Please close the door. Tolong tutup pintunya. +Please go to the bank. Tolong pergilah ke bank. +Please take your seat. Silakan duduk. +Please tell the truth. Tolong katakan yang sebenarnya. +Please tell the truth. Tolong katakan kebenarannya. +Please tell the truth. Tolong ceritakan yang sebenarnya. +Read it again, please. Tolong bacakan sekali lagi. +She is afraid of cats. Dia takut kucing. +She's eight years old. Dia delapan tahun. +She's in the bathroom. Dia di kamar mandi. +She's still under age. Dia masih di bawah umur. +Show me your passport. Tunjukkan paspor Anda. +Shut the door, please. Tolong tutup pintunya. +Sit wherever you like. Duduklah di manapun yang kau sukai. +So you give up, right? Jadi kamu menyerah, benar? +Stop worrying so much. Jangan terlalu khawatir. +Take care of yourself. Jaga dirimu sendiri. +Tell me what you want. Katakan padaku apa yang kau inginkan. +Tests start next week. Ujian akan mulai minggu depan. +That isn't my problem. Itu bukan masalahku. +That should be enough. Itu cukup. +That's awesome, right? Itu mengagumkan sekali, bukan? +That's not my concern. Itu bukan urusanku. +That's not my problem. Itu bukan masalahku. +That's not surprising. Itu bukanlah hal yang mengejutkan. +The Milky Way is huge. Bima Sakti besar. +The cake is too sweet. Kuenya terlalu manis. +The faucet is leaking. Kerannya bocor. +The money disappeared. Uang telah menghilang. +The radio is too loud. Suara radionya terlalu keras. +The sun is going down. Mataharinya mulai terbenam. +These are my children. Mereka ini adalah anak-anakku. +They're eating apples. Mereka sedang memakan apel. +This heater burns gas. Pemanas ini berbahan bakar gas. +This is a Chinese fan. Ini adalah kipas Tiongkok. +This is not expensive. Ini tidak mahal. +This isn't my problem. Ini bukan masalahku. +This makes me curious. Ini membuatku penasaran. +This should be washed. ini harus dicuci. +Tom and Mary are done. Tom dan Mary putus. +Tom appeared confused. Tom terlihat kebingungan. +Tom can't play tennis. Tom tidak bisa bermain tenis. +Tom clapped his hands. Tom bertepuk tangan. +Tom closed the drawer. Tom menutup lacinya. +Tom continued talking. Tom lanjut berbicara. +Tom did as I told him. Tom melakukan apa yang aku katakan. +Tom doesn't like beef. Tom tidak suka daging sapi. +Tom has a pretty wife. Tom mempunyai istri yang cantik. +Tom has a stomachache. Tom sakit perut. +Tom has been expelled. Tom telah dikeluarkan. +Tom has been poisoned. Tom telah diracuni. +Tom has to be stopped. Tom harus dihentikan. +Tom is always bananas. Tom selalu konyol. +Tom is always healthy. Tom selalu sehat. +Tom is bigger than me. Tom lebih besar ketimbang aku. +Tom is reading a book. Tom sedang membaca buku. +Tom is taller than me. Tom lebih tinggi daripada aku. +Tom is taller than me. Tom lebih tinggi dari saya. +Tom isn't the traitor. Tom bukanlah penghianat. +Tom looks dumbfounded. Tom tampak tercengang. +Tom misses his family. Tom merindukan keluarganya. +Tom refused to let go. Tom menolak untuk melepas. +Tom spoke up for Mary. Tom berbicara untuk Mary. +Tom studies very hard. Tom sangat tekun belajar. +Tom was quite helpful. Tom sudah cukup membantu. +Tom wouldn't sit down. Tom tidak akan duduk. +Tom's hands are large. Tangan Tom besar. +Watch your mouth, Tom. Jaga mulutmu, Tom. +We're on our way home. Kami sedang berada dalam perjalanan pulang. +We're still searching. Kami masih mencari. +What a waste of money! Buang-buang duit aja! +What are you drinking? Kamu minum apa? +What can I do for you? Apa yang bisa aku lakukan untuk kamu? +What do you guys have? Kalian punya apa? +What grade are you in? Kamu kelas berapa? +What if Tom finds out? Bagaimana kalau Tom mengetahuinya? +What made you do this? Apa yang membuatmu melakukan ini? +What makes you so sad? Apa yang membuatmu begitu sedih? +What time did you eat? Kamu makan jam berapa? +What's in your pocket? Apa yang ada di dalam kantongmu? +What's wrong with you? Apa yang salah denganmu ? +What's wrong with you? Ada apa denganmu? +What's your last name? Siapa nama belakangmu? +What's your specialty? Jurusanmu apa? +When did Tom buy that? Kapan Tom membeli itu? +When is your birthday? Kapan ulang tahunmu? +When is your birthday? Kapan anda berulang tahun? +When will you be back? Kapan kamu akan kembali? +Where are you heading? Kamu mau menuju ke mana? +Where are you heading? Anda akan menuju ke mana? +Where are you staying? Di mana Anda menginap? +Where are your things? Ada dimana barang-barangmu? +Where is my newspaper? Di mana koranku? +Where is the bus stop? Di mana tempat pemberhentian busnya? +Where's Tom moving to? Tom pindah ke mana? +Where's the newspaper? Korannya mana? +Who am I talking with? Dengan siapa saya bicara? +Who is that gentleman? Siapakah pria itu? +Whose bicycle is this? Sepeda siapa ini? +Why do they come here? Kenapa mereka datang kemari? +Why was this a secret? Mengapa ini rahasia? +Would you care to try? Anda ingin mencoba? +Would you like to eat? Apa kau mau makan? +You can't be a doctor. Kamu tidak bisa menjadi seorang dokter. +You deserve the prize. Kau layak mendapatkan hadiah itu. +You must do your duty. Kau harus melaksanakan tugasmu. +You shouldn't move it. Kau seharusnya tidak memindahkannya. +You'd better hurry up. Sebaiknya kamu cepat-cepat. +You'd better sit here. Sebaiknya kau duduk di sini. +You'll never be alone. Kamu tak akan pernah sendirian. +You're older than Tom. Kamu lebih tua daripada Tom. +Your hair is too long. Rambutmu terlalu panjang. +Your shoes are untied. Sepatumu belum terikat. +A mosquito just bit me. Aku baru saja digigit nyamuk. +A promise is a promise. Janji adalah janji. +Are you coming with me? Apa kamu mau ikut? +Are you speaking to me? Apa kau bicara padaku? +Business has been good. Bisnis selalu dalam keadaan baik. +Can I pick my own desk? Bolehkah saya memilih tempat duduk saya sendiri? +Can you play the piano? Bisakah kau bermain piano? +Can your brother drive? Bisakah saudaramu mengendarai mobil? +Cats don't eat bananas. Kucing tidak makan pisang. +Close the door, please. Tolong tutup pintunya. +Did you watch the game? Apa kamu melihat pertandingan itu? +Do one thing at a time. Kerjakan satu hal dalam satu waktu. +Do you have any coffee? Apa kau punya kopi? +Do you know the reason? Apa kau tahu alasannya? +Do you like my T-shirt? Apakah kamu menyukai kaus oblong saya? +Do you really love Tom? Apa kamu benar-benar mencintai Tom? +Do you study every day? Apa kamu belajar setiap hari? +Do you want to help me? Kamu mau membantu saya? +Don't be a wet blanket. Jangan suka mengganggu kesenangan orang lain. +Don't underestimate me. Jangan meremehkanku. +Give me back my wallet. Kembalikan dompetku. +Good morning, everyone. Selamat pagi, semuanya. +Have you already eaten? Sudah makan? +Have you seen anything? Kamu melihat sesuatu? +He delivers newspapers. Dia mengantar koran. +He has a bright future. Dia punya masa depan yang cerah. +He has bad handwriting. Dia memiliki tulisan tangan yang buruk. +He is blind in one eye. Sebelah matanya buta. +He isn't able to do it. Dia tidak mampu melakukannya. +He may have told a lie. Dia bisa saja berbohong. +He was going to school. Dia baru akan berangkat menuju ke sekolah. +He won't come, will he? Dia tidak akan datang, kan? +He's going to sit here. Dia akan duduk di sini. +He's stronger than you. Dia lebih kuat darimu. +How long was Tom there? Sudah berapa lama Tom di sana? +How much is this watch? Berapa harga jam tangan ini? +I am a college student. Aku adalah mahasiswa. +I am a college student. Saya mahasiswa. +I am ashamed of myself. Aku malu pada diriku sendiri. +I am to meet him there. Saya akan bertemu dengannya di sana. +I can't read your mind. Aku tidak bisa membaca pikiranmu. +I cried all night long. Aku menangis semalam suntuk. +I don't agree with him. Aku tidak setuju dengan dia. +I don't agree with you. Aku tidak setuju denganmu. +I don't get you at all. Aku benar-benar tidak memahamimu. +I don't have a bicycle. Saya tidak punya sepeda. +I don't like it at all. Aku tidak menyukainya sama sekali. +I don't need your help. Aku tidak butuh bantuanmu. +I don't regret a thing. Aku tidak menyesali apapun. +I don't want any sugar. Saya tidak mau gula. +I felt the house shake. Aku merasakan rumahnya berguncang. +I found my lost wallet. Aku menemukan dompetku yang hilang. +I had to get back home. Aku harus pulang. +I have a bad toothache. Aku menderita sakit gigi yang parah. +I have only just begun. Aku baru saja mulai. +I have to find Tom now. Aku harus menemukan Tom sekarang. +I have to get up early. Aku harus bangun pagi-pagi. +I hope he can help you. Saya harap dia bisa membantuku. +I hope to see you soon. Aku harap aku bisa segera bertemu denganmu lagi. +I knew he would accept. Aku tahu dia akan setuju. +I know Tom is innocent. Aku tahu Tom tidak bersalah. +I like pizza very much. Aku sangat suka dengan piza. +I mean what I'm saying. Aku serius dengan apa yang kukatakan. +I saw her wash the car. Saya melihatnya mencuci mobil. +I saw it in a magazine. Aku melihatnya pada sebuah majalah. +I think he is a doctor. Aku pikir dia adalah seorang dokter. +I think you should sit. Aku pikir kau harus duduk. +I told Tom a few jokes. Aku memberitahu Tom beberapa lelucon. +I want to buy them all. Saya ingin membeli semuanya. +I want to win for once. Saya ingin menang barang sekali. +I was a little nervous. Aku agak gugup. +I was away for a while. Tadi saya pergi sebentar. +I was in the mountains. Aku di gunung. +I was raised in Boston. Aku dibesarkan di Boston. +I wasn't aware of that. Aku tidak menyadari hal itu. +I wholeheartedly agree. Saya sepenuhnya setuju. +I will gladly help you. Saya dengan senang hati akan membantu anda. +I will not do it again. Aku tidak akan melakukannya lagi. +I wish I were in Paris. Andaikan saya ada di Paris +I would love to see it. Saya ingin melihatnya. +I'd like to rent a car. Aku ingin menyewa sebuah mobil. +I'd rather go swimming. Aku lebih memilih pergi berenang. +I'll be going with you. Aku akan pergi denganmu. +I'll be going with you. Aku akan ikut denganmu. +I'll go no matter what. Aku akan pergi apapun yang terjadi. +I'm a realistic person. Aku adalah orang yang realistis. +I'm anxious to see you. Aku ingin sekali bertemu denganmu. +I'm going to need help. Aku akan membutuhkan bantuan. +I'm happy I could help. Saya senang bisa membantu. +I'm happy to hear that. Saya senang mendengar hal itu. +I'm not kidding around. Aku tidak sedang bercanda. +I'm not messing around. Aku tidak sedang membuang-buang waktu. +I'm thinking about you. Aku memikirkan tentang dirimu. +I've caught a bad cold. Aku terkena flu berat. +Is it a recent picture? Apakah ini gambar yang tadi? +It doesn't look so bad. itu tidak terlalu terlihat buruk +It might rain tomorrow. Hujan mungkin akan turun besok. +It rained hard all day. Hujan deras turun selama sehari penuh. +It was quite fantastic. Itu cukup luar biasa. +It's entirely my fault. Seluruhnya adalah kesalahanku. +It's for you to decide. Itu terserah padamu. +It's like one of those. Ini seperti satu dari barang-barang itu. +It's too noisy in here. Di sini terlalu berisik. +Just follow your heart. Ikutilah kata hatimu. +Let us finish our work. Mari kita selesaikan pekerjaan kita. +Let's make this simple. Mari kita menyederhanakannya. +My father is a teacher. Ayah saya seorang guru. +My house faces the sea. Rumahku menghadap laut. +New York is a big city. New York adalah sebuah kota yang besar. +Please add up the bill. Tolong jumlahkan total tagihannya. +Please don't cry again. Tolong, jangan menangis lagi. +Please open the window. Tolong buka jendelanya. +Please pay the cashier. Silakan membayar di kasir. +Put on your good shoes. Pakailah sepatu yang paling bagus. +Save me some ice cream. Sisakan aku es krimnya. +See you in the morning. Sampai jumpa besok pagi. +She crossed the street. Dia menyeberang jalan. +She had a healthy baby. Dia punya bayi yang sehat. +She is habitually late. Dia kebiasaan datang terlambat. +She loves her children. Dia mencintai anak-anaknya. +She shaved her armpits. Dia mencukur bulu ketiaknya. +She's younger than him. Dia lebih muda darinya. +Should I buy something? Apakah saya harus membelikannya barang? +Smoking is bad for you. Merokok tidak baik untuk Anda. +So what do you suggest? Jadi apa yang kau sarankan? +Stop playing with that. Berhenti memainkan itu. +Stop worrying about me. Berhentilah mengkhawatirkanku. +Thank you ever so much. Terima kasih banyak. +Thanks for helping Tom. Terima kasih telah membantu Tom. +That sound is annoying. Suara itu sangat mengganggu. +That's pretty annoying. Itu sangat menjengkelkan. +That's very easy to do. Itu sangat mudah dilakukan. +The door wasn't closed. Pintunya belum ditutup. +The eggs are still hot. Telurnya masih panas. +The hunter shot a bear. Pemburu tersebut menembak seekor beruang. +The negotiation is off. Negosiasinya dibatalkan. +The pig is growing fat. Babi itu bertambah gemuk. +The rain lasted a week. Hujannya bertahan selama seminggu. +The rules have changed. Aturan-aturanya sudah berubah. +The smell was horrible. Baunya sangat tidak enak. +The smell was terrible. Baunya sangat tidak enak. +The train came on time. Keretanya datang tepat waktu. +The train flipped over. Kereta tersebut terguling. +The wind has died down. Tiupan anginnya semakin pelan. +The wine was excellent. Minuman anggur itu rasanya luar biasa. +There's no class today. Tidak ada kelas hari ini. +They didn't believe me. Mereka tidak percaya padaku. +They have just arrived. Mereka baru saja sampai. +They live in our block. Mereka tinggal di blok kami. +They went to the beach. Mereka pergi ke pantai. +This food is too salty. Makanan ini terlalu asin. +This is an ancient law. Ini adalah sebuah hukum kuno. +This is not a sentence. Ini bukan kalimat. +This is not my problem. Ini bukan masalah saya. +This is the last straw! Ini yang terakhir! +This is the last straw. Ini yang terakhir. +This is very confusing. Ini sangat membingungkan. +This room is very warm. Ruangan ini sangat hangat. +This work is half-done. Pekerjaan ini sudah setengah selesai. +Today is extremely hot. Hari ini sangat panas. +Today's Tom's birthday. Hari ini ulang tahun Tom. +Tom and I are students. Tom dan saya adalah pelajar +Tom continued speaking. Tom lanjut berbicara. +Tom continued to speak. Tom lanjut berbicara. +Tom could replace Mary. Tom bisa menggantikan Mary. +Tom crossed the street. Tom menyeberangi jalan itu. +Tom doesn't have a car. Tom tidak punya mobil. +Tom dreamed about Mary. Tom memimpikan Mary +Tom explained it to me. Tom menjelaskannya padaku. +Tom flushed the toilet. Tom menyiram toilet. +Tom got out of his car. Tom keluar dari mobilnya. +Tom got out of the car. Tom keluar dari mobil. +Tom had a very bad day. Tom menghadapi hari yang sangat buruk. +Tom hasn't arrived yet. Tom belum sampai. +Tom is a buddy of mine. Tom adalah seorang kawanku. +Tom is a good employee. Tom adalah pegawai yang baik. +Tom is afraid of dying. Tom takut mati. +Tom is alone with Mary. Tom sedang berduaan dengan Mary. +Tom is beating up Mary. Tom memukuli Mary. +Tom is getting jealous. Tom mulai cemburu. +Tom is good at cooking. Tom pandai dalam hal memasak. +Tom is looking for you. Tom sedang mencarimu. +Tom isn't able to swim. Tom tidak bisa berenang. +Tom looks just like me. Tom tampak seperti diriku. +Tom really misses Mary. Tom sungguh merindukan Mary. +Tom says he's innocent. Tom berkata dia tidak bersalah. +Tom set down his spoon. Tom meletakkan sendoknya. +Tom should just resign. Tom sebaiknya mengundurkan diri. +Tom stayed for a while. Tom tinggal selama beberapa waktu. +Tom wants to kill Mary. Tom ingin membunuh Mary. +Tom was a little drunk. Tom sedikit mabuk. +Tom was very surprised. Tom sangat terkejut. +We all have our faults. Kita semua pasti punya kesalahan. +We danced to the music. Kami menari mengikuti alunan musik. +We must obey the rules. Kita harus mematuhi peraturan. +We plan to stay a week. Kami berencana untuk tinggal selama seminggu. +We want you to take it. Kami ingin kau membawanya. +We waste a lot of time. Kita banyak membuang waktu. +We're all very excited. Kami semua sangat bersemangat. +We're lucky, aren't we? Kita beruntung, kan? +We're lucky, aren't we? Kami beruntung, kan? +We've been cooperative. Kami selalu kooperatif. +We've been helping Tom. Kami selalu membantu Tom. +We've done what we can. Kami telah melakukan yang kami bisa. +What do you want to do? Apa yang ingin kau lakukan? +What does your aunt do? Bibimu sedang melakukan apa? +What fun would that be? Memang apa bagusnya itu? +What is your name, sir? Siapa nama anda, pak ? +What made you so angry? Apa yang membuatmu begitu marah? +What time can you come? Pada pukul berapa Anda bisa datang? +What time does it open? Bukanya pada pukul berapa? +What's your major, Tom? Apa jurusanmu, Tom? +What's your occupation? Apa pekerjaanmu? +When did you finish it? Kapan kamu menyelesaikannya? +When do you want to go? Kamu ingin pergi kapan? +Where did you try them? Di mana kamu mencobanya? +Where do you come from? Dari mana asalmu? +Where is the newspaper? Korannya mana? +Where've you guys been? Ke mana saja kalian? +Which way is the beach? Pantainya ada di sebelah mana? +Who did you give it to? Kepada siapa kamu memberikannya? +Whose is that notebook? Buku catatan itu punya siapa? +Whose notebook is that? Buku catatan itu punya siapa? +Whose umbrella is this? Ini payung milik siapa? +Why are you still here? Kenapa kamu masih di sini? +Why do you need change? Kenapa kamu membutuhkan uang kembalian? +Why should this happen? Mengapa ini harus terjadi? +Will you come tomorrow? Apakah kau akan datang besok? +Will you open the door? Boleh tolong buka pintunya? +Would you like to come? Apakah Anda akan datang? +You are my best friend. Kau adalah sahabat karibku. +You could have done it. Kau harusnya bisa melakukannya. +You had plenty of time. Kau punya banyak waktu. +You have to be patient. Kau harus bersabar. +You just can't give up. Kamu tidak boleh menyerah. +You may close the door. Kamu boleh menutup pintunya. +You may use my new car. Kau boleh menggunakan mobil baruku. +You must go to bed now. Kau harus pergi tidur sekarang. +You seem to like fruit. Sepertinya Anda suka dengan buah-buahan. +You should know better. Kamu harusnya tahu. +You should stay in bed. Kau harus tetap beristirahat. +You should've told Tom. Harusnya kamu memberi tahu Tom. +You were at my wedding. Kamu ada pada acara pernikahanku. +You were late for work. Kau terlambat untuk bekerja. +You'd better go by bus. Lebih baik kau pergi dengan bus. +You're perfectly right. Kau memang benar. +You're very courageous. Kamu berani sekali. +Your cake is delicious. Kuemu enak. +Your plan sounds great. Rencanamu kedengarannya bagus. +Are you attracted to me? Apa kau tertarik padaku? +Are you sure about that? Apa kau yakin dengan hal itu? +Are you sure about this? Apa kau yakin dengan hal ini? +At least I wasn't alone. Paling tidak aku tidak seorang diri. +Can I borrow your radio? Bisa aku pinjam radiomu? +Can I see the wine list? Bisakah aku melihat daftar minuman anggurnya? +Can I see your passport? Dapatkah saya melihat paspor anda? +Can I use a credit card? Bisa pakai kartu kredit? +Can we go to the circus? Bisakah kita pergi ke sirkus? +Can you eat raw oysters? Apa kau bisa memakan tiram mentah? +Can you get it repaired? Bisakah kau memperbaikinya? +Can you read this kanji? Dapatkah kau membaca kanji ini? +Can't you speak English? Bisakah kau menggunakan bahasa Inggris? +Did Tom know what to do? Apa Tom tahu apa yang harus ia lakukan? +Did you come here alone? Apa kau datang kemari sendirian? +Did your wish come true? Apakah harapanmu terkabul? +Didn't you see anything? Kamu tidak melihat apa-apa? +Do I look like an idiot? Apakah aku terlihat seperti seorang idiot? +Do they have a computer? Apakah mereka punya komputer? +Do you feel like eating? Apa kau mau makan? +Do you really mean that? Apa kau serius mengatakannya? +Do you still read books? Apa kau masih membaca buku-buku? +Do you want some coffee? Ingin minum kopi? +Do you want to use mine? Apa kamu mau pinjam punyaku? +Don't go out after dark. Jangan pergi keluar setelah hari menjadi gelap. +Don't make a fool of me. Jangan mempermainkanku. +Don't play in this room. Jangan bermain di kamar ini. +Don't read in this room. Jangan membaca di kamar ini. +Everyone makes mistakes. Semua orang pernah melakukan kesalahan. +Everything's dirt-cheap. Semuanya sangat murah. +Everything's very cheap. Semuanya sangat murah. +Father is angry with me. Ayahku marah padaku. +Get me an extra blanket. Carikan aku selimut lagi. +Give us a ride downtown. Tolong antarkan kami sampai ke pusat kota. +Good morning, everybody. Selamat pagi, semuanya. +Have you seen something? Kamu melihat sesuatu? +He asked for more money. Dia meminta lebih banyak uang. +He gets mad very easily. Dia sangat mudah marah. +He's my younger brother. Dia adikku. +He's my younger brother. Dia adik laki-lakiku. +Here's my email address. Ini alamat e-mailku. +Hey! Let's start eating. Ayo! Kita mulai makan. +How about taking a rest? Mau istirahat? +How can I know for sure? Bagaimana caranya agar aku bisa mengetahuinya secara pasti? +How did this effect you? Bagaimana efeknya untukmu? +How did you get injured? Bagaimana kamu bisa terluka? +How do you do that, Tom? Bagaimana kamu melakukannya, Tom? +How long do horses live? Berapa lama kuda hidup? +I always walk to school. Aku selalu berjalan ke sekolah. +I am a realistic person. Aku adalah orang yang realistis. +I am disgusted with you. Aku sudah muak denganmu. +I am not good at sports. Aku tidak jago dalam hal olahraga. +I can't give up smoking. Aku tidak bisa berhenti merokok. +I couldn't convince Tom. Aku tidak bisa membujuk Tom. +I couldn't get to sleep. Aku tidak bisa tidur. +I don't like it, either. Aku juga tidak menyukainya. +I don't want it anymore. Aku sudah tidak menginginkannya. +I don't want to die yet. Aku masih belum mau mati. +I don't want to see you. Aku tidak mau melihat kalian. +I don't work for anyone. Aku tidak bekerja untuk siapapun. +I got an F in chemistry. Aku mendapat nilai F di pelajaran kimia. +I had no one to turn to. Tidak ada seorang pun yang bisa kutemui. +I had to keep my secret. Saya harus menjaga rahasia saya. +I have no money with me. Aku tidak membawa uang. +I have so much to learn. Ada banyak hal yang harus aku pelajari. +I have to know for sure. Aku harus tahu dengan pasti. +I have to take medicine. Aku harus minum obat. +I haven't had lunch yet. Aku belum makan siang. +I haven't seen anything. Aku belum lihat apapun. +I heard someone whistle. Aku mendengar seseorang bersiul. +I hope it stops raining. Aku harap hujannya berhenti. +I hope that I can do it. Aku harap aku bisa melakukannya. +I hope to hear from you. Kami ingin mendengarnya dari Anda. +I know Tom isn't guilty. Aku tahu Tom tidak salah. +I know what I'm feeling. Aku tahu apa yang sedang aku rasakan. +I know why Tom resigned. Aku tahu kenapa Tom mengundurkan diri. +I like my job very much. Aku sangat menyukai pekerjaanku. +I lived there for years. Aku bertahun-tahun tinggal di sana. +I met him on the street. Aku bertemu dengannya di jalan. +I must go to the toilet. Aku harus pergi ke toilet. +I must go to the toilet. Saya harus pergi ke toilet. +I need more information. Aku butuh informasi lagi. +I need some good advice. Aku membutuhkan sedikit saran. +I need some information. Aku butuh beberapa informasi. +I need to know for sure. Aku perlu tahu secara pasti. +I often have bad dreams. Aku sering bermimpi buruk. +I often have nightmares. Aku sering bermimpi buruk. +I play volleyball often. Saya sering bermain voli. +I really need your help. Aku sangat membutuhkan bantuanmu. +I should read that book. Aku harus membaca buku itu. +I still want to be here. Aku masih ingin di sini. +I suppose you're hungry. Kamu sepertinya lapar. +I think Tom is loveable. Saya pikir Tom mudah disukai. +I think Tom is sensible. Aku pikir Tom adalah orang yang bijaksana. +I think Tom should stay. Aku pikir Tom harus tetap tinggal. +I tried doing just that. Saya telah mencoba melakukan hal tersebut. +I usually get up at six. Biasanya saya bangun pada pukul enam. +I want him in my office. Saya ingin dia ada di kantorku. +I want more information. Aku ingin lebih banyak informasi. +I want to be an actress. Saya ingin menjadi aktris. +I want to do everything. Saya ingin melakukan segalanya. +I want to go to a hotel. Aku ingin pergi ke sebuah hotel. +I want to look like her. Aku ingin kamu berpenampilan seperti dia. +I want to sing the song. Aku ingin menyanyikan lagu itu. +I was just about to eat. Saya sudah hampir mau makan. +I will love you forever. Saya mencintaimu selamanya. +I wish I wasn't married. Saya harap saya belum menikah +I'll be better tomorrow. Aku akan baik-baik saja besok. +I'll come to your place. Aku akan pergi ke tempatmu. +I'll give you something. Aku akan memberikanmu sesuatu. +I'll lend you this book. Aku akan meminjamkanmu buku ini. +I'm disappointed in you. Aku kecewa padamu. +I'm glad you enjoyed it. Saya senang Anda menikmatinya. +I'm pleased to meet you. Senang bertemu denganmu. +I'm so glad you're back. Aku sangat senang kau kembali. +I'm sorry to be so late. Maaf aku sudah terlambat cukup lama. +I'm still the boss here. Aku masih bosnya di sini. +I've done nothing wrong. Aku tidak melakukan kesalahan apapun. +I've never seen the sea. Saya belum pernah melihat laut. +I've tried that already. Aku sudah mencobanya. +Is everything all right? Apa semuanya baik-baik saja? +Is this water drinkable? Apa air ini bisa diminum? +It didn't mean anything. Itu tidak berarti apa-apa. +It was a stupid mistake. Itu kesalahan yang bodoh. +It's a misunderstanding. Ini salah paham. +It's entirely up to you. Itu sepenuhnya terserah padamu. +It's going to rain soon. Sebentar lagi hujan akan turun. +It's very noisy in here. Di sini sangat berisik. +Keep an eye on the bags. Awasilah tas-tas itu. +Let me get you a brandy. Akan kubawakan sebotol brendi untukmu. +Listen to who's talking. Dengarkanlah orang yang sedang berbicara. +Lovely sunset, isn't it? Senja yang indah, ya? +Mary can speak Japanese. Mary bisa Bahasa Jepang. +May I borrow your knife? Bolehkah aku meminjam pisaumu? +May I borrow your radio? Boleh aku pinjam radiomu? +May I hang up your coat? Boleh kugantungkan jasmu? +May I see the wine list? Boleh saya lihat daftar minuman anggurnya? +May I see your passport? Boleh saya melihat paspor Anda? +May I take your picture? Bolehkah aku mengambil gambarmu? +May I use your car, Dad? Bolehkah Saya menggunakan mobilmu, yah? +My brother is a teacher. Saudaraku adalah seorang guru. +My brother is very tall. Adik saya badannya sangat tinggi. +My brother is very tall. Kakak saya badannya sangat tinggi. +My camera is waterproof. Kameraku tahan air. +My health has been good. Badanku selalu dalam keadaan sehat. +No stitches were needed. Tidak perlu dijahit. +Now give me what I want. Sekarang berikan aku apa yang aku mau. +Paper is made from wood. Kertas terbuat dari kayu. +Please answer in French. Tolong jawab dalam bahasa Prancis. +Please call me a doctor. Tolong panggilkan dokter. +Please have a seat here. Silakan duduk di sini. +Please lend me your car. Tolong pinjamkan aku mobilmu. +Please say hello to her. Tolong sampaikan salamku kepadanya. +Push the button, please. Tolong tekan tombolnya. +She is very intelligent. Dia sangat pintar. +She took care of my dog. Dia merawat anjing saya. +She's not young, is she? Dia tidak muda ya. +Show me what you bought. Tunjukkan padaku apa yang kamu beli. +So, what do you suggest? Jadi, apa yang Anda sarankan? +Sorry, I made a mistake. Maaf, aku membuat sebuah kesalahan. +Stay away from the door. Menjauhlah dari pintu. +Tell me about your plan. Beritahu aku tentang rencanamu. +That's the right answer. Itulah jawaban yang benar. +That's what I told them. Itulah yang aku katakan pada mereka. +That's what I was doing. Itulah yang sedang saya lakukan tadi. +The TV was on all night. Televisi menyala sepanjang malam. +The bus hasn't come yet. Bisnya belum datang. +The desk drawer is open. Laci mejanya terbuka. +The odds are two to one. Peluangnya adalah dua dibanding satu. +The proverb is familiar. Pepatah itu terdengar familiar. +The sky is getting dark. Langitnya semakin gelap. +The snake shed its skin. Ularnya berganti kulit. +The train has just left. Keretanya baru saja berangkat. +The world changes a lot. Dunia telah banyak berubah. +There's plenty of water. Airnya banyak. +These flowers have died. Bunga-bunga ini sudah mati. +They said they're happy. Mereka berkata bahwa mereka bahagia. +They used to love jokes. Dulu mereka suka bercanda. +They're all watching TV. Mereka semua menonton TV. +This account is correct. Akun ini benar. +This is a movie for men. Ini adalah film untuk laki-laki. +This paragraph is vague. Kalimat ini tidak jelas. +Today is Tom's birthday. Hari ini ulang tahun Tom. +Tom began to understand. Tom mulai mengerti. +Tom can't run very fast. Tom tidak bisa lari dengan sangat cepat. +Tom cut himself shaving. Tom terluka ketika sedang bercukur. +Tom didn't try to argue. Tom tidak mencoba untuk membantah. +Tom doesn't like cheese. Tom tidak suka keju. +Tom dug up the potatoes. Tom memanen kentang-kentangnya. +Tom fell into the water. Tom jatuh ke dalam air. +Tom had to do some work. Tom harus melakukan beberapa perkerjaan. +Tom has a decent salary. Tom punya gaji yang lumayan. +Tom has another problem. Tom punya permasalahan lain. +Tom has been good to me. Tom selalu baik kepadaku. +Tom has been good to us. Tom selalu baik kepada kami. +Tom has good intentions. Tom memiliki niat yang baik. +Tom hid under the table. Tom bersembunyi di bawah meja. +Tom is a friend of mine. Tom adalah seorang kawanku. +Tom is a friend of mine. Tom adalah seorang temanku. +Tom is in constant pain. Tom merasakan sakit yang tidak ada henti-hentinya. +Tom is not able to swim. Tom tidak bisa berenang. +Tom just wanted to help. Tom hanya ingin membantu. +Tom likes fried chicken. Tom suka ayam goreng. +Tom put on his raincoat. Tom memakai jas hujan. +Tom ran across the road. Tom berlari sepanjang jalan. +Tom said he's no expert. Tom berkata dia bukan ahlinya. +Tom says the same thing. Tom mengatakan hal yang sama. +Tom says this is absurd. Tom berkata ini tidak masuk akal. +Tom says this is normal. Tom berkata ini normal. +Tom seemed uninterested. Tom terlihat tidak tertarik. +Tom signed the document. Tom menandatangani dokumennya. +Tom sleeps all the time. Tom tidur sepanjang waktu. +Tom still has some time. Tom masih ada waktu. +Tom still loves his job. Tom masih menyukai pekerjaannya. +Tom still loves it here. Tom masih betah disini. +Tom thinks the same way. Tom juga berpikiran sama. +Tom thinks you're lying. Tom berpikir kalau kau berbohong. +Tom used to be very shy. Tom dulunya sangat pemalu. +Tom wanted to be famous. Tom ingin terkenal. +Tom wants to be a pilot. Tom ingin menjadi seorang pilot. +Tom was late for dinner. Tom terlambat untuk makan malam. +Tom was shocked by this. Tom syok karena ini. +Tom was shot and killed. Tom tertembak dan terbunuh. +Tom was shot and killed. Tom ditembak dan dibunuh. +Tom was shot and killed. Tom ditembak dan terbunuh. +Tom wasn't a bit sleepy. Tom tidak sedang mengantuk. +Tom will have no choice. Tom tidak akan punya pilihan. +Tom will quit on Monday. Tom akan berhenti hari senin. +Tom wore a white jacket. Tom mengenakan jaket putih. +Tom worked all his life. Tom bekerja sepanjang hidupnya. +Try to keep from crying. Cobalah untuk tidak menangis. +Turn the flame down low. Kecilkan apinya. +We are having a meeting. Kami sedang rapat. +We didn't learn a thing. Kita tidak mengambil hikmah sama sekali. +We didn't learn a thing. Kami tidak mengambil hikmah sama sekali. +We didn't need to hurry. Kita tidak perlu tergesa-gesa. +We felt the house shake. Kami merasakan rumahnya berguncang. +We have only three left. Kita mempunyai tiga lagi. +We have to do something. Kita harus melakukan sesuatu. +We have to keep working. Kita harus tetap bekerja. +We have to keep working. Kita harus terus bekerja. +We have to stay healthy. Kita harus tetap sehat. +We need to do something. Kita perlu melakukan sesuatu. +We never work on Sunday. Kami tidak pernah bekerja di hari Minggu. +We should wait for help. Kita harus menunggu datangnya bantuan. +We solved both problems. Kami menyelesaikan kedua permasalahan itu. +We take oil for granted. Kita menyia-nyiakan minyak. +We use our feet to walk. Kami menggunakan kaki kami untuk berjalan. +We'll fight to the last. Kita akan berjuang sampai akhir. +We're worried about you. Kami mengkhawatirkanmu. +We've already done that. Kita sudah melakukan itu. +We've already done that. Kami sudah melakukan itu. +What I'm saying is true. Apa yang aku katakan itu benar. +What are you doing here? Apa yang sedang kamu lakukan di sini? +What are you hoping for? Apa harapanmu? +What are you looking at? Apa yang sedang kamu lihat? +What color is your hair? Apa warna rambutmu? +What did the doctor say? Apa yang dokter katakan? +What did you talk about? Kamu membicarakan tentang apa? +What do you want to eat? Kamu mau makan apa? +What do you want to say? Apa yang ingin kamu katakan? +What kind of play is it? Permainan apa sih itu? +What made you come here? Apa yang membuatmu datang ke sini? +What makes you say that? Apa yang membuatmu mengatakan itu? +What should we focus on? Kita harus fokus pada apa? +What should we focus on? Kami harus fokus pada apa? +What sports do you like? Olahraga apa yang kau sukai? +What time do you get up? Anda bangun pada pukul berapa? +What we do is up to you. Apa yang kita lakukan tergantung padamu. +What're you waiting for? Kamu sedang menunggu apa? +What're you waiting for? Apa yang sedang kamu tunggu? +What's happening to you? Kamu kenapa? +What's your destination? Tujuanmu ke mana? +When are you going home? Kapan kamu pulang ke rumah? +When are you going home? Kapan kamu akan pulang? +When are you going home? Kapan Anda pulang ke rumah? +When will you come back? Kapan kamu akan kembali? +When will you come home? Kapan kamu pulang ke rumah? +When will you come home? Kapan Anda pulang ke rumah? +Where are you all going? Kalian semua mau pergi ke mana? +Where can I buy a brush? Di mana saya bisa membeli sikat? +Where can I catch a bus? Di mana saya bisa menaiki sebuah bus? +Where do you want to go? Kau ingin pergi ke mana? +Where do you want to go? Anda ingin pergi ke mana? +Where have you two been? Ke mana saja kalian berdua? +Who are you waiting for? Siapa yang sedang anda tunggu l +Who is the team's coach? Siapa pelatih timnya? +Who told you I was sick? Siapa yang memberitahumu aku sakit? +Who told you to do that? Siapa yang menyuruhmu melakukan itu? +Who told you to go home? Siapa yang menyuruh kamu pulang? +Who wants hot chocolate? Siapa mau cokelat panas? +Why don't you get a job? Mengapa kamu tidak memperoleh pekerjaan? +Why is he staring at me? Kenapa dia menatapku? +Work as hard as you can. Bekerjalah sekuat yang kamu bisa. +Would you like to dance? Maukah kau berdansa? +Write your address here. Tulis alamatmu di sini. +You are a good customer. Anda seorang pelanggan yang baik. +You can keep the change. Kau bisa menyimpan kembaliannya. +You can swim, can't you? Kamu bisa berenang, kan? +You can't come tomorrow. Kamu tidak bisa datang besok. +You don't have to hurry. Kau tidak perlu tergesa-gesa. +You don't need to panic. Kau tidak perlu panik. +You don't need to shout. Kamu tidak perlu berteriak +You don't smoke, do you? Anda tidak merokok, bukan? +You have a lot of nerve! Kurang ajar sekali kamu! +You mustn't tell anyone. Kamu tidak boleh memberitahukannya pada siapapun. +You should have done so. Seharusnya kamu melakukannya. +You should have seen it. Kamu harusnya melihatnya. +You should not go alone. Kau seharusnya tidak pergi seorang diri. +You should not go alone. Kau tidak boleh pergi sendirian. +You should see a doctor. Kau harus pergi ke dokter. +You should see a doctor. Kamu harus pergi ke dokter. +You're absolutely right. Kau memang benar. +You're completely right. Kau memang benar. +You're taller than I am. Kau lebih tinggi ketimbang aku. +You've dropped your pen. Kau telah menjatuhkan penamu. +You've got to apologize. Kamu harus minta maaf. +Your dress is very nice. Gaunmu indah sekali. +Your jokes aren't funny. Lelucon Anda tidak lucu. +Your wife is mad at you. Istrimu marah padamu. +A glass of water, please. Tolong segelas air putih. +A truck ran over our dog. Sebuah truk menabrak anjing kami. +Always count your change. Selalu hitung kembalianmu. +Are you buying into this? Apa kau percaya akan hal ini? +Are you expecting anyone? Apakah kamu sedang menunggu seseorang? +Are you fond of swimming? Apakah kamu sangat menyukai berenang? +Are you off duty tonight? Apa kau tidak bertugas malam ini? +Are you on the committee? Apakah Anda anggota dari komite? +Can I pay by credit card? Bisakah saya membayar dengan menggunakan kartu kredit? +Can you throw a fastball? Apa kau bisa melempar bola cepat? +Cats can see in the dark. Kucing bisa melihat dalam kegelapan. +Cut the cloth diagonally. Potong kainnya secara diagonal. +Darwin changed the world. Darwin telah mengubah dunia. +Do we need to discuss it? Apa kita perlu mendiskusikannya? +Do you have a light beer? Apa kalian punya bir ringan? +Do you have enough money? Apakah kamu punya uang cukup? +Do you know who they are? Tahukah anda siapa mereka itu? +Do you like French wines? Apa kau suka minuman anggur Prancis? +Do you mean what you say? Apa kau serius dengan apa yang kau katakan? +Do you plan to go abroad? Apa kamu berencana pergi ke luar negeri? +Do you think I'm kidding? Apa kamu pikir aku bercanda? +Do you want to try it on? Anda mau mencobanya? +Does this sound familiar? Apa ini terdengar tidak asing? +Don't be late for school. Jangan terlambat datang ke sekolah. +Don't make fun of people. Jangan mempermainkan orang lain. +Don't pick up that phone. Jangan angkat telepon itu. +Don't scare me like that! Jangan menakut-nakutiku seperti itu! +Don't smoke in this room. Jangan merokok di ruangan ini. +Don't you ever come back. Jangan pernah kau kembali. +Don't you have a bicycle? Apakah kamu punya sepeda? +Don't you have a bicycle? Apakah Anda punya sepeda? +Don't you have a bicycle? Bukannya kamu punya sepeda? +Don't you have a bicycle? Bukannya Anda punya sepeda? +Everybody makes mistakes. Semua orang pernah melakukan kesalahan. +Everything has been good. Semuanya selalu dalam keadaan baik. +Flour is made into bread. Tepungnya dibuat menjadi roti. +Get everyone out of here. Suruh semua orang keluar dari sini. +Give me a bottle of wine. Berikan aku sebotol anggur. +Give me something to eat. Berikan aku sesuatu untuk dimakan. +Give me the bill, please. Tolong bonnya. +Have you eaten lunch yet? Apakah kamu sudah makan? +Have you ever seen a UFO? Apakah kamu pernah melihat UFO? +Have you ever seen a UFO? Pernah melihat UFO? +Have you seen him before? Apa kau pernah bertemu dengannya sebelumnya? +He disregarded my advice. Dia tidak mengindahkan nasihatku. +He doesn't like fighting. Dia tidak suka berkelahi. +He dressed up as a woman. Dia berpakaian seperti wanita. +He is certain to succeed. Dia pasti berhasil. +He is not coming, either. Dia juga tidak datang. +He is painting a picture. Dia sedang melukis sebuah gambar. +He made me his assistant. Dia menjadikanku asistennya. +He's reading a novel now. Dia sedang membaca novel sekarang. +Hello, how are you doing? Halo, apa kabar? +Hello, how are you doing? Halo, bagaimana kabarmu? +Help yourself to a drink. Silakan dinikmati minumannya. +His father calls him Tom. Ayahnya memanggilnya Tom. +How are you feeling, Tom? Bagaimana perasaanmu, Tom? +How do you get to school? Kamu pergi ke sekolah dengan apa? +How is the weather today? Bagaimana cuaca hari ini? +How is your name spelled? Bagaimana mengeja namamu. +How much is the bus fare? Berapa ongkos busnya? +I am pleased to meet you. Senang bertemu denganmu. +I am pleased with myself. Aku merasa senang dengan diriku sendiri. +I bought a pair of shoes. Aku membeli sepasang sepatu. +I can end your suffering. Aku bisa mengakhiri penderitaanmu. +I can sing it in English. Aku bisa menyanyikannya dalam bahasa Inggris. +I can't eat another bite. Aku tidak bisa makan lebih banyak lagi. +I can't stand it anymore. Aku tidak tahan lagi. +I can't stand it anymore. Aku sudah tak mampu menahannya lagi. +I can't stand it anymore. Aku sudah tidak tahan lagi. +I can't take Tom's money. Aku tidak bisa menerima uang Tom. +I can't take it any more. Aku tidak tahan lagi. +I can't take it any more. Aku sudah tak mampu menahannya lagi. +I can't take it any more. Aku sudah tidak tahan lagi. +I didn't know about this. Aku tidak tahu tentang hal ini. +I didn't mean to do that. Aku tidak berniat melakukannya. +I don't care if it snows. Aku tidak peduli meskipun turun salju. +I don't know for certain. Aku tidak tahu pastinya. +I don't know what to say. Saya tidak tahu harus berkata apa. +I don't know what to say. Saya tidak tahu harus berbicara apa. +I don't like all of them. Aku tidak menyukai kesemuanya. +I don't like you anymore. Aku sudah tidak menyukaimu lagi. +I don't love her anymore. Aku tidak mencintainya lagi. +I don't want to go alone. Aku tidak mau pergi sendirian. +I don't want you to quit. Aku tidak ingin kau berhenti. +I felt sad for no reason. Saya merasa sedih tanpa alasan. +I had a stroke last year. Saya terserang strok tahun lalu. +I have caught a bad cold. Aku terkena flu berat. +I have some French books. Aku mempunyai beberapa buku berbahasa Prancis. +I haven't washed my hair. Aku belum keramas. +I hope he'll wait for me. Kuharap dia akan menungguku. +I hope you're having fun. Aku harap kalian bersenang-senang. +I know what Tom would do. Aku tahu apa yang akan Tom lakukan. +I like the way it sounds. Aku suka dengan bunyinya. +I like the way you smile. Aku suka cara kamu tersenyum. +I like to eat watermelon. Aku suka makan semangka. +I must've made a mistake. Saya pasti sudah membuat kesalahan. +I need to learn Japanese. Saya perlu belajar bahasa Jepang. +I often go to the movies. Aku sering pergi ke bioskop. +I ran into an old friend. Aku berjumpa dengan kawan lamaku. +I read an exciting story. Aku membaca sebuah cerita yang mendebarkan. +I saw Tom in the hallway. Aku melihat Tom di lorong. +I saw her sweep the room. Saya telah melihatnya menyapu kamar. +I stayed home for a week. Aku tinggal di rumah selama seminggu. +I think it's a good idea. Saya pikir itu ide yang bagus. +I thought I heard a thud. Sepertinya aku mendengar suara benda yang jatuh. +I want something to read. Aku ingin sesuatu untuk dibaca. +I want to feel important. Aku ingin merasa penting. +I was at a movie theater. Aku ada di bioskop. +I was caught in a shower. Aku terjebak di tengah hujan. +I was caught in the rain. Aku kehujanan. +I will be sixteen in May. Usia saya akan menjadi 16 tahun bulan Mei ini. +I will not tolerate this. Saya tidak akan membiarkan ini. +I would like to see that. Saya ingin melihatnya. +I'd like to see a doctor. Aku ingin pergi ke dokter. +I'll be at home tomorrow. Aku ada di rumah besok. +I'll call you back later. Aku akan menelepon balik nanti. +I'll do better next time. Aku akan melakukannya dengan lebih baik lain kali. +I'll fix you some coffee. Aku akan membuatkanmu kopi. +I'll give you this money. Aku akan memberimu uang ini. +I'll make you a new suit. Aku akan membuatkanmu pakaian baru. +I'll never do this again. Aku tidak akan pernah melakukannya lagi. +I'm Tom and this is Mary. Saya Tom dan ini Mary. +I'm a university student. Aku adalah mahasiswa. +I'm completely exhausted. Aku benar-benar capek. +I'm getting sick of this. Aku mulai muak dengan hal ini. +I'm going to go clean up. Aku mau bersih-bersih. +I'm going to go with you. Aku akan pergi denganmu. +I'm in trouble, aren't I? Aku dalam masalah, ya? +I'm not afraid of ghosts. Aku tidak takut dengan hantu. +I'm not convinced at all. Aku tidak terbujuk sama sekali. +I'm so happy you're back. Aku senang sekali kamu kembali. +I'm sorry I let you down. Aku minta maaf sudah mengecewakanmu. +I've already arranged it. Saya sudah mengaturnya. +I've always liked soccer. Aku selalu suka dengan sepak bola. +Isn't that what Tom said? Bukannya Tom berkata seperti itu? +It is unfortunately true. Sayang, benar. +It is unfortunately true. Sayangnya itu benar. +It rained hard yesterday. Kemarin hujan deras. +It turned out to be true. Ternyata itu benar. +It turned out to be true. Ternyata itu memang benar. +It was a foolish mistake. Itu kesalahan yang bodoh. +It's a beautiful country. Ini adalah negara yang sangat indah. +It's not about the money. Ini bukan soal uang. +It's not good to overeat. Terlalu banyak makan itu tidak baik. +It's our job to help you. Sudah tugas kami membantu anda. +Let me have a look at it. Biarkan aku melihatnya. +Let's do it after school. Mari kita melakukannya sepulang sekolah. +Let's do it another time. Mari kita lakukan lain kali. +Let's go and take a look. Ayo pergi dan lihat. +Let's hope Tom was right. Semoga saja Tom benar. +Look out for rock slides. Hati-hatilah terhadap longsoran batu. +Mary has not started yet. Mary belum mulai. +Mary is a beautiful girl. Mary adalah gadis yang cantik. +Mary is weaving a carpet. Mary sedang menenun sebuah karpet. +Mary isn't my girlfriend. Mary itu bukan pacarku. +May I ask a favor of you? Bolehkah saya minta tolong? +May I eat this hamburger? Bolehkah saya memakan hamburger ini? +May I turn off the light? Bolehkah aku mematikan lampunya? +My bicycle's been stolen. Sepedaku dicuri. +My car needs a brake job. Rem mobilku perlu diservis. +My family is a large one. Keluargaku keluarga besar. +My family is a large one. Keluargaku adalah keluarga besar. +My family is a large one. Keluargaku adalah keluarga yang besar. +Next Monday is a holiday. Senin depan libur. +No one is doing anything. Tidak ada yang melakukan apa-apa. +Nobody is doing anything. Tidak ada yang melakukan apa-apa. +Nobody knows you're here. Tidak ada yang tahu kamu di sini. +Pass me the salt, please. Tolong ambilkan aku garamnya. +Pass me the wine, please. Tolong ambilkan aku anggurnya. +Please put on your shoes. Tolong kenakan sepatu Anda. +Please turn on the radio. Tolong nyalakan radionya. +She divorced her husband. Dia bercerai dari suaminya. +She has married a nobody. Dia menikah dengan orang biasa. +She looked up at the sky. Ia melihat ke atas langit. +She must have told a lie. Dia pasti sudah berkata bohong. +She's wearing sunglasses. Ia mengenakan kacamata hitam. +Shut up and let me think. Saya sedikitpun tidak punya uang. +Someone stole my bicycle. Seseorang mencuri sepedaku. +That house belongs to me. Rumah itu milikku. +That house is very small. Rumah itu sangat kecil. +That wasn't there before. Itu tidak ada di sana sebelumnya. +That's all I want to say. Hanya itu yang ingin ku sampaikan. +That's what interests me. Itulah yang membuatku tertarik. +The blood test is normal. Tes darahnya normal. +The debate is continuing. Debatnya berlanjut. +The experiment succeeded. Percobaannya berhasil. +The police are after you. Polisi itu mengejarmu. +The puppy wants to sleep. Anak anjing itu ingin tidur. +The television is broken. Televisinya sudah rusak. +The train got in on time. Keretanya datang tepat waktu. +The train was due at six. Keretanya dijadwalkan untuk tiba pada pukul enam. +They paid customs duties. Mereka membayar bea masuk. +This baby is 3 weeks old. Bayi ini usianya tiga minggu. +This baby is 3 weeks old. Usia bayi ini tiga minggu. +This flag is very pretty. Bendera ini sangat bagus. +This is a great question. Ini pertanyaan yang bagus +This is for internal use. Ini untuk penggunaan dalam. +This is how to cook rice. Ini adalah cara untuk menanak nasi. +This is my email address. Ini alamat e-mail saya. +Timing is very important. Pemilihan waktu itu sangat penting. +Tom came by this morning. Tom datang pagi ini. +Tom could've been killed. Tom bisa saja terbunuh. +Tom didn't want to do it. Tom enggan melakukan itu. +Tom died a natural death. Tom meninggal dengan wajar. +Tom fell down the stairs. Tom jatuh dari tangga. +Tom gave Mary his kidney. Tom memberikan Mary ginjalnya. +Tom has to get back home. Tom harus pulang ke rumah. +Tom is a college student. Tom adalah seorang mahasiswa. +Tom is a convicted felon. Tom adalah penjahat terhukum. +Tom is acting on his own. Tom bertindak atas kemauannya sendiri. +Tom is one of my friends. Tom adalah salah satu dari temanku. +Tom is probably sleeping. Tom mungkin sedang tidur. +Tom is smarter than I am. Tom lebih cerdas dariku. +Tom is trying not to cry. Tom mencoba untuk tidak menangis. +Tom isn't afraid to fail. Tom tidak takut gagal. +Tom just doesn't like me. Tom hanya tidak suka padaku. +Tom knew Mary was hungry. Tom tahu Mary sedang lapar. +Tom looks a bit confused. Tom terlihat sedikit kebingungan. +Tom loves being outdoors. Tom sangat suka berada di luar. +Tom might still be alive. Tom mungkin masih hidup. +Tom never left the house. Tom tidak pernah meninggalkan rumah. +Tom never saw Mary again. Tom tidak pernah melihat Mary lagi. +Tom often makes mistakes. Tom sering membuat kesalahan. +Tom passed away recently. Tom meninggal dunia baru-baru ini. +Tom pointed to the floor. Tom menunjuk lantai. +Tom ran down to the lake. Tom berlari ke danau. +Tom reached for his cane. Tom meraih tongkatnya. +Tom says he's busy today. Tom berkata dia sibuk hari ini. +Tom seemed kind of upset. Tom terlihat seperti sedang sedih. +Tom stared at the ground. Tom melihat ke arah tanah. +Tom tried to defend Mary. Tom mencoba untuk melindungi Mary. +Tom used to get up early. Tom terbiasa bangun lebih awal. +Tom wanted grandchildren. Tom menginginkan cucu. +Tom wants to be the boss. Tom ingin menjadi bosnya. +Tom wants to go to Japan. Tom ingin pergi ke Jepang. +Tom was anxious to leave. Tom cemas untuk pergi. +Tom was looking for help. Tom sedang mencari pertolongan. +Tom was murdered by Mary. Tom dibunuh Mary. +Tom went to buy dog food. Tom pergi membeli makanan anjing. +Tomorrow is her birthday. Besok dia berulang tahun. +Wait in the waiting room. Silakan menunggu di ruang tunggu. +We are worried about you. Kami mengkhawatirkanmu. +We import tea from India. Kami mengimpor teh dari India. +We only have three hours. Kita hanya punya tiga jam. +We really need your help. Kami benar-benar membutuhkan bantuanmu. +We talked over the phone. Kami berbicara melalui telepon. +We'll be seeing you, Tom. Sampai jumpa lagi, Tom. +We'll be waiting for you. Kami akan menunggu Anda. +We've done what we could. Kami telah melakukan yang kami bisa. +We've got major problems. Kita mendapat masalah yang besar. +We've got major problems. Kami mendapat masalah besar. +We've run short of money. Kami kekurangan dana. +Welcome to San Francisco. Selamat datang di San Fransisco. +What are you going to do? Apa yang akan kau lakukan? +What are you laughing at? Kau menertawakan apa? +What are you looking for? Apa yang sedang kamu cari? +What are you snacking on? Kamu lagi ngemil apa? +What are you up to today? Apa yang ingin kamu lakukan hari ini? +What are your intentions? Apa tujuanmu? +What did you do that for? Untuk apa kau melakukannya? +What do you suggest then? Lalu apa yang kau sarankan? +What do you want from us? Apa yang kau inginkan dari kami? +What does USSR stand for? Apa kepanjangan dari USSR? +What time are you coming? Jam berapa kamu akan datang? +What time do you get off? Kamu berangkat jam berapa? +What time do you go home? Kamu pulang jam berapa? +What time will you leave? Kamu berangkat jam berapa? +What time will you leave? Kau akan berangkat jam berapa? +When are you coming home? Kapan kamu pulang ke rumah? +When are you coming home? Kapan Anda pulang ke rumah? +When does the show start? Kapan pertunjukannya mulai? +When should we check out? Kapan kami harus lapor keluar? +When was your first love? Kapan cinta pertamamu? +When will you leave here? Kapan kamu berangkat dari sini? +Where are you headed for? Kamu menuju ke mana? +Where can I buy a ticket? Di mana saya bisa beli tiket? +Where can I buy a ticket? Beli tiket di mana, ya? +Where does he want to go? Dia ingin pergi ke mana? +Which sports do you like? Olahraga mana yang kamu sukai? +Who do you think you are? Kamu pikir kamu ini siapa? +Why did you open the box? Kenapa kau membuka kotaknya? +Why do I need to do this? Kenapa aku perlu melakukan ini? +Why don't you believe me? Kenapa kamu tidak mempercayaiku? +Why won't you believe me? Kenapa kamu tidak mempercayaiku? +Will you give me a drink? Bisakah kau memberikanku minuman? +Wine is made from grapes. Minuman anggur terbuat dari anggur. +You are absolutely right. Kau memang benar. +You can dance, can't you? Kamu bisa menari, kan? +You can do it, can't you? Kamu bisa melakukannya, kan? +You can't lift the piano. Kau tidak bisa mengangkat piano itu. +You did an excellent job. Kau mengerjakannya dengan sangat baik. +You didn't need to hurry. Kau tidak perlu terburu-buru. +You look different today. Kamu terlihat berbeda hari ini. +You may come if you like. Silakan datang jika Anda berkenan. +You said you were hungry. Anda bilang anda lapar. +You should get back home. Kamu sebaiknya pulang ke rumah. +You shouldn't be in here. Kamu seharusnya tidak berada di sini. +You shouldn't go to work. Kau sebaiknya tidak pergi bekerja. +You've got a lot of guts. Kamu berani sekali. +You've got to be kidding! Kau pasti bercanda! +You've set a bad example. Kau memberi contoh yang buruk. +Your book is on the desk. Bukumu ada di atas meja. +Your tie has come undone. Dasimu lepas. +A rat ran across the road. Seekor tikus berlari melintasi jalan. +A strong wind was blowing. Sebuah angin kencang berhembus. +Anyone can make a mistake. Setiap orang bisa berbuat salah. +Are you going to shoot me? Apa kau akan menembakku? +Are you having a busy day? Apa harimu sibuk? +Are you telling the truth? Apa kau mengatakan yang sebenarnya? +Australia is no exception. Tidak terkecuali Australia. +Can I do anything for you? Ada yang bisa saya lakukan untuk Anda? +Can we get Tom to do that? Apakah kita bisa membuat Tom melakukan itu? +Could you look at me, Tom? Dapatkah kamu melihatku, Tom? +Did I tell you I had this? Apakah aku memberitahumu kalau aku memiliki ini? +Did you find your letters? Apa kamu menemukan surat-suratmu? +Did you get this from Tom? Apakah kamu mendapatkan ini dari Tom? +Did you go out last night? Apa semalam kau pergi keluar? +Did you notice any change? Apa kau melihat adanya perubahan? +Do you have Tom's address? Kamu punya alamatnya Tom? +Do you have any allergies? Apa Anda punya alergi? +Do you have any questions? Apakah ada pertanyaan? +Do you know Tom's address? Apa kamu tahu alamat rumah Tom? +Do you know what happened? Apa kau tahu apa yang sedang terjadi? +Do you like peanut butter? Kamu suka selai kacang? +Do you understand me, Tom? Apakah kamu memahami maksudku, Tom? +Do you want to come along? Apa kamu mau ikut? +Do you work out regularly? Apakah kamu berolahraga secara rutin? +Does your friend like tea? Apakah temanmu suka teh? +Don't look at me that way. Jangan melihatku seperti itu! +Don't trust what Tom says. Jangan percaya pada apa yang Tom katakan. +Drink less and sleep more. Kurangi minum dan tidurlah lebih banyak. +Each student has a locker. Tiap siswa memiliki lokernya masing-masing. +Everybody looks up to him. Semua orang menaruh hormat padanya. +Everybody tasted the food. Semuanya mencicipi makanannya. +Everyone believed his lie. Semua orang mempercayai kebohongannya. +Everyone here is friendly. Semua orang di sini ramah. +Everything's really cheap. Semuanya sangat murah. +Finding work is difficult. Sulit sekali mencari pekerjaan. +Finding work is difficult. Mencari pekerjaan itu susah. +Give me a hundred dollars. Beri aku seratus dolar. +Go home to your wife, Tom. Pulanglah ke istrimu, Tom. +Have you eaten dinner yet? Kamu sudah makan malam belum? +Have you eaten supper yet? Kamu sudah makan malam belum? +Have you ever been abroad? Kamu pernah ke luar negeri? +Have you finished the job? Apakah kau sudah menyelesaikan pekerjaan itu? +He broke the world record. Dia memecahkan rekor dunia. +He couldn't stop laughing. Dia tidak bisa berhenti tertawa. +He doesn't know any of us. Dia tidak mengenal satupun dari kami. +He gets angry very easily. Dia sangat mudah marah. +He hired some new workers. Dia mempekerjakan beberapa pekerja baru. +He likes bread and butter. Dia suka roti dan mentega. +He often plays the guitar. Dia sering bermain gitar. +He seems to be in trouble. Dia sepertinya dalam masalah. +He wanted to buy the book. Dia ingin membeli buku tersebut. +He was afraid of his wife. Dia takut dengan istrinya. +He was blue from the cold. Dia menjadi pucat karena kedinginan. +He'll help you if you ask. Dia akan membantumu jika kau memintanya. +He's sleeping like a baby. Dia tidur seperti bayi. +He's standing on his head. Dia berdiri di atas kepalanya. +Her hobby is bodybuilding. Hobinya adalah binaraga. +How did your interview go? Bagaimana dengan wawancara anda? +How did your interview go? Bagaimana wawancara anda telah berjalan? +How late is the bank open? Banknya buka sampai pukul berapa? +How long will you be gone? Kamu pergi selama berapa lama? +How many bags do you have? Berapa banyak tas yang Anda bawa? +How much is this umbrella? Payung ini berapa harganya? +Humans can't live on Mars. Manusia tidak bisa hidup di Mars. +I agree with your opinion. Saya setuju dengan pendapat kamu. +I almost missed the train. Aku hampir saja ketinggalan keretanya. +I am going to play tennis. Saya akan bermain tenis. +I am living the good life. Aku menjalani hidup yang baik. +I appreciate your efforts. Saya menghargai kerja keras anda. +I ate a hot dog for lunch. Saya makan hot dog untuk makan siang. +I bought a red sports car. Aku membeli sebuah mobil sport merah. +I came to Japan last year. Aku datang ke Jepang tahun lalu. +I can't bend my right arm. Aku tidak bisa menekuk tangan kananku. +I can't explain it either. Aku juga tidak dapat menjelaskannya. +I can't go until he comes. Aku tidak bisa pergi sebelum dia datang. +I can't lift my right arm. Aku tidak bisa mengangkat lengan kananku. +I can't remember his name. Aku tidak bisa mengingat namanya. +I can't take this anymore. Aku tidak tahan lagi. +I can't take this anymore. Aku sudah tidak tahan lagi. +I didn't mean to hurt you. Aku tidak bermaksud menyakitimu. +I didn't want to waste it. Aku tidak mau menyia-nyiakannya. +I don't care what happens. Aku tidak peduli akan apa yang akan terjadi. +I don't have a phone book. Saya tidak punya buku telepon. +I don't know what I'll do. Aku tidak tahu apa yang akan kulakukan. +I don't think that's true. Saya tidak mengira itu benar +I don't want that anymore. Aku sudah tidak menginginkan itu. +I had to work on an essay. Tadi aku harus mengerjakan esaiku. +I haven't eaten lunch yet. Aku belum makan siang. +I heard you lost your job. Aku dengar kau kehilangan pekerjaanmu. +I just finished breakfast. Aku baru saja selesai sarapan. +I just finished breakfast. Saya baru saja selesai makan pagi. +I just told Tom the truth. Aku cuma memberitahu Tom yang sebenarnya. +I like both dogs and cats. Aku suka anjing dan kucing. +I need someone to talk to. Saya perlu seseorang untuk diajak bicara. +I need to get some stamps. Aku butuh beberapa perangko. +I prefer modern furniture. Aku lebih suka mebel modern. +I prefer poetry to novels. Aku lebih suka puisi daripada novel. +I saw it with my own eyes. Aku melihatnya dengan mataku sendiri. +I saw you with a tall boy. Aku melihatmu bersama anak laki-laki yang badannya tinggi. +I should ask, shouldn't I? Aku harus bertanya, bukan? +I think Tom is aggressive. Aku pikir Tom adalah seorang yang agresif. +I think that ghosts exist. Aku pikir hantu itu ada. +I think that she's honest. Kurasa dia jujur. +I think that you're wrong. Aku pikir kau salah. +I think they're using you. Aku pikir mereka memperalat kamu. +I want something to drink. Aku menginginkan sesuatu untuk diminum. +I want you to work harder. Aku ingin kamu bekerja lebih keras lagi. +I watched TV this morning. Aku menonton TV pagi ini. +I wish I had this problem. Saya berharap saya memperoleh problem ini. +I work for an oil company. Saya bekerja di sebuah perusahaan minyak. +I'd like something to eat. Aku menginginkan sesuatu untuk dimakan. +I'd like the bill, please. Tolong bonnya. +I'd like to know for sure. Aku ingin tahu secara pasti. +I'd rather die than leave. Lebih baik aku mati daripada aku pergi. +I'll get this bag for you. Aku akan membelikan tas ini untukmu. +I'll give you this camera. Aku akan memberimu kamera ini. +I'll go to a museum today. Aku akan pergi ke sebuah museum hari ini. +I'll lend you my notebook. Aku akan meminjamkanmu buku catatanku. +I'll return home tomorrow. Saya akan pulang kerumah besok. +I'll visit a museum today. Aku akan mengunjungi sebuah museum hari ini. +I'll wait at the bus stop. Akan kutunggu di halte bus. +I'm delighted to meet you. Senang bertemu denganmu. +I'm glad I could help out. Saya senang bisa membantu. +I'm going to be out today. Aku akan bepergian hari ini. +I'm going to the restroom. Saya akan pergi ke toilet sebentar. +I'm just messing with you. Aku cuma main-main denganmu. +I'm looking forward to it. Aku menantikannya. +I'm not always so lenient. Aku tidak selalu bersikap toleran. +I'm not really that sorry. Aku tidak begitu menyesal. +I'm not what I used to be. Aku tidak sama seperti dulu. +I'm telling you the truth. Aku mengatakan padamu yang sebenarnya. +I've been writing letters. Aku sedang menulis surat. +I've eaten too much today. Aku terlalu banyak makan hari ini. +I've got a plane to catch. Pesawatku sudah mau berangkat. +I've just finished eating. Aku baru saja selesai makan. +I've never been to Europe. Aku belum pernah ke Eropa? +If you don't eat, you die. Kau akan mati jika kau tidak makan. +Is it something important? Apakah ini penting? +Is this water OK to drink? Apa air ini baik untuk diminum? +It depends on the context. Itu tergantung pada konteks. +It doesn't take very long. Tidak memerlukan waktu lama. +It is best left untouched. Lebih baik kita meninggalkannya tidak tersentuh. +It is out of the question. Ini di luar pertanyaan? +It seems overpriced to me. Sepertinya itu terlalu mahal bagiku. +It's OK to be scared, Tom. Tak apa untuk takut, Tom. +It's OK to be scared, Tom. Tidak masalah merasa takut, Tom. +It's Tom's birthday today. Hari ini ulang tahun Tom. +It's been a difficult day. Hari yang cukup berat. +It's time to go to school. Waktunya pergi ke sekolah. +Keep your classroom clean. Jagalah kebersihan kelasmu. +Let me say goodbye to Tom. Biarkan saya mengucapkan selamat tinggal kepada Tom. +Let's do it one more time. Mari kita melakukannya sekali lagi. +Let's do it when he comes. Mari kita melakukannya ketika ia tiba. +Let's get out of the rain. Mari kita mencari tempat untuk berteduh. +Let's talk about your job. Mari kita membicarakan tentang pekerjaanmu. +Mary likes milk very much. Mary sangat suka susu. +May I have a bus schedule? Boleh saya meminta sebuah jadwal keberangkatan bus? +May I see your claim tags? Bolehkah saya melihat kupon Anda? +Maybe I'll leave tomorrow. Mungkin besok saya akan pergi. +Maybe Tom would like that. Mungkin Tom akan menyukai itu. +My apartment is near here. Apartemen saya ada di dekat sini. +My battery is running out. Baterai saya habis. +My home is in the country. Rumahku di kampung. +Nature is full of mystery. Alam semesta penuh dengan misteri. +One of the guards is dead. Salah seorang dari para penjaga mati. +Pizza is my favorite food. Piza adalah makanan favoritku. +Please lend me your knife. Tolong pinjamkan aku pisaumu. +Please pass me the butter. Tolong ambilkan aku menteganya. +Please turn off the light. Tolong matikan lampunya. +Please turn off the radio. Tolong matikan radionya. +Read it once more, please. Tolong bacalah sekali lagi. +School begins at 8:10 a.m. Kegiatan sekolah dimulai pada pukul 8:10 pagi. +School starts next Monday. Sekolah mulai Senin depan. +She's got the best grades. Dia mendapatkan nilai terbaik. +She's pregnant with twins. Kandungannya kembar. +Some people never grow up. Beberapa orang tidak pernah menjadi dewasa. +Tell Tom I don't like him. Beritahu Tom aku tidak suka padanya. +Thanks for your hard work. Terima kasih atas kerja kerasmu. +That is a reputable store. Itu adalah toko yang terkemuka. +That tie really suits you. Dasi itu benar-benar cocok denganmu. +That'll remain our secret. Itu akan tetap menjadi rahasia kita. +The doctor gave it to her. Dokter itu memberikannya padanya. +The event made him famous. Kejadian itu membuat dia terkenal. +The pain hasn't gone away. Penyakitnya belum sembuh. +The police can't find Tom. Polisi tidak berhasil menemukan Tom. +The pond is 3 meters deep. Kedalaman kolam tersebut tiga meter. +The rain lasted four days. Hujannya bertahan selama empat hari. +The station is pretty far. Stasiunnya lumayan jauh. +The train arrived on time. Keretanya tiba tepat waktu. +There are no comments yet. Belum ada komentar. +There are no health risks. Tidak ada resiko-resiko kesehatan. +There's not enough coffee. Kopinya kurang. +They accomplished nothing. Mereka tidak menyelesaikan apapun. +They didn't find the bomb. Mereka tidak menemukan bomnya. +They have plenty of money. Mereka punya banyak uang. +They rejected my proposal. Mereka menolak proposalku. +They were waiting for Tom. Mereka sedang menunggu Tom. +They won the silver medal. Mereka memenangkan medali perak. +They're very enthusiastic. Mereka sangat antusias. +This is a fantastic place. Ini adalah tempat yang sangat bagus. +This is my younger sister. Ini adikku. +This is my younger sister. Ini adik perempuanku. +This room is large enough. Ruangan ini cukup luas. +This wasn't cheap, was it? Ini tidak murah, bukan? +Tom always makes me laugh. Tom selalu membuatku tertawa. +Tom appeared to be crying. Tom kelihatannya menangis. +Tom asked us to be silent. Tom meminta kami untuk diam. +Tom clicked off the light. Tom mematikan lampunya. +Tom clicked the light off. Tom mematikan lampunya. +Tom doesn't like the idea. Tom tidak menyukai ide tersebut. +Tom had to clean his room. Tom harus membersihkan kamarnya. +Tom has a bad disposition. Tom mempunyai perangai yang buruk. +Tom is Mary's best friend. Tom adalah teman baik Mary. +Tom is a lot better today. Tom jauh lebih baik hari ini. +Tom is careless, isn't he? Tom itu masa bodoh, kan? +Tom is finishing his work. Tom sedang menyelesaikan pekerjaannya. +Tom is growing a mustache. Tom menumbuhkan kumis. +Tom is here to protect me. Tom di sini untuk melindungiku. +Tom is mentally disturbed. Tom terganggu secara mental. +Tom is not in his bedroom. Tom tidak sedang berada di kamarnya. +Tom is sitting on a chair. Tom sedang duduk diatas sebuah kursi. +Tom is thirteen years old. Tom berumur tiga belas tahun. +Tom isn't afraid of death. Tom tidak takut mati. +Tom isn't as rich as Mary. Tom tidak sekaya Mary. +Tom isn't very photogenic. Tom tidak terlalu cocok untuk difoto. +Tom isn't watching TV now. Tom tidak sedang menonton TV sekarang. +Tom knows he's in trouble. Tom tahu dia dalam masalah. +Tom likes science fiction. Tom menyukai sains fiksi. +Tom likes to travel alone. Tom suka melakukan perjalanan sendirian. +Tom loves science fiction. Tom menyukai sains fiksi. +Tom may have already left. Tom mungkin saja sudah pergi. +Tom may have been injured. Tom mungkin saja terluka. +Tom might be able to help. Tom mungkin bisa membantu. +Tom never arrives on time. Tom tidak pernah datang tepat waktu. +Tom really likes antiques. Tom sungguh menyukai barang antik. +Tom really makes me angry. Tom sungguh membuatku marah. +Tom took part in the race. Tom ikut berpartisipasi pada balapan. +Tom tried to deceive Mary. Tom mencoba menipu Mary. +Tom wants to meet with me. Tom ingin bertemu denganku. +Tom was in seventh heaven. Tom sudah ada di langit ketujuh +Tom was working part-time. Tom bekerja paruh waktu. +Tom wiped the table clean. Tom mengelap mejanya sampai bersih. +Turn on the light, please. Tolong nyalakan lampu. +Turn on the light, please. Tolong nyalakan lampunya. +Turn on the radio, please. Bisa tolong nyalakan radionya. +We are having a good time. Kami bersenang-senang. +We go abroad every summer. Kami pergi ke luar negri setiap musim panas. +We had a chat for a while. Kami berbincang sebentar. +We had a lot of furniture. Kami memiliki banyak sekali furnitur. +We have a lot of homework. Pekerjaan rumah kami sangat banyak. +We need to speak with you. Kami perlu bicara dengan Anda. +We prepared for an attack. Kami bersiap untuk melancarkan serangan. +We walked among the trees. Kami berjalan di antara pepohonan. +We were caught in a storm. Kami terperangkap dalam badai. +We're all so proud of you. Kami semua sangat bangga padamu. +We're going to be rescued. Kita akan diselamatkan. +We've done the impossible. Kami telah melakukan hal yang mustahil. +We've got to do something. Kita harus melakukan sesuatu. +What color are Tom's eyes? Apa warna mata Tom? +What do you want to drink? Kamu mau minum apa? +What do you want to drink? Kau mau minum apa? +What do you want to drink? Mau minum apa? +What do you want to drink? Apa yang ingin kau minum? +What do you want to drink? Anda ingin minum apa? +What goes on in this room? Apa yang sedang terjadi di ruangan ini? +What have you done to Tom? Apa yang sudah kau perbuat pada Tom? +What kind of test is that? Ujian apa itu? +What number bus do I take? Bus nomor berapa yang saya ambil? +What symptoms do you have? Gejala-gejala apa saja yang Anda alami? +What time are you leaving? Kamu berangkat jam berapa? +What time is it there now? Di sana pukul berapa sekarang? +What time is it there now? Di sana sekarang jam berapa? +What'll you have to drink? Kamu mau minum apa? +What'll you have to drink? Kau mau minum apa? +What'll you have to drink? Mau minum apa? +What's that on your shirt? Apa yang ada di bajumu itu? +What's the situation like? Bagaimana keadaannya? +What's your favorite food? Apa makanan favoritmu? +What's your friend's name? Nama temanmu siapa? +When are you walking home? Kapan kamu pulang ke rumah? +When did it begin to rain? Kapan hujannya mulai turun? +When did you realize that? Kapan kamu menyadari hal itu? +When does the movie start? Kapan filmnya mulai? +When will you return home? Kapan kamu kembali ke rumah? +When will you return home? Kapan kamu akan kembali ke rumah? +Where are you going to go? Kau mau pergi ke mana? +Where are you going to go? Anda akan pergi ke mana? +Where are you guys headed? Kalian mau menuju ke mana? +Where did you get the hat? Dari mana kamu dapat topi itu? +Where does she want to go? Dia ingin pergi ke mana? +Where is the bus terminal? Di mana terminal busnya? +Where is the nearest bank? Di mana bank terdekat? +Where were you last night? Semalam kamu ke mana? +Where's the train station? Stasiun kereta ada di mana? +Where's the train station? Ada di mana stasiun kereta apinya? +Where's the train station? Stasiun kereta apinya di mana? +Who painted this painting? Siapa yang melukis lukisan ini? +Who's your favorite actor? Siapa aktor favoritmu? +Why can't we go visit Tom? Kenapa kita tidak bisa mengunjungi Tom? +Why didn't you believe me? Kenapa kau tidak mempercayaiku? +Why do I have to help Tom? Mengapa aku harus menolong Tom? +Why doesn't Tom like Mary? Kenapa Tom tidak menyukai Mary? +Would you care to join me? Maukah Anda bergabung dengan saya? +Would you like some fruit? Apakah Anda mau buah? +Write on every other line. Tulislah tiap setelah satu baris. +Yesterday was my birthday. Kemarin adalah hari ulang tahunku. +You are selling him short. Kau meremehkan dia. +You are tired, aren't you? Kamu lelah, ya? +You drink too much coffee. Kamu terlalu banyak minum kopi. +You have a gift for music. Kamu punya bakat di bidang musik. +You have the wrong number. Kau salah memasukkan nomor telepon. +You have to pay the price. Kau harus membayar harganya +You must control yourself. Kamu harus mengendalikan dirimu. +You must not give up hope. Kamu tidak boleh berhenti berharap. +You must tighten the knot. Kamu harus kencangkan ikatannya. +You ought to see a doctor. Kamu harus pergi ke dokter. +You seem to be a busy guy. Kau terlihat seperti orang sibuk. +You seem to be a busy man. Kau terlihat seperti orang sibuk. +You should be proud of me. Kau harusnya bangga denganku. +You'd better listen to me. Ada baiknya kamu mendengarkanku. +You'd better not go there. Sebaiknya kamu tidak pergi ke sana. +You'd better see a doctor. Sebaiknya kau pergi ke dokter. +You're not yourself today. Kamu tidak seperti dirimu hari ini. +You're too drunk to drive. Kau terlalu mabuk untuk mengemudi. +You've done a perfect job. Kau mengerjakannya dengan sempurna. +You've given me your cold. Aku tertular pilekmu. +Your English is improving. Bahasa Inggrismu meningkat. +A minute has sixty seconds. Dalam satu menit ada 60 detik. +A student wants to see you. Seorang siswa ingin bertemu dengan Anda. +Add 5 and 2, and you get 7. 5 tambah 2, hasilnya 7. +After all, it's reasonable. Lagipula, itu masuk akal. +Anybody can make a mistake. Setiap orang bisa berbuat salah. +Are you a Japanese student? Apakah kamu siswa dari Jepang? +Are you certain about that? Apa kau yakin dengan hal itu? +Are you certain about this? Apa kau yakin dengan hal ini? +Are you sure that's enough? Kamu yakin itu cukup? +Aren't you being very rude? Tidakkah kamu menjadi sangat kasar? +At what time does it close? Jam berapa tutupnya? +Banks open at nine o'clock. Bank buka pada pukul sembilan. +Be sure to bring rain gear. Jangan lupa membawa jas hujan. +Bring me a bucket of water. Bawakan aku seember air. +Can I borrow your scissors? Boleh pinjam gunting? +Can I borrow your scissors? Boleh aku pinjam guntingmu? +Can I find you on Facebook? Bisakah aku menemukanmu di Facebook? +Can you lend me 10,000 yen? Bisakah kau meminjamkanku 10.000 yen? +Can you slow down a little? Bisakah kamu lebih pelan? +Can't a woman have a dream? Bisakah seorang wanita memiliki impian? +Could you stay out of this? Bisakah kau tidak ikut campur dalam urusan ini? +Did you enjoy your holiday? Apa kau menikmati liburanmu? +Did you follow any of that? Apa kau mengikuti perkembangannya? +Did you go to see a doctor? Apakah Anda sudah pergi ke dokter? +Do what you think is right. Lakukan apa yang kamu pikir benar. +Do you belong to any clubs? Apa kamu mengikuti sebuah klub? +Do you go to school by bus? Apa kau pergi ke sekolah dengan bus? +Do you have life insurance? Apakah Anda memiliki asuransi jiwa? +Do you know the difference? Apakah Anda tahu perbedaannya? +Do you think that's enough? Apa kamu pikir itu cukup? +Don't beat around the bush. Jangan bicara berputar-putar. +Don't worry about the past. Jangan mengkhawatirkan tentang masa lalu. +Don't you think it's risky? Apakah anda tidak berfikir ini beresiko? +Drop by my office any time. Silakan mampir ke kantor saya kapanpun juga. +Fill the bottle with water. Isi botolnya dengan air. +Fill the bucket with water. Isi embernya dengan air. +Give me something to drink. Beri aku sesuatu untuk diminum. +Giving up isn't the answer. Menyerah bukan jawaban. +Hang on just a second, Tom. Tunggu sebentar, Tom. +Hang your coat on the hook. Gantung jasmu pada sangkutan. +Have you changed your mind? Apa kamu berubah pikiran? +Have you ever visited Rome? Pernahkah kau mengunjungi Roma? +He arrived here last night. Dia tiba di sini tadi malam. +He decided to quit smoking. Dia memutuskan untuk berhenti merokok. +He is a handsome young man. Ia pemuda yang tampan. +He loses his temper easily. Dia mudah sekali marah. +He played tennis yesterday. Dia bermain tenis kemarin. +He wished he had more time. Dia berharap dia memiliki lebih banyak waktu. +He's always late for class. Dia selalu telat ke kelas. +He's always short of money. Dia selalu kekurangan uang. +Holland is a small country. Belanda adalah negara yang kecil. +How about going for a swim? Bagaimana kalau pergi berenang? +How did you like the party? Bagaimana pestanya? +How long does a bear sleep? Berapa lama beruang tidur? +How long have we been here? Berapa lama kita sudah berada di sini? +How much money do you want? Berapa banyak uang yang kamu inginkan? +How often do you go abroad? Seberapa sering kamu pergi ke luar negeri? +I am tired of hearing that. Saya bosan mendengar hal itu. +I can't attend the meeting. Saya tidak bisa menghadiri rapat itu. +I can't deal with this now. Saya tidak bisa menangani ini sekarang. +I can't raise my right arm. Aku tidak bisa menaikkan lengan kananku. +I can't remember any of it. Aku tidak dapat mengingat apapun tentang hal itu. +I caught a cold last month. Bulan lalu saya sakit flu. +I didn't touch your guitar. Aku tidak menyentuh gitarmu. +I don't have those answers. Aku tidak memiliki jawaban-jawaban itu. +I don't know what you mean. Aku tidak tahu apa maksudmu. +I don't remember any of it. Aku tidak ingat apa-apa tentang hal itu. +I don't think you're crazy. Aku tidak berpikir kalau kau gila. +I don't trust him any more. Aku sudah tidak lagi mempercayai dia. +I don't trust him any more. Aku sudah tidak percaya padanya. +I don't understand English. Saya tidak mengerti bahasa Inggris. +I feel like having a drink. Aku merasa ingin minum. +I forgot to close the door. Aku lupa menutup pintunya. +I forgot your phone number. Aku lupa nomor teleponmu. +I had intended to go there. Aku berencana pergi ke sana. +I have some things for you. Saya ada beberapa barang buat kamu. +I have to go to the toilet. Aku harus pergi ke toilet. +I have to go to the toilet. Saya harus pergi ke toilet. +I have to use the bathroom. Saya harus pergi ke kamar mandi. +I have to use the restroom. Aku harus pergi ke kamar kecil. +I helped write that report. Saya bantu menulis laporan itu. +I know you worry about Tom. Aku tahu kamu khawatir pada Tom. +I like fish more than meat. Aku lebih suka ikan ketimbang daging. +I like going to the movies. Aku suka pergi ke bioskop. +I like to read story books. Saya suka membaca buku cerita. +I must have made a mistake. Aku pasti sudah membuat sebuah kesalahan. +I need to go get my laptop. Aku perlu pergi mengambil laptopku. +I need to go to the toilet. Aku harus pergi ke toilet. +I need to go to the toilet. Saya harus pergi ke toilet. +I need to use the bathroom. Saya harus pergi ke kamar mandi. +I really do need your help. Aku benar-benar membutuhkan bantuanmu. +I think I'm going to faint. Rasanya aku mau pingsan. +I think that's the problem. Saya pikir itulah masalahnya. +I think you've got the flu. Saya kira Anda terkena flu. +I understand your feelings. Aku mengerti perasaanmu. +I understood what she said. Saya dapat mengerti apa yang dia katakan. +I want to change the world. Aku ingin mengubah dunia. +I wanted to show it to you. Aku ingin menunjukkannya padamu. +I was still a student then. Saya masih pelajar saat itu. +I will be at home tomorrow. Saya ada di rumah besok. +I will do anything for you. Aku akan melakukan apa saja untukmu. +I'd like to master English. Aku ingin menguasai bahasa Inggris. +I'd like to speak with Tom. Saya ingin berbicara dengan Tom. +I'll give you this pendant. Aku akan memberimu liontin ini. +I'll phone you every night. Saya akan menelpon anda setiap malam. +I'm listening to the radio. Saya sedang mendengarkan radio. +I'm living with my parents. Aku tinggal bersama orangtua. +I'm off to help my friends. Aku pergi membantu teman-temanku. +I've just finished my work. Aku baru menyelesaikan pekerjaanku. +I've read both these books. Aku sudah membaca kedua buku ini. +I've written three letters. Aku sudah menulis tiga surat. +In other words, he is lazy. Dengan kata lain, dia malas. +Is one thousand yen enough? Apakah seribu yen cukup? +Is there a delivery charge? Apa ada biaya pengiriman? +It kept raining for a week. Hujan terus terun selama seminggu. +It was love at first sight. Itu adalah cinta pada pandangan yang pertama. +It's a confidential matter. Ini perihal yang rahasia. +It's all happening so fast. Semuanya terjadi begitu cepat. +It's more than you deserve. Itu lebih dari yang kamu minta. +It's none of your business. Ini bukan urusanmu. +It's very cold in my house. Di rumahku sangat dingin. +Lend me some books to read. Pinjamkan padaku beberapa buku untuk dibaca. +Let's listen to some music. Mari kita mendengarkan musik. +Let's talk about your work. Mari kita membicarakan tentang pekerjaanmu. +Look at that tall building. Lihat gedung yang tinggi itu. +Many young men went to war. Banyak pemuda ikut perang. +Music makes our life happy. Musik membuat hidup kita bahagia. +My birthday is coming soon. Hari ulang tahunku akan segera tiba. +My father is not talkative. Ayahku tidak suka banyak bicara. +My hobby is reading novels. Hobiku adalah membaca novel. +My sister is fond of music. Adikku suka musik. +My sister is fond of music. Kakakku suka musik. +Nobody is going to stop me. Tak akan ada yang bisa menghentikanku. +Now isn't a very good time. Sekarang bukanlah waktu yang tepat. +Pass me the butter, please. Tolong ambilkan aku menteganya. +Please pay at the register. Silakan membayar di kasir. +Please read the text below. Silakan baca tulisan di bawah ini. +Please take off your shoes. Tolong lepas sepatu Anda. +Please turn off the lights. Tolong matikan lampu-lampunya. +Please write with a pencil. Tolong tulis menggunakan pensil. +Probably he will come soon. Kemungkinan dia akan segera datang. +Put in a little more sugar. Tambahkan sedikit gula. +She bought a loaf of bread. Dia membeli sepotong roti. +She drives an imported car. Ia mengendarai mobil impor. +She forced him to sit down. Dia memaksanya untuk duduk. +She has long arms and legs. Dia memiliki lengan dan kaki yang panjang. +She is playing with a doll. Dia bermain dengan boneka. +She took care of his wound. Ia merawat lukanya. +She was invited to a party. Dia telah diundang untuk sebuah pesta +She went there last summer. Dia pergi ke sana musim panas lalu. +So what are you suggesting? Jadi kau menyarankan apa? +Something's not right here. Ada sesuatu yang ga bener nih. +Suicide is a desperate act. Bunuh diri adalah tindakan nekat. +Take the road on the right. Ambil jalan di sebelah kanan. +That's all Tom talks about. Itulah yang dibicarakan oleh Tom. +That's your responsibility. Itu tanggungjawabmu. +The air felt a little cold. Udaranya terasa agak dingin. +The archer killed the deer. Pemanah itu membunuh rusanya. +The fountain is over there. Air mancurnya ada di sebelah sana. +The job is almost finished. Pekerjaannya hampir selesai. +The meeting started at ten. Rapatnya dimulai pada pukul sepuluh. +The meeting was last month. Rapat itu dilaksanakan sebulan yang lalu. +The painting won't be sold. Lukisan itu tidak akan dijual. +The plane landed at Narita. Pesawat itu mendarat di Narita. +The rain changed into snow. Hujannya berubah menjadi salju. +The rain continued all day. Hujannya berlanjut hingga sehari penuh. +The world is a crazy place. Dunia adalah tempat yang gila. +There is no room for doubt. Tidak ada ruang untuk ragu. +They asked after my father. Mereka menanyakan ayah saya. +They called their son John. Mereka menamai anak laki-laki mereka John. +They just want to have fun. Mereka hanya ingin bersenang-senang. +This aroused her suspicion. Hal ini membuatnya merasa curiga. +This book deals with China. Buku ini berkaitan dengan Cina. +This is never going to end. Hal ini tidak akan pernah berakhir. +This man is very, very old. Pria ini benar-benar sangat tua. +Tom and I aren't strangers. Tom dan aku bukan orang asing. +Tom and Mary are here, too. Tom dan Mary juga ada di sini. +Tom and Mary are outsiders. Tom dan Mary adalah orang luar. +Tom can't make up his mind. Tom tidak dapat memutuskannya. +Tom doesn't have an office. Tom tidak punya kantor. +Tom goes to school on foot. Tom ke sekolah dengan berjalan kaki. +Tom has confidence in Mary. Tom percaya pada Mary. +Tom has low blood pressure. Tom memiliki tekanan darah rendah. +Tom is a man you can trust. Tom laki-laki yang bisa kamu percaya. +Tom is a self-educated man. Tom adalah seorang otodidak. +Tom is bleeding internally. Tom mengalami pendarahan dalam. +Tom is impatient, isn't he? Tom tidak sabaran, ya? +Tom is itching for a fight. Tom sudah tidak tahan ingin berkelahi. +Tom is three years old now. Tom saat ini berusia tiga tahun. +Tom is trying not to laugh. Tom sedang berusaha untuk tidak tertawa +Tom kissed me on the mouth. Tom mencumbuku. +Tom lives across the river. Tom tinggal di seberang sungai. +Tom looks busy, doesn't he? Bukankah Tom terlihat sibuk? +Tom might be seriously ill. Tom mungkin sedang sakit berat. +Tom played a trick on Mary. Tom menipu Mary. +Tom probably can't do that. Tom mungkin tidak bisa melakukannya. +Tom promised me he'd do it. Tom berjanji padaku bahwa dia akan melakukannya. +Tom seemed to be surprised. Tom terlihat terkejut. +Tom shot Mary with a rifle. Tom menembak Mary dengan senapan. +Tom speaks relatively fast. Tom bicaranya relatif cepat. +Tom walked along the shore. Tom berjalan di sepanjang tepi pantai. +Tom was working last night. Tom bekerja semalam. +Tom will go there tomorrow. Tom akan pergi ke sana besok. +Tom won't like that answer. Tom tidak akan menyukai jawaban itu. +Tom would like some coffee. Tom ingin kopi. +Tom's hair has turned gray. Rambut Tom sudah memutih. +Turn the radio up a little. Besarkan volume radionya sedikit. +Until he comes, I can't go. Sebelum dia datang, aku tidak bisa pergi. +Wait here till I come back. Tunggulah di sini hingga aku kembali. +We are about to leave here. Kami baru saja akan pergi meninggalkan tempat ini. +We both have the same name. Kita berdua punya nama yang sama. +We both have the same name. Kami berdua punya nama yang sama. +We don't care what he does. Kami tidak peduli dengan apa yang dia perbuat. +We don't know where we are. Kami tidak tahu di mana kami berada. +We have breakfast at seven. Kami sarapan pada pukul tujuh. +We make decisions together. Kami membuat keputusan bersama. +We must always do our best. Kita harus selalu melakukan yang terbaik. +We played soccer yesterday. Kami bermain sepak bola kemarin. +We should obey our parents. Kita harus mematuhi kedua orang tua kita. +We shouldn't have told Tom. Harusnya kita tidak memberi tahu Tom. +We'll have to do something. Kita harus melakukan sesuatu. +We're going to the theater. Kami akan pergi ke teater. +We've done the best we can. Kami telah melakukan yang terbaik yang kami bisa. +We've got very little time. Waktu kita sangat sedikit. +Weapons are forbidden here. Di sini senjata dilarang. +What are you going to play? Apa yang akan kamu mainkan? +What are you talking about? Apa yang sedang kamu bicarakan? +What kind of stone is this? Batu apa sih ini? +What's always on your mind? Apa yang selalu membuatmu khawatir? +What's in fashion in Paris? Apa yang sedang mengetren di Paris? +What's the matter with you? Ada apa denganmu? +What's your favorite sport? Apa olahraga favoritmu? +What's your marital status? Apa status perkawinanmu? +When did you get to London? Kapan Anda tiba di London? +When will you be back home? Kapan kamu pulang ke rumah? +Where are you going anyway? Memangnya kamu mau pergi ke mana? +Where did you get this key? Di mana kamu mendapatkan kunci ini? +Where did you learn French? Di mana Anda belajar bahasa Prancis? +Where does your uncle live? Di mana pamanmu tinggal? +Where is the train station? Stasiun kereta ada di mana? +Where is the train station? Ada di mana stasiun kereta apinya? +Where is the train station? Stasiun kereta apinya di mana? +Where would you like to go? Kau ingin pergi ke mana? +Where would you like to go? Anda ingin pergi ke mana? +Who is your favorite actor? Siapa aktor favoritmu? +Who's your favorite writer? Penulis favoritmu siapa? +Why are we going to Boston? Kenapa kita pergi ke Boston? +Why are you looking so sad? Mengapa kamu terlihat begitu sedih? +Why are you so tired today? Kenapa kau sangat lelah hari ini? +Why don't you have a party? Bagaimana kalau mengadakan pesta? +Would you please step back? Bisakah Anda mundur ke belakang? +Would you say it once more? Maukah kau mengatakannya sekali lagi? +Wow! It's been a long time. WOW! sudah sekian lama. +You and I are good friends. Kau dan aku adalah sahabat. +You are always complaining. Kamu selalu saja mengeluh. +You are deceiving yourself. Kamu sedang menipu dirimu sendiri. +You can depend on his help. Kamu bisa mengandalkan bantuannya. +You can smoke in this room. Kamu boleh merokok di ruangan ini. +You did what you had to do. Kamu telah melakukan apa yang harus kamu lakukan +You haven't changed at all. Kau tidak berubah sama sekali. +You lied to me, didn't you? Kau berbohong, kan? +You make me feel so guilty. Kamu membuatku merasa sangat bersalah. +You must fulfill your duty. Kau harus memenuhi kewajibanmu. +You must perform your duty. Kau harus melaksanakan tugasmu. +You should be more careful. Kau harus lebih berhati-hati. +You speak English fluently. Kau berbicara bahasa Inggris dengan fasih. +You'd better not wait here. Kamu sebaiknya tidak menunggu di sini. +Your work is below average. Pekerjaanmu di bawah rata-rata. +Apples are scarce this year. Buah apel sedang langka tahun ini. +Are we going to attack them? Anda tidak perlu mengatakan apa-apa lagi. +Blood is thicker than water. Darah lebih kental dari air. +By the way, how old are you? Ngomong-ngomong,berapa umurmu? +Can I take your word for it? Bisakah aku memegang kata-katamu? +Can you come back on Monday? Bisakah Anda kembali pada hari Senin? +Come to the party, will you? Datanglah ke pesta, oke? +Could you sign here, please? Bisa tolong Anda tanda tangan di sini? +Did you buy a return ticket? Apa kau membeli tiket pulang? +Did you buy anything to eat? Apakah Anda membeli sesuatu untuk dimakan? +Did you buy anything to eat? Apa kau membeli sesuatu untuk dimakan? +Didn't anything else happen? Apakah tidak ada hal lain yang terjadi? +Do you believe in evolution? Apa kau percaya pada evolusi? +Do you ever think about Tom? Pernahkah kamu memikirkan tentang Tom? +Do you have any soft drinks? Apakah kamu punya minuman ringan? +Do you have time on Tuesday? Apakah Anda ada waktu luang di hari Selasa? +Do you know Tom's real name? Apa kamu tahu nama asli Tom? +Do you know what time it is? Apa kamu tahu jam berapa sekarang? +Do you need a place to stay? Apakah Anda butuh tempat tinggal? +Do you want anything to eat? Apa kau mau makan? +Do you want anything to eat? Apa kau ingin makan sesuatu? +Do you want it gift wrapped? Apa Anda ingin ini dibungkus? +Do you want to eat anything? Apa kau ingin makan sesuatu? +Dogs run faster than people. Anjing berlari lebih cepat dari manusia. +Don't be noisy in this room. Jangan ribut di ruangan ini. +Don't make me go back there. Jangan membuatku kembali ke sana. +Don't walk alone after dark. Jangan berjalan seorang diri setelah hari menjadi gelap. +First think, and then speak. Pikir dulu, lalu ngomong +France is in Western Europe. Perancis ada di Eropa Barat. +Have you ever been to Japan? Apakah kamu pernah ke Jepang? +Have you ever donated blood? Apa kau pernah mendonorkan darah? +Have you ever eaten insects? Apakah Anda pernah makan serangga? +Have you forgotten about me? Apakah kau telah melupakanku? +Have you had dinner already? Kamu sudah makan malam? +Have you had dinner already? Apa kau sudah makan malam? +Have you washed the car yet? Sudahkah kau mencuci mobilnya? +Have you washed the car yet? Apa kau sudah mencuci mobilnya? +He breathed his last breath. Dia menghembuskan nafas terakhirnya. +He did a very foolish thing. Dia melakukan hal yang sangat bodoh. +He does not watch TV at all. Dia tidak menonton TV sama sekali. +He doesn't care about money. Dia tidak peduli dengan uang. +He doesn't want you to know. Dia tidak ingin kamu tahu. +He feels a lot better today. Dia merasa jauh lebih baik hari ini. +He gave me his phone number. Dia memberikan saya nomor teleponnya. +He pretended to be sleeping. Dia pura-pura tidur. +He scarcely ever watches TV. Dia jarang nonton TV. +He was caught by the police. Dia telah ditangkap oleh polisi. +His advice was very helpful. Saran darinya sangat bermanfaat. +How did dinner go yesterday? Bagaimana makan malam kemarin? +How long have you been gone? Sudah berapa lama kamu pergi? +How long will you stay here? Berapa lama kau akan tinggal di sini? +How much did you guys spend? Berapa banyak yang kalian habiskan? +How much fabric did you buy? Berapa banyak kain yang kau beli? +How much time will you need? Berapa banyak waktu yang kau butuhkan? +How often do the buses come? Seberapa sering busnya datang? +Hurry up, or you'll be late. Cepat, nanti terlambat. +I am dying to see her again. Aku benar-benar rindu untuk bertemu dengannya lagi. +I bought a hat at the store. Aku membeli topi di toko itu. +I can't speak French at all. Saya sama sekali tidak bisa berbahasa Prancis. +I can't stand it any longer. Aku tidak mampu menahannya lebih lama lagi. +I couldn't possibly do that. Aku tidak bisa melakukannya. +I don't consider him honest. Saya tidak menganggap dia jujur. +I don't feel like going out. Aku sedang malas pergi keluar. +I don't know where he lives. Saya tidak tahu di mana dia tinggal. +I expect you to be punctual. Aku ingin kamu selalu tepat waktu. +I forgot to lock the drawer. Aku lupa mengunci lacinya. +I have just finished eating. Saya baru saja selesai makan. +I have no knife to cut with. Aku tidak punya pisau untuk memotongnya. +I have nothing better to do. Tidak ada hal lain yang bisa kulakukan. +I have read the book before. Aku pernah membaca buku itu sebelumnya. +I haven't met him even once. Aku tidak pernah sekalipun bertemu dengannya. +I invited them to the party. Aku mengundang mereka ke pesta. +I just don't have much time. Aku cuma tidak punya banyak waktu. +I know where you want to be. Aku tahu di mana kau ingin berada. +I pushed Tom into the water. Saya mendorong Tom kedalam air. +I really do just want to go. Aku benar-benar cuma ingin pergi. +I really shouldn't tell you. Sungguh seharusnya aku tidak memberitahumu. +I still think Tom is guilty. Saya masih berpikir Tom bersalah. +I think Tom should eat more. Aku rasa Tom harus makan lebih banyak. +I thought you could help me. Aku kira kau bisa membantuku. +I usually go to bed at nine. Aku biasanya pergi tidur jam sembilan. +I want to ask you something. Aku ingin menanyakan sesuatu padamu. +I want to be as tall as Tom. Saya mau setinggi Tom +I want to know what that is. Aku ingin tahu apa itu. +I want to know what's funny. Saya penasaran apanya yang lucu. +I want you guys to meet Tom. Aku ingin kalian bertemu dengan Tom. +I was absent from the party. Aku tidak hadir dalam pesta itu. +I went to the zoo yesterday. Aku pergi ke kebun binatang kemarin. +I will get it back from Tom. Aku akan mengambilnya kembali dari Tom. +I will go to Tokyo tomorrow. Aku akan pergi ke Tokyo besok. +I wish we had your problems. Masalah kami lebih buruk ketimbang masalah kalian. +I wish you a happy birthday. Aku ucapkan selamat ulang tahun. +I wish you were close to me. Aku harap kau berada dekat denganku. +I wish you'd told me before. Andai saja kau memberitahuku sebelumnya. +I wonder what it feels like. Aku penasaran bagaimana rasanya. +I wonder why Tom needs that. Saya heran mengapa Tom membutuhkannya. +I would rather stay at home. Aku lebih memilih tinggal di rumah. +I'd like to know the reason. saya ingin tahu alasannya +I'd like to see your father. Aku ingin bertemu dengan ayahmu. +I'll be back within an hour. Aku akan kembali dalam waktu satu jam. +I'll get you another lawyer. Aku akan mencarikanmu pengacara yang lain. +I'll have to think about it. Aku akan memikirkannya dulu. +I'm always surprised by him. Dia selalu membuatku terkejut. +I'm glad I was able to help. Saya senang bisa membantu. +I'm just looking, thank you. Tidak terima kasih, saya hanya melihat-lihat saja. +I'm looking for another job. Saya sedang mencari pekerjaan yang lain. +I'm not sure where to start. Aku tidak tahu mulai dari mana. +I'm not used to the job yet. Saya belum terbiasa dengan pekerjaan itu. +I'm sorry to disappoint you. Aku minta maaf sudah mengecewakanmu. +I'm taking a walk in a park. Aku berjalan-jalan di taman. +I've been waiting for hours. I telah menunggu beberapa jam. +I've caught a terrible cold. Aku terkena flu berat. +I've climbed Mt. Fuji twice. Aku telah mendaki gunung Fuji dua kali. +I've never climbed Mt. Fuji. Aku belum pernah mendaki gunung Fuji. +I've updated the blog entry. Aku sudah memperbarui entri blognya. +In Japan, it's now 3:00 a.m. Di Jepang, sekarang 3:00 pagi. +Is something wrong with you? Kamu kenapa? +Is there a cat on the table? Apa ada kucing di atas meja? +Is this water okay to drink? Apa air ini baik untuk diminum? +It happened a long time ago. Itu terjadi dahulu kala. +It is more than I can stand. Ini sudah diluar batas kemampuanku. +It is nice to see you again. Senang bertemu kamu lagi. +It takes courage to succeed. Diperlukan keberanian untuk berhasil. +It was Tom who told me that. Tom yang memberitahukan saya soal itu. +It's an ecological disaster. Ini adalah sebuah bencana ekologis. +It's been snowing all night. Salju turun sepanjanng malam. +It's good that Tom did that. Baguslah jika Tom yang melakukannya. +It's only a ten-minute walk. Hanya sepuluh menitan berjalan kaki. +It's six degrees below zero. Enam derajat dibawah nol. +It's very cold this evening. Sore ini sangat dingin. +Leave the book where it was. Tinggalkan buku di tempat asalnya. +Let me give you some advice. Aku akan memberimu sedikit nasihat. +Let us know where you'll be. Beritahu kami di mana kamu berada? +Let your hair down a little. Santai saja, tidak usah khawatir. +Let's go back to the office. Mari kembali ke kantor. +Let's talk over a cold beer. Mari kita mengobrol sambil minum bir dingin. +Lincoln set the slaves free. Lincoln membebaskan para budak itu. +Maybe I shouldn't stay here. Mungkin seharusnya aku tidak menetap di sini. +Most people think I'm crazy. Banyak orang mengira aku gila. +My favorite sport is skiing. Olahraga favoritku adalah bermain ski. +My grandfather was a farmer. Kakekku dulunya adalah seorang petani. +My hobby is writing stories. Hobiku menulis cerita. +My house faces to the south. Rumahku menghadap selatan. +Open your book to page nine. Buka bukumu ke halaman sembilan. +Parties can be a lot of fun. Pesta bisa jadi sangat menyenangkan. +Perhaps he missed the train. Mungkin dia tadi ketinggalan kereta. +Please don't make fun of me. Tolong jangan permainkan saya. +Please tell me your address. Tolong beritahukan alamat Anda. +Say goodbye to your friends. Pamitlah pada teman-temanmu. +See what the problem is, OK? Lihatlah permasalahannya, oke? +She allowed him to go alone. Ia membolehkannya pergi sendirian. +She didn't tell me her name. Dia tidak memberitahuku namanya. +She looked at me and smiled. Dia melihatku dan tersenyum. +She was robbed of her purse. Dompetnya dicuri. +Thank you for your interest. Terima kasih atas ketertarikan Anda. +Thanks for your quick reply. Terima kasih telah membalasnya dengan cepat. +That looks suspicious to me. Itu tampak mencurigakan bagiku. +That's the only possibility. Hanya itu kemungkinannya. +That's what I'm looking for. Itu yang sedang kucari. +The audience appeared bored. Penonton tersebut nampak bosan. +The audience appeared bored. Para hadirin nampak bosan. +The gate is closed at eight. Gerbangnya ditutup jam delapan. +The island is warm all year. Pulau itu hangat sepanjang tahun. +The meeting begins at three. Rapatnya akan dimulai pada pukul tiga. +The meeting was almost over. Rapatnya sudah hampir selesai. +The roof of my house is red. Atap rumahku merah. +The sky has become overcast. Langitnya menjadi mendung. +The taxi is waiting outside. Taksi itu menunggu di luar. +The work was very difficult. Pekerjaan itu sangat sulit. +They still haven't woken up. Mereka masih belum bangun. +This bottle holds one liter. Botol ini memuat satu liter. +This is all very disturbing. Semua ini sangat menganggu. +This method is sure to work. Metode ini pasti bekerja. +This room has three windows. Ada tiga jendela di ruangan ini. +This room is not very large. Ruangan ini tidak terlalu besar. +This room will soon heat up. Ruangan ini akan segera menjadi lebih hangat. +This rose is very beautiful. Mawar ini sangat indah. +To love life is to love God. Mencintai kehidupan adalah mencintai Tuhan. +Tom and I both like sailing. Tom dan aku sama-sama suka berlayar. +Tom doesn't even own a suit. Bahkan sebuah jas saja Tom tidak punya. +Tom finally gave up smoking. Akhirnya Tom berhenti merokok. +Tom got home after midnight. Tom sampai di rumah lewat tengah malam. +Tom has everything he needs. Tom memiliki semua yang ia butuhkan. +Tom has high blood pressure. Tom punya darah tinggi. +Tom is a university student. Tom adalah mahasiswa. +Tom is obsessed with trains. Tom terobsesi dengan kereta api. +Tom is peeling the potatoes. Tom sedang mengupasi kentang-kentangnya. +Tom is playing with his son. Tom bermain dengan anak laki-lakinya. +Tom is relocating to Boston. Tom pindah ke Boston. +Tom is waiting for Mary now. Tom sedang menunggu Mary sekarang. +Tom isn't going to hurt you. Tom tidak akan menyakitimu. +Tom isn't used to city life. Tom tidak terbiasa dengan kehidupan kota. +Tom knows there's a problem. Tom tahu ada masalah. +Tom left school an hour ago. Tom meninggalkan sekolah sejam yang lalu. +Tom looks a little confused. Tom terlihat sedikit kebingungan. +Tom looks tired, doesn't he? Bukankah Tom terlihat lelah? +Tom misses his family a lot. Tom sangat merindukan keluarganya. +Tom never even said goodbye. Tom tidak pernah mengatakan selamat tinggal. +Tom picked a lot of flowers. Tom memetik banyak bunga. +Tom proofread my manuscript. Tom memeriksa tulisan saya. +Tom ran back into the woods. Tom berlari kembali ke hutan. +Tom ran out into the street. Tom berlari keluar ke jalan. +Tom really likes Mary a lot. Tom sangat menyukai Mary. +Tom said that for the laugh. Tom mengatakannya sebagai hiburan. +Tom says everyone does that. Tom mengatakan semua orang melakukannya. +Tom seems a little confused. Tom sepertinya agak kebingungan. +Tom seems to be sympathetic. Tom terlihat bersimpati. +Tom shouldn't even be there. Tom bahkan tidak semestinya berada di sana. +Tom thanked me for the gift. Tom berterima kasih atas hadiah yang aku berikan padanya. +Tom tried to commit suicide. Tom mencoba untuk bunuh diri. +Tom was completely worn out. Tom benar-benar kelelahan. +Tom wished he had more time. Tom berharap dia memiliki waktu yang lebih panjang. +Tomorrow I'm going to Paris. Besok saya pergi ke Paris. +Tomorrow is when I get paid. Besok adalah hari di mana aku akan mendapatkan gaji. +Try this on. It's your size. Cobalah yang ini. Ini ukuranmu. +Wake me up at eight o'clock. Bangunkan saya pada pukul delapan +Wake me up at eight o'clock. Bangunkan aku jam delapan tepat. +We ate a very delicious pie. Kami memakan pai yang sangat enak. +We could just leave it here. Kita bisa meninggalkannya di sini. +We have two television sets. Kami memiliki dua buah televisi. +We leave tomorrow afternoon. Kami berangkat besok siang. +We went to London last year. Kami pergi ke London tahun lalu. +We were next-door neighbors. Kami dulu saling bertetangga. +We'll see who answers first. KIta lihat siapa yang akan menjawabnya terlebih dahulu. +We're going to watch a play. Kami akan pergi melihat sebuah pementasan drama. +We've made a final decision. Kami telah membuat keputusan terakhir. +Well, should we get started? Baiklah, mau mulai sekarang? +What are you all looking at? Kamu sedang melihat apa? +What are you going to drink? Kamu mau minum apa? +What are you going to drink? Kau mau minum apa? +What are you going to drink? Mau minum apa? +What are you going to drink? Apa yang ingin kau minum? +What are you thinking about? Apa yang sedang kamu pikirkan? +What do you think of reggae? Apa pendapat Anda tentang Reggae? +What do you want to do next? Apa yang ingin kamu lakukan selanjutnya? +What impressed Tom the most? Hal apa yang paling berkesan bagi Tom? +What is the matter with you? Ada apa denganmu? +What is your favorite sport? Apa olahraga favoritmu? +What is your favorite sport? Apa olahraga favorit Anda? +What size shoes do you wear? Berapa ukuran sepatu yang kamu kenakan? +What sport do you like best? Olahraga apa yang paling Anda sukai? +What time does school begin? Jam berapa kegiatan sekolah akan dimulai? +What time should I check in? Pada pukul berapa saya harus lapor masuk? +What will the neighbors say? Apa kata tetangga? +What would I do without you? Apa yang akan kulakukan tanpamu? +What's your favorite number? Apa angka favoritmu? +When did you move to Berlin? Kapan kamu pindah ke Berlin? +When is a good time for you? Kamu bisanya kapan? +Where are we eating tonight? Kami makan di mana malam ini? +Where did you buy that book? Di mana kamu membeli buku itu? +Where do you think he lives? Menurutmu dia tinggal di mana? +Which house did you live in? Rumah mana yang kamu tinggali? +Which house did you live in? Kau tinggal di rumah yang mana? +Which is your favorite team? Tim mana yang kamu favoritkan? +Which team are you a fan of? Tim mana yang kamu gemari? +Who is your favorite author? Pengarang favoritmu siapa? +Why are you in such a hurry? Mengapa kamu terburu-buru seperti itu? +Why are you in your pajamas? Kenapa kamu mengenakan piyama? +Why did she come home early? Kenapa dia pulang lebih awal? +Why do horses wear blinders? Kenapa kuda memakai pelindung mata? +Why not have dinner with us? Kenapa tidak makan malam bersama kami? +Would you like to go abroad? Apa kamu ingin pergi ke luar negeri? +You can go home if you like. Kalau kamu mau, kamu bisa pulang lebih awal. +You do want that, don't you? Kamu menginginkannya, bukan? +You have a beautiful sister. Saudarimu cantik. +You have very acute hearing. Kamu memiliki pendengaran yang tajam. +You look as healthy as ever. Kau terlihat sehat seperti biasanya. +You may leave your bag here. Kau bisa meninggalkan tasmu di sini. +You need to be more careful. Kau perlu lebih berhati-hati lagi. +You need to be more careful. Kau perlu lebih cermat lagi. +You probably don't remember. Kamu mungkin tidak mengingatnya. +You should just talk to Tom. Kamu seharusnya langsung berbicara dengan Tom. +You shouldn't be alone, Tom. Anda seharusnya tidak sendirian, Tom. +You won't be late, will you? Kau tidak akan terlambat, bukan? +You'd better leave us alone. Tinggalkan kami sendiri. +You're really a hard worker. Kau benar-benar seorang pekerja keras. +You're thirty minutes early. Kamu lebih cepat tiga puluh menit. +A banker's life is difficult. Kehidupan seorang bankir itu sulit. +All the members were present. Semua anggota hadir. +All who knew him admired him. Semua orang yang mengenalnya mengaguminya. +Are you angry at what I said? Apakah kamu marah pada apa yang aku katakan? +Are you guys sure about this? Apa kalian yakin dengan hal ini? +Are you meeting someone here? Apakah kau akan menemui seseorang di sini? +Are you the person in charge? Apakah kau adalah orang yang bertugas di sini? +Both of his parents are well. Kedua orang tuanya baik-baik saja. +Can you fix the broken radio? Bisakah kau memperbaiki radio yang rusak itu? +Could you send me a brochure? Bisakah kau mengirimiku sebuah brosur? +Do you have feelings for Tom? Apakah kamu memiliki perasaan terhadap Tom? +Do you have something to say? Apa ada sesuatu yang ingin kau katakan? +Do you want some pumpkin pie? Apa kamu mau beberapa potong kue pai? +Do you want something to eat? Apa kau ingin makan sesuatu? +Do you want to eat something? Apa kau ingin makan sesuatu? +Do you want to give it a try? Anda mau mencobanya? +Don't expect too much of him. Jangan terlalu berharap padanya. +Don't expect too much of him. Jangan berharap terlalu banyak padanya. +Don't forget to pay the rent. Jangan lupa untuk membayar biaya sewanya. +Don't make a scene in public. Jangan buat keributan di depan umum. +Don't make noise. Keep quiet. Jangan berisik. Harap tenang. +Don't underestimate my power. Jangan meremehkan kekuatanku. +Don't work yourself too hard. Jangan terlalu memaksakan diri. +Everybody speaks well of her. Semua orang memuji dirinya. +Excuse me, have you seen Tom? Permisi, apakah kamu melihat Tom dimana? +Excuse me, is Tom here today? Permisi, apakah Tom di sini hari ini? +Fill it with regular, please. Tolong isi penuh dengan yang reguler. +Have a look at the world map. Lihatlah peta dunia. +Have you bought a watermelon? Kamu sudah beli semangka? +Have you ever been to Kyushu? Apa kau pernah pergi ke Kyushu? +Have you ever been to London? Kau pernah pergi ke London? +Have you ever been to London? Apa kau pernah pergi ke London? +Have you ever been to Mexico? Apakah Anda pernah ke Meksiko? +Have you ever been to Mexico? Apakah kamu pernah ke Meksiko? +Have you ever been to Mexico? Apakah kalian pernah ke Meksiko? +Have you ever been to Mexico? Pernah ke Meksiko? +He always tells vulgar jokes. Dia selalu melontarkan candaan vulgar. +He drove the truck to Dallas. Ia membawa truknya ke Dallas. +He hasn't talked to me since. Dia sudah tidak berbicara dengan saya lagi sejak itu. +He is a teacher and novelist. Dia adalah seorang guru dan novelis. +He is allergic to house dust. Dia alergi pada debu rumah. +He is anxious to go with you. Dia ingin sekali pergi denganmu. +He is eager to become famous. Dia ingin menjadi terkenal. +He is known as a rock singer. Dia dikenal sebagai seorang penyanyi rok. +He is trying to quit smoking. Dia sedang berusaha untuk berhenti merokok. +He is, indeed, a hard worker. Dia memang seorang pekerja keras. +He plays the piano very well. Dia memainkan piano dengan sangat baik. +He promised he would tell us. Dia telah berjanji akan memberi tahu kita. +He urged us to obey the rule. Dia meminta kami untuk mematuhi peraturan. +He's a cold person like that. Seperti itulah dia, orang yang dingin. +He's collecting various data. Dia mengumpulkan berbagai data. +His data is often inaccurate. Datanya sering tidak akurat. +His new film is worth seeing. Film barunya layak ditonton. +How about eating out with me? Mau pergi makan bersamaku? +How about going to the movie? Bagaimana kalau pergi ke bioskop? +How are you feeling now, Tom? Bagaimana perasaanmu sekarang, Tom? +How does Tom feel about that? Apa yang Tom rasakan tentang hal itu? +How does Tom know about that? Bagaimana Tom mengetahui hal itu? +How long did you stay abroad? Berapa lama kau tinggal di luar negeri? +How many rackets do you have? Berapa banyak raket yang kau miliki? +How was your summer vacation? Bagaimana liburan musim panas Anda? +Human trafficking is a crime. Perdagangan manusia adalah tindak pidana. +I advise you to stop smoking. Saya sarankan Anda untuk berhenti merokok. +I already think you're crazy. Aku sudah berpikir kalau kau gila. +I am going to Tokyo tomorrow. Aku akan pergi ke Tokyo besok. +I bought a round-trip ticket. Aku membeli tiket pulang pergi. +I bought two bottles of milk. Saya membeli susu dua botol. +I came near to being drowned. Aku hampir saja tenggelam. +I can speak English a little. Saya bisa berbicara bahasa Inggris sedikit. +I can speak English a little. Saya kurang mahir berbicara dalam bahasa inggris. +I can't bear this any longer. Aku sudah tidak tahan dengan hal ini. +I can't tell you what I know. Aku tidak bisa memberitahumu apa yang aku ketahui. +I did it with my eyes closed. Saya melakukannya dengan mata tertutup. +I didn't say this was heaven. Aku tidak berkata bahwa ini adalah surga. +I do it every Sunday morning. Saya melakukannya setiap Minggu pagi. +I don't like stubborn people. Saya tidak suka orang keras kepala. +I don't read newspapers much. Saya jarang baca koran. +I don't trust him any longer. Aku sudah tidak lagi mempercayai dia. +I don't trust him any longer. Aku sudah tidak percaya padanya. +I don't want to live forever. Aku tidak ingin hidup selamanya. +I found a dollar on the road. Saya menemukan satu dolar di jalan. +I generally have lunch there. Aku biasa makan siang di sana. +I have absolute trust in you. Aku percaya sepenuhnya padamu. +I have nothing to say to you. Tidak ada yang ingin kukatakan padamu. +I have read this book before. Aku pernah membaca buku ini sebelumnya. +I have seen that girl before. Aku pernah melihat gadis itu sebelumnya. +I have to go to the bathroom. Saya harus pergi ke kamar mandi. +I haven't seen him for years. Aku tidak pernah bertemu dengannya selama bertahun-tahun. +I hope nothing's been broken. Aku harap tidak ada yang dirusak. +I hope this is the right one. Aku harap ini yang benar. +I intend to be there by 2:30. Saya berencana tiba di sana pada pukul 2:30. +I know it was you who did it. Aku tahu kalau kamu yang telah melakukannya. +I need to go to the bathroom. Saya harus pergi ke kamar mandi. +I ordered a book from London. Aku memesan sebuah buku dari London. +I prefer to travel in my car. Saya lebih memilih berpergian dengan mobil. +I remember seeing that movie. Saya ingat dulu pernah nonton film itu +I should've told Tom earlier. Seharusnya aku memberitahu Tom lebih awal. +I study English and Japanese. Saya belajar bahasa Inggris dan bahasa Jepang. +I think Tom will return soon. Kurasa Tom akan segera kembali. +I think we'd better help Tom. Aku pikir kita perlu membantu Tom. +I walked 10 kilometers today. Aku berjalan sejauh 10 kilometer hari ini. +I want you to read this book. Saya ingin kamu baca buku ini. +I was born on March 22, 1962. Saya lahir pada tanggal 22 Maret 1962. +I went to Bali in the summer. Saya pergi ke Bali saat libur musim panas. +I will get up early tomorrow. Aku akan bangun lebih awal besok. +I wish I could speak English. Aku harap aku bisa berbahasa Inggris. +I wish it would stop raining. Aku harap hujannya akan berhenti. +I wish you'd told me earlier. Andai saja kau memberitahuku lebih awal. +I would like to study Arabic. Aku mau belajar bahasa Arab. +I'd like to hear your advice. Saya ingin mendengar nasihat Anda. +I'd like two kilos of apples. Saya ingin membeli dua kilo apel. +I'll have to take my chances. Aku akan mencoba peruntunganku. +I'll never forget Tom's face. Aku tidak akan pernah melupakan wajah Tom. +I'll take whatever I can get. Aku akan mengambil apapun yang bisa ku ambil. +I'm going to wait until 2:30. Kutunggu sampai pukul 2:30. +I'm going to wait until 2:30. Akan kutunggu sampai pukul 2:30. +I'm no longer afraid of dogs. Aku tidak lagi takut anjing. +I'm not asking for your help. Aku tidak meminta bantuanmu. +I'm pretty good at first aid. Saya cukup ahli dalam pertolong pertama. +I'm sorry I disappointed you. Aku minta maaf sudah mengecewakanmu. +I'm sure you understand that. Aku yakin kau memahaminya. +I'm writing a message to Tom. Saya sedang menulis pesan kepada Tom. +I'm writing a song in French. Aku menulis sebuah lagu dalam bahasa Prancis. +I've been wanting to see you. Aku selalu ingin bertemu denganmu. +I've just finished breakfast. Aku baru saja selesai sarapan. +I've just finished breakfast. Saya baru saja selesai makan pagi. +In case it rains, I won't go. Jika turun hujan, maka aku tidak akan pergi. +It kept raining all day long. Hujan terus turun hingga sehari penuh. +It seemed like a dream to me. Ini terasa seperti mimpi bagiku. +It was a full moon yesterday. Kemarin bulan purnama. +It was dark under the bridge. Di bawah jembatan gelap. +It was good working with you. Saya senang bisa bekerja dengan Anda. +It wasn't interesting at all. Itu sama sekali tidak menarik. +It's Tom who deserves credit. Tomlah yang pantas mendapatkan penghargaan. +It's a privilege to meet you. Sebuah kehormatan bisa bertemu Anda. +It's already started to rain. Sudah mulai turun hujan. +It's clear that you're wrong. Kau jelas-jelas sudah salah. +It's getting worse and worse. Semakin buruk +It's important to read books. Sangat penting untuk membaca buku. +Japan is famous for Mt. Fuji. Jepang terkenal akan Gunung Fujinya. +Keep a copy of that document. Simpan salinan dari dokumen itu. +Leave the chairs as they are. kembalikan kursinya seperti semula. +Let's go to the hospital now. Ayo ke rumah sakit sekarang. +Let's just hope Tom is alone. Semoga saja Tom sendirian. +Life is hard, death is cheap. Kehidupan itu susah, kematian itu murah. +May I borrow your dictionary? Apakah aku boleh meminjam kamusmu? +May I borrow your dictionary? Apakah saya boleh meminjam kamus Anda? +Maybe she forgot my birthday. Mungkin dia lupa hari ulang tahunku. +Maybe someone made Tom do it. Mungkin seseorang membuat Tom melakukan hal itu. +My boss was forced to resign. Bosku dipaksa mengundurkan diri. +My father works in a factory. Ayah saya bekerja di sebuah pabrik. +My hobby is collecting coins. Hobiku mengoleksi koin. +My house is near the station. Rumahku dekat stasiun. +Naples is a picturesque city. Naples adalah kota yang indah. +No one welcomed the proposal. Tidak ada yang menyambut baik proposal itu. +Nothing ever makes him angry. Tidak ada hal yang bisa membuatnya marah. +Politics didn't interest him. Dia tidak tertarik dengan politik. +She complained of a headache. Dia mengeluh sakit kepala. +She died yesterday afternoon. Dia meninggal dunia kemarin siang. +She is eight months pregnant. Dia hamil delapan bulan. +She is singing with a guitar. Dia bernyanyi dengan gitar. +She plays golf every weekend. Dia bermain golf tiap akhir pekan. +She ran as fast as she could. Dia berlari secepatnya. +Should I stay or should I go? Haruskah aku tinggal atau haruskah aku pergi? +So far, they haven't arrived. Sekarang, mereka belum sampai. +Some animals eat their young. Beberapa hewan memakan anaknya yang masih muda. +Some of the birds didn't fly. Beberapa ekor dari burung-burung itu tidak terbang. +Some of the money was stolen. Sejumlah uang telah dicuri. +Something was wrong with Tom. Ada yang salah dengan Tom. +Sorry, I can't stay for long. Maaf, saya tidak bisa tinggal lebih lama. +Thank you for giving me this. Terima kasih telah memberiku ini. +Thank you for your hard work. Terima kasih atas kerja kerasmu. +Thanks for your quick answer. Terima kasih telah menjawabnya dengan cepat. +That's because you're a girl. Itu karena kamu perempuan. +That's why I have to do this. Itulah kenapa aku harus melakukan ini. +The meeting finished at nine. Rapatnya selesai pada pukul sembilan. +The meeting lasted two hours. Rapatnya berlangsung selama dua jam. +The rules should be followed. Peraturan seharusnya dipatuhi. +The rules should be followed. Peraturannya harus dipatuhi. +The snow lasted for two days. Saljunya bertahan hingga 2 hari. +The train was about to leave. Keretanya sudah akan berangkat. +There is a desk in this room. Ada sebuah meja di ruangan ini. +There's so much I want to do. Ada banyak sekali hal yang ingin kulakukan. +They forgot to lock the door. Mereka lupa mengunci pintu. +They'll probably come by car. Mereka kemungkinan akan datang dengan mobil. +They're very cheerful people. Mereka merupakan orang-orang yang ceria. +This has all happened before. Semua ini telah terjadi sebelumnya. +This house has two bathrooms. Rumah ini memiliki dua kamar mandi. +This morning, I saw an angel. Pagi ini, aku melihat seorang malaikat. +Tom begged Mary not to leave. Tom meminta Mary untuk tidak pergi. +Tom didn't see the stop sign. Tom tidak melihat rambu berhenti. +Tom doesn't get enough sleep. Tom tidak mendapat tidur yang cukup. +Tom doesn't know anyone here. Tom tidak mengenal siapa-siapa. +Tom got rid of his old books. Tom menyingkirkan buku-buku lamanya. +Tom has never had a mustache. Tom tak pernah berkumis. +Tom is a computer programmer. Tom adalah seorang pemrogram komputer. +Tom is a high school student. Tom adalah seorang siswa SMA. +Tom is a man you can rely on. Tom laki-laki yang bisa kamu andalkan. +Tom is leaving in three days. Tom akan berangkat dalam tiga hari. +Tom is mowing his front lawn. Tom sedang memotong rumput di halaman depannya. +Tom is still in the hospital. Tom masih berada di rumah sakit. +Tom knows he hears something. Tom tahu dia mendengar sesuatu. +Tom looked at the fuel gauge. Tom melihat indikator bahan bakar. +Tom looked down at the floor. Tom melihat ke arah lantai. +Tom looked like he was happy. Tom terlihat seperti dia sedang bahagia. +Tom looks sleepy, doesn't he? Bukankah Tom terlihat mengantuk? +Tom lost his reading glasses. Tom kehilangan kacamata bacanya. +Tom may not like this at all. Tom mungkin tidak menyukai hal ini sama sekali. +Tom met Mary three years ago. Tom bertemu Mary tiga tahun yang lalu. +Tom must've worked very hard. Tom pasti telah bekerja sangat keras. +Tom opened the door for Mary. Tom membukakan pintu untuk Mary. +Tom opened the gate for Mary. Tom membukakan gerbang untuk Mary. +Tom pretended to be ignorant. Tom bertindak seolah-olah acuh. +Tom put his seatbelt back on. Tom memakai kembali sabuk pengamannya. +Tom quietly entered the room. Tom diam-diam memasuki ruangan itu. +Tom ran back down the stairs. Tom berlari kembali menuruni tangga. +Tom really misses his family. Tom sangat merindukan keluarganya. +Tom saw his name on the list. Tom berkata dia melihat namanya pada daftar. +Tom says I'm a good listener. Tom berkata saya adalah pendengar yang baik. +Tom walked across the street. Tom berjalan menyeberangi jalan itu. +Tom was out with his friends. Tom sedang pergi bersama dengan temannya. +Turn down the volume, please. Tolong kecilkan volume suaranya. +We don't have any more bread. Kita sudah tidak punya roti lagi. +We enjoyed watching the game. Kami menikmati pertandingan itu. +We have important work to do. Kita memiliki pekerjaan penting yang harus dilakukan. +We saw the monkey at the zoo. Kami melihat monyet di kebun binatang. +We'd better do what they ask. Sebaiknya kita turuti saja kemauan mereka. +We're very lucky to be alive. Kita beruntung sudah hidup. +We're very lucky to be alive. Kami beruntung sudah hidup. +What direction are you going? Ke arah mana Anda akan pergi? +What do you have in your bag? Apa yang kau simpan di dalam tasmu? +What do you have in your bag? Apa yang ada di dalam tasmu? +What do you think this means? Menurutmu apa arti ini? +What grade is your sister in? Adikmu kelas berapa? +What have you done this week? Apa saja yang kamu lakukan minggu ini? +What makes this so different? Apa yang membuat ini begitu berbeda? +What would you like to drink? Kamu mau minum apa? +What would you like to drink? Kau mau minum apa? +What would you like to drink? Mau minum apa? +What would you like to drink? Apa yang ingin kau minum? +What would you like to drink? Anda ingin minum apa? +What's the fare to Liverpool? Berapa tarif untuk ke Liverpool? +What's your favorite subject? Apa pelajaran favoritmu? +Whatever happened, it's over. Apapun yang terjadi, semuanya sudah berakhir. +When could you start working? Kapan kamu bisa mulai bekerja? +When did the accident happen? Kapan kecelakaan itu terjadi? +When will you come back home? Kapan kamu pulang ke rumah? +When will you come back home? Kapan Anda pulang ke rumah? +When will you visit me again? Kapan kau akan mengunjungiku lagi? +Where do you want to go, sir? Anda ingin pergi ke mana, Pak? +Where is the railway station? Stasiun kereta ada di mana? +Where is the railway station? Ada di mana stasiun kereta apinya? +Where is the railway station? Stasiun kereta apinya di mana? +Which credit cards can I use? Kartu kredit mana yang bisa saya gunakan? +Who told you that I was sick? Siapa yang memberitahumu kalau aku sakit? +Who will look after the baby? Siapa yang akan menjaga bayinya? +Why didn't you say something? Kenapa kau tidak berkata sepatah katapun? +Why don't you eat vegetables? Kenapa kamu tidak makan sayur? +Winter is my favorite season. Musim dingin adalah musim favoritku. +Work is so frustrating today. Pekerjaan hari ini sangat melelahkan. +Would you like another apple? Apa kau mau apel lagi? +Write the date of your birth. Tulislah tanggal lahirmu. +You aren't busy now, are you? Kamu nggak sibuk kan sekarang? +You can't smoke in this room. Kamu tidak boleh merokok di ruangan ini. +You didn't tell him anything? Kamu tidak mengatakan apa-apa padanya? +You look very charming today. Kau terlihat sangat menawan hari ini. +You may go anywhere you like. Kamu boleh pergi ke mana pun yang kamu suka. +You may go anywhere you like. Kalian boleh pergi ke mana pun yang kalian suka. +You seem like a smart person. Kamu sepertinya seorang yang pandai. +You should have come earlier. Seharusnya kamu datang lebih awal. +You should've seen the movie. Anda seharusnya telah menonton film itu. +You're still mad, aren't you? Kamu masih marah, ya? +Your pen is better than mine. Pulpenmu lebih baik daripada milikku. +"Thank you." "You're welcome." "Terima kasih." "Sama-sama." +Actually, I've never seen one. Sebenarnya, aku belum pernah melihatnya. +All that glitters is not gold. Tidak semua kertas kecil adalah cek. +Are any seats still available? Apa masih ada kursi yang tersedia? +Can you print that out for me? Bisakah kau mencetaknya untukku? +Close the door when you leave. Tutup pintunya ketika kamu pergi. +Could we have a table outside? Bisakah kami duduk di meja luar? +Could we make this a priority? Bisakah kita memprioritaskan ini? +Could you turn down the radio? Bisakah kau kecilkan volume radionya? +Could you turn down the radio? Bisa tolong kecilkan volume radionya? +Could you turn off the lights? Bisakah kau mematikan lampu-lampunya? +Could you wait a little while? Dapatkah kamu menunggu sebentar? +Did Tom ask you to write this? Apakah Tom memintamu untuk menulis ini? +Did you know Tom worked there? Apakah kamu tahu Tom berkerja di sana? +Did you leave the window open? Apa kamu membiarkan jendelanya terbuka? +Do you eat at home or eat out? Apakah anda makan dirumah atau makan diluar ? +Do you happen to have matches? Apa kamu mempunyai korek? +Do you know where we're going? Apa kamu tahu kemana kita akan pergi? +Do you live with your parents? Apa kamu tinggal dengan orangtuamu? +Do you mind turning on the TV? Bisa minta tolong nyalakan TV-nya? +Do you want me to do anything? Ada sesuatu yang kamu ingin aku lakukan? +Do you want me to go with you? Kamu ingin aku ikut denganmu? +Do you want to drink some tea? Kamu mau minum teh? +Don't come so early next time. Lain kali jangan datang terlalu awal. +Don't tell me you're quitting. Jangan katakan kalau kau berhenti. +Dry the pants on the radiator. Keringkan celananya di atas radiator. +Excuse me, I'm coming through. Permisi, saya lewat. +Give me three pieces of chalk. Berikan aku tiga buah kapur. +Have you already eaten dinner? Kamu sudah makan malam? +Have you already eaten dinner? Apa kau sudah makan malam? +Have you already eaten supper? Kamu sudah makan malam? +Have you already eaten supper? Apa kau sudah makan malam? +Have you ever been to America? Pernah ke Amerika? +Have you ever been to America? Apakah Anda pernah ke Amerika? +Have you ever been to America? Pernahkah kamu ke Amerika? +Have you ever eaten an insect? Apakah Anda pernah makan seekor serangga? +Have you finished packing yet? Apakah kau sudah selesai mengepaknya? +Have you thought this through? Apa kamu sudah memikirkannya dengan baik? +He can cope with the problems. Dia bisa mengatasi persoalan itu. +He gets lost wherever he goes. Dia selalu tersesat di mana pun dia pergi. +He is no better than a beggar. Dia tidak lebih baik daripada seorang pengemis. +He is the image of his father. Dia adalah gambaran dari ayahnya. +He is too drunk to drive home. Ia terlalu mabuk untuk berkemudi menuju rumah. +He looks just like his father. Dia terlihat sangat mirip dengan ayahnya. +He took Tom on a fishing trip. Dia mengajak Tom pergi memancing. +He took a book from the shelf. Dia mengambil sebuah buku dari rak. +He whispered something to her. Ia membisikkan sesuatu padanya. +He's attracted to black women. Dia tertarik pada wanita berkulit hitam. +He's not cut out for teaching. Dia tidak cocok untuk mengajar. +His new film is disappointing. Film barunya mengecewakan. +How could Tom do this to Mary? Bagaimana bisa Tom melakukan ini pada Mary? +How did your date go with Tom? Bagaimana jalannya kencanmu dengan Tom? +How did your date with Tom go? Bagaimana jalannya kencanmu dengan Tom? +How long have you been abroad? Sudah berapa lama Anda di luar negeri? +How many children do you have? Berapa jumlah anak Anda? +How many people in your party? Berapa banyak orang yang ada di partai Anda? +How many pictures did you buy? Berapa banyak gambar yang kau beli? +How old are your children now? Berapa usia anak-anakmu saat ini? +How's the weather in New York? Bagaimana cuacanya di New York? +How's the weather in New York? Cuaca di New York bagaimana? +Hurry up, or you will be late. Cepatlah, atau kau akan terlambat. +I can eat anything but onions. Aku bisa memakan apa saja kecuali bawang. +I could be away for some time. Saya akan pergi selama beberapa waktu. +I do not trust him any longer. Aku sudah tidak lagi mempercayai dia. +I do not trust him any longer. Aku sudah tidak percaya padanya. +I don't approve your decision. Aku tidak setuju dengan keputusan kalian. +I don't even have a boyfriend. Aku bahkan tidak punya pacar. +I don't feel sick or anything. Aku tidak merasa sakit atau apapun. +I don't have anything to hide. Tidak ada yang perlu aku sembunyikan. +I don't want to live with you. Aku tidak ingin hidup denganmu. +I got a lot of mosquito bites. Aku mendapat banyak gigitan nyamuk. +I guess it sounds a bit silly. Aku rasa itu terdengar agak konyol. +I had to respect Tom's wishes. Aku harus menghormati keinginan Tom. +I have a serious skin problem. Aku memiliki masalah kulit yang serius. +I have nothing further to say. Sudah tidak ada yang ingin aku katakan. +I have to cook the vegetables. Aku harus memasak sayur-sayurannya. +I haven't slept well recently. Aku tidak tidur dengan nyenyak akhir-akhir ini. +I haven't told you everything. Aku belum memberitahumu semuanya. +I hear that he sold his house. Aku dengar ia telah menjual rumahnya. +I hope I didn't interrupt you. Kuharap aku tidak mengganggumu. +I just don't know what to say. Aku tidak tahu harus bilang apa. +I knew that Tom wasn't hungry. Aku tahu kalau Tom tidak lapar. +I know you must be frightened. Aku tahu, kamu pasti ketakutan. +I know you're going to say no. Aku tahu kalau kau akan bilang tidak. +I like reading mystery novels. Aku suka membaca novel misteri. +I like science fiction novels. Aku suka novel fiksi ilmiah. +I need to find out what to do. Aku perlu mengetahui apa yang harus dilakukan? +I overheard your conversation. Aku tidak sengaja mendengar percakapanmu. +I saw him crossing the street. Aku melihat dia menyeberang jalan. +I should have taken the money. Harusnya aku tidak mengambil uangnya. +I think I'm gonna go to sleep. Aku pikir aku akan pergi tidur. +I want something hot to drink. Aku ingin sesuatu yang hangat untuk diminum. +I want to come back next year. Aku mau kembali tahun depan. +I want to go and have a drink. Saya ingin pergi minum. +I want to know what you think. Aku ingin tahu apa yang kau pikirkan. +I want to teach you something. Aku ingin mengajarimu sesuatu. +I was caught in a traffic jam. Aku terjebak dalam kemacetan lalu lintas. +I wasn't looking for anything. Saya tidak mencari apa apa +I won't be able to pay for it. Aku tidak mampu untuk membayarnya. +I work for a shipping company. Aku bekerja di sebuah perusahaan pengapalan. +I'd be happy to work with you. Saya senang bisa bekerja dengan Anda. +I'll be free all day tomorrow. Saya akan bebas selama seharian besok. +I'll drive you to the airport. Aku akan mengantarmu sampai ke bandara. +I'm about the same age as you. Aku hampir seusia denganmu. +I'm afraid Tom might get hurt. Saya khawatir Tom akan terluka. +I'm afraid it's going to rain. Aku takut sebentar lagi akan turun hujan. +I'm coming over to your place. Aku mampir ke tempatmu. +I'm extremely grateful to you. Saya benar-benar sangat berterima kasih +I'm going to Europe next week. Aku akan pergi ke Eropa minggu depan. +I'm going to go get some food. Aku pergi untuk membeli makanan. +I'm taking an exam in January. Aku mengikuti ujian pada Januari. +I'm tired of eating fast food. Aku sudah bosan memakan makanan siap saji. +I'm young, but I'm not afraid. Saya masih muda, tetapi sudah tidak takut. +I've been expecting your call. Aku menantikan panggilan telepon darimu. +I've gotta go to the bathroom. Aku harus ke kamar mandi. +Iron is more useful than gold. Besi lebih berguna daripada emas. +Is this going to take a while? Apa ini akan memakan waktu beberapa lama? +It all depends on the weather. Semua tergantung cuaca. +It is hardly worth discussing. Tidak ada gunanya mendiskusikannya. +It rained for hours and hours. Hujan terus-menerus turun selama berjam-jam. +It's exactly as you say it is. Tepat seperti apa yang Anda katakan. +It's exactly as you say it is. Tepat seperti yang kau katakan. +Japanese is our mother tongue. Bahasa jepang adalah bahasa ibu kita. +Just pretend nothing happened. Berpura-pura seperti tidak terjadi apa-apa. +Learning English is hard work. Belajar bahasa Inggris adalah kerja keras. +Let's take a break for coffee. Mari istirahat dan minum kopi. +Mary is carrying a watermelon. Mary membawa semangka. +Mary went to the beauty salon. Mary pergi ke salon. +May I have a road map, please? Boleh saya minta peta jalannya, tolong. +May I have something to drink? Bolehkah saya meminta sesuatu untuk diminum? +Mom and Dad gave me a bicycle. Ibu dan ayah memberikan aku sepeda. +My hobby is playing the piano. Hobiku bermain piano. +My mother has cooked ten eggs. Ibuku telah merebus sepuluh butir telur. +My pen isn't as good as yours. Pulpenku tidak sebagus milikmu. +My watch is five minutes fast. Jam tanganku lebih cepat lima menit. +My watch keeps very good time. Jamku sangat akurat. +Only my mother understands me. Hanya ibuku yang mengerti aku. +Our car broke down last night. Mobil kami rusak semalam. +Parents are usually very wise. Orang tua biasanya sangat bijaksana. +Perhaps it will rain tomorrow. Mungkin besok akan turun hujan. +Remember to answer his letter. Jangan lupa membalas suratnya. +She has never danced with him. Dia tidak pernah menari bersamanya. +She married him for his money. Dia menikahi cowo itu karena uangnya +She saw him eating a sandwich. Dia melihatnya memakan roti lapis. +She went out to buy some food. Dia pergi keluar untuk membeli beberapa makanan. +She's really smart, isn't she? Dia benar-benar pintar, ya? +Stick a stamp on the envelope. Tempelkan sebuah perangko pada amplopnya. +Summers are very hot in Kyoto. Musim panas di Kyoto sangat panas. +That happened a long time ago. Itu sudah lama terjadi. +That was Tom's favorite color. Itu adalah warna favorit Tom. +That's someone else's problem. Itu masalah orang lain. +The bank is three blocks away. Banknya terletak di tiga blok dari sini. +The bridge is open to traffic. Jembatan itu terbuka untuk lalu lintas. +The bus stopped and we got on. Bis itu berhenti dan kami masuk +The candle went out by itself. Lilinnya padam dengan sendirinya. +The candle went out by itself. Lilinnya mati sendiri. +The car crashed into the wall. Mobil itu menabrak dinding. +The desk is covered with dust. Mejanya tertutup oleh debu. +The difficult question is why. Pertanyaan yang sulit adalah 'kenapa'. +The experiment was successful. Percobaannya berhasil. +The guide led us to the hotel. Pemandu mengantarkan kami ke hotel. +The king oppressed his people. Raja itu telah menindas rakyatnya. +The station is two miles away. Stasiunnya terletak 2 mil dari sini. +The train arrived on schedule. Kereta itu tiba sesuai jadwal. +The train arrived on schedule. Keretanya tiba sesuai jadwal. +The vase was broken to pieces. Vas itu pecah berkeping-keping +There is a glass on the table. Ada gelas di atas meja. +There is a glass on the table. Ada sebuah gelas di atas meja. +There was a problem at school. Tadi ada masalah di sekolah. +They don't talk to me anymore. Mereka tidak lagi berbicara denganku. +This film is based on a novel. Film ini didasarkan pada novel. +This girl is driving me crazy. Gadis ini membuatku gila. +This is worth one million yen. Ini senilai satu juta yen. +This room is too small for us. Ruangan ini terlalu sempit untuk kita. +This room is too small for us. Ruangan ini terlalu sempit untuk kami. +Three quarters of them agreed. Tiga perempat dari mereka setuju. +Tom and Mary fight constantly. Tom dan Mary selalu bertengkar. +Tom applied for a scholarship. Tom mendaftar sebuah beasiswa. +Tom asked me where I got this. Tom bertanya padaku dimanakah aku mendapatkan ini. +Tom came home early yesterday. Tom pulang ke rumah lebih awal kemarin. +Tom came home early yesterday. Tom pulang lebih awal kemarin. +Tom could scarcely believe it. Tom hampir tidak mempercayainya. +Tom grabbed his coat and left. Tom mengambil mantelnya dan pergi. +Tom has never seen Mary dance. Tom belum pernah melihat Mary menari. +Tom hasn't seen the video yet. Tom belum menonton videonya. +Tom is almost always cheerful. Tom hampir selalu bahagia. +Tom is an electrical engineer. Tom adalah seorang sarjana arus kuat. +Tom is disagreeable, isn't he? Tom merasa terganggu, bukan? +Tom is playing the violin now. Tom sedang bermain violin sekarang. +Tom is reading a history book. Tom sedang membaca buku sejarah. +Tom is taller than his mother. Tom lebih tinggi daripada ibunya. +Tom is very worried about you. Tom sangat mengkhawatirkan kamu. +Tom isn't quite himself today. Tom tidak seperti dirinya hari ini. +Tom just wanted to be helpful. Tom hanya ingin mencoba membantu. +Tom knew it was time to leave. Tom tahu ini saatnya untuk pergi. +Tom looked down at the ground. Tom melihat ke arah tanah. +Tom lost all the money he had. Tom kehilangan semua uangnya. +Tom may change his mind later. Tom mungkin akan berubah pikiran nanti. +Tom may have known the answer. Tom mungkin sudah mengetahui jawabannya. +Tom moved out three weeks ago. Tom pindah keluar tiga minggu yang lalu. +Tom must be found immediately. Tom harus ditemukan secepatnya. +Tom needs to follow my advice. Tom butuh mengikuti saran saya. +Tom never brought anyone here. Tom tidak pernah membawa siapa-siapa kemari. +Tom never even left the house. Tom tidak pernah sekalipun meninggalkan rumah. +Tom paid no attention to Mary. Tom tidak memperhatikan Mary. +Tom probably forgot it's here. Tom mungkin lupa ini di sini. +Tom rolled his window back up. Tom menutup kaca jendelanya. +Tom said he'll call you later. Tom berkata dia akan menghubungi kamu kembali. +Tom saw Mary break the window. Tom melihat Mary memecahkan kaca jendela. +Tom should be back any second. Tom seharusnya sudah kembali sekarang. +Tom sometimes comes home late. Tom kadang-kadang telat pulang ke rumah. +Tom tried to suppress a smile. Tom berusaha menahan senyum. +Tom's methods were unorthodox. Metode-metode milik Tom tidak lazim. +We had a very vigorous debate. Kami telah melakukan debat yang sangat hangat. +We have some encouraging news. Kami memiliki beberapa berita yang menyemangatkan. +We just need to bide our time. Kita hanya perlu menunggu waktu tepat. +We talked late into the night. Kami berbincang-bincang hingga larut malam. +We took the enemy by surprise. Kami dikejutkan oleh musuh. +We went swimming in the river. Kami pergi berenang di sungai. +We're working for world peace. Kami bekerja demi perdamaian dunia. +We've already lost three days. Kami sudah kehilangan tiga hari. +We've been friends ever since. Kami menjadi teman sejak saat itu. +What if Tom doesn't come back? Bagaimana jika Tom tidak kembali? +What time does boarding begin? Embarkasinya akan dimulai pada pukul berapa? +What time does the play begin? Jam berapa pertunjukkannya akan dimulai? +What time will the game start? Jam berapa pertandingannya akan mulai? +What time will you be leaving? Kamu berangkat jam berapa? +What time will you be leaving? Kau akan berangkat jam berapa? +Where is the closest hospital? Di mana rumah sakit yang paling dekat? +Where is the railroad station? Stasiun kereta ada di mana? +Where is the railroad station? Ada di mana stasiun kereta apinya? +Where is the railroad station? Stasiun kereta apinya di mana? +Who did you write a letter to? Ditujukan kepada siapa surat itu? +Why were you absent yesterday? Kenapa kemarin kamu tidak masuk? +Why won't you talk to me, Tom? Kenapa kamu tidak mau berbicara denganku, Tom? +Why would you want to do that? Mengapa kamu mau melakukannya? +Would you like some more beer? Apa Anda mau bir lagi? +You can eat anything you want. Kau bisa makan apapun yang kau inginkan. +You can eat whatever you like. Kau bisa makan apapun sesukamu. +You cannot smoke in this room. Kamu tidak boleh merokok di ruangan ini. +You know everything I do, Tom. Kamu tahu semua yang kulakukan, Tom. +You must conform to the rules. Kalian harus mematuhi aturan. +You need to be more attentive. Kau perlu lebih cermat lagi. +You should be more reasonable. Seharusnya kau lebih rasional. +You should be more reasonable. Kau harus menjadi lebih rasional. +You're cuter than your sister. Kamu lebih manis ketimbang adikmu. +Your bike is better than mine. Sepedamu lebih baik ketimbang milikku. +Your birthday is drawing near. Ulang tahunmu semakin dekat. +Your objection has been noted. Keberatan anda telah dicatat. +A car is faster than a bicycle. Mobil lebih cepat daripada sepeda. +A dog followed me to my school. Seekor anjing mengikutiku sampai ke sekolah. +Are you attempting to bribe me? Kamu mencoba memeras saya? +Are you going to school by bus? Apa kau pergi ke sekolah dengan bus? +Aren't you sick of eating here? Apa kau tidak jenuh terus-terusan makan di sini? +Can I use my medical insurance? Bisakah saya menggunakan asuransi kesehatan saya? +Can anybody guess what this is? Adakah yang bisa menebak apa ini? +Could you please do me a favor? Bisakah Anda membantu saya? +Did you read the whole article? Apa kamu membaca keseluruhan artikelnya? +Did you tell Tom Mary did this? Kamu memberitahu Tom Mary melakukan ini? +Do you have a driver's license? Apa kau memiliki SIM? +Do you like playing volleyball? Apa kau suka bermain voli? +Do you want any of these books? Apa kamu menginginkan buku-buku ini? +Do you want something to drink? Apa kamu mau minum sesuatu? +Don't make fun of other people. Jangan mempermainkan orang lain. +Drivers should wear seat belts. Seorang pengemudi harus mengenakan sabuk pengaman. +Even Tom is a little surprised. Bahkan Tom sedikit terkejut. +Everybody came to an agreement. Semuanya sepakat. +Excuse me, I'm here to see Tom. Permisi, saya ingin bertemu dengan Tom. +Few people visit me these days. Akhir-akhir ini, sedikit orang mengunjungiku. +Gold is far heavier than water. Emas jauh lebih berat ketimbang air. +Have you been to London before? Apakah Anda pernah ke London sebelumnya? +Have you ever climbed Mt. Fuji? Apakah kamu pernah mendaki Gunung Fuji? +Have you ever climbed Mt. Fuji? Apakah Anda pernah mendaki Gunung Fuji? +Have you turned in your report? Sudahkah kamu menyerahkan laporanmu? +He could find her house easily. Dia bisa menemukan rumahnya dengan mudah. +He disappeared without a trace. Dia menghilang tanpa jejak. +He dropped in at the bookstore. Dia mampir ke toko buku. +He felt lost and uncomfortable. Dia merasa bingung dan tidak nyaman. +He has no interest in politics. Dia tidak tertarik pada politik. +He hit his head against a rock. Dia membenturkan kepalanya ke sebuah batu. +He is often absent from school. Dia sering absen dari sekolah. +He makes his living by singing. Dia hidup sebagai seorang penyanyi. +He shook hands with his friend. Dia bersalaman dengan temannya. +He tried to sleep on the floor. Dia mencoba tidur di lantai. +He was too drunk to drive home. Ia terlalu mabuk untuk berkemudi menuju rumah. +He's in the hospital right now. Dia sedang di rumah sakit sekarang. +He's reading a novel right now. Dia sedang membaca novel sekarang. +Health is worth more than gold. Kesehatan itu lebih berharga dibandingkan dengan emas. +Her mother is writing a letter. Ibunya sedang menulis surat. +Hey, how's it going down there? Hei, gimana keadaannya di bawah? +His new movie is disappointing. Film barunya mengecewakan. +His writing is very subjective. Tulisannya sangat subjektif. +How did you spend your holiday? Apa yang Anda lakukan untuk menghabiskan waktu liburan Anda? +How long will Tom stay with us? Berapa lama Tom akan tinggal bersama kami? +I am ashamed of having done so. Saya malu telah melakukan hal tersebut. +I am busy now and can't go out. Saya sedang sibuk dan tidak bisa pergi. +I am pleased with my new house. Saya merasa senang dengan rumah baru saya. +I am positive that he is wrong. Aku yakin bahwa dia salah. +I believe you know what I mean. Saya yakin Anda tahu apa maksud saya. +I bought a dozen pencils today. Aku membeli satu lusin pensil hari ini. +I can't stand this hot weather. Aku tidak tahan dengan cuaca panas ini. +I didn't want to humiliate Tom. Saya tidak ingin mempermalukan Tom. +I don't expect to be gone long. Saya tidak menyangka akan pergi lama. +I don't know what I should say. Aku tidak tahu apa yang harus aku katakan. +I don't know where my keys are. Aku tidak tahu di mana kunciku. +I don't know why that happened. Aku tidak tahu mengapa itu bisa terjadi. +I don't want to live with that. Aku tidak mau tinggal dengan itu. +I don't want to wait that long. Saya tidak ingin menunggu selama itu. +I got the bicycle at a bargain. Saya membeli sepeda dengan menawar. +I have a date with Tom tonight. Malam ini saya kencan dengan Tom. +I have to go to the men's room. Aku harus pergi ke kamar kecil. +I hear my uncle died of cancer. Saya dengar paman saya meninggal karena kanker. +I hear that you play the piano. Aku dengar kau bermain piano. +I hope I'll see you again soon. Saya harap saya dapat bertemu anda lagi, segera. +I know what Tom is going to do. Aku tahu apa yang akan Tom lakukan. +I live next to an old bookshop. Saya tinggal di dekat sebuah toko buku tua. +I lost my camera the other day. Aku kehilangan kameraku beberapa hari yang lalu. +I love the taste of watermelon. Aku sangat suka rasanya semangka. +I should cancel the trip to LA. Saya sebaiknya membatalkan perjalanan ke LA. +I simply don't understand this. Aku sama sekali tidak memahami ini. +I slipped and twisted my ankle. Aku terpeleset dan kakiku terkilir. +I still haven't heard from him. Aku masih belum menerima kabar darinya. +I think my suitcase was stolen. Sepertinya koper saya telah dicuri. +I think your answer is correct. Aku pikir jawabanmu benar. +I want something cold to drink. Aku ingin minuman dingin. +I want to be more than friends. Saya ingin menjadi lebih dari sekedar teman. +I want to drink something cold. Aku ingin minum sesuatu yang dingin. +I want to say something to you. Ada hal yang ingin aku katakan padamu. +I wanted to get a lot of money. Saya ingin mendapatkan uang yang banyak. +I was expecting you last night. Aku mengharapkanmu semalam. +I will wait here till he comes. Saya akan menunggu di sini sampai dia datang. +I wonder what Tom is doing now. Aku penasaran apa yang sedang dilakukan Tom sekarang. +I'd like to buy a refrigerator. Aku ingin membeli sebuah kulkas. +I'd like to stay for one night. Aku ingin menginap semalam. +I'd like to stay for one night. Saya ingin menginap semalam. +I'd like you to read this book. Saya ingin kamu baca buku ini. +I'll be here when you get back. Aku akan di sini saat kau kembali. +I'll go crazy if this keeps up. Aku bisa gila kalau begini terus. +I'm glad I could be of service. Saya senang bisa membantu. +I'm here to help you, actually. Aku di sini untuk membantumu sebenarnya. +I've always wanted to meet you. Aku selalu ingin bertemu denganmu. +I've been up most of the night. Aku telah terjaga sepanjang malam. +If it rains, I'll stay at home. Jika hujan, aku akan tinggal di rumah. +Is there anything on the floor? Apa ada sesuatu di atas lantai? +Is this your first trip abroad? Apakah ini pertama kalinya kamu ke luar negeri? +Is this your first trip abroad? Apakah ini kali pertama kamu ke luar negeri? +It is too dark to play outside. Terlalu gelap untuk bermain di luar. +It rained continuously all day. Hujannya tidak berhenti hingga seharian penuh. +It stopped snowing an hour ago. Saljunya berhenti turun sejam yang lalu. +Let me see what I can find out. Mari lihat apa yang bisa kutemukan. +Let's find something to sit on. Mari kita mencari sesuatu untuk diduduki. +My boss is very cheerful today. Bos saya sangat gembira hari ini +My hobby is listening to music. Hobiku mendengarkan musik. +My hobby is playing the guitar. Hobiku bermain gitar. +My opinions are similar to his. Pendapatku mirip dengannya. +My son believes in Santa Claus. Anak laki-lakiku percaya akan Santa Claus. +Our school is across the river. Sekolah kami ada di seberang sungai. +Paris is the capital of France. Paris adalah ibukota dari Prancis. +Parking and admission are free. Parkir dan masuknya gratis. +Perhaps you're trying too hard. Mungkin kamu berusaha terlalu keras. +Please allow us to do the work. Tolong izinkan kami mengambil pekerjaan ini. +Public opinion began to change. Opini publik mulai berubah. +Remove your shirt and lie down. Lepas kaosmu dan berbaringlah. +She advised him to work harder. Ia memberitahunya untuk bekerja lebih keras. +She got good grades in English. Dia mendapatkan nilai bagus dalam bahasa inggris. +She has a cheerful personality. Dia punya kepribadian yang ceria. +She hopes to become a designer. Dia ingin menjadi desainer. +She left her gloves in the car. Dia meninggalkan sarung tangannya di dalam mobil. +She wanted to help her friends. Dia ingin membantu teman-temannya. +She whispered something to him. Ia membisikkan sesuatu padanya. +She will come back before long. Dia akan kembali tidak lama lagi. +She's a beauty from a distance. Dia cantik dari jauh. +Sorry I'm late for the meeting. Maaf saya datang terlambat. +Study hard, and you'll succeed. Belajarlah dengan rajin, maka kau akan berhasil. +That's what they were planning. Itulah yang sedang mereka rencanakan. +The bank isn't open on Sundays. Banknya tidak buka pada hari Minggu. +The boy knocked the glass over. Anak laki-laki itu menjatuhkan gelasnya. +The capital of France is Paris. Ibukota dari Prancis adalah Paris. +The deer was killed by hunters. Rusa itu dibunuh oleh para pemburu. +The main crop of Japan is rice. Produk pertanian utama Jepang adalah beras. +The rain lasted for three days. Hujannya bertahan selama tiga hari. +The station is 100 meters away. Stasiunnya terletak 100 meter dari sini. +The visitor sat across from me. Tamunya duduk berhadapan dengan saya. +There is little room for doubt. Masih ada kemungkinan kalau itu benar. +There is no chair in this room. Tidak ada kursi di ruangan ini. +There was no one there but Tom. Di sana tidak ada orang selain Tom. +There's no reason to be afraid. Tidak ada alasan untuk takut. +There's nothing in this drawer. Di dalam laci ini tidak ada apa-apa. +These are gifts for my friends. Ini hadiah untuk teman-temanku. +They are not at all interested. Mereka tidak tertarik sama sekali. +They have been here since 1989. Mereka sudah ada di sini sejak 1989. +This desk is too heavy to lift. Meja ini terlalu berat untuk diangkat. +This is what I do for a living. Ini yang kulakukan untuk hidup. +This room gets little sunshine. Ruangan ini mendapat sedikit sinar matahari. +This room has air conditioning. Ruangan ini ada AC nya. +This room has air conditioning. Ada AC di ruangan ini. +Tom asked Mary to quit her job. Tom meminta Mary untuk berhenti bekerja. +Tom asked Mary to stop working. Tom meminta Mary untuk berhenti bekerja. +Tom couldn't even look at Mary. Tom sampai tidak sanggup melihat ke arah Mary. +Tom couldn't find the bus stop. Tom tidak dapat menemukan tempat pemberhentian busnya. +Tom doesn't feel like studying. Tom merasa seperti sedang tidak belajar. +Tom doesn't like to be touched. Tom tidak suka disentuh. +Tom grabbed the book from Mary. Tom merebut buku itu dari Mary. +Tom had a good opinion of Mary. Tom dulu memiliki anggapan yang baik tentang Mary. +Tom has been bitten by a snake. Tom telah digigit oleh seekor ular. +Tom has been quite cooperative. Tom sudah cukup kooperatif sejauh ini. +Tom is 3 years older than Mary. Tom tiga tahun lebih tua dari Mary. +Tom is on good terms with John. Tom berteman baik dengan John. +Tom knew he was being followed. Tom tahu jika dia sedang diikuti. +Tom left Boston a few days ago. Tom meninggalkan Boston beberapa hari lalu. +Tom likes to travel by himself. Tom suka berkeliling sendiri. +Tom might never trust me again. Tom mungkin tidak akan pernah mempercayaiku lagi. +Tom might not want to see Mary. Tom mungkin tidak ingin melihat Mary. +Tom narrowly escaped being hit. Tom hampir kena pukul. +Tom prepared supper by himself. Tom menyiapkan makan malan sendiri. +Tom really did a fantastic job. Tom sungguh telah melakukan pekerjaan yang luar biasa. +Tom regretted quitting his job. Tom menyesal telah meninggalkan pekerjaannya. +Tom resumed sweeping the floor. Tom melanjutkan menyapu lantai. +Tom rode his bicycle to school. Tom mengendarai sepeda ke sekolah. +Tom set the alarm on his watch. Tom mengatur pengingat pada jamnya. +Tom started clearing the table. Tom mulai membersihkan meja. +Tom turned the doorknob slowly. Tom memutar gagang pintu secara perlahan. +Tom walked toward the entrance. Tom berjalan menuju pintu masuk. +Tom wanted to go into politics. Tom ingin terjun ke dunia politik. +Tom wants me to take his place. Tom ingin aku mengambil posisinya. +Tom went shopping for dog food. Tom pergi membeli makanan anjing. +Tom went to Boston to see Mary. Tom pergi ke Boston untuk menemui Mary. +Tom went to school with my son. Tom pergi ke sekolah bersama dengan anak laki-laki saya. +Tom works every day but Sunday. Tom bekerja setiap hari kecuali hari minggu. +Tom's skull has been fractured. Tempurung kepala Tom retak. +Tom's speech quieted the crowd. Pidato Tom membuat hadirin terdiam. +Try to be generous and forgive. Cobalah untuk menjadi seorang yang murah hati dan pemaaf. +Unfortunately, she didn't come. Sayangnya, dia tidak datang. +We all know you don't eat meat. Kita semua tahu kalau kau tidak mengonsumsi daging. +We all wear uniforms to school. Kami semua memakai seragam ke sekolah. +We don't have a lot of trouble. Kami tidak punya banyak masalah. +We found the front door locked. Kami mengetahui bahwa pintu depan terkunci. +We made pancakes for breakfast. Kami membuat kue dadar untuk makan pagi. +We met at the door of my house. Kami bertemu di depan pintu rumahku. +We took turns with the driving. Kami mengemudi secara bergantian. +We're here to support you, Tom. Kami di sini untuk mendukungmu Tom. +We're in the same group, right? Kita dalam grup yang sama, kan? +We've had a difficult schedule. Kami punya jadwal yang sulit. +We've had bad weather recently. Akhir-akhir ini cuacanya buruk. +What did Tom wear to the party? Apa yang Tom kenakan di pesta? +What did you do on the weekend? Apa yang kau lakukan di akhir pekan? +What do you have your feet for? Untuk apa kau memiliki kaki? +What does he say in his letter? Apa yang dia katakan di dalam suratnya? +What is it you want to tell us? Apa yang ingin kamu katakan pada kami? +What kind of historian are you? Sejarawan macam apa Anda? +What made you change your mind? Apa yang membuat pikiranmu berubah? +What time did you arrive there? Anda tiba di sana pada pukul berapa? +What was the weather yesterday? Bagaimana cuaca kemarin? +Which is heavier, lead or gold? Mana yang lebih berat, timbel atau emas? +Which subject do you like best? Pelajaran mana yang paling kamu sukai? +Who will take care of the baby? Siapa yang akan merawat bayinya? +Why do bees die after stinging? Mengapa lebah meninggal setelah menyengat? +Why were you late this morning? Kenapa kau terlambat pagi ini? +Will you stay here for a while? Maukah kalian tinggal di sini sementara? +Will you stay here for a while? Maukah kamu tinggal di sini sementara? +Would you like anything to eat? Apa kau mau makan? +Would you like anything to eat? Apa kau ingin makan sesuatu? +You are no longer a mere child. Kamu bukan lagi seorang anak kecil. +You can handle this without me. Kamu bisa melakukannya tanpa aku. +You can have anything you want. Kau bisa memiliki apapun yang kau inginkan. +You can have whatever you want. Kau bisa memiliki apapun yang kau inginkan. +You don't have to say anything. Anda tidak perlu mengatakan apa-apa. +You have a good sense of humor. Kau punya selera humor yang bagus. +You have no need to be ashamed. Seharusnya kamu tak perlu merasa malu. +You look very pale. Are you OK? Anda terlihat sangat pucat. Apakah Anda baik-baik saja? +You may not like what you hear. Anda mungkin tidak menyukai apa yang anda dengar. +You may not smoke in this room. Anda tidak boleh merokok di ruangan ini. +You never mentioned that to me. Kamu tidak pernah menyebutkan hal itu padaku. +You should consult your doctor. Kau harus berkonsultasi dengan doktermu. +You shouldn't underestimate me. Sebaiknya kau tidak meremehkanku. +You'd better do what I suggest. Sebaiknya kamu lakukan sesuai saran saya. +You'll forget about me someday. Kau akan melupakanku suatu hari nanti. +You'll need a temporary bridge. Kau akan membutuhkan sebuah jembatan sementara. +Your answer doesn't make sense. Jawaban anda tidak masuk akal. +Your watch is ten minutes slow. Jam tanganmu terlambat sepuluh menit. +A few students were left behind. Beberapa orang siswa ditinggalkan. +Are you absolutely sure of that? Apa kau benar-benar yakin dengan hal itu? +As a rule, I don't drink coffee. Saya terbiasa untuk tidak meminum kopi. +Astronomy is an expensive hobby. Astronomi merupakan hobi yang mahal. +Call Tom and see what he thinks. Panggil Tom dan cari tahu apa pendapatnya. +Can I ask you one more question? Bolehkah saya bertanya satu kali lagi? +Can you check the tire pressure? Apakah kamu bisa mengecek tekanan bannya? +China is much bigger than Japan. Tiongkok jauh lebih besar ketimbang Jepang. +Could you call a doctor, please? Bisakah kau memanggilkanku seorang dokter? +Did you buy a round trip ticket? Apa kau membeli tiket pulang pergi? +Did you pack your bags yourself? Apa kau mengemas barang-barangmu seorang diri? +Didn't you and Tom ever do that? Bukankah kamu dan Tom pernah melakukan hal itu? +Didn't you used to be a teacher? Bukankah dulu kamu adalah seorang guru? +Do you commute to school by bus? Apa kau pulang pergi ke sekolah dengan bus? +Do you feel like going swimming? Apa kamu mau pergi berenang? +Do you think Tom is still alive? Menurutmu Tom masih hidup? +Do you think Tom is still alive? Apa menurutmu Tom masih hidup? +Don't let Tom hear you say that. Jangan biarkan Tom mendengarkanmu mengatakan itu. +Don't let me become discouraged. Jangan buat aku patah semangat. +Don't make a decision right now. Jangan buat keputusan sekarang! +Don't you remember the question? Apakah kamu tidak ingat pertanyaannya? +Eggs are getting more expensive. Telur semakin mahal. +Every cloud has a silver lining. Habis gelap terbitlah terang +Five gallons of regular, please. Tolong 5 galon yang reguler. +Give me something to write with. Berikan aku sesuatu yang bisa aku tulisi. +Gold is more precious than iron. Emas lebih berharga ketimbang besi. +Half of the students are absent. Setengah dari para siswa tidak hadir. +Have I called you at a bad time? Apakah saya menghubungi anda pada saat yang kurang tepat? +Have you been told when to come? Apakah Anda sudah diberitahu kapan harus datang? +Have you finished breakfast yet? Sudahkah kau menghabiskan sarapanmu? +Have you finished breakfast yet? Apa kau sudah menghabiskan sarapanmu? +He advised her to stop drinking. Dia memberitahu si perempuan untuk berhenti minum. +He and his mother went shopping. Dia dan ibunya pergi berbelanja. +He comes back from Sydney today. Dia kembali dari Sydney hari ini. +He did not go out, but sat down. Dia tidak pergi keluar, tetapi duduk. +He doesn't read many newspapers. Dia tidak terlalu banyak membaca koran. +He dropped the cup and broke it. Dia menjatuhkan dan memecahkan gelasnya. +He has an uncontrollable temper. Dia punya temperamen yang tidak terkontrol. +He knows how to teach languages. Dia tahu cara mengajar bahasa. +He often doesn't come to school. Dia sering tidak datang ke sekolah. +He received cheers and applause. Dia mendapat sorakan dan tepuk tangan. +He reminds me of my grandfather. Dia mengingatkan pada kakekku. +He set out for Canada yesterday. Kemarin, dia meninggalkan Kanada. +He stood aside for her to enter. Tom bergeser untuk membiarkannya lewat. +He writes letters to his mother. Dia menulis surat untuk ibunya. +Her mother made her a new dress. Ibunya membuatkan baju baru untuknya. +His data is not accurate at all. Datanya sama sekali tidak akurat. +His mother is worried about him. Ibunya mengkhawatirkan anaknya. +How could I not see this coming? Bagaimana bisa aku tidak menyadari hal ini? +How do you feel about this, Tom? Apa yang kamu rasakan tentang ini, Tom? +How much do you charge per hour? Berapa besar Anda mematok biaya per jamnya? +How's it going with you and Tom? Bagaimana hubunganmu dengan Tom? +Humans aren't meant to be alone. Manusia tidak seharusnya sendiri. +I am badly in need of your help. Aku sangat membutuhkan bantuanmu. +I am busy cooking at the moment. Saat ini saya sedang sibuk memasak. +I am leaving for Tokyo tomorrow. Aku akan pergi ke Tokyo besok. +I apologize for having to leave. Saya meminta maaf karena harus pergi. +I believe that you will succeed. Saya yakin kamu akan berhasil. +I can't believe what I'm seeing. Aku tidak percaya dengan apa yang aku lihat. +I can't decide which car to buy. Aku tidak bisa memilih mobil mana yang mau kubeli. +I can't read my own handwriting. Tulisan sendiri pun tak dapat saya baca. +I don't know where we'll arrive. Aku tidak tahu di mana kita akan sampai. +I don't think I'm narrow-minded. Aku kira aku tidak berpikiran sempit. +I don't want to be part of this. Aku tidak ingin menjadi bagian dari ini. +I feel I'm wasting my time here. Aku merasa kalau aku membuang-buang waktuku di sini. +I fell asleep with a sweater on. Aku tertidur dengan mengenakan sebuah sweter. +I guess Tom is looking for Mary. Kurasa Tom sedang mencari Mary. +I had bought it the week before. Aku membelinya seminggu yang lalu. +I had no choice but to go there. Aku tidak punya pilihan lain selain pergi ke sana. +I had no idea where I should go. Saya tidak tau kemana seharusnya Saya pergi. +I have a sharp pain in my chest. Dadaku rasanya nyeri. +I have to do something else now. Ada hal lain yang harus ku kerjakan. +I just ate sushi and drank beer. Saya baru saja makan sushi dan minum bir. +I left my dictionary downstairs. Aku meninggalkan kamusku di lantai bawah. +I met up with her on the street. Aku bertemu dengannya di jalan. +I remember seeing you somewhere. Aku seperti pernah melihatmu di suatu tempat. +I said I'd talk to Tom about it. Aku bilang aku akan bicara pada Tom tentang hal itu. +I stood here for thirty minutes. Saya berdiri disini selama tiga puluh menit. +I study math as hard as English. Aku belajar matematika dengan giat, segiat waktu aku belajar bahasa Inggris. +I told Tom we could do it today. Aku memberitahu Tom kalau kita bisa melakukannya hari ini. +I took your umbrella by mistake. Aku salah membawa payungmu. +I visited Fukuoka ten years ago. Saya pernah mengunjungi Fukuoka 10 tahun yang lalu. +I want coffee, toast, and jelly. Aku mau kopi, roti panggang, dan jeli. +I want this garbage out of here. Saya mau sampah ini dibuang. +I want to go on a trip with you. Aku ingin pergi jalan-jalan denganmu. +I want to invite you to a party. Saya ingin mengundang kamu ke sebuah pesta. +I was at home all day yesterday. Kemarin, saya di rumah sepanjang hari. +I was writing her a love letter. Aku menulis sebuah surat cinta untuknya. +I will never tell it to anybody. Saya tidak akan memberitahu siapapun. +I wish I could've stayed longer. Aku berharap bisa tinggal lebih lama. +I wonder what Tom is doing here. Aku penasaran apa yang Tom lakukan di sini. +I'd like to know what you think. Aku ingin tahu apa yang kau pikirkan. +I'll give you anything but this. Kuberikan apapun padamu kecuali ini. +I'm getting ready for the worst. Aku bersiap untuk kemungkinan terburuk. +I'm glad you could make it, Tom. Aku bersyukur kamu dapat melakukannya, Tom. +I'm going over to Tom's tonight. Aku akan pergi ke rumah Tom malam ini. +I'm just trying to help you out. Aku hanya ingin membantumu. +I'm looking for a part-time job. Saya sedang mencari pekerjaan paruh waktu. +I'm looking for a part-time job. Saya sedang mencari pekerjaan paruh-waktu. +I'm not sure how I can help you. Aku tidak yakin bagaimana bisa membantumu. +I'm not sure if this is correct. Aku tidak yakin jika ini benar. +If I were you, I wouldn't do it. Kalau aku jadi kamu, aku tidak akan melakukan itu. +If anybody can fix it, it's Tom. Jika ada orang yang dapat memperbaikinya, orang itu adalah Tom. +In doing anything, do your best. Ketika melakukan sesuatu, lakukanlah yang terbaik. +Is there a knife in the kitchen? Apakah di dapur ada pisau? +Is there a problem with my work? Apakah ada masalah dengan pekerjaan saya? +Is there a tour guide available? Apa ada pemandu wisatanya? +Is there anything I should know? Apakah ada sesuatu yang perlu aku ketahui? +It is written in simple English. Itu ditulis dengan menggunakan bahasa Inggris sederhana. +It was the worst day of my life. Ini adalah hari yang paling buruk seumur hidupku. +It's a pity that you can't come. Sayang sekali Anda tidak bisa datang. +Learning a language is not easy. Belajar bahasa tidaklah mudah. +Let's wait for the rain to stop. Mari kita menunggu hujannya berhenti. +May I see your driver's license? Boleh saya melihat SIM Anda? +May I see your passport, please? Bolehkah saya melihat paspor Anda? +Millions of men lost their jobs. Jutaan pria kehilangan pekerjaan mereka. +Music is the universal language. Musik adalah bahasa universal. +My aunt brought me some flowers. Bibiku membawakanku beberapa bunga. +My aunt made a new skirt for me. Bibi saya membuatkan saya rok baru. +My father doesn't like football. Ayahku tidak suka sepak bola. +Night is when most people sleep. Malam adalah waktu di mana kebanyakan orang beristirahat. +Nobody cares about our problems. Tidak ada yang peduli terhadap masalah kita. +Not everything can be explained. Tidak semua hal bisa dijelaskan. +Of course she can speak English. Jelas dia bisa berbahasa Inggris. +One of my horses died yesterday. Salah satu kudaku mati kemarin. +Please give me a sheet of paper. Tolong berikan selembar kertas. +Please give me your credit card. Tolong berikan saya kartu kreditmu. +Please shut the door behind you. Tolong tutup pintu di belakangmu. +She advised him to study harder. Ia memberitahunya untuk belajar lebih keras. +She is looking for her car keys. Dia sedang mencari kunci mobilnya. +She says her life is monotonous. Dia berkata bahwa kehidupannya monoton. +She set it aside for future use. Dia menyimpannya agar bisa digunakan nanti. +She tends to be late for school. Dia suka terlambat ke sekolah. +She took the taxi to the museum. Dia naik taksi ke museum. +Someone has stolen all my money. Seseorang telah mencuri semua uangku. +Someone is knocking on the door. Seseorang mengetuk pintu. +Something horrible has happened. Sesuatu yang mengerikan telah terjadi. +Tell your mother about the trip. Beritahukan ibumu soal perjalanan itu. +That doesn't seem too difficult. Sepertinya itu tidak terlalu sulit. +That should get Tom's attention. Itu pasti akan menarik perhatiannya Tom. +That was interesting, wasn't it? Itu tadi menarik, ya? +The ball rolled across the road. Bola itu menggelinding melintasi jala. +The dog was sleeping on the mat. Anjing itu tidur di atas tikar. +The fire burned down ten houses. Api itu membakar habis sepuluh rumah. +The girl standing there is Mary. Gadis yang berdiri di sana adalah Mary. +The movie starts at ten o'clock. Filmnya akan mulai pada pukul sepuluh. +The museum is around the corner. Museumnya ada di dekat sini. +The old couple sat side by side. Pasangan lanjut usia itu duduk berdampingan. +The old man is angry and bitter. Orang tua itu marah dan merasa sakit hati. +The ship's crew is now complete. Kru kapalnya sekarang lengkap. +The story turned out to be true. Sepertinya cerita itu benar adanya. +There is a shopping area nearby. Ada tempat perbelanjaan di dekat sini. +They got married six months ago. Mereka menikah enam bulan yang lalu. +This hotel does not serve lunch. Hotel ini tidak menyediakan makan siang. +This is a hazard to your health. Ini membahayakan kesehatan Anda. +Tom answered in the affirmative. Tom menyetujuinya. +Tom arrived three minutes early. Tom tiba tiga menit lebih awal. +Tom ate only one slice of bread. Tom cuma makan satu potong roti. +Tom didn't have to be so formal. Tom tidak perlu seformal itu. +Tom enjoys playing tricks on me. Tom senang mengerjaiku. +Tom filled the glass with water. Tom mengisi gelas dengan air. +Tom forgot to go to the meeting. Tom lupa mengikuti rapat. +Tom gladly accepted Mary's gift. Tom dengan senang hati menerima hadiah dari Mary. +Tom has shaved off his mustache. Tom telah mencukur kumisnya. +Tom is a personal enemy of mine. Tom adalah musuh pribadi saya. +Tom is alone in the living room. Tom berada seorang diri di ruang keluarga. +Tom is getting ready for school. Tom bersiap pergi ke sekolah. +Tom is hiding something from us. Tom menyembunyikan sesuatu dari kita. +Tom is more intelligent than me. Tom lebih cerdas dariku. +Tom is much taller than you are. Tom jauh lebih tinggi daripada kamu. +Tom is quick-tempered, isn't he? Tom gampang marah, ya? +Tom is taller than anybody else. Tom lebih tinggi dibanding yang lain. +Tom is the tallest in his class. Tom adalah yang tertinggi di kelasnya. +Tom is wearing a biohazard suit. Tom mengenakan baju biobahaya. +Tom laid his cards on the table. Tom meletakkan kartu-kartunya di atas meja. +Tom left only a few minutes ago. Tom pergi beberapa menit yang lalu. +Tom moved here three months ago. Tom pindah ke sini tiga bulan yang lalu. +Tom never gave in to temptation. Tom tidak pernah menyerah pada godaan. +Tom offered Mary a stick of gum. Tom menawarkan sebatang permen kepada Mary. +Tom often cries when he's drunk. Tom seringkali menangis saat dia mabuk. +Tom practiced every day at home. Tom berlatih setiap hari di rumah. +Tom put on one of John's shirts. Tom mengenakan salah satu baju milik John. +Tom realizes he's being ignored. Tom menyadari dirinya sedang dihiraukan. +Tom received a letter from Mary. Tom menerima surat dari Mary. +Tom seemed to be very surprised. Tom terlihat sangat terkejut. +Tom seldom speaks to us anymore. Tom sudah jarang berbicara dengan kami. +Tom slowly walked up the stairs. Tom menaiki tangga secara perlahan. +Tom sold his house for $300,000. Tom menjual rumahnya $300000. +Tom still doesn't know I'm here. Tom belum tahu bahwa saya di sini. +Tom went to Boston to meet Mary. Tom pergi ke Boston untuk menemui Mary. +Unless it rains, I will go, too. Kalau tidak hujan, aku akan ikut pergi. +We climbed Mt. Fuji last summer. Kami mendaki Gunung Fuji musim panas tahun lalu. +We discussed the plan yesterday. Kami mendiskusikan rencana itu kemarin. +We don't really have to sell it. Kita tidak harus menjualnya. +We eat to live, not live to eat. Kita makan untuk hidup, bukan hidup untuk makan +We go fishing from time to time. Kami memancing dari waktu ke waktu. +We killed time by playing cards. Kami menghabiskan waktu dengan bermain kartu. +We shouldn't have told Tom that. Mestinya kita tidak memberi tahu itu pada Tom. +We've known each other for ages. Sudah lama kami saling kenal. +What are you doing this weekend? Apa yang kalian lakukan akhir pekan ini? +What are you punishing them for? Untuk apa kau menghukum mereka? +What did you think of the party? Bagaimana menurutmu pestanya? +What do you have in your pocket? Apa yang kau simpan di dalam kantongmu? +What have you learned about Tom? Apa yang kamu ketahui tentang Tom? +What time do you start check-in? Mulai dari jam berapa saya bisa lapor masuk? +Where did you get your hair cut? Di mana kamu mencukur rambut? +Won't you join our conversation? Mau bergabung dalam pembicaraan kami? +Would you check the oil, please? Maukah anda memeriksa olinya? +Would you like something to eat? Apa kau ingin makan sesuatu? +Would you like to eat something? Apa kau ingin makan sesuatu? +Would you like to travel abroad? Apa kau ingin pergi jalan-jalan ke luar negeri? +You don't have to come tomorrow. Kamu tidak harus datang besok. +You don't have to come tomorrow. Anda tidak harus datang besok. +You have nothing to worry about. Tidak ada yang perlu dikhawatirkan. +You should keep your mouth shut. Kau harus menjaga mulutmu agar tetap diam. +You'd better consult the doctor. Sebaiknya kau berkonsultasi dengan dokter. +You've got bags under your eyes. Kamu punya kantung mata. +Your English has improved a lot. Bahasa Inggrismu mengalami banyak peningkatan. +Your bicycle is similar to mine. Sepedamu mirip dengan milikku. +Your chair is identical to mine. Kursimu sama persis dengan milikku. +Your opinion is similar to mine. Pendapatmu mirip dengan pendapatku. +Your problem is similar to mine. Masalahmu sama denganku. +Your team is stronger than ours. Tim kalian lebih kuat ketimbang tim kami. +"How old are you?" "I'm sixteen." "Berapa umurmu?" "Aku enam belas tahun." +A driver was sleeping in the car. Seorang sopir tidur didalam mobil. +All the boys didn't laugh at him. Semua anak laki-laki tidak menertawakannya. +Are there still some empty seats? Apa masih ada beberapa kursi kosong? +Are you free on Friday afternoon? Apakah Anda ada acara Jumat siang? +Are you sure you heard something? Kamu yakin mendengar sesuatu? +At first, I thought she was sick. Pada awalnya aku mengira dia sakit. +At what time will you be leaving? Kamu berangkat jam berapa? +At what time will you be leaving? Kau akan berangkat jam berapa? +Can it be phrased in another way? Bisakan itu diungkapkan dengan cara lain? +Can you put it down on the table? Dapatkah kamu meletakannya di meja? +Cats can see even in dark places. Kucing bisa melihat meskipun di tempat gelap. +Could you turn that down, please? Bisa tolong dikecilkan ? +Do I have your word on that, Tom? Dapatkah saya mempercayai perkataanmu terhadap itu, Tom? +Do these paintings appeal to you? Apa kau suka lukisan-lukisan ini? +Do you have any questions for me? Apa kau memiliki beberapa pertanyaan untukku? +Do you know how to open this box? Apakah kamu tahu cara membuka kotak ini? +Do you know how to speak English? Apa Anda tahu bagaimana caranya berbicara dalam bahasa Inggris? +Do you play a musical instrument? Apa kau memainkan sebuah instrumen musik? +Do you realize what you're doing? Apa kamu sadar akan apa yang kamu perbuat? +Don't hesitate to ask for advice. Jangan sungkan untuk meminta saran. +Don't let anything slow you down. Jangan biarkan apapun memperlambat jalanmu. +Exercise is good for your health. Berolahraga baik untuk kesehatanmu. +Find Tom before he hurts someone. Temukan Tom sebelum ia menyakiti seseorang. +Friendship requires mutual trust. Persahabatan membutuhkan rasa saling percaya. +Have you ever had food poisoning? Apa kau pernah keracunan makanan? +Have you finished your lunch yet? Sudahkan kau menghabiskan makan siangmu? +Have you finished your lunch yet? Apa kau sudah menghabiskan makan siangmu? +Have you taken your medicine yet? Apakah kamu sudah minum obat? +Have you taken your medicine yet? Sudah minum obat? +He has a hundred dollars at most. Dia cuma punya seratus dolar paling banyak. +He listened to music in his room. Dia mendengarkan musik di kamarnya. +He was satisfied with the result. Dia puas dengan hasilnya. +He's a carbon copy of his father. Dia adalah salinan dari ayahnya. +His loud voice drew my attention. Suaranya yang nyaring menarik perhatianku. +How many languages can you speak? Berapa banyak bahasa yang bisa Anda pahami? +How many people are in this room? Ada berapa banyak orang dalam kamar ini? +How much does he earn in a month? Berapa banyak yang dia peroleh per bulan? +How much does this umbrella cost? Payung ini berapa harganya? +Hurry up, or you'll miss the bus. Cepatlah, atau kau akan ketinggalan busnya. +I am acquainted with your father. Aku mengenal ayahmu. +I am tired of my monotonous life. Aku lelah dengan kehidupanku yang monoton. +I became a lawyer to help people. Aku menjadi seorang pengacara untuk membantu orang-orang. +I brought you a little something. Aku membawakanmu sesuatu. +I bumped into your dad yesterday. Saya bertemu dengan ayahmu kemarin. +I couldn't forget you if I tried. Aku tidak dapat melupakanku ketika aku mencobanya. +I don't care what Tom looks like. Aku tidak peduli Tom terlihat seperti apa. +I don't expect anything from you. Aku tidak mengharapkan apa-apa darimu. +I don't have any free time today. Aku tidak punya waktu luang hari ini. +I don't need an answer right now. Aku tidak membutuhkan jawaban saat ini. +I don't want to do this with you. Saya tidak mau melakukan ini dengan kamu. +I don't want to get into trouble. Aku tidak mau mendapat masalah. +I don't want to see Tom get hurt. Aku tidak mau melihat Tom tersakiti. +I have to go there for my father. Saya harus pergi ke sana demi ayah saya. +I haven't read all of his novels. Aku belum membaca semua novelnya. +I hope I haven't interrupted you. Kuharap aku tidak mengganggumu. +I just wish you'd told me before. Andai saja kau memberitahuku sebelumnya. +I know how much you meant to Tom. Aku tahu seberapa berartinya dirimu bagi Tom. +I like summer better than winter. Aku lebih suka musim panas daripada musim dingin. +I never expected to see you here. Aku tidak menyangka akan bertemu denganmu di sini. +I received your letter yesterday. Aku menerima suratmu kemarin. +I see no need for Tom to do that. Aku rasa Tom tidak perlu melakukannya. +I should've been able to do more. Seharusnya aku bisa melakukan lebih. +I think I may have to get a loan. Aku rasa aku harus mencari pinjaman. +I wrote three letters last night. Aku menulis tiga pucuk surat semalam. +I'll call back in twenty minutes. Saya akan menghubungi kembali dalam 20 menit. +I'll drop you off at the station. Saya akan menurunkanmu di stasiun. +I'm allergic to synthetic rubber. Aku alergi pada karet sintetis. +I'm quitting my job as a teacher. Saya berhenti dari pekerjaan saya sebagai seorang guru. +I'm sure I won't be disappointed. Saya yakin tidak akan kecewa. +I'm sure I'll be able to find it. Saya yakin saya akan dapat menemukannya. +I've been trying to quit smoking. Aku sedang berusaha untuk berhenti merokok. +I've changed my website's layout. Aku telah mengubah tata letak situs webku. +I've got three hours to find Tom. Aku menghabiskan waktu 3 jam untuk mencari Tom. +I've got to go to the men's room. Aku harus pergi ke kamar kecil. +Is there any food you don't like? Apa ada makanan yang tidak kamu suka? +Isn't that what needs to be done? Bukankah itu adalah hal yang seharusnya dilakukan? +It doesn't have to end like this. Seharusnya tidak menjadi seperti ini. +It looks like it's going to rain. Sepertinya akan turun hujan. +It was too bad you couldn't come. Sayang sekali kamu tidak bisa datang. +Keep children away from the pond. Jauhkan anak-anak dari kolam. +Last night I had a strange dream. Mimpiku semalam aneh. +Let's not talk about it any more. Sebaiknya kita jangan membicarakan ini lagi. +Most Englishmen are conservative. Kebanyakan orang Inggris konservatif. +Mother is cooking in the kitchen. Ibu sedang masak di dapur. +My brother sends you his regards. Kakak saya menitipkan salamnya untuk anda. +My father would often go fishing. Ayahku dulu sering pergi memancing. +My little brother is watching TV. Adikku sedang menonton TV. +My parents aren't home right now. Orang tua saya tidak di rumah sekarang. +New Hampshire is next to Vermont. New Hampshire ada di sebelah Vermont. +Not all of the staff was present. Tidak semua pegawai datang hadir. +Old people are usually very wise. Orang tua biasanya sangat bijaksana. +Please call me up if you want me. Silakan panggil saya bila butuh sesuatu. +Please help yourself to the cake. Silakan dinikmati kuenya. +Please move your car out of here. Tolong pindahkan mobil Anda dari sini. +She gave birth to a healthy baby. Dia melahirkan bayi yang sehat. +She suffocated him with a pillow. Ia mencekiknya dengan bantal. +Smoking is harmful to the health. Merokok berbahaya bagi tubuh. +Tell me more about what happened. Beritahu aku apa lagi yang terjadi. +Ten paper plates cost one dollar. Sepuluh lembar piring kertas harganya 10 dolar. +Ten years is a long time to wait. Sepuluh tahun adalah waktu yang lama untuk menunggu. +That doesn't interest me anymore. Saya tidak tertarik lagi dengan itu +That doesn't sound too difficult. Kedengarannya itu tidak terlalu sulit. +That job takes a lot of strength. Pekerjaan itu memerlukan banyak tenaga. +That's what makes the difference. Hal itulah yang membuat perbedaan. +The United States borders Canada. Amerika Serikat berbatasan dengan Kanada. +The boy complained of a headache. Anak laki-laki itu mengeluh sakit kepala. +The bus leaves every ten minutes. Busnya berangkat setiap 10 menit. +The meeting took place yesterday. Rapatnya diadakan kemarin. +The red dress looked good on her. Terusan merah terlihat bagus dipakainya. +The singer has a beautiful voice. Penyanyi tersebut memiliki suara yang indah. +The sky became darker and darker. Langitnya semakin gelap dan gelap. +There are many mysteries in life. Ada banyak misteri dalam kehidupan. +This is the only camera I've got. Hanya ini kamera yang aku dapatkan. +This isn't exactly what I wanted. Ini tidak seperti yang aku inginkan. +Tom appreciated Mary's hard work. Tom menghargai kerja keras Mary. +Tom couldn't hide his excitement. Tom tidak mampu menyembunyikan antusiasmenya. +Tom didn't look happy to see you. Tom tak terlihat senang menemuimu. +Tom doesn't believe in evolution. Tom tidak percaya evolusi. +Tom doesn't know what went wrong. Tom tidak mengetahui apa yang salah. +Tom had a car accident in Boston. Tom mengalami kecelakaan mobil di Boston. +Tom hasn't arrived in Boston yet. Tom masih belum tiba di Boston. +Tom is almost as tall as you are. Tom hampir sama tingginya dengan kamu. +Tom is interested in mathematics. Tom tertarik pada matematika. +Tom left without even telling me. Tom pergi tanpa memberitahuku. +Tom likes making paper airplanes. Tom suka membuat pesawat kertas. +Tom likes tea better than coffee. Tom lebih suka teh daripada kopi. +Tom likes to listen to Mary sing. Tom suka mendengar nyanyian Mary. +Tom lives alone in a large house. Tom tinggal sendiri di rumah yang besar +Tom looks like he's seen a ghost. Tom nampak seperti telah melihat setan. +Tom made me wait for three hours. Tom membuat saya menunggu selama tiga jam. +Tom may not be busy, but Mary is. Tom mungkin tidak sibuk, tetapi Mary mungkin. +Tom might think I don't like him. Tom mungkin berpikir bahwa aku tidak menyukainya. +Tom nudged the door open a crack. Tom mendorong pintunya dan membukanya sedikit. +Tom often swears when he's angry. Tom sering bersumpah serapa ketika marah. +Tom pointed to a spot on the map. Tom menunjuk suatu tempat di peta. +Tom probably won't become famous. Tom mungkin tidak akan pernah menjadi terkenal. +Tom realized Mary wasn't kidding. Tom menyadari Mary tidak sedang bercanda. +Tom says he can wait a long time. Tom berkata dia dapat menunggu lama. +Tom screamed as loud as he could. Tom berteriak sekencang-kencangnya. +Tom seems very angry, doesn't he? Tom kelihatannya sangat marah, ya? +Tom slipped out of the classroom. Tom menyelinap keluar kelas. +Tom thanked everyone for waiting. Tom berterima kasih kepada semuanya karena telah menunggu. +Tom took charge of the situation. Tom mengambil alih situasi. +Tom tried to answer the question. Tom mencoba menjawab pertanyaan itu. +Tom waited for Mary to come home. Tom menunggu Mary pulang ke rumah. +Tom wanted to wear his new shoes. Tom ingin mengenakan sepatu barunya. +Tom was confused by the question. Tom dibingungkan oleh pertanyaan itu. +Tom was unable to hide his tears. Tom tidak kuasa menahan air matanya. +Tom will be here in five minutes. Tom akan sampai di sini dalam lima menit. +Tom's father is a police officer. Ayah Tom adalah seorang polisi. +Tom's parents were both teachers. Kedua orang tua Tom adalah guru. +Tom's proposal wasn't acceptable. Lamaran Tom tidak diterima. +Two for the lunch buffet, please. Saya pesan dua bufet santap siang. +Uncle Tom is my mother's brother. Paman Tom adalah adik ibuku. +Wait until I tell Tom about this. Tunggu sampai aku memberitahu Tom tentang hal ini. +We always have to obey the rules. Kami selalu patuh terhadap peraturan. +We had to learn to read the word. Kita diharuskan untuk belajar membaca kata. +We have to do this the right way. Kita harus melakukannya dengan benar. +We haven't known each other long. Kami belum lama saling mengenal. +We hope prices are going to drop. Kami berharap harga-harga akan turun. +We need to conserve our strength. Kita perlu menghemat tenaga kita. +We saw an island in the distance. Kami melihat sebuah pulau di kejauhan. +We should look after our parents. Kita harus memperhatikan kedua orang tua kita. +We still have a lot of food left. Persediaan makanan masih banyak. +We're a little worried about Tom. Kami sedikit khawatir dengan Tom. +We've got a very serious problem. Kami mendapatkan masalah yang sangat serius. +We've known each other for years. Sudah bertahun-tahun kami saling kenal. +What did you do over the weekend? Apa yang kau lakukan di akhir pekan? +What do you do in your free time? Apa yang kamu lakukan saat luang? +What happened wasn't Tom's fault. Apa yang terjadi bukanlah kesalahan Tom. +What happens if Tom doesn't pass? Apa yang terjadi jika Tom tidak lulus? +What train you are going to take? Kereta apa yang akan kamu naiki? +What's it we're waiting for here? Untuk apa kita menunggu di sini? +What's your favorite kind of art? Jenis seni apa yang menjadi favorit Anda? +What's your favorite winter food? Apa makanan musim dingin favoritmu? +When did the accident take place? Kapan kecelakaan itu terjadi? +When did you learn to make pizza? Kapan kamu belajar membuat pizza +Why are people always so cynical? Kenapa orang selalu terlalu sinis. +Would you mind shutting the door? Bisa tolong Anda tutup pintunya? +Would you please open the window? Bisakah kau membuka jendelanya? +You always make the same mistake. Kamu selalu melakukan kesalahan yang sama. +You and Tom have a lot in common. Kamu dan Tom punya banyak kesamaan. +You can call me anytime you like. Kau bisa menelponku kapan saja. +You can't come to Boston with me. Kau tidak bisa pergi ke Boston denganku. +You didn't have to tell Tom that. Kamu tak perlu memberitahukan Tom soal itu. +You have good reason to be angry. Kamu punya alasan tepat untuk marah. +You have the wrong idea about me. Kau salah menilai diriku. +You know what I am talking about. Kau pasti tahu apa yang aku maksud. +You know what they say about Tom. Kamu tahu apa yang mereka katakan tentang Tom. +You look familiar. Do I know you? Anda seperti kenalan saya. Apakah saya mengenal anda? +You must not touch the paintings. Kau tidak boleh menyentuh lukisannya. +You'd better consult your doctor. Sebaiknya kau berkonsultasi dengan doktermu. +You're in better shape than I am. Anda berada dalam kondisi yang lebih baik daripada aku. +Your plan seems better than mine. Rencanamu sepertinya lebih baik daripada milikku. +A customs declaration is required. Memerlukan pemberitahuan pabean. +All right. I'll accept your offer. Baik, aku akan terima tawaranmu. +All right. I'll accept your offer. Baik, saya akan terima tawaran Anda. +Almost three thousand people died. Hampir tiga ribu orang mati. +Are you joking or are you serious? Kau main-main atau serius? +Aren't you still living in Boston? Bukannya kamu masih tinggal di Boston? +Both Tom and Mary are from Boston. Baik Tom dan Mary keduanya berasal dari Boston. +Correct my spelling if it's wrong. Koreksi ejaan saya bila itu salah. +Could you please pass me the salt? Bisa minta tolong ambilkan garamnya? +Do you guys want something to eat? Apa kalian ingin makan sesuatu? +Do you have a non-smoking section? Apakah ada area bebas rokok? +Do you have an English dictionary? Apa kau memiliki sebuah kamus bahasa Inggris? +Do you have any further questions? Apakah ada pertanyaan lagi? +Do you want to go swimming or not? Kamu ingin pergi berenang atau tidak? +Don't be afraid. I won't hurt you. Jangan takut. Aku tidak akan melukaimu. +Don't you have an air conditioner? Kamu tidak punya AC? +Everyone deserves a second chance. Semua orang layak untuk mendapatkan kesempatan kedua. +God created the world in six days. Tuhan menciptakan dunia dalam waktu enam hari. +Have you ever eaten Japanese food? Kamu pernah makan masakan Jepang? +He had friends all over the world. Dia memiliki teman di seluruh dunia. +He has coached us for half a year. Dia telah melatih kami selama setengah tahun. +He hid his sadness behind a smile. Dia menyembunyikan kesedihannya dibalik senyum. +He is very sensitive to criticism. Ia sangat sensitif pada kritikan. +He resembles his father very much. Dia sangat mirip dengan ayahnya. +He said good night to his parents. Dia mengucapkan selamat malam pada orang tuanya. +He took a book from the bookshelf. Dia mengambil sebuah buku dari rak buku. +He was jealous of their happiness. Dia iri dengan kebahagiaan mereka. +He was scared you would shoot him. Dia takut kamu akan menembaknya. +Her beauty was beyond description. Kecantikannya tidak bisa diungkapkan dengan kata-kata. +His house is far from the station. Rumahnya jauh dari stasiun. +How about something cold to drink? Apakah Anda mau minum sesuatu yang dingin? +How dare you talk to me like that! Beraninya kamu bilang seperti itu padaku! +How much did you drink last night? Kamu minum berapa banyak semalam? +Hurry up, or we'll miss the train. Cepat, atau kita akan ketinggalan keretanya. +I always said Tom was a smart kid. Aku selalu bilang kalau Tom anak yang pandai. +I am sure of his passing the exam. Aku yakin dia akan berhasil melewati tesnya. +I apologize for what Tom has done. Saya minta maaf atas apa yang telah diperbuat oleh Tom. +I bought a watch and an empty box. Saya membeli jam tangan dan kotak kosongnya. +I can get you everything you need. Saya dapat memenuhi semua kebutuhan anda. +I can't rule out that possibility. Aku bisa menghilangkan kemungkinan itu. +I did nothing during the holidays. Saya tidak melakukan apa-apa selama liburan. +I don't have anything to tell you. Tidak ada yang ingin kuberitahukan padamu. +I don't know how deep the lake is. Saya tidak tahu danau ini seberapa dalam. +I don't know when he'll come back. Saya tidak tahu kapan dia akan kembali. +I don't think we have enough time. Aku tidak berpikir kita memiliki cukup waktu. +I guess you didn't get my message. Aku rasa kau tidak menerima pesanku. +I have three chickens in my house. Ada tiga ayam di rumah saya. +I have three chickens in my house. Di rumah saya ada tiga ekor ayam. +I haven't been sleeping very well. Aku tidak tidur dengan nyenyak akhir-akhir ini. +I haven't heard of him since then. Saya tidak mendengar kabarnya semenjak itu. +I hope no one sits in front of us. Aku harap tidak ada seorangpun yang akan duduk di depan kita. +I hope you know what you're doing. Aku harap kau tahu apa yang kau perbuat. +I know exactly what Tom was doing. Aku tahu tepatnya apa yang Tom lakukan. +I know who your secret admirer is. Aku tahu siapa penggemar rahasiamu. +I like white wine better than red. Aku lebih suka anggur putih daripada merah. +I must get the book back from him. Aku harus mengambil kembali bukuku darinya. +I only told Tom what Mary told me. Aku hanya memberi tahu Tom apa yang Mary beritahu padaku. +I saw Tom and Mary leave together. Saya melihat Tom dan Mary berangkat bersama. +I succeeded because of his advice. Saya berhasil karena nasihatnya. +I think I know why Tom isn't here. Aku kira aku tahu kenapa Tom tidak ada di sini. +I think I remember how to do that. Aku pikir aku sudah ingat bagaimana cara melakukannya. +I think you and he wanna be alone. Aku akan meninggalkan kalian berdua. +I thought Tom and Mary were happy. Aku kira Tom dan Mary bahagia. +I told Tom I didn't want his help. Saya beritahu Tom bahwa saya tidak butuh pertolongannya. +I want to go back to being a baby. Aku ingin kembali menjadi bayi. +I want you to go to Osaka at once. Aku ingin kamu segera pergi ke Osaka. +I wasn't expecting that to happen. Saya tidak menduga hal itu dapat terjadi. +I wish you wouldn't smoke so much. Saya harap kamu tidak akan merokok terlalu banyak. +I wonder why Tom is staring at me. Aku penasaran kenapa Tom memandangiku. +I wouldn't lose any sleep over it. Saya tidak ingin kekurangan tidur karena ini. +I'd rather stay home this weekend. Aku lebih memilih tetap berada di rumah akhir pekan ini. +I'll call you when dinner's ready. Aku akan memanggilmu saat makan malamnya sudah siap. +I'm so happy to be done with that. Aku sangat senang masalahnya sudah selesai. +I'm sorry, but I'm busy right now. Maaf, tapi saya sibuk saat ini. +I'm tired of this monotonous life. Aku lelah dengan hidup yang monoton ini. +I've been looking forward to this. Aku sudah lama menantikan hal ini. +I've got to go to church tomorrow. Aku harus pergi ke gereja besok. +I've known her since I was little. Saya sudah mengenalnya sejak kecil +If you help me, I'll try it again. Jika kamu membantu saya, saya akan mencoba lagi. +In the meantime, she began to cry. Sementara itu, dia mulai menangis. +It has been raining since Tuesday. Hujan terus-menerus turun sejak hari Selasa. +It never pays to lose your temper. Marah tidak memberikan manfaat apa-apa. +Italy is a very beautiful country. Italy adalah negara yang paling indah. +Keep your room as neat as you can. Jagalah kamarmu agar tetap bersih dan rapi. +Kyoto is visited by many tourists. Kyoto dikunjungi oleh banyak turis. +Let's wait until it stops raining. Mari kita menunggu hingga hujannya berhenti. +Make sure you don't hurt yourself. Pastikan kamu tidak melukai dirimu sendiri. +Many students have part-time jobs. Banyak siswa melakukan kerja sambilan. +Mary isn't the right girl for you. Mary bukan gadis yang tepat untukmu. +Nobody pays much attention to Tom. Tidak ada orang yang cukup memperhatikan Tom. +One is red and the other is white. Yang satu merah dan yang lainnya putih. +Photography is an expensive hobby. Fotografi merupakan hobi yang mahal. +Please drop me off at the station. Tolong turunkan saya di stasiun. +Please give me something to drink. Tolong berikan saya sesuatu untuk diminum. +Please help yourself to the fruit. Silakan dinikmati buahnya. +Please tell me about your company. Silakan ceritakan tentang perusahaan anda. +She is as beautiful as her mother. dia secantik ibunya +She is unable to cope with stress. Dia tidak mampu mengatasi stres. +She taught music for thirty years. Dia telah mengajar musik selama 30 tahun. +She visited her husband in prison. Dia mengunjungi suaminya yang dipenjarakan. +Shine your shoes before going out. Semir sepatumu sebelum pergi ke luar. +Smoking is forbidden in this area. Dilarang merokok di area ini. +So, what do we do in the meantime? Jadi, apa yang akan kita lakukan selagi menunggu? +Somebody has left the window open. Seseorang pasti meninggalkan jendela dalam keadaan terbuka. +Someone told me Tom left his wife. Seseorang memberitahuku kalau Tom meninggalkan istrinya. +Sometimes I go, sometimes I don't. Kadang aku pergi, kadang tidak. +Take your hand out of your pocket. Keluarkan tanganmu dari sakumu. +That hat looks really good on Tom. Topi itu terlihat bagus dipakai oleh Tom. +That sounds like a very good deal. Kedengarannya sangat bagus. +That's it. I've done all I can do. Oke cukup. Aku sudah melakukan semua yang aku bisa. +The accident caused a traffic jam. Kecelakaan itu mengakibatkan kemacetan. +The arrow indicates the way to go. Arah panah menunjukkan jalan yang harus dihalui. +The defeat completely crushed him. Kekalahan itu sangat menghancurkan dia. +The desk seems small in this room. Meja itu terlihat kecil di ruangan ini. +The meeting will be held tomorrow. Rapatnya akan dilaksanakan besok. +The money on the desk is not mine. Uang yang ada di atas meja bukan milikku. +The question is what do we do now. Pertanyaannya adalah apa yang akan kita lakukan sekarang. +The rain lasted through the night. Hujannya bertahan selama semalam penuh. +The same thing happens every year. Hal yang sama terjadi setiap tahun. +The sky is clear almost every day. Langitnya hampir setiap hari cerah. +The suspect is a caucasian female. Tersangkanya perempuan Kaukasia. +There are no roses without thorns. Tidak ada mawar yang tidak berduri. +There are ten people in this room. Ada sepuluh orang di ruangan ini. +There is no easy road to learning. Tidak ada jalan yang mudah untuk belajar. +There were few people in the park. Hanya ada sedikit orang di taman. +There were no roses in the garden. Tidak ada bunga mawar di taman. +They are frantically backpedaling. Mereka mengayuh mundur sepedanya dengan panik. +They speak English in New Zealand. Mereka berbicara dalam bahasa Inggris di Selandia Baru. +They're attempting to contact her. Mereka mencoba untuk menghubunginya. +This house is full of spider webs. Rumah ini penuh dengan sarang laba-laba. +This old book is worth 50,000 yen. Buku tua ini bernilai 50.000 yen. +This problem deserves considering. Masalah ini layak dipertimbangkan. +This river runs into Lake Ontario. Sungai ini mengalir ke Danau Ontario +Those are nice gloves you have on. Sarung tanganmu bagus ya. +Tom and Mary did what they had to. Tom dan Mary melakukan apa yang harus mereka lakukan. +Tom asked Mary to lower her voice. Tom meminta Mary untuk memelankan suaranya +Tom borrowed some money from Mary. Tom meminjam sedikit uang dari Mary. +Tom can't have done it by himself. Tom tidak mungkin melakukannya seorang diri. +Tom could do nothing to help Mary. Tom tidak dapat melakukan apapun untuk menolong Mary. +Tom decided to ignore the problem. Tom memutuskan untuk mengabaikan permasalahannya. +Tom didn't talk to Mary all night. Tom tidak mengajak bicara Mary selama semalaman. +Tom eats more ice cream than I do. Tom memakan lebih banyak es krim daripada aku. +Tom gave Mary a box of chocolates. Tom memberi Mary sekotak coklat. +Tom goes for a walk every morning. Tom pergi jalan-jalan setiap pagi. +Tom has arrived in Boston already. Tom sudah sampai di Boston. +Tom has offered to walk Mary home. Tom menawarkan Mary untuk mengantarkannya pulang. +Tom is more intelligent than I am. Tom lebih cerdas dariku. +Tom is playing catch with his son. Tom bermain lempar-lemparan dengan anak laki-lakinya. +Tom is quite successful, isn't he? Tom lumayan berhasil, ya? +Tom is ugly, but he's really nice. Tom jelek, tapi ia sangat baik. +Tom isn't accustomed to city life. Tom tidak terbiasa dengan kehidupan kota. +Tom just looked down at the floor. Tom hanya melihat ke arah lantai. +Tom likes to make paper airplanes. Tom suka membuat pesawat kertas. +Tom locked himself in his bedroom. Tom mengunci dirinya dalam kamar. +Tom looks a bit tired, doesn't he? Bukankah Tom terlihat sedikit lelah? +Tom made an excuse for being late. Tom membuat alasan atas keterlambatannya. +Tom narrowly escaped being killed. Tom hampir saja terbunuh. +Tom needs all the help he can get. Tom sangat membutuhkan bantuan. +Tom needs to change his lifestyle. Tom perlu mengubah gaya hidupnya. +Tom now knows Mary wasn't kidding. Tom sekarang menyadari Mary tidak sedang bercanda. +Tom once owned this piece of land. Tom pernah memiliki sekompleks tanah ini. +Tom pretended not to be listening. Tom berlaku seolah-olah tidak mendengarkan. +Tom realized it was time to leave. Tom menyadari sekarang adalah waktu untuk pergi. +Tom really likes basketball a lot. Tom sangat menyukai bermain basket. +Tom sat down and crossed his legs. Tom duduk dan menyilangkan kakinya. +Tom should've kept his mouth shut. Tom seharusnya menutup mulutnya rapat. +Tom slowly looked around the room. Tom melihat sekitar ruangan secara perlahan. +Tom started to descend the stairs. Tom mulai menuruni tangganya. +Tom visited Australia last summer. Tom mengunjungi Australia musim panas kemarin. +Tom wants to be popular at school. Tom ingin menjadi terkenal di sekolah. +Tom wants us to improve ourselves. Tom ingin kita untuk memperbaiki diri kita. +Tom works every day except Sunday. Tom bekerja setiap hari kecuali hari minggu. +Tom, I want to show you something. Tom, aku ingin menunjukkan sesuatu. +Vigorous exercise makes you sweat. Latihan yang semanga membuatmu berkeringat. +We're already planning to do that. Kami sudah merencanakan itu. +What do you usually do on Sundays? Apa yang biasa kamu lakukan pada hari Minggu? +What made you decide to come here? Apa yang membuatmu memutuskan untuk datang kemari? +When are you going back to Boston? Kapan kita pergi ke Boston lagi? +When was the last time you danced? Kapan terakhir kali kamu menari? +Which flower do you like the most? Bunga apa yang paling kamu sukai? +Which train are you going to take? Kereta mana yang akan kamu naiki? +Which train are you going to take? Kereta mana yang akan Anda naiki? +Would you like something to drink? Apakah kamu mau minuman? +Would you like to take in a movie? Film apa yang ingin kamu tonton? +You didn't sign all the documents. Kamu tidak menandatangani semua dokumennya +You have no idea who I am, do you? Kamu tidak tahu siapa aku, kan? +You may choose whichever you want. Kamu boleh pilih apapun yang kamu suka. +You might want to wait over there. Mungkin lebih baik kau menunggu di sebelah sana. +You shouldn't tell Tom everything. Kau tidak perlu memberi tahu Tom segalanya. +You'd better take care of it soon. Sebaiknya kamu segera mengurusnya. +You're the prettiest girl in town. Kau adalah gadis tercantik di kota. +You've got a great sense of humor. Kau punya selera humor yang bagus. +A cat appeared from under the desk. Seekor kucing muncul dari kolong meja. +A cat came out from under the desk. Seekor kucing keluar dari kolong meja. +Are we allowed to use the elevator? Apakah kita diperbolehkan menggunakan lift? +Are you feeling all right now, Tom? Apakah kamu baik-baik saja, Tom? +Compass needles point to the north. Jarum kompas menunjuk ke utara. +Could you call again later, please? Bisakah kau menelepon lagi nanti? +Did you make this doll by yourself? Apakah kamu membuat sendiri boneka ini? +Do you know what the difference is? Apakah Anda tahu perbedaannya? +Do you want to play tennis with us? Kamu mau main tenis bersama kami? +Does Tom know what to do with this? Apakah Tom mengetahui apa yang harus dilakukan dengan ini? +Don't be afraid of making mistakes. Jangan takut membuat kesalahan. +Don't just eat fish. Eat meat, too. Jangan hanya makan ikan, makan daging juga. +Don't you think that's a bit weird? Bukankah itu agak aneh? +Every time they meet, they quarrel. Setiap kali bertemu, mereka bertengkar. +Have you eaten your dinner already? Apa kau sudah menghabiskan makan malammu? +He can't even float let alone swim. Dia tidak bisa mengapung, apalagi berenang. +He is afraid to fly in an airplane. Dia takut terbang dengan pesawat. +He is tired of watching television. Dia lelah menonton televisi. +He kept me waiting for a long time. Dia membuat saya menunggu lama. +He made all of the clothes himself. Semua bajunya dibuat oleh dia sendiri. +He shook hands with her and smiled. Dia berjabat tangan dengannya dan tersenyum. +He was brave in the face of danger. Dia begitu berani di hadapan mara bahaya. +He was forced to sign the document. Dia dipaksa untuk menandatangani dokumen. +He was very good at playing tennis. Dia dulu sangat pandai bermain tenis. +Her behavior is my primary concern. Perilakunya adalah perhatian utamaku. +Her husband is now living in Tokyo. Suaminya tinggal di Tokyo sekarang. +Honesty is no guarantee of success. Kejujuran bukan jaminan sukses. +How can copyright laws be enforced? Bagaimana undang-undang hak cipta bisa ditegakkan? +How long were you and Tom together? Berapa lama kamu dan Tom bersama? +How much do you charge by the hour? Berapa besar Anda mematok biaya per jamnya? +How much is the most expensive car? Berapa harga mobil paling mahal? +How much is the rent for this room? Berapa biaya sewa untuk ruangan ini? +I am afraid that he might get hurt. Saya kuatir, mungkin dia mendapatkan luka. +I am going to go to Tokyo tomorrow. Aku akan pergi ke Tokyo besok. +I can't put up with him any longer. Aku sudah tidak tahan dengannya. +I don't expect you to be my friend. Aku tidak menyangka kalau kamu menjadi temanku. +I don't have any problem with that. Saya tidak keberatan dengan itu. +I don't really approve of gambling. Aku tidak begitu setuju dengan perjudian. +I don't see what's wrong with that. Aku tidak tahu apa yang salah dengan itu. +I don't think I've seen you before. Aku pikir aku belum pernah bertemu denganmu sebelumnya. +I don't want pizza. I'm not hungry. Aku tidak menginginkan piza. Aku tidak sedang lapar. +I don't want to show it to Tom yet. Aku masih belum mau menunjukkannya kepada Tom. +I eat dinner at quarter past seven. Saya makan malam pada pukul tujuh lewat lima belas menit. +I have two brothers and one sister. Aku punya dua saudara laki-laki dan satu saudara perempuan. +I haven't done this in a long time. Aku sudah lama tidak melakukan ini. +I haven't received any email today. Hari ini, saya belum mendapat e-mail apapun. +I heard an awesome story yesterday. Aku mendengar cerita yang mengagumkan kemarin. +I know what that piece of paper is. Aku tahu kertas apa itu. +I love hanging out with my friends. Aku suka pergi berkumpul dengan teman-temanku. +I never wanted to compete with you. Aku tidak pernah ingin bersaing denganmu. +I stayed indoors because it rained. Aku tetap berada di dalam karena hujan sedang turun. +I still don't remember calling you. Aku masih tidak ingat kalau aku memanggilmu. +I thought Tom had gotten over Mary. Aku pikir Tom sudah lelah mengejar Mary. +I told Tom I could do it by myself. Aku memberitahu Tom kalau aku bisa melakukannya sendiri. +I want to leave this place quickly. Aku ingin cepat meninggalkan tempat ini. +I wasn't married when we first met. Aku masih belum menikah saat pertama kali kita bertemu. +I'd like you to keep this a secret. Aku ingin kau menyembunyikan hal ini. +I'll help you if you're in trouble. Aku akan membantu saat kau dalam masalah. +I'm getting sick and tired of this. Aku mulai muak dan lelah dengan hal ini. +I'm interested in oriental pottery. Aku tertarik dengan tembikar oriental. +I'm not as healthy as I used to be. Aku tidak sesehat dulu. +I'm not sure what else I should do. Aku tidak yakin apa lagi yang harus aku lakukan. +I'm probably going to be busy soon. Aku mungkin akan sibuk sebentar lagi. +I'm sick of conferences these days. Akhir-akhir ini aku bosan dengan rapat. +I'm sorry I didn't call last night. Maaf aku tidak meneleponmu semalam. +I'm still trying to get used to it. Aku masih berusaha membiasakan diri. +I'm the one who stole the painting. Akulah yang mencuri lukisan itu. +I've finished watering the flowers. Aku sudah selesai menyirami bunga-bunganya. +I've got two brothers and a sister. Aku punya dua saudara laki-laki dan satu saudara perempuan. +I've never seen you look so scared. Aku belum pernah melihatmu terlihat sangat ketakutan. +I've waited for this my whole life. Aku sudah menunggu hal ini seumur hidupku. +If Tom were older, he'd understand. Jika Tom lebih dewasa, dia akan mengerti. +If you don't go, I won't go either. Kalau kau tidak pergi, maka aku juga tidak akan pergi. +Is there anything I can do for you? Apakah ada sesuatu yang bisa saya lakukan untuk Anda? +It is a pity that he died so young. Sayang sekali dia meninggal di usia yang sangat muda. +It's a pity that you can't join us. Sangat disayangkan Anda tidak dapat bergabung dengan kami. +It's a pity that you couldn't come. Sayang sekali kamu tidak bisa datang. +It's not like you to cry at movies. Ini tidak seperti kamu menangis di bioskop. +Land prices are very high in Japan. Harga tanah di Jepang mahal sekali. +Meetings are held every other week. Rapat diadakan setiap seminggu sekali. +My internet connection was cut off. Koneksi internetku terputus. +My mother is a high school teacher. Ibuku adalah seorang guru SMA. +No one was more surprised than Tom. Tidak ada seorangpun yang lebih terkejut dari Tom. +Only 514 people have been in space. Hanya 514 orang yang pernah ke luar angkasa. +Our galaxy is called the Milky Way. Galaksi kita dinamakan Bima Sakti. +Please don't let this happen again. Tolong jangan biarkan hal ini terulang kembali. +Please give Tom another chance, OK? Tolong beri Tom kesempatan lain, OK? +Please show me how I have to do it. Tunjukkan padaku bagaimana caranya untuk melakukan itu. +Please shuffle the cards carefully. Kocok kartu reminya dengan hati-hati. +Please take a look at that picture. Tolong lihat gambar itu. +She is able to grasp the situation. Dia mampu memahami situasi yang ada. +She is on the wrong side of twenty. Dia sudah berusia lebih dari 20 tahun. +She is very sensitive to criticism. Ia sangat sensitif pada kritikan. +She makes herself up every morning. Dia berdandan setiap pagi. +Summer vacation begins next Monday. Liburan musim panasnya mulai besok Senin. +Thank you for giving me the option. Terima kasih telah memberikanku pilihan. +That country has natural resources. Negara itu memiliki sumber daya alam. +The food and service are excellent. Makanan dan pelayanannya baik sekali. +The lion is the king of the jungle. Singa adalah raja rimba. +The patient is steadily recovering. Keadaan pasiennya perlahan mulai membaik. +The pen is mightier than the sword. Pena lebih kuat daripada pedang. +The price of gold fluctuates daily. Harga dari emas berubah-ubah setiap harinya. +The ship will make a stop at Cadiz. Kapal akan berlabuh di Cadiz. +The war could not last much longer. Perang tidak bisa berlangsung lebih lama lagi. +The water's warm enough for a swim. Airnya sudah cukup hangat untuk berenang. +The wind is blowing from the north. Angin sedang berhembus dari utara. +There is a television in this room. Ada televisi di ruangan ini. +There were no radios in those days. Tidak ada radio pada saat itu. +There's a rowboat right over there. Ada perahu dayung di sebelah sana. +There's no need for you to be here. Kamu tidak perlu berada di sini. +They were watching the sunset then. Kemudian mereka melihat matahari terbit. +This desk is designed for children. Meja ini diperuntukkan bagi anak-anak. +This is the cheapest store in town. Ini toko paling murah yang ada di kota. +This is what Tom does for a living. Ini yang dilakukan Tom untuk hidup. +This matter is of great importance. Hal ini sangat penting. +This room is just about big enough. Ruangan ini cukup besar. +Tom didn't know where he should go. Tom tidak tahu tahu ke mana ia harus pergi. +Tom doesn't think Mary wants to go. Tom merasa Mary tidak ingin pergi. +Tom doesn't trust what anyone says. Tom tidak mau mempercayai apapun yang dikatakan orang lain. +Tom doesn't want Mary to touch him. Tom tidak ingin Mary menyentuhnya. +Tom doesn't want anything to drink. Tom tidak ingin minum apa-apa. +Tom grudgingly did what Mary asked. Tom melakukan apa yang Mary minta dengan berat hati. +Tom has caused us a lot of trouble. Tom sudah menyusahkan kita semua. +Tom has just come back from Boston. Tom baru saja kembali dari Boston. +Tom has never eaten raw horse meat. Tom belum pernah memakan daging kuda mentah. +Tom hasn't said a word all evening. Tom tidak berkata sepatah kata pun sepanjang sore. +Tom is exactly the same age as you. Tom itu seumuran dengan mu +Tom knows Mary is hiding something. Tom tahu Mary menyembunyikan sesuatu. +Tom lost his son in a car accident. Tom kehilangan anak laki-lakinya akibat kecelakaan mobil. +Tom might not know that we're here. Tom mungkin tidak tahu jika kita di sini. +Tom never goes to places like that. Tom tidak pernah pergi ke tempat seperti itu. +Tom obviously got what he came for. Tom secara jelas mendapatkan apa yang seharusnya dia dapat. +Tom picked up the phone and dialed. Tom mengangkat teleponnya dan melakukan panggilan. +Tom pleaded with Mary not to leave. Tom memohon kepada Mary untuk tidak pergi. +Tom poured brandy into the glasses. Tom menuang brandy ke dalam gelas. +Tom poured cold water over himself. Tom menyiramkan air dingin ke dirinya sendiri. +Tom probably went out for some air. Tom mungkin pergi keluar untuk membeli air. +Tom promised to keep it to himself. Tom berjanji menyimpannya untuk dirinya sendiri. +Tom says he's cut down on drinking. Tom bilang dia mengurangi frekuensi minumnya. +Tom says he's feeling better today. Tom berkata dia merasa lebih baik hari ini. +Tom scolded his son for being late. Tom memarahi anak laki-lakinya karena telah terlambat. +Tom scolded his son for being lazy. Tom memarahi anak laki-lakinya karena telah malas. +Tom seems to understand what I say. Tom terlihat mengerti apa yang saya katakan. +Tom should arrive in a few minutes. Tom akan tiba beberapa menit lagi. +Tom should've arrived by this time. Tom seharusnya sudah sampai sekarang. +Tom slammed the bathroom door shut. Tom menutup pintu kamar mandi secara keras. +Tom thought it was a good solution. Tom mengira itu adalah solusi yang baik. +Waiter, please bring me some water. Pelayan, tolong bawakan aku air. +We are giving Tom a birthday party. Kami akan berikan Tom, pesta ulang tahun. +We have known each other for years. Sudah bertahun-tahun kami saling kenal. +We talked until two in the morning. Kami berbincang-bincang hingga pukul dua pagi. +We were all present at the meeting. Kami semua hadir pada pertemuan itu. +What does the Bible say about this? Apa yang Alkitab katakan tentang hal ini? +What exactly do you know about Tom? Tepatnya apa yang kamu ketahui tentang Tom? +What have you been doing this week? Apa saja yang sudah kamu lakukan minggu ini? +What have you been doing this week? Apa saja yang kamu lakukan minggu ini? +What subjects do you like the best? Pelajaran apa yang paling kau sukai? +When I bite down, this tooth hurts. Ketika aku menggigit, gigi yang ini terasa sakit. +When I heard it, I was dumbfounded. Aku tercengang ketika mendengarnya. +When was the last time you ate out? Kapan terakhir kamu makan di luar? +Where do you want to sleep tonight? Kamu ingin tidur di mana malam ini? +Where there is smoke there is fire. Ada gula, ada semut. +Where will you go for the vacation? Ke mana Anda akan pergi liburan? +Which subject do you like the most? Pelajaran mana yang paling kamu sukai? +Who would do such a terrible thing? Siapa yang tega melakukan perbuatan keji seperti itu? +Why don't you come dancing with me? Maukah kamu berdansa denganku? +Why don't you ever wash the dishes? Kenapa kau tidak pernah mencuci piring-piringnya? +Why don't you have anything to say? Mengapa tidak ada yang ingin kau sampaikan? +Why haven't you done your homework? Kenapa kamu belum mengerjakan PRmu? +Will you be at the concert tonight? Kamu akan ada di konser malam ini ? +Wolves won't usually attack people. Serigala biasanya tidak menyerang manusia. +You can pick out any book you like. Kau bisa mengambil buku manapun yang kau suka. +You don't have to say another word. Kamu tidak perlu bilang apa-apa lagi. +You don't need to worry about that. Anda tidak perlu kuatir dengan hal itu. +You have to learn standard English. Kamu harus mempelajari bahasa Inggris yang baku. +A friend of mine is studying abroad. Seorang temanku sedang belajar di luar negeri. +Accuracy is important in arithmetic. Akurasi merupakan hal yang penting dalam aritmatika. +Air is to man what water is to fish. Udara bagi manusia layaknya air bagi ikan. +Are you interested in baseball, Tom? Tom, kamu tertarik dengan permainan bisbol? +Be careful not to make any mistakes. Hati-hati jangan sampai membuat kesalahan. +Did you catch any fish in the river? Apa kamu berhasil menangkap ikan di sungai? +Did you hear about yesterday's fire? Apa kamu dengar tentang kebakaran yang terjadi kemarin? +Did you tell Tom that Mary did this? Kamu memberitahu Tom kalau Mary melakukan ini? +Do you have a lot of money with you? Apa kau membawa banyak uang? +English is tougher for me than math. Bahasa Inggris lebih sulit bagiku daripada matematika. +Even Tom was surprised to hear that. Bahkan Tom terkejut mendengarkan itu. +Everybody was thrilled by his story. Semua orang merasa tegang karena ceritanya. +Everyone needs a place to call home. Semua orang memerlukan tempat yang disebut rumah. +Excuse me, how much is this sweater? Maaf, berapa harga sweter ini? +Fresh food is indeed very delicious. Makanan segar memang sangat lezat. +Have you ever been to the Black Sea? Apakah kau pernah pergi ke Laut Hitam? +Have you ever gotten food poisoning? Apa kau pernah keracunan makanan? +Have you finished reading the novel? Apa kamu sudah selesai membaca novel itu? +He has a good head on his shoulders. Dia punya otak yang cerdas. +He married a girl of his own choice. Dia menikahi seorang gadis pilihannya. +Here is a song from the first album. Ini dia sebuah lagu dari album perdana. +How can you bear such a humiliation? Bagaimana kamu bisa tahan dengan penghinaan itu? +How did you become a police officer? Bagaimana kau bisa menjadi seorang polisi? +How long did you live on the island? Sudah berapa lama Anda tinggal di pulau tersebut? +How many hours of sleep do you need? Berapa lama waktu tidur yang kamu butuhkan? +How many pens are there on the desk? Ada berapa banyak pena di atas meja? +How many people are on the list now? Berapa banyak orang yang ada di dalam daftar sekarang? +How shall we deal with this problem? Bagaimana kita mengatasi permasalahan ini? +I ache all over after the exercises. Badanku terasa sakit semua setelah berolahraga. +I am quite comfortable in this room. Saya cukup nyaman di ruangan ini. +I asked her if she knew his address. Aku bertanya padanya apakah ia tahu alamat ini. +I can't be sure of anything anymore. Aku tidak lagi yakin dengan apapun. +I can't put up with this any longer. Aku tidak mampu menahannya lebih lama lagi. +I can't put up with this any longer. Aku sudah tidak tahan dengan hal ini. +I don't have anything to say to you. Tidak ada yang ingin kukatakan padamu. +I don't see how you can ignore this. Saya tidak mengerti bagaimana bisa Anda menolak ini. +I don't want Tom to hear about this. Aku tidak ingin Tom mendengar tentang hal ini. +I don't wish to meet with him again. Saya tidak ingin bertemu lagi dengannya. +I got acquainted with him in France. Aku berkenalan dengannya di Prancis. +I have a large collection of stamps. Saya punya banyak koleksi perangko. +I have a large collection of stamps. Aku memiliki banyak koleksi perangko. +I have a reservation for six-thirty. Saya sudah memesan yang pukul enam tiga puluh. +I just don't feel safe here anymore. Aku hanya tidak lagi merasa aman di sini. +I know it's not as easy as it looks. Aku tahu ini tidak semudah kelihatannya. +I leave for London tomorrow morning. Besok pagi aku berangkat menuju London. +I like to go fishing with my father. Aku suka pergi memancing dengan ayahku. +I made use of this good opportunity. Aku mempergunakan kesempatan yang baik ini. +I need someone who can speak French. Saya membutuhkan seseorang yang bisa berbahasa Prancis. +I shouldn't have run that red light. Aku seharusnya tidak menerobos lampu merah itu. +I thank you very much for your help. Saya sangat berterimakasih atas bantuan Anda. +I think I'll brown bag it this week. Aku pikir aku akan membawa bekal makanan minggu ini. +I thought perhaps you could help us. Aku kira kau mungkin bisa membantu kami. +I thought you might want to see Tom. Aku pikir kau perlu bertemu dengan Tom. +I tried to imagine life on the moon. Aku mencoba membayangkan kehidupan di bulan. +I want to know what you're thinking. Aku ingin tahu apa yang sedang kau pikirkan. +I wanted to go back to your village. Aku ingin kembali ke desamu. +I was a prison warden for ten years. Aku sudah menjadi sipir penjara selama sepuluh tahun. +I wonder if my life is worth living. Aku ingin tahu apa hidupku ini berharga? +I'd never seen you like that before. Saya belum pernah melihat Anda seperti itu sebelumnya. +I'll give you a call in the morning. Saya akan menelponmu besok pagi. +I'll tell you what you want to know. Aku akan memberitahumu apa yang ingin kau ketahui. +I'm disappointed that he's not here. Aku kecewa dia tidak di sini. +I'm going to try to go to sleep now. Aku akan mencoba untuk tidur sekarang. +I'm in love with the girl next door. Aku jatuh cinta dengan gadis sebelah. +I'm never wearing these shoes again. Aku tidak akan mengenakan sepatu-sepatu ini lagi. +I'm not as stupid as you think I am. Saya tidak sebodoh yang kamu kira. +I'm not sure what else I need to do. Aku tidak yakin apa lagi yang perlu aku lakukan? +I'm not used to treatment like that. Saya tidak terbiasa dengan perawatan seperti itu. +I'm writing a letter to my daughter. Aku menulis surat untuk putriku. +I've been waiting for you for hours. Aku sudah menunggumu selama sejam. +I've decided to go a little further. Saya putuskan untuk berusaha sedikit lagi. +In Switzerland, spring comes in May. Di Swis, musim semi datang pada bulan Mei. +Is this some kind of practical joke? Apa ini lelucon? +It is said that he is a millionaire. Dikatakan bahwa dia seorang jutawan. +It will not be long before he comes. Ia akan datang tidak lama lagi. +It's a beautiful day here in Boston. Hari ini adalah sebuah hari yang indah di Boston. +Keep an eye on the baby for a while. Awasi bayinya sebentar. +Keep an eye on the baby for a while. Jaga bayinya sebentar. +Let's not have any more foolishness. Mari kita tidak menambah-nambah lagi kebodohan. +My father passed away two years ago. Ayah saya meninggal dua tahun yang lalu. +No one noticed till it was too late. Tak ada seorangpun yang menyadarinya saat itu. Pada saat ada yang menyadarinya, itu sudah terlambat +Our plane took off exactly at 6 p.m. Pesawat kami lepas landas tepat jam 6 malam. +Pass me the salt and pepper, please. Tolong ambilkan garam dan mericanya. +Please just tell me what's going on. Tolong katakan saja apa yang terjadi. +She advises me on technical matters. Dia memberitahuku tentang masalah-masalah teknis. +She and I are about the same height. Tinggi badanku dan dia hampir sama. +She grew up to be a great scientist. Dia tumbuh menjadi seorang ilmuwan hebat. +She starts her job at seven o'clock. Dia mulai bekerja pada Pukul tujuh. +She was born at six a.m. on July 17. Dia lahir pada 17 Juli, pukul 6 pagi. +Since it was raining, I stayed home. Karena sedang turun hujan, aku tidak keluar dari rumah. +Smoking is not allowed in this room. Tidak diperbolehkan merokok di ruangan ini. +Studying a foreign language is hard. Belajar bahasa asing itu sulit. +Sugar replaced honey as a sweetener. Gula menggantikan madu sebagai pemanis. +That isn't what I was saying at all. Aku sama sekali tidak berkata demikian. +The boy tried moving the heavy sofa. Anak laki-laki itu mencoba memindahkan sofa yang berat itu. +The customs office is at the border. Kantor Bea dan Cukai ada di perbatasan. +The elephant was brought to the zoo. Gajah itu dibawa ke kebun binatang. +The island is easy to reach by boat. Pulau itu mudah dijangkau dengan perahu. +The old man was almost hit by a car. Pria tua itu hampir tertabrak sebuah mobil. +The road runs parallel to the river. Jalan itu sejajar dengan sungai. +The tire factory employs 250 people. Pabrik ban itu mempekerjakan 250 orang. +Their hut is situated in the valley. Gubuk mereka berada di dalam lembah. +There is an exception to every rule. Selalu ada pengecualian dalam peraturan. +There's no way I'm going to do that. Aku tidak akan pernah mau melakukannya. +They don't teach you that in school. Kamu tidak diajari itu di sekolah. +They stayed at the hotel for a week. Mereka tinggal di hotel selama seminggu. +Tom arrived at home early yesterday. Tom tiba di rumah lebih awal kemarin. +Tom came here to ask us to help him. Tom datang kemari untuk meminta kami menolongnya. +Tom couldn't possibly have hit Mary. Mana mungkin Tom memukul Mary. +Tom didn't meet Mary or anyone else. Tom tidak bertemu dengan Mary atau siapapun juga. +Tom doesn't like speaking in public. Tom tidak suka berbicara di depan umum. +Tom eats lunch by himself every day. Tom makan siang sendirian setiap hari. +Tom has difficulty making decisions. Tom kesulitan dalam membuat keputusan. +Tom is considering joining the army. Tom mempertimbangkan untuk bergabung dengan militer. +Tom is interested in mountaineering. Tom tertarik pada pendakian gunung. +Tom is talking to Mary on the phone. Tom sedang berbicara dengan Mary di telepon. +Tom kissed Mary and she slapped him. Tom mencium Mary dan Mary pun menamparnya. +Tom may talk to Mary if he wants to. Tom akan berbicara dengan Mary jika dia ingin. +Tom motioned for Mary to follow him. Tom mengisyaratkan Mary untuk mengikutinya. +Tom needs to lower his expectations. Tom perlu menurunkan ekspektasinya. +Tom nervously handed Mary the knife. Tom secara gugup menyerahkan pisau kepada Mary. +Tom never gives anything to anybody. Tom tidak pernah memberikan apapun pada siapapun. +Tom offered his seat to an old lady. Tom menawarkan kursinya kepada seorang nenek. +Tom persuaded Mary to join our band. Tom membujuk Mary bergabung dengan band kami. +Tom poured cold water over his head. Tom menuangkan air dingin ke kepalanya. +Tom pretended that he didn't see it. Tom berlaku seolah-olah tidak melihatnya. +Tom probably knows I don't like him. Tom mungkin tahu aku tidak menyukainya. +Tom promised to never be late again. Tom berjanji untuk tidak terlambat lagi. +Tom put the pencil down on the desk. Tom meletakkan pensilnya di atas meja. +Tom really likes playing the guitar. Tom sangat suka bermain gitar. +Tom said he wanted to be left alone. Tom bilang dia ingin ditinggal sendiri. +Tom saw Mary coming down the stairs. Tom melihat Mary datang menuruni tangga. +Tom saw Mary getting ready to leave. Tom melihat Mary bersiap untuk pergi. +Tom saw Mary heading into the woods. Tom melihat Mary pergi ke hutan. +Tom seems to be looking for someone. Tom terlihat seperti sedang mencari seseorang. +Tom stirred his coffee with a spoon. Tom mengaduk kopinya dengan sebuah sendok. +Two glasses of orange juice, please. Saya pesan dua gelas jus jeruk. +Watch out! There's a big hole there. Hati-hati! Di sana ada lubang besar. +Watch out! There's a big hole there. Awas! Ada lubang besar di sana. +We can't sleep because of the noise. Kami tak bisa tidur karena suara ribut itu. +We didn't actually see the accident. Kami tidak benar-benar melihat kecelakaan itu. +We managed to swim across the river. Kami berhasil berenang menyebrangi sungai. +We were working hard on the project. Kami telah bekerja keras pada proyek ini. +We're having a problem with pigeons. Kami bermasalah dengan merpati. +What on earth are you talking about? Apa yang kau bicarakan? +What on earth are you talking about? Kau ini bicara apa? +What time do you usually leave home? Kapan biasanya Anda meninggalkan rumah? +When I grow up, I want to be a king. Saat besar nanti, aku ingin menjadi raja. +When did you start wearing contacts? Kapan kamu mulai pakai lensa? +Where are Tom and his family living? Dimana Tom dan keluarganya tinggal? +Where did you take your glasses off? Di mana kamu melepas kacamatamu? +Where there's a will, there's a way. Dimana ada kemauan, disitu ada jalan. +Where there's a will, there's a way. Dimana ada keinginan, disitu ada jalan. +Where were you the entire afternoon? Kemana saja kamu sepanjang siang ini? +Why are you staring at me like that? Mengapa kamu memandangku seperti itu? +Will you please turn down the radio? Bisa tolong kecilkan volume radionya? +Would you carry my luggage upstairs? Bisakah Anda membawakan koper saya ke lantai atas? +Would you explain it in more detail? Apakah Anda bisa menjelaskannya lebih rinci? +Would you put those bags in the car? Bisakah kau memasukkan tas-tas itu ke dalam mobil? +You can eat lunch here in this room. Kamu bisa makan siang di ruangan ini. +You should get a good night's sleep. Anda perlu mendapatkan tidur yang berkualitas. +Your composition has a few mistakes. Terdapat beberapa kesalahan pada karanganmu. +Almost all the students like English. Hampir semua siswa menyukai bahasa Inggris. +Any student can answer that question. Semua siswa bisa menjawab pertanyaan itu. +Can you play any musical instruments? Apa kau bisa memainkan sebuah instrumen musik? +Could I have one more coffee, please? Boleh minta kopi lagi? +Could you give me a few more minutes? Bisakah saya minta beberapa menit lagi? +Did Tom say how he was able to do it? Apa Tom mengatakan bagaimana ia bisa melakukannya? +Did you and Tom ever talk about that? Apakah kamu dan Tom pernah membicarakan hal itu? +Did you do your homework by yourself? Apakah kamu sendiri yang mengerjakan PR-mu? +Do you know what Tom was doing there? Apakah kamu tahu apa yang Tom lakukan di sini? +Do you understand what you're saying? Apakah kamu paham dengan apa yang kamu katakan? +Don't you regret getting that tattoo? Tidakkah kamu menyesal membuat tato itu? +Free advice isn't always good advice. Nasihat gratis tidak selalu nasihat yang baik. +He gives her everything she asks for. Dia memberikannya segala hal yang ia minta. +He is not always busy in the morning. Dia selalu sibuk di pagi hari. +He left his daughter a great fortune. Dia meninggalkan warisan yang banyak untuk anak perempuannya. +He slipped while crossing the street. Dia terpeleset saat sedang menyeberang jalan. +He will be a doctor when he grows up. Dia akan menjadi dokter ketika sudah besar. +He's the last man that I want to see. Dialah pria terakhir yang ingin saya lihat. +How many times did you see the movie? Sudah berapa kali kamu menonton film itu? +I arrived here at eight this morning. Saya sampai di sini pukul delapan pagi ini. +I can't decide what to eat for lunch. Aku tidak bisa memutuskan akan makan apa untuk makan siang. +I can't put up with this hot weather. Aku tidak tahan dengan cuaca panas ini. +I don't see anything wrong with this. Saya tidak melihat ada yang salah dengan yang ini. +I have no idea what Tom said to Mary. Aku tidak tahu apa yang Tom katakan pada Mary. +I heard something fall to the ground. Aku dengar sesuatu jatuh ke tanah. +I just wanted to say that I love you. Aku hanya ingin berkata bahwa aku cinta padamu. +I just wanted to tell you I love you. Aku hanya ingin bilang aku cinta padamu +I know that you still think about me. Aku tahu bahwa kau masih memikirkanku. +I liked what you said at the meeting. Aku suka dengan perkataanmu waktu rapat tadi. +I make it a rule not to stay up late. Aku membiasakan diri untuk tidak begadang. +I returned the knife that I borrowed. Saya mengembalikan pisau yang telah saya pinjam. +I started learning Chinese last week. Aku mulai mempelajari bahasa Mandarin minggu lalu. +I stayed home because it was raining. Aku tetap berada di rumah karena hujan sedang turun. +I still don't know how that happened. Aku masih tidak tahu bagaimana itu bisa terjadi. +I think there's a mistake on my bill. Saya kira ada yang salah pada tagihan saya. +I told you not to turn on the lights. Sudah saya katakan jangan menyalakan lampu. +I tried to put an end to the quarrel. Aku berusaha untuk menghentikan pertengkaran itu. +I will write to you as soon as I can. Aku akan menulis surat untukmu sesegera mungkin. +I won't be able to visit you anymore. Aku tidak bisa lagi mengunjungimu. +I would like to have a cup of coffee. Aku ingin minum kopi. +I'll be sixteen years old next month. Bulan depan umur saya enam belas tahun. +I'll never ask you for anything else. Aku tidak akan memintamu yang lain-lain lagi. +I'll show you how to properly use it. Saya akan menunjukkan cara menggunakannya dengan benar. +I'm afraid Tom won't be able to come. Aku rasa Tom tidak akan bisa datang. +I'm afraid you don't have any choice. Kurasa kamu tidak punya pilihan lain. +I'm sorry I kept you waiting so long. Maaf membuatmu menunggu begitu lama. +I'm sorry, did I say something wrong? Maaf, apakah ada yang salah dengan perkataanku? +I've been in Australia several years. Aku sudah beberapa tahun di Australia. +If you were Tom, what would you want? Kalau saja kau adalah Tom, apa yang kau inginkan? +Lack of sleep is bad for your health. Kurang tidur tidak baik bagi kesehatan anda. +My father helped me with my homework. Ayahku membantuku mengerjakan PRku. +My mom likes my brother more than me. Ibuku menyukai adikku lebih dari aku. +My son still believes in Santa Claus. Anak laki-lakiku masih percaya akan Santa Claus. +My younger brother is taller than me. Adik laki-lakiku lebih tinggi dariku. +Nobody knows where he has escaped to. Tak seorangpun tahu kemana dia melarikan diri. +One must do one's best in everything. Seseorang harus melakukan yang terbaik dalam hal apapun. +Only my mother really understands me. Hanya ibuku yang benar-benar mengerti aku. +Our school library is small, but new. Perpustakaan sekolah kami kecil, tetapi masih baru. +Patience is a rare virtue these days. Kesabaran merupakan kebajikan yang sukar ditemukan belakangan ini. +Please show me your driver's license. Tolong perlihatkan SIM Anda. +School begins the day after tomorrow. Kegiatan sekolah akan dimulai besok lusa. +Seen from a distance, she's a beauty. Dari jauh dia cantik. +She did not answer all the questions. Dia tidak menjawab semua pertanyaan. +She gave him something cold to drink. Dia memberikannya sesuatu yang dingin untuk diminum. +She held out her hand and I shook it. Ia mengulurkan tangannya dan aku pun menjabatnya. +She invited me to her birthday party. Dia mengundangku ke pesta ulang tahunnya. +She was born and brought up in Osaka. Dia dilahirkan dan dibesarkan di Osaka. +Show me your driving license, please. Tolong tunjukkan SIM Anda. +Something's happening on Park Street. Sesuatu terjadi di jalan Park. +Stop spending money on stupid things. Berhentilah mengeluarkan uang untuk hal yang tidak penting. +That's not important for you to know. Tidaklah penting untuk kau ketahui. +The bus leaves every fifteen minutes. Busnya berangkat setiap 15 menit. +The cellar is ugly, dark, and stinky. Ruang bawah tanahnya jelek, gelap, dan berbau. +The island was struck by the typhoon. Pulau itu dihantam topan. +The royal palace was built on a hill. Istana kerajaan tersebut dibangun di atas bukit. +The students did the work themselves. Para siswa mengerjakan sendiri tugas mereka. +The supermarket opens at ten o'clock. Supermarketnya buka jam sepuluh tepat. +The view from this room is wonderful. Pemandangan dari kamar ini sangat bagus. +The workers were proud of their work. Para pekerja bangga akan pekerjaannya. +The world doesn't revolve around you. Dunia tidak berputar mengelilingimu. +Their losses reached one million yen. Kerugian mereka mencapai satu juta yen. +There was almost nothing in the room. Hampir tidak ada apa-apa di kamar tersebut. +These books aren't just for children. Buku-buku ini bukan hanya untuk anak-anak. +They don't always obey their parents. Mereka tidak selalu patuh kepada orang tua mereka. +They submitted the case to the court. Mereka mengajukan kasus itu ke pengadilan. +This book is suitable for your needs. Buku ini sesuai dengan kebutuhanmu. +This college was established in 1910. Kampus ini didirikan pada tahun 1910. +This is the best camera in the store. Ini adalah kamera terbaik di toko tersebut. +Tom asked if he needed to wear a tie. Tom bertanya apakah ia perlu mengenakan dasi. +Tom carefully read over the contract. Tom membaca kontrak itu dengan hati-hati. +Tom didn't think he could trust Mary. Tom tidak yakin kalau dia bisa mempercayai Mary. +Tom doesn't know how much it'll cost. Tom tidak tahu berapa biayanya. +Tom doesn't know how to speak French. Tom tidak tahu cara berbicara bahasa Perancis. +Tom grows all the vegetables he eats. Tom menanam sendiri semua sayuran yang ia makan. +Tom has been very unlucky, hasn't he? Tom benar-benar kurang beruntung, ya? +Tom is leaving Kobe tomorrow morning. Tom akan meninggalkan Kobe besok pagi. +Tom is still not answering his phone. Tom masih tidak mengangkat teleponnya. +Tom is the newest member of our team. Tom anggota terbaru tim kami. +Tom is the newest member of our team. Tom anggota terbaru tim kita. +Tom isn't used to living in the city. Tom tidak terbiasa hidup di kota. +Tom left about an hour ago with Mary. Tom pergi sejam yang lalu dengan Mary +Tom left to meet you three hours ago. Tom pergi untuk menemuimu tiga jam yang lalu. +Tom managed to swim across the river. Tom berhasil berenang menyeberangi sungai. +Tom pointed to the chair next to his. Tom menunjuk kursi disebelahnya. +Tom probably just forgot you're here. Tom mungkin saja lupa kamu di sini. +Tom sat at his desk reading a report. Tom duduk membaca laporan di mejanya. +Tom saw Mary's name on the list, too. Tom juga melihat nama Mary di daftar. +Tom says he's trying to quit smoking. Tom berkata dia sedang berusaha berhenti merokok. +Tom shouldn't have said those things. Tom tidak seharusnya mengucapkan perkataan itu. +Tom spends a lot of his time reading. Tom banyak menghabiskan waktunya dengan membaca. +Tom thought Mary seemed really happy. Tom mengira Mary terlihat sangat senang. +Tom walked in through the front door. Tom melangkah masuk melalui pintu depan. +We got here at exactly the same time. Kami tiba di sini hampir bersamaan. +We have a reservation for six-thirty. Kami sudah memesan yang pukul enam tiga puluh. +We should've known Tom would be late. Kita seharusnya tahu kalau Tom akan terlambat. +We went to the park to take pictures. Kami pergi ke taman untuk berfoto. +What was the name of that restaurant? Apa nama restoran itu? +Where's the nearest department store? Di mana supermarket terdekat? +Who is the girl standing at the door? Siapa anak perempuan yang sedang berdiri di pintu? +Why don't you play the banjo anymore? Kenapa kamu sudah tidak bermain banjo lagi? +Would you like another cup of coffee? Anda ingin segelas kopi lagi? +You can't lift the piano by yourself. Kau tidak bisa mengangkat pianonya seorang diri. +You look lovely just the way you are. Dirimu apa adanya sudah terlihat cantik. +You reach him by calling this number. Kamu dapat menghubunginya dengan menelpon nomor ini. +You should be very proud of yourself. Kamu pasti sangat bangga dengan dirimu. +You should put that cash in the safe. Kau seharusnya memasukkan uang tunai itu ke dalam brankas. +You'd better tell Tom not to do that. Kamu sebaiknya memberitahu Tom untuk tidak melakukannya. +You're not the only one who's hungry. Bukan hanya kamu saja yang merasa lapar. +Your mother is in critical condition. Ibumu dalam keadaan kritis. +"How old are you?" "I'm 16 years old." "Berapa umurmu?" "Aku 16 tahun." +A reasonable compromise must be found. Sebuah kesepakatan yang berdasar harus bisa ditemukan. +A woman fell from a ship into the sea. Seorang perempuan jatuh ke laut dari sebuah kapal. +Are you absolutely certain about this? Apa kau benar-benar yakin dengan hal ini? +Are you serious about getting married? Apakah kamu serius ingin menikah? +Are you taking any medicine regularly? Apakah Anda mengonsumsi obat-obatan tertentu secara rutin? +Berlin is the largest city in Germany. Berlin adalah kota terbesar di Jerman. +Can I use your car for a little while? Bisakah saya meminjam mobil Anda sebentar? +Could you please repeat it once again? Bisakah Anda mengulanginya sekali lagi? +Did you hear about the fire yesterday? Apa kamu dengar tentang kebakaran yang terjadi kemarin? +Didn't your parents teach you manners? Apa orang tuamu tidak mengajarimu sopan santun? +Do you also have this in other colors? Apakah kamu juga punya ini dengan warna yang lain? +Do you usually have tea for breakfast? Apa kau biasa minum teh untuk sarapan? +Do you want to pay with a credit card? Apakah Anda ingin membayar dengan kartu kredit? +Do your children have their own rooms? apakah anak-anakmu punya kamar sendiri +Do your children have their own rooms? Anak-anak lu punya kamar sendiri ga? +Does it snow a lot here in the winter? Apakah di sini salju turun dengan deras saat musim dingin? +Everybody was interested in the story. Semua orang tertarik pada cerita tersebut. +He apologized for having offended her. Dia meminta maaf karena telah menyinggungnya. +He did his best never to think of her. Dia berusaha keras untuk tidak lagi memikirkan dirinya. +He drew two squares on the blackboard. Dia menggambar dua buah persegi pada papan tulis. +He gets a haircut three times a month. Dia mencukur rambutnya tiga kali sebulan. +Hurry up! If you don't, we'll be late. Cepat! Jika tidak, kita akan terlambat. +I agree with your opinion about taxes. Saya setuju dengan pendapat Anda mengenai pajak. +I can't imagine why Tom would do that. Aku tidak bisa membayangkan kenapa Tom harus melakukan itu. +I didn't know anything about his plan. Aku tidak tahu apa-apa tentang rencananya. +I do not live to eat, but eat to live. Saya tidak hidup untuk makan, tapi makan untuk hidup. +I don't know who called you yesterday. Aku tidak tahu siapa yang memanggilmu kemarin. +I don't know who painted this picture. Aku tidak tahu siapa yang menggambar gambar ini. +I don't like his smart way of talking. Aku tidak suka cara bicaranya yang lancang. +I don't think I'll ever see Tom again. Aku pikir aku tidak akan pernah bertemu Tom lagi. +I don't want to drink too much coffee. Saya tidak ingin banyak minum kopi. +I don't want to speak ill of the dead. Aku tidak mau berbicara buruk tentang orang yang sudah mati. +I got this job with my teacher's help. Saya mendapatkan pekerjaan ini dengan bantuan guru saya. +I have a business proposition for you. Aku memiliki tawaran bisnis denganmu. +I have no idea what I'm talking about. Aku tidak tahu apa yang aku bicarakan. +I have to pay a little more attention. Aku harus sedikit lebih memperhatikan. +I just realized something interesting. Aku baru saja menyadari sesuatu yang menarik. +I meet with him once every six months. Aku bertemu dengannya tiap enam bulan sekali. +I once wanted to be an astrophysicist. Aku pernah ingin menjadi seorang astronom fisika. +I really like the way your hair looks. Aku sangat suka gaya rambutmu. +I think I may know what this is about. Aku pikir aku mungkin mengetahui apa ini sebenarnya. +I thought Tom would say hello to Mary. Ku pikir Tom akan menyapa Mary tadi. +I thought you didn't care about money. Aku pikir kamu tidak peduli tentang uang. +I thought you might feel the same way. Saya kira kamu merasakan hal yang sama. +I was going to ask you the same thing. Aku hendak bertanya kepadamu hal yang sama. +I'll be back by tomorrow, if possible. Kalau memungkinkan, saya akan kembali besok. +I'm going to take full responsibility. Aku akan bertanggung jawab penuh. +I've just had new tires put on my car. Aku baru saja memasang ban baru pada mobilku. +If you're tired, you should go to bed. Kalau kamu lelah, lebih baik kamu istirahat sekarang. +Is there something you want to ask me? Apakah ada sesuatu yang ingin kamu tanyakan padaku? +It is very hot in this room, isn't it? Ruangan ini sangat panas yah? +It was very lucky that you came today. Beruntung sekali kamu datang hari ini. +It's not going to be a problem, is it? Hal ini tidak akan menjadi masalah, bukan? +It's not safe to text while you drive. Mengetik SMS selagi Anda mengemudi bisa membahayakan keselamatan Anda. +My brother is always acting foolishly. Adikku selalu bertingkah konyol. +No one is to leave without permission. Tidak ada yang boleh keluar tanpa permisi. +No one is to leave without permission. Tidak ada yang boleh keluar tanpa izin. +Once a month, I go to the hairdresser. Satu kali dalam satu bulan, aku pergi ke salon. +Pick up that paper there on the floor. Pungutlah kertas yang ada diatas lantai. +Please give me a pillow and a blanket. Tolong berikan saya bantal dan selimut. +Please give me your permanent address. Tolong beritahu saya alamat tetap Anda. +Rats! I've got to work overtime again. Sial! Aku harus kerja lembur lagi. +She can take control of the situation. Dia mampu menguasai situasi yang ada. +She has taught music for thirty years. Dia telah mengajar musik selama 30 tahun. +She poured boiling water into the cup. Dia menuangkan air mendidih ke dalam cangkir. +That's it. I've done everything I can. Oke cukup. Aku sudah melakukan apapun yang aku bisa. +The Normans conquered England in 1066. Bangsa Norman menaklukkan Inggris pada tahun 1066. +The boxer got up on the count of nine. Petinju itu bangun pada hitungan kesembilan. +The child soon fell asleep in the bed. Anak itu seketika tertidur di ranjangnya. +The island is a paradise for children. Pulau itu bagaikan surga bagi anak-anak. +The more you study, the more you know. Semakin banyak kamu belajar, semakin banyak kamu tahu. +The problem is we don't know anything. Masalahnya kita tidak tahu apa-apa. +The rain just stopped, so let's leave. Hujannya baru saja berhenti, jadi ayo kita berangkat. +The ship was flying the American flag. Kapal itu mengibarkan bendera Amerika. +The weather has been good until today. Sampai hari ini cuacanya selalu dalam keadaan baik. +There are still people who can't read. Masih ada orang-orang yang tidak bisa membaca. +There was nothing I could do about it. Tidak ada yang bisa kuperbuat akan hal itu. +They left before the end of the movie. Mereka beranjak pergi sebelum filmnya berakhir. +This novel is difficult to understand. Novel ini susah dimengerti. +Thomas Edison invented the light bulb. Thomas Edison menciptakan bola lampu. +Today you can eat as much as you want. Hari ini Anda bisa makan sebanyak yang Anda inginkan. +Tom always tries to help other people. Tom selalu mencoba membantu orang lain. +Tom didn't realize what was happening. Tom tidak menyadari apa yang sedang terjadi tadi. +Tom doesn't know much about Indonesia. Tom tidak tahu banyak tentang Indonesia. +Tom hardly ever speaks French anymore. Tom sudah jarang berbicara dalam bahasa Prancis. +Tom lives in the apartment above Mary. Tom tinggal di apartemen diatas tempat Mary. +Tom looks as though he's seen a ghost. Tom nampak seperti telah melihat hantu. +Tom made no attempt to defend himself. Tom tidak berusaha melindungi dirinya sendiri. +Tom made the right decision after all. Pada akhirnya Tom membuat keputusan yang tepat. +Tom must've found out that I was here. Tom pasti tahu jika aku pernah di sini. +Tom needs to lose three or four kilos. Tom perlu menurunkan berat badan tiga atau empat kilo. +Tom poked his pencil through the hole. Tom mencucukkan pensilnya kedalam lubang. +Tom realized Mary was waiting for him. Tom menyadari Mary menunggu dirinya. +Tom really likes swimming, doesn't he? Bukankah Tom sungguh menyukai berenang? +Tom said he'd never speak to me again. Tom berkata dia tidak akan pernah berbicara denganku lagi. +Tom saw a boy waiting at the bus stop. Tom melihat seorang anak laki-laki menunggu di halte. +Tom took aim and fired a warning shot. Tom membidik dan menembakkan tembakan peringatan. +Tom tried to push Mary into the water. Tom mencoba mendorong Mary kedalam air. +Tom understands what needs to be done. Tom paham apa yang harus dituntaskan. +Tom was unable to hide his excitement. Tom tidak mampu menyembunyikan antusiasmenya. +Tom wasn't injured in the train wreck. Tom tidak terluka dalam kecelakaan kereta itu. +Tom, Mary and John are in the kitchen. Tom, Mary, dan John sedang berada di dapur. +We don't even know how to contact Tom. Kita bahkan tidak tahu cara menghubungi Tom. +We have had a lot of rain this summer. Kita dapat banyak hujan musim panas ini. +We mustn't waste our energy resources. Kita tidak boleh membuang-buang percuma sumber energi kita. +What's your favorite item of clothing? Pakaian apa yang paling kamu sukai? +When will your new novel be published? Kapan novel barumu akan diterbitkan? +Where did Tom get all that money from? Tom mendapatkan uang itu semua dari mana? +Who in the world do you think you are? Kamu pikir kamu ini siapa? +Who's your favorite character on Glee? Siapa karakter favoritmu di Glee? +You always try to blame somebody else. Kamu selalu mencoba menyalahkan orang lain. +You don't really believe that, do you? Kau tidak benar-benar mempercayainya, kan? +You should be ashamed of your conduct. Kamu seharusnya malu dengan tingkah laku kamu itu. +You should follow the doctor's advice. Kau harus mengikuti petunjuk dokter. +You should've paid your bills on time. Kau seharusnya membayar tagihanmu tepat waktu. +All you have to do is press the button. Yang harus kau lakukan adalah menekan tombolnya. +Are you spending Thanksgiving with Tom? Apa kamu menghabiskan waktu bersama Tom di hari Thanksgiving? +Could I speak to you for a moment, Tom? Dapatkah saya berbicara denganmu sebentar, Tom? +Did Tom say anything to you about that? Apakah Tom mengatakan sesuatu kepadamu tentang hal itu? +Do you believe the witness's statement? Kamu percaya pernyataan saksi itu? +Do you remember the night Tom was born? Apa kau ingat malam ketika Tom lahir? +Do you think Tom looks like an old man? Apa menurutmu Tom terlihat seperti orang tua? +Don't you know what happened yesterday? Tidakkah kau tahu apa yang terjadi kemarin? +Drivers must observe the traffic rules. Para pengendara harus mematuhi peraturan lalu-lintas. +Have you ever heard anything like that? Pernahkah kau mendengar yang seperti itu? +He attributes his success to good luck. Dia menganggap kalau dirinya berhasil karena beruntung. +He made me wait for about half an hour. Dia membuatku menunggu selama hampir setengah jam. +He sat surrounded by his grandchildren. Dia duduk sambil dikelilingi cucu-cucunya. +He turned out to be nothing but a liar. Dia tidak lain dan tidak bukan adalah seorang pembohong. +He was hit by a car and died instantly. Dia tertabrak mobil dan tewas di tempat. +He worked hard to make his child happy. Dia bekerja keras untuk membahagiakan anaknya. +His new novel will come out next month. Novel barunya akan terbit bulan depan. +How many classes do you have on Monday? Di hari Senin jam pelajaranmu ada berapa banyak? +How many times have you been to Boston? Sudah berapa kali kamu ke Boston? +I do not know if it will rain tomorrow. Aku tidak tahu apakah besok akan hujan. +I don't know how to put it in Japanese. Aku tidak tahu bagaimana cara mengatakannya dalam bahasa Jepang. +I don't know whether it is true or not. Aku tidak tahu apakah itu benar atau tidak. +I don't like pepperoni pizza that much. Saya tidak seberapa suka pizza pepperoni. +I don't want to be disturbed until ten. Saya tidak ingin diganggu hingga jam sepuluh. +I hope we'll see each other again soon. Kuharap kita akan segera bertemu lagi. +I hope you two are very happy together. Aku harap kalian berdua bahagia. +I interpreted their silence as consent. Saya menganggap diamnya mereka sebagai tanda setuju. +I like swimming and playing basketball. Saya gemar berenang dan bermain bola basket. +I like white wine better than red wine. Aku lebih suka anggur putih daripada anggur merah. +I like white wine better than red wine. Saya lebih suka anggur putih daripada anggur merah. +I met an old student of mine in London. Di London saya bertemu dengan anak didik saya yang dulu. +I still haven't learned to drive a car. Aku masih belum belajar mengendarai mobil. +I suppose we should tell Tom the truth. Aku pikir kita harus memberitahu Tom yang sebenarnya. +I think I can come over this afternoon. Saya pikir saya bisa datang siang ini. +I think it would be good for all of us. Aku pikir itu baik untuk kita semua. +I told my wife to get ready in a hurry. Aku memberitahu istriku untuk cepat bersiap-siap. +I want you to reconsider your decision. Saya ingin Anda mempertimbangkan kembali keputusan Anda. +I was thinking about Tom earlier today. Aku memikirkan tentang Tom beberapa saat yang lalu. +I will take both this one and that one. Aku akan mengambil baik yang ini dan yang itu. +I wish Tom hadn't told Mary about that. Aku harap Tom belum memberitahukan hal itu kepada Mary. +I'll buy you whatever clothes you want. Saya akan membelikan pakaian apa saja yang kamu mau. +I'll show you the car I've just bought. Akan ku tunjukkan padamu mobil yang baru aku beli. +If you want to be happy, then be happy. Kalau kamu ingin bahagia, maka berbahagialah. +Is hitchhiking prohibited in Australia? Apakah mencari tumpangan dilarang di Australia? +It was all I could do to keep standing. Hanya ini yang dapat aku lakukan untuk bertahan. +Late autumn in Scotland is rather cold. Suhu di Skotlandia cukup dingin pada akhir musim gugur. +Let's leave the problem until tomorrow. Mari kita tunda masalah itu hingga besok. +Look, Tom, we don't have time for this. Sudahlah, Tom, kita tidak punya waktu untuk hal ini. +Mary decided never to see him any more. Mary memutuskan untuk tidak akan menemuinya lagi. +My cassette tape recorder needs fixing. Perekam pita kasetku perlu diperbaiki. +My children don't have their own rooms. Anak-anakku tidak memiliki kamarnya sendiri. +My children don't have their own rooms. Anak-anakku tidak punya kamar sendiri. +My father didn't allow me to marry him. Ayahku tidak membolehkanku menikahinya. +My mom doesn't speak English very well. Ibuku tidak bisa bahasa Inggris dengan baik. +My younger brother is taller than I am. Adik laki-lakiku lebih tinggi dariku. +Nobody knows why he turns down my help. Tidak ada yang tahu mengapa dia menolak pertolonganku. +Please remain seated for a few minutes. Tolong duduk sebentar. +She participated in the beauty contest. Dia mengikuti kontes kecantikan. +She went to the station to see him off. Dia pergi ke stasiun untuk mengiringi keberangkatannya. +Tell me why you didn't do what I asked. Katakan padaku kenapa kau tidak melakukan apa yang aku minta. +The 1990s began with the Gulf incident. Tahun 1990-an dimulai dengan peristiwa Teluk +The car left a cloud of dust behind it. Mobil itu mengeluarkan asap tebal. +The children are making a lot of noise. Anak-anak itu membuat banyak kegaduhan. +The deal fell apart at the last minute. Kesepakatannya batal di menit terakhir. +The dog has a very keen sense of smell. Anjing memiliki daya penciuman yang sangat tajam. +The garage is at the side of the house. Garasinya terletak di sebelah rumah. +The heat was so intense that I fainted. Suhunya sangat panas hingga aku pun pingsan. +The man lent me two books this morning. Orang itu telah meminjamkanku dua buku pagi ini. +The missing cat has not been found yet. Kucing yang hilang tersebut masih belum ditemukan. +The moon is the earth's only satellite. Bulan adalah satu-satunya satelit bumi. +The muddy road has ruined my new shoes. Jalan yang berlumpur itu telah merusak sepatu baruku. +The wrestler weighs over 200 kilograms. Berat pegulat itu lebih dari 200 kilogram. +There are still people who cannot read. Masih ada orang-orang yang tidak bisa membaca. +There's a calendar hanging on the wall. Di sana terdapat kalender menggantung di dinding. +There's been a lot of rain this summer. Musim panas ini banyak turun hujan. +They suggested to him that he go alone. Mereka menyarankannya untuk pergi sendirian. +This is a good place to pitch our tent. Ini adalah tempat yang bagus untuk kami mendirikan tenda. +This is the reason I disagree with you. Ini adalah alasan kenapa saya kurang setuju dengan Anda. +This plant doesn't need a lot of light. Tumbuhan ini tidak memerlukan banyak cahaya. +This room is used for various purposes. Ruangan ini serba guna. +Those who are present are all Japanese. Semua yang telah hadir adalah orang Jepang. +Tom admitted that he had been defeated. Tom tadi mengakui kekalahannya +Tom always wears goggles when he swims. Tom selalu mengenakan kacamata ketika dia berenang. +Tom currently teaches English in Japan. Tom sekarang mengajar bahasa Inggris di Jepang. +Tom decided to run for class president. Tom memutuskan untuk mencalonkan diri sebagai ketua kelas. +Tom didn't notice how Mary was dressed. Tom tidak tahu bagaimana Mary berpakaian. +Tom didn't understand Mary's reasoning. Tom tidak memahami pertimbangan Mary. +Tom has a small cabin on the lakefront. Tom memiliki sebuah pondok kecil di depan danau. +Tom is preparing dinner in the kitchen. Tom mempersiapkan makan malam di dapur. +Tom is sitting at the table over there. Tom duduk di meja sebelah sana. +Tom is still in kindergarten, isn't he? Tom masih TK, kan? +Tom is three years older than his wife. Tom lebih tua tiga tahun dari istrinya. +Tom isn't any busier than anybody else. Tom tidak lebih sibuk dari siapa pun. +Tom knew that Mary needed to buy a car. Tom tahu kalau Mary perlu membeli mobil. +Tom knows that Mary can't speak French. Tom tahu bahwa Mary tidak bisa berbicara bahasa Prancis. +Tom shivered when he saw the black cat. Tom merinding ketika ia melihat kucing hitam itu. +Tom showed Mary how to sharpen a knife. Tom menunjukkan Mary bagaimana cara mengasah pisau. +Tom showed up early for practice today. Tom datang lebih awal untuk berlatih hari ini. +Tom suggested ways we could save money. Tom menyarankan cara-cara agar kita dapat menghemat uang. +Tom told me he likes going to concerts. Tom bilang ke aku kalau dia suka pergi nonton konser. +Tom tossed the soda can into the trash. Tom melempar kaleng sodanya ke dalam tong sampah. +Tom tried to persuade Mary to help him. Tom mencoba membujuk Mary untuk membantunya. +Tom waited on the front porch for Mary. Tom menunggu Mary di beranda depan. +Tom wanted another piece of watermelon. Tom mau sepotong semangka lagi. +We don't really have to sell our house. Kita tidak sampai harus menjual rumah kita. +We used to go camping when I was a kid. Dulu kami suka berkemah ketika aku masih kecil. +What prevented you from coming earlier? Apa yang menghalangimu untuk datang lebih awal? +Where else in Boston do you want to go? Di Boston, kamu ingin pergi ke mana lagi? +You can't leave me here alone with Tom. Kau tidak bisa meninggalkanku di sini sendirian dengan Tom. +You don't have to answer this question. Kamu tidak perlu menjawab pertanyaan ini. +You don't have to answer this question. Anda tidak perlu menjawab pertanyaan ini. +You don't need to answer that question. Kamu tidak perlu menjawab pertanyaan itu. +You don't need to answer this question. Anda tidak perlu menjawab pertanyaan ini. +You may choose whichever book you like. Kamu boleh pilih buku mana saja yang kamu suka. +You may choose whichever book you like. Kau boleh memilih buku manapun yang kau suka. +You still don't have enough experience. Kau masih belum punya cukup pengalaman. +You're wearing your sweater inside out. Kamu memakai sweter terbalik. +All Tom wanted was some peace and quiet. Yang Tom inginkan adalah kedamaian dan ketenangan. +All you have to do is to tell the truth. Yang harus kau lakukan adalah mengatakan yang sebenarnya. +Biddle was an extremely intelligent man. Biddle dulunya adalah seorang yang sangat cerdas. +Call 1-800-828-6322 for a free brochure. Hubungi 1-800-828-6322 untuk gratis brosur. +Can any of you suggest another solution? Bisakah kamu memberikan solusi lain? +Cats can see things even when it's dark. Kucing bisa melihat sesuatu meski saat gelap. +Could you please not smoke in this room? Bisa tolong untuk tidak merokok tidak ruangan ini? +Do not forget to meet me at the station. Jangan lupa untuk bertemu saya di stasiun. +Don't leave the bicycle out in the rain. Jangan tinggalkan sepeda di bawah hujan. +Have you ever been to a foreign country? Pernahkah kau pergi ke luar negeri? +Have you ever visited a foreign country? Kamu pernah ke negara lain? +He can count up to ten with his fingers. Dia bisa menghitung sampai sepuluh dengan jarinya. +He can't be hungry. He's just had lunch. Tidak mungkin dia lapar. Dia baru saja makan siang. +He did not intend to hurt your feelings. Dia tidak bermaksud menyakiti perasaanmu. +He fell in love with her at first sight. Dia jatuh cinta padanya pada pandangan pertama. +He had the courage to decline the offer. Dia punya nyali untuk menolak tawaran itu. +He had the nerve to ask me to marry him. Dia tanpa tahu malu memintaku menikah dengannya. +He is still not accustomed to city life. Dia masih belum terbiasa dengan kehidupan kota. +He is still not back from the mountains. Dia belum kembali dari gunung. +How long have you and Tom been together? Sudah berapa lama kamu dan Tom bersama? +How long have you been wearing contacts? Sudah berapa lama kamu pakai lensa? +I am not sure how to pronounce the word. Saya tidak yakin bagaimana cara mengucapkan kata itu +I didn't know you were such a good cook. Saya tidak tahu kalau kamu pandai memasak. +I don't have as much money as you think. Aku tidak punya banyak uang seperti yang kau kira. +I don't know whether to cry or to laugh. Aku tak tahu apakah mesti menangis atau tertawa. +I don't want Tom singing at our wedding. Aku tidak mau Tom bernyanyi di pernikahan kita. +I had a small dinner party last weekend. Minggu kemarin, saya mengadakan pesta makan malam kecil. +I keep telling myself it doesn't matter. Aku terus berkata kepada diriku bahwa itu tidak masalah. +I know Portuguese, English, and Russian. Saya dapat memahami bahasa Portugis, Inggris, dan Rusia. +I like white roses better than red ones. Aku lebih suka mawar putih daripada mawar merah. +I thought I told you to clean your room. Aku pikir aku telah menyuruhmu untuk membersihkan kamarmu. +I thought that Tom was going to kill me. Aku pikir tadi Tom ingin membunuhku. +I thought you might be too busy to help. Aku pikir kau mungkin terlalu sibuk untuk bisa membantuku. +I thought you might know where Tom went. Kupikir kamu tahu kemana Tom pergi. +I told Tom I thought it was a good idea. Aku berkata pada Tom bahwa aku pikir itu adalah ide yang bagus. +I want to buy myself a garbage disposal. Aku ingin membeli sebuah tempat pembuangan sampah. +I'd like to thank Tom for all he's done. Aku ingin berterima kasih kepada Tom atas apa yang ia lakukan. +I'll give you an answer in a day or two. Aku akan jawab dalam satu atau dua hari. +I'll talk with you about this later, OK? Aku akan membicarakan ini denganmu nanti, ok? +I'm going to do what I believe is right. Aku akan melakukan apa yang aku yakini itu benar. +I'm not as big a fool as you think I am. Aku tidak sebodoh yang kamu kira. +I'm thinking about changing my supplier. Aku berpikir untuk mengganti pemasokku. +I'm very pleased with Tom's performance. Saya sangat puas dengan penampilan Tom. +In Japan, it's three in the morning now. Di Jepang, sekarang pukul tiga pagi. +Is there a washing machine in her house? Apa ada mesin cuci di dalam rumahnya? +Mary doesn't like men who look like Tom. Mary tidak menyukai pria yang terlihat seperti Tom. +My French teacher is the same age as me. Guru bahasa Prancisku usianya sama denganku. +My friend's father is a famous novelist. Ayah temanku adalah seorang novelis terkenal. +My mother has been dead these ten years. Ibuku sudah tiada sepuluh tahun ini. +My mother is now in the kitchen cooking. Ibuku sekarang sedang memasak di dapur. +My shoelace got caught in the escalator. Tali sepatuku tersangkut di eskalator. +Our school festival was held last month. Festival sekolah kami diadakan bulan lalu. +Praising children is an important thing. Memuji anak adalah hal yang penting. +Remind me that the meeting is on Monday. Ingatkan aku kalau rapatnya diadakan hari Senin. +She used to go to the movies on Sundays. Dulu dia pergi ke bioskop pada hari Minggu. +She wanted to live a more relaxing life. Dia ingin menjalani hidup dengan lebih santai. +Sometimes he acts as if he were my boss. Terkadang dia bertingkah seolah-olah dia adalah bosku. +Staying at home is not a pleasant thing. Berada di rumah bukan hal yang menyenangkan. +Strange things happened on her birthday. Hal yang aneh telah terjadi di hari ulang tahunnya. +Tell her that I am looking for the keys. Bilang ke dia, saya sedang mencari kunci. +That's what I want to talk to you about. Itulah yang ingin aku bicarakan denganmu. +The company rewarded him with promotion. Perusahaan menghadiahkan kenaikan jabatan padanya. +The swimming pool is open to the public. Kolam renangnya terbuka untuk umum. +The volcano has erupted twice this year. Gunung berapi itu telah meletus dua kali tahun ini. +There are hardly any books in this room. Hampir tidak ada buku di ruangan ini. +There was nothing really wrong with Tom. Sama sekali tidak ada yang salah dengan Tom. +They checked whether the room was empty. Mereka memeriksa apakah ruangan itu kosong. +This box is empty. It has nothing in it. Kotak ini kosong. Tidak ada apapun di dalamnya. +This picture reminds me of my childhood. Foto ini mengingatkanku pada masa kecilku +This room can hold three hundred people. Ruangan ini bisa menampung tiga ratus orang. +This soup is really delicious, isn't it? Sup ini benar-benar lezat, ya? +This train runs between Tokyo and Osaka. Kereta ini berjalan antara Tokyo dan Osaka. +Tom and Mary played tennis all day long. Tom dan Mary bermain tenis seharian. +Tom and Mary were talking to each other. Tom dan Mary saling berbicara. +Tom asked for permission to leave early. Tom meminta izin untuk pulang lebih awal. +Tom didn't find what he was looking for. Tom tidak menemukan apa yang sedang ia cari. +Tom doesn't need to go there by himself. Tom tidak perlu pergi ke sana sendirian. +Tom had no food or water for three days. Tom tidak makan dan minum selama tiga hari. +Tom has been there for over three years. Tom sudah berada di sana selama lebih dari tiga tahun. +Tom has never lived anywhere but Boston. Tom tidak pernah tinggal di tempat lain selain Boston. +Tom has two brothers who live in Boston. Tom punya dua saudara lelaki yang tinggal di Boston. +Tom looks as if he lost his best friend. Tom nampak seperti telah kehilangan teman baiknya. +Tom picked the box up and looked inside. Tom mengangkat kotak dan melihat isinya. +Tom picked up the knife and examined it. Tom mengambil pisau dan memeriksanya. +Tom pushed the wheelchair down the hall. Tom mendorong kursi roda melewati lorong. +Tom stood up and walked out of the room. Tom berdiri dan berjalan keluar ruangan. +Tom wants to be the center of attention. Tom ingin menjadi pusat perhatian. +Tom went splashing through the shallows. Tom pergi melewati sungai yang dangkal dengan berjalan kaki. +Tom won't do that unless you ask him to. Tom tidak akan melakukannya kecuali jika kau memintanya. +We don't want to be the last ones there. Kami tidak ingin menjadi yang terakhir di sana. +We opposed his plan to build a new road. Kami bertentangan denga rencananya membangun jalan baru. +What you are saying does not make sense. Yang kamu katakan itu tidak masuk akal. +What's your favorite television program? Apa acara televisi kesukaanmu? +When was the last time you fed the cows? Kapan terakhir kali kamu memberi makan sapi-sapi itu? +Where is the tourist information office? Di mana letak kantor pusat informasi turis? +Where's there a supermarket around here? Di sekitar sini supermarket ada di mana? +Will you tell me how to get to Shinjuku? Maukah anda memberitahu saya bagaimana cara pergi ke Shinjuku? +You don't need to go unless you want to. Kamu tidak harus pergi kecuali kalau kamu memang mau. +You never told me that you were married. Kamu tidak pernah memberitahuku kalau kamu telah menikah. +You should follow your teacher's advice. Kamu harus mengikuti petunjuk gurumu. +You were at home yesterday, weren't you? Kau kemarin berada di rumah, kan? +A lot of birthday cards will arrive soon. Bayak kartu ulang tahun yang akan segera datang. +Are you serious about what you're saying? Apa kau serius dengan apa yang kau katakan? +Cats have the ability to see in the dark. Kucing punya kemampuan melihat dalam gelap. +City officials often have sticky fingers. Pejabat kota seringkali bertangan panjang. +Come on, guys. This is not funny anymore. Ayolah, teman-teman. Ini sudah tidak lucu lagi. +Could I please have one more can of beer? Bisa saya pesan satu kaleng bir lagi? +Do you have a similar saying in Japanese? Apakah ada pepatah yang mirip dalam bahasa Jepang? +Do you have any questions about the food? Apa kamu punya pertanyaan tentang makanannya? +Do you know any of the boys in this room? Apa kamu mengenal salah satu dari anak-anak di ruangan ini? +Does Tom know how much you paid for that? Apakah Tom tahu berapa banyak yang kamu keluarkan untuk itu? +Does it rain much here during the summer? Apakah di sini sering hujan saat musim panas? +Everything I've told you may not be true. Semua yang telah aku beritahukan padamu mungkin tidak sepenuhnya benar. +Have you already started learning French? Apa kamu sudah mulai belajar bahasa Prancis? +Have you already started learning French? Apa kau sudah mulai mempelajari bahasa Prancis? +Have you finished cleaning your room yet? Sudahkah kau selesai membersihkan kamarmu? +He fits the description in the newspaper. Dia cocok dengan apa yang tertulis di koran. +He held his tongue and didn't say a word. Dia menahan lidahnya dan tidak mengatakan sepatah katapun. +He is on the point of leaving for Canada. Dia akan segera berangkat menuju ke Kanada. +He suggested that I write to her at once. Dia menyarankan agar aku segera menulis surat kepadanya. +He was chosen to be a member of the team. Dia terpilih menjadi anggota tim. +He was elected governor of Texas in 1994. Dia terpilih sebagai Gubernur Texas pada tahun 1994. +His letter says he'll arrive next Sunday. Di suratnya tertulis kalau dia akan tiba hari Minggu besok. +How would you feel if your wife left you? Apa yang kau rasakan ketika istrimu meninggalkanmu? +I barely have enough money for groceries. Aku nyaris tak punya uang untuk membeli makanan. +I didn't expect Tom to be at the meeting. Aku tidak menyangka Tom hadir dalam rapat. +I didn't think we needed to wait for Tom. Saya rasa kita tidak perlu menunggu Tom. +I don't believe you. You're always lying. Aku tidak percaya padamu. Kau selalu berbohong. +I don't think anyone thinks you're crazy. Aku tidak berpikir kalau ada orang menganggapmu gila. +I doubt you will be happy with my report. Aku ragu kamu akan senang melihat laporanku. +I have my supper at a quarter past seven. Saya makan malam pada pukul tujuh lewat lima belas menit. +I have no interest in doing this anymore. Aku tidak tertarik untuk melakukan hal ini lagi. +I heard that Tom plans to move to Boston. Saya mendengar bahwa Tom berencana pindah ke Boston. +I hope you're not going to disappoint me. Saya harap kamu tidak akan membuat saya kecewa. +I just assumed Mary was Tom's girlfriend. Saya beranggapan bahwa Mary adalah pacarnya Tom +I just want you to remember this feeling. Aku cuma ingin kamu mengingat perasaan ini. +I know that you lied to me the other day. Aku tahu kamu berbohong kapan hari. +I love sports. I get that from my father. Aku suka olahraga. Itu menurun dari ayahku. +I think I can help Tom with his homework. Aku pikir aku bisa membantu Tom mengerjakan PRnya. +I think I know why Tom doesn't like Mary. Aku pikir aku tahu kenapa Tom tidak suka pada Mary. +I think I will take a vacation this week. Kupikir aku akan berlibur pekan ini. +I think we have some unfinished business. Aku pikir kita punya beberapa urusan yang belum diselesaikan. +I think we need to find a new babysitter. Aku pikir kita perlu mencari pengasuh bayi yang baru. +I think you've been trying to contact us. Ku kira kau sedang mencoba menghubungi kami tadi. +I will go, provided the weather is clear. Aku akan pergi jika cuacanya cerah. +I wrote a letter to my parents back home. Aku menulis surat untuk orang tuaku yang ada di kampung halaman. +I'd like to show Tom what I bought today. Saya ingin menunjukkan Tom apa yang kubawa hari ini. +I'm afraid the situation is very serious. Aku enggan mengatakannya, tapi situasinya memang sangat serius. +I'm pretty impressed with Tom's progress. Aku sangat terkesan dengan perkembangan Tom. +I'm very sorry, but we can't let you out. Maafkan saya, tetapi kami tidak dapat mengeluarkanmu. +Is it true that Tom doesn't like to swim? Apakah benar Tom tidak suka berenang? +It was a party to celebrate her birthday. Itu adalah pesta perayaan hari ulang tahunnya. +It was like watching a slow motion movie. Tadi itu seperti menonton film gerak lambat. +It's fun to learn about foreign cultures. Belajar tentang budaya asing itu menyenangkan. +It's hard not to come to this conclusion. Kesimpulan ini sulit untuk dipungkiri. +It's on the first floor of that building. Itu ada di lantai satu dari bangunan itu. +Languages are subject to constant change. Bahasa adalah subjek dari perubahan yang konstan. +Left alone, the little girl began to cry. Tinggalkan sendiri, gadis kecil itu mulai menangis. +Mary and Alice often wear the same thing. Mary dan Alice sering mengenakan pakaian yang sama. +My name is known by everyone in our town. Namaku dikenal oleh semua orang di kota kami. +Perhaps she doesn't remember my birthday. Mungkin dia lupa hari ulang tahunku. +Please make sure that the door is locked. Tolong pastikan bahwa pintunya terkunci. +Please refrain from smoking in this room. Tolong jangan merokok di ruangan ini. +She allegedly killed him in self-defense. Dia diduga membunuhnya karena membela diri. +She stayed at the hotel for several days. Dia menginap di hotel beberapa hari. +That book is available in only one store. Buku itu tersedia hanya di satu toko. +That was the first time I got on a plane. Ini adalah pertama kali saya naik pesawat. +That's it. I've done everything I can do. Oke cukup. Aku sudah melakukan apapun yang bisa kulakukan. +That's the one thing I hadn't thought of. Itu adalah satu hal yang belum aku pikirkan. +The apple doesn't fall far from the tree. Buah apel tidak jatuh jauh dari pohonnya. +The big building was blazing with lights. Bangunan besar itu gemerlap dengan cahaya. +The customs officials examined the boxes. Petugas Bea dan Cukai memeriksa kotak-kotak. +The drinks were served in coconut shells. Minumannya disajikan dalam tempurung kelapa. +The food was so good that I ate too much. Makanannya sangat enak sampai-sampai saya makan terlalu banyak. +The group tried to solve social problems. Kelompok tersebut berusaha untuk memecahkan masalah-masalah sosial. +The octopus is hiding in a coconut shell. Gurita ini bersembunyi di dalam tempurung kelapa. +The teacher is with the school principal. Pak guru bersama dengan kepala sekolah. +There is an urgent need for a new system. Ada kebutuhan mendesak akan sistem baru. +There is little food in the refrigerator. Ada sedikit makanan di kulkas. +There is too much furniture in this room. Ada terlalu banyak perabotan di ruangan ini. +This compass will be useful on your trip. Kompas ini akan berguna bagi perjalanan Anda. +Tom and Mary both turned around to watch. Tom dan Mary keduanya berbalik untuk melihat. +Tom asked Mary to go to a movie with him. Tom mengajak Mary pergi menonton film bersamanya. +Tom bought the cheapest one in the store. Tom membeli yang termurah dari toko itu. +Tom could tell that Mary wanted to leave. Tom dapat mengatakan bahwa Mary ingin pergi. +Tom didn't know because I never told him. Tom tidak tahu karena aku tidak pernah memberitahunya. +Tom didn't think you would like the idea. Tom tidak yakin kau akan suka dengan ide itu. +Tom doesn't watch TV except on Saturdays. Tom tidak menonton TV kecuali hari Sabtu. +Tom has decided not to stay until Monday. Tom memutuskan untuk tidak menginap sampai hari Senin. +Tom knew something went wrong, didn't he? Tom tahu ada yang salah, iya kan? +Tom knows exactly what this is all about. Tom tahu persis apa yang ada dibalik semua ini. +Tom pulled the door closed and locked it. Tom menarik pintu hingga tertutup dan menguncinya. +Tom raised the three children by himself. Tom mengasuh tiga anak sendirian. +Tom really knows how to cook, doesn't he? Bukankah Tom sungguh tahu cara memasak? +Tom recommended that I apply for the job. Tom merekomendasikan saya untuk melamar pekerjaan. +Tom said doing that would be a good idea. Tom bilang, hal itu merupakan ide bagus +Tom said that he wanted to be left alone. Tom berkata kalau dia ingin menyendiri. +Tom says he doesn't want to study French. Tom bilang dia tidak ingin belajar bahasa Perancis. +Tom seemed to be worried about something. Tom terlihat mengkhawatirkan sesuatu. +Tom showed up at John and Mary's wedding. Tom hadir pada pernikahan John dan Mary. +Tom spends way too much time goofing off. Tom terlalu banyak menyia-nyiakan waktu. +Tom wanted Mary to go to Boston with him. Tom ingin Mary pergi ke Boston bersamanya. +Tom was the first guy who broke my heart. Tom laki-laki pertama yang membuatku patah hati. +We don't want to scare the children away. Kami tidak ingin menakut-nakuti anak-anak itu. +We have more customers than we can count. Kami punya banyak pelanggan dari yang mampu kami hitung. +We have one of your friends here with us. Seorang temanmu ada bersama kami di sini. +We have to stay here until Tom gets back. Kita harus tetap di sini sampai Tom kembali. +We must pay attention to traffic signals. Kamu harus memperhatikan rambu-rambu lalu lintas. +We must sleep at least eight hours a day. Kita harus tidur paling tidak selama delapan jam sehari. +What time is the plane scheduled to land? Jam berapa rencana kedatangan pesawat? +Who's taking responsibility for the loss? Siapa yang bertanggung jawab atas kehilangan ini? +Why do you think it was Tom who did that? Mengapa kamu mengira bahwa Tom yang melakukannya? +You don't have to answer those questions. Kamu tidak perlu menjawab pertanyaan-pertanyaan itu. +You have a tendency to not pay attention. Kamu punya kebiasaan tidak memperhatikan. +You must be tired after such a long trip. Kamu pasti lelah setelah perjalanan jauh. +You need to look at the big picture here. Kamu perlu melihat gambar besar itu di sini. +You should buy yourself something to eat. Kamu harus makan sesuatu. +You were a soldier during the war, right? Kau dulu seorang tentara kan waktu perang itu terjadi? +Admission to the museum is thirty dollars. Harga tiket masuk ke museum tiga puluh dollar. +Admission to the museum is thirty dollars. Tiket masuk ke museum harganya tiga puluh dollar. +All the students in my class are friendly. Semua siswa di kelasku sangat bersahabat. +All you have to do is sign your name here. Yang perlu Anda lakukan hanyalah menandatangani nama Anda di sini. +As a result of the blow, he became insane. Akibat pukulan itu, dia menjadi gila. +Can you change this into American dollars? Bisa tukar ini ke dolar Amerika? +Countless stars were twinkling in the sky. Bintang yang tak terkian berkerlapan di langit. +Does Tom really expect me to believe that? Benarkah Tom menyangka saya akan mempercayai itu? +Don't beat your head against a stone wall. Jangan benturkan kepalamu ke tembok batu. +Don't you think Tom looks like an old man? Apa menurutmu Tom tidak terlihat seperti orang tua? +Employers sometimes exploit their workers. Pemberi kerja kadang-kadang memanfaatkan pekerjanya. +French has many more vowels than Japanese. Bahasa Prancis memiliki bunyi vokal lebih banyak daripada bahasa Jepang. +He comes back from Singapore next January. Dia kembali dari Singapura bulan Januari depan. +He made an important scientific discovery. Dia membuat penemuan ilmiah penting. +He succeeded in swimming across the river. Dia berhasil berenang melewati sungai itu. +He thinks that his success is due to luck. Dia menganggap kalau keberhasilannya adalah karena keberuntungan. +He was spreading mulch in the flower beds. Dia menyebar mulsa di ladang bunga. +He's the head of the marketing department. Dia kepala dari departemen pemasaran. +How come you don't play the banjo anymore? Kenapa kamu sudah tidak bermain banjo lagi? +How many books can I take out at one time? Berapa buku yang bisa saya ambil dalam sekali? +I can't believe that Tom is a grandfather. Saya tidak bisa percaya bahwa Tom adalah seorang kakek. +I could go for a nice hot pizza right now. Sekarang saya ingin piza hangat yang lezat. +I didn't know your father had passed away. Saya tidak tahu kalau Ayah Anda telah meninggal dunia. +I don't want to say that to my girlfriend. Aku tidak mau mengatakan itu pada pacarku. +I have already finished reading this book. Aku sudah selesai membaca buku ini. +I think that Japan is a very safe country. Menurut saya Jepang adalah negara yang paling aman. +I think you should talk to Tom about this. Saya rasa kamu harus berbicara dengan Tom tentang hal ini. +I wish our classroom were air-conditioned. Aku harap kelas kita berpendingin ruangan. +I'm counting on you to keep an eye on Tom. Aku mengandalkanmu untuk mengawasi Tom. +I'm sorry, but I already have a boyfriend. Maaf, tapi saya sudah punya pacar. +I'm starting to lose my patience with you. Saya mulai kehilangan kesabaran terhadap anda. +Is he speaking English, French, or German? Apakah dia berbicara bahasa Inggris, Perancis, atau Jerman? +It was a great privilege working with you. Suatu kehormatan bisa bekerja sama dengan anda. +It was not until yesterday that I knew it. Baru kemarin aku mengetahuinya. +It was snowing when I reached the station. Salju sedang turun saat aku mencapai stasiun. +Let me think it over for a couple of days. Biarkan aku berpikir selama beberapa hari. +Mail service in that country is not quick. Pelayanan surat di negara itu tidak cepat. +My French teacher is the same age as I am. Guru bahasa Prancisku usianya sama denganku. +No one knows what'll happen in the future. Tidak seorang pun akan tahu apa yang akan terjadi di masa depan. +People sometimes make illogical decisions. Terkadang orang membuat keputusan yang tidak masuk akal. +Recently he's become a really nice person. Akhir-akhir ini ia menjadi orang yang sangat baik. +She was the only one to survive the crash. Dia adalah satu-satunya orang yang selamat dari kecelakaan itu. +Some of my friends can speak English well. Beberapa temanku bisa bahasa Inggris dengan baik. +That's the stupidest thing I've ever said. Itu hal terbodoh yang pernah kuucapkan. +The apple does not fall far from the tree. Buah apel tidak jatuh jauh dari pohonnya. +The fireman rushed into the burning house. Petugas pemadam kebakaran menerobos masuk ke dalam rumah yang sedang terbakar. +The man raised his hand to ask a question. Laki-laki itu mengangkat tangan untuk bertanya +The meeting was put off until next Friday. Rapat tersebut ditunda hingga Jumat depan. +The only language Tom can speak is French. Satu-satunya bahasa yang bisa Tom gunakan adalah bahasa Prancis. +The problem is we don't have enough money. Masalahnya adalah kita tidak punya cukup uang. +Their offer to buy the house was rejected. Tawaran mereka untuk membeli rumah itu ditolak. +There are still people who are illiterate. Masih ada orang yang tuna aksara. +There are too many people in that rowboat. Perahu dayung itu sudah terlalu banyak orang. +These butterflies are rare in our country. Kupu-kupu ini langka di negara kami. +They satisfied their thirst at the spring. Mereka melepaskan dahaga mereka di sumber mata air itu. +This molecule has a crystalline structure. Molekul ini berstruktur kristal. +To make matter worse, the traffic was bad. Membuat hal semakin buruk, lalu lintasnya buruk. +Tom and I used to work together in Boston. Tom dan aku dulu bekerja bersama di Boston. +Tom could see Mary was about ready to cry. Tom melihat Mary ingin menangis. +Tom doesn't know when Mary will come back. Tom tidak tahu kapan Mary akan kembali. +Tom fell down the stairs and hit his head. Tom jatuh dari tangga dan kepalanya terbentur. +Tom has been in trouble many times before. Tom sudah seringkali mendapat masalah sebelumnya. +Tom is alone in the dining room with Mary. Tom berada seorang diri di ruang dapur bersama Mary. +Tom is going to wait until Mary gets here. Tom akan menunggu hingga Mary tiba. +Tom makes a lot more money than Mary does. Tom menghasilkan lebih banyak uang ketimbang Mary. +Tom massages his temples with his fingers. Tom memijat pelipisnya dengan jarinya. +Tom picked up a rock and threw it at Mary. Tom mengambil batu dan melemparkannya pada Mary. +Tom promised me he wouldn't do that again. Tom berjanji padaku bahwa dia tidak akan melakukan hal itu lagi. +Tom received a fax from Mary this morning. Tom menerima sebuah faks dari Mary pagi ini. +Tom retired from the army three years ago. Tom pensiun dari dinas tentara tiga tahun yang lalu. +Tom used to come to visit us every summer. Tom biasanya datang mengunjungi kami setiap musim panas. +Tom would never forgive us if we did that. Tom tidak akan pernah memaafkan kita jika kita melakukan itu. +Tom's mouth was taped shut with duct tape. Mulut Tom diplester dengan lakban. +We were directly in the path of the storm. Kami berada tepat di jalur badai. +What kind of food do you want me to bring? Jenis makanan apa yang harus ku bawa? +What will we be doing this time next week? Apa yang akan kita lakukan minggu depan di waktu seperti ini? +What will we be doing this time next week? Minggu depan di waktu seperti ini, kita ngapain? +What you're doing is just a waste of time. Apa yang kau lakukan itu hanya membuang-buang waktu. +When did you start wearing contact lenses? Kapan kamu mulai pakai lensa kontak? +When life gives you lemons, make lemonade. Berakit-rakit ke hulu, berenang-renang ke tepian; bersakit-sakit dahulu, bersenang-senang kemudian. +When life gives you lemons, make lemonade. Saat kehidupan memberikanmu lemon, buatlah limun. +Why would you want talk to Tom about that? Kenapa kau ingin membicarakan hal itu dengan Tom? +You can make an educated guess, can't you? Kamu bisa menebak dengan baik, kan? +You could go bowling with Tom if you want. Kau bisa pergi bermain boling dengan Tom kalau kau mau. +You must be careful not to make him angry. Kamu harus hati-hati jangan membuatnya marah. +You must not make noises in the classroom. Di dalam kelas tidak boleh berisik. +"Pass me the salt, please." "Here you are." "Tolong ambilkan garam." "Ini, silahkan" +Are you sure you don't want to sleep on it? Apa kamu yakin tidak mau tidur di atasnya? +Didn't you notice us going out of the room? Kamu tidak menyadari kami keluar dari kamar? +Do you know the man standing on the bridge? Apakah Anda kenal dengan orang yang berdiri di atas jembatan itu? +Do you know the real reason Tom isn't here? Apa kamu tahu alasan sebenarnya mengapa Tom tidak berada di sini? +Englishmen are, on the whole, conservative. Orang Inggris pada umumnya konservatif. +Every part of the island has been explored. Setiap jengkal pulau telah dijelajahi. +Generally speaking, history repeats itself. Pada umumnya, sejarah akan terulang kembali. +He caught hold of a rope and saved himself. Dia meraih talinya dan menyelamatkan diri. +He dates the custom from the colonial days. Dia memperkirakan bahwa adat kebiasaan itu telah dimulai sejak jaman kolonial. +He finished his work without sleep or rest. Dia menyelesaikan pekerjaannya tanpa tidur maupun istirahat. +He has made little progress in his English. Dia mengalami sedikit kemajuan dalam Bahasa Inggris. +He is reputed the best lawyer in this city. Dia bereputasi sebagai pengacara terbaik di kota ini. +Her hair grew back to it's original length. Rambutnya kembali panjang seperti sediakala. +How did you know Tom was going to be fired? Bagaimana kamu tahu kalau Tom akan dipecat? +How long have you been waiting for the bus? Sudah berapa lama menunggu bus? +I am ashamed about what happened yesterday. Saya malu dengan kejadian kemarin. +I can pay no more than $50 a week for rent. Aku tidak bisa membayar lebih dari $50 seminggu untuk sewa. +I had to finish the job by the stated date. Aku harus menyelesaikan pekerjaan itu pada tanggal yang ditentukan. +I have been abroad several times this year. Saya sudah beberapa kali keluar negeri tahun ini. +I have something that I want to say to you. Ada hal yang ingin aku katakan padamu. +I have to make the best of that small room. Aku harus memanfaatkan ruang yang kecil itu sebaik-baiknya. +I have to withdraw some cash from the bank. Saya perlu mengambil uang di bank. +I just want to know what actually happened. Aku hanya ingin mengetahui apa yang sebenarnya terjadi. +I just wanted to check to see if you're OK. Aku cuma ingin melihat apa kamu baik-baik saja. +I met my teacher on the way to the station. Saya bertemu dengan guru saya dalam perjalanan ke stasiun. +I need Tom to do a couple of things for me. Aku perlu Tom melakukan beberapa hal untukku. +I never dreamed that I would meet you here. Tak pernah kubermimpi akan bertemu denganmu di sini. +I saw you driving by my house this morning. Aku melihatmu berkendara melewati rumahku pagi ini. +I thought for sure you'd left town already. Saya yakin kamu sudah meninggalkan kota. +I want everyone to hear what I have to say. Aku ingin semuanya mendengarkan apa yang aku katakan. +I'm sorry I wasn't able to do that for you. Maaf saya tidak bisa membantumu melakukan itu. +Is this computer connected to the Internet? Apa komputer ini terhubung pada internet? +It is getting colder and colder day by day. Makin hari makin dingin. +It takes 10 minutes to walk to the station. Memerlukan waktu 10 menit untuk bisa sampai ke stasiun dengan berjalan kaki. +It was Tom that broke the window yesterday. Yang memecahkan kaca kemarin adalah Tom. +Let me congratulate you on your engagement. Selamat atas pertunangan Anda. +Let's see if we can do it without any help. Mari kita lihat apakah kita bisa melakukannya tanpa bantuan apapun atau tidak. +Mary declined an invitation to the concert. Mary menolak undangan ke konser. +My brother is holding a camera in his hand. Kakakku memegang sebuah kamera di tangannya. +My fingers are so cold they have gone numb. Jari-jariku terasa sangat dingin sampai-sampai mati rasa. +My mother and father aren't home right now. Ibu dan ayah saya tidak di rumah sekarang. +My mother wants me to study in Switzerland. Ibu ingin aku kuliah di Swiss. +Nearly 80 percent of the land is mountains. Hampir 80 persen daerah ini adalah pegunungan. +Please turn right at the next intersection. Tolong belok kanan di persimpangan berikutnya. +Recent advances in medicine are remarkable. Beberapa kemajuan dalam ilmu kedokteran belakangan ini sangat menakjubkan. +Sapporo is the fifth largest city in Japan. Sapporo merupakan kota terbesar kelima di Jepang. +She has the bad habit of always being late. Dia punya kebiasaan buruk selalu datang terlambat. +She seems to have left for Tokyo yesterday. Tampaknya dia telah meninggalkan Tokyo kemarin. +Someone broke into my apartment last night. Seseorang mendobrak masuk apartemenku semalam. +That's why he did not go overseas to study. Karena itulah dia tidak pergi belajar ke luar negeri. +The bridge had been built before that time. Jembatannya telah dibangun sebelum waktu itu. +The king imposed heavy taxes on his people. Raja itu mengenakan pajak yang tinggi pada rakyatnya. +There are more women than men in the world. Ada lebih banyak perempuan daripada laki-laki di dunia. +There is nothing like summer and ice cream. Tidak ada yang lebih baik dari musim panas dan es krim. +This is too hard a problem for me to solve. Permasalahan ini terlalu sulit bagi saya untuk menyelesaikannya. +Tom and Mary have recently moved to Boston. Tom dan Mary pindah ke Boston baru-baru ini. +Tom burned his fingers on a hot frying pan. Jari Tom terbakar setelah tidak sengaja menyentuh wajan penggorengan yang panas. +Tom could tell that Mary was pretty scared. Tom dapat mengatakan bahwa Mary cukup ketakutan. +Tom didn't know what Mary thought about it. Tom tidak tahu apa yang Mary pikirkan tentang hal itu. +Tom doesn't get invited to parties anymore. Tom tidak lagi diundang ke pesta. +Tom doesn't seem to be having any problems. Tom tidak terlihat memiliki masalah. +Tom doesn't think this is such a good idea. Tom merasa ini bukan ide yang baik. +Tom has never lived anywhere except Boston. Tom tidak pernah tinggal di tempat lain selain Boston. +Tom hasn't had a fight with anybody lately. Tom tidak berkelahi dengan siapa pun akhir-akhir ini. +Tom loved Mary, who didn't love him at all. Tom mencintai Mary yang tidak mencintainya sama sekali. +Tom made good use of the money we lent him. Tom menggunakan uang pinjaman kita dengan baik. +Tom never told anybody about what happened. Tom tidak pernah memberitahu siapapun tentang apa yang terjadi. +Tom never would've dated someone like Mary. Tom tidak akan pernah berkencan dengan seseorang seperti Mary. +Tom picked the diamond up and looked at it. Tom mengambil intan dan mengamatinya. +Tom read Mary's letter over and over again. Tom membaca surat Mary berulang kali. +Tom turned off the light and went to sleep. Tom mematikan lampu dan pergi tidur. +Tom was punished for not telling the truth. Tom dihukum karena tidak berkata jujur. +Tom was standing at the foot of the stairs. Tom berdiri di atas anak tangga. +We are going to cycle to the lake tomorrow. Kami akan bersepeda ke danau besok. +We can't have a press conference on Friday. Kita tidak dapat mengadakan konferensi pers pada hari Jumat. +What do you call this vegetable in English? Apa bahasa Inggrisnya sayuran ini? +Which do you like better, summer or winter? Mana yang lebih kamu suka: musim panas atau musim dingin? +Which do you like better, summer or winter? Kamu lebih suka musim panas atau musim dingin? +You should trust me when I tell you things. Kau harus percaya padaku saat aku memberitahumu sesuatu. +You will feel better after a night's sleep. Kamu akan merasa lebih baik setelah tidur malam. +"How old is she?" "She is twelve years old." "Berapa umurnya?" "Dia dua belas tahun." +A number of people die in traffic accidents. Sejumlah orang meninggal dalam kecelakaan lalu-lintas. +Do it your own way if you don't like my way. Lakukan caramu sendiri kalau kamu tidak menyukai caraku. +Do you know anything about fixing computers? Kamu tahu sesuatu tentang memperbaiki komputer? +Do you think you could make it before lunch? Kamu kira bisa selesai sebelum makan siang? +Even the strongest man can't stop a typhoon. Bahkan orang terkuat pun tidak bisa menghentikan angin topan. +Few treasures are worth as much as a friend. Seorang teman sama berharganya dengan harta. +From now on, let's eat lunch in the kitchen. Mulai sekarang, mari kita makan siang di dapur. +He was relieved of his heavy responsibility. Dia telah terbebas dari tanggung jawabnya yang berat. +I am in no position to do anything about it. Saya tidak punya kapasitas untuk mengatasi hal ini. +I can't understand what he is trying to say. Saya tidak paham apa yang ia coba katakan. +I don't think I'll be able to pass the test. Sepertinya saya tidak akan bisa lulus tes. +I don't want to work under these conditions. Aku tidak ingin bekerja dalam kondisi ini. +I forgot Tom knew how to play the accordion. Aku lupa kalau Tom tahu cara memainkan akordion. +I have to think about what needs to be done. Saya harus berpikir tentang apa yang harus diselesaikan. +I just can't stand this hot weather anymore. Aku sudah tidak tahan lagi dengan cuaca panas ini. +I suggest we stay home and watch television. Sebaiknya kita di rumah dan menonton televisi. +I think I mistakenly sent that email to Tom. Saya rasa saya telah salah mengirim surel itu ke Tom. +I think this is beside the point, right now. Aku pikir ini tidak ada hubungannya, untuk saat ini. +I will give you a bicycle for your birthday. Aku akan berikan kamu sepeda di hari ulang tahunmu. +I'd like to put something in the hotel safe. Aku mau menyimpan sesuatu di brankas hotel. +I'd like to show this picture of Tom to you. Aku ingin menunjukkan foto Tom ini kepadamu. +I'll call for you at eight tomorrow morning. Aku akan menjemputmu jam delapan besok pagi. +I'm colorblind. I can't tell red from green. Saya buta warna, Saya tidak dapat membedakan merah dan hijau. +If you take a nap here, you'll catch a cold. Kalau kamu tidur di sini, nanti kamu kena pilek. +It seems a waste of time to wait any longer. Sepertinya akan membuang-buang waktu jika kita menunggu lebih lama lagi. +It's unclear if they love each other or not. Belum jelas apakah mereka saling mencintai. +Keep all medicines out of reach of children. Jauhkan obat-obatan dari jangkauan anak-anak. +Kyoto is famous for its shrines and temples. Kyoto terkenal dengan kuil dan viharanya. +Let's do this again. It's been a lot of fun. Mari kita melakukannya lagi. Ini sangat menyenangkan. +Mary is a girl who is pleasant to talk with. Mary adalah gadis yang enak diajak bicara. +Nobody knows what will happen in the future. Tidak seorang pun akan tahu apa yang akan terjadi di masa depan. +Please write down your contact address here. Tolong tulis alamat dan nomor kontak Anda di sini. +She couldn't convince him to ask for a loan. Dia tidak dapat membujuknya untuk memberinya pinjaman. +She left for Paris at the end of last month. Dia meninggalkan Paris akhir bulan yang lalu. +She was chosen from ten thousand applicants. Dia terpilih dari sepuluh ribu pendaftar lainnya. +Take hold of the rope, and I'll pull you up. Eratkan talinya, dan saya akan menarik kamu ke atas. +The beach was closed due to shark sightings. Pantainya tutup dikarenakan penampakan hiu. +The bus was late because of the traffic jam. Busnya terlambat karena lalu lintas yang macet. +The bus was late because of the traffic jam. Busnya terlambat karena kemacetan lalu lintas. +The doctor persuaded him to give up smoking. Doktor membujuknya untuk berhenti merokok. +The fireman could not extinguish the flames. Petugas pemadam itu tidak dapat menjinakkan api. +The government has been reforming education. Pemerintah terus memperbarui sistem pendidikan. +The island is about two miles off the coast. Pulau itu terletak dua mil dari pantai. +The police promised to look into the matter. Pihak kepolisian berjanji untuk menyelidiki kasus itu. +The population of the city is about 100,000. Populasi kota ini adalah sekitar 100,000 jiwa. +The road which leads to the hotel is narrow. Jalan yang menuju arah hotel itu sempit. +The station is a ten minute drive from here. Stasiunnya berjarak 10 menit dari sini dengan kendaraan. +The thief forced her to hand over the money. Perampok itu memaksanya untuk menyerahkan uangnya. +The trouble is that I have no money with me. Masalahnya saya tidak punya uang. +The two boys look more alike than I thought. Kedua anak laki-laki itu ternyata lebih mirip daripada yang aku pikirkan. +Tom barely avoided crashing into Mary's car. Tom nyaris menabrak mobil Mary. +Tom doesn't know anything about Mary's plan. Tom tidak mengetahui apapun tentang rencana Mary. +Tom doesn't play golf as much as he used to. Tom tidak lagi sering bermain golf seperti dulu. +Tom is still being questioned by the police. Saat ini Tom masih dimintai kesaksian oleh polisi. +Tom isn't as good a golfer as he says he is. Tom bukan pemain golf yang baik, sebaik yang ia katakan. +Tom just stood there watching everybody eat. Tom berdiri di sana sambil melihat semua orang makan. +Tom promised not to go out after dark alone. Tom berjanji untuk tidak pergi keluar tengah malam sendirian. +Tom said he didn't know why Mary was absent. Tom bilang dia tidak tahu kenapa Mary absen. +Tom wants to know when we're going to leave. Tom ingin tahu kapan kita akan berangkat. +Tom was badly injured in a traffic accident. Tom terluka parah saat kecelakaan lalu-lintas. +Tom works for a large financial institution. Tom bekerja untuk sebuah lembaga keuangan yang besar. +Tom's eyes are red, and he looks very tired. Mata Tom merah, dan ia terlihat sangat lelah. +Tom's situation is getting more complicated. Situasi Tom menjadi semakin sulit. +Traffic lights are used to regulate traffic. Lampu lalu-lintas digunakan untuk mengatur lalu lintas. +We collect stamps from all around the world. Kami mengumpulkan perangko dari seluruh dunia. +We have more music coming up, so stay tuned. Masih ada banyak musik yang akan kami putar, jadi jangan ke mana-mana. +We were late as a result of the traffic jam. Kami terlambat akibat dari kemacetan lalu lintas. +What is the most romantic city in the world? Kota apa yang paling romantis di dunia? +What time will the train arrive in Yokohama? Pada jam berapa kereta akan sampai di Yokohama? +What's your favorite non-alcoholic beverage? Apa minuman tidak beralkohol kesukaanmu? +Whatever he may say, I won't change my mind. Apapun yang dia bilang, aku tidak akan berubah pikiran. +Whatever you may say, you won't be believed. Apapun yang kau katakan tidak akan dipercaya. +Who was it that bought this skirt yesterday? Siapa yang membeli rok ini kemarin? +Why did you let Tom go to Boston by himself? Kenapa kamu membiarkan Tom pergi ke Boston sendirian? +Would you please help me carry my suitcases? Bisakah Anda membantu saya membawa koper-koper ini? +You are the only one who can save the world. Kamu satu-satunya yang bisa menyelamatkan dunia. +You know many interesting places, don't you? Anda mengetahui banyak lokasi yang menarik ya? +You made the mistake on purpose, didn't you? Kamu membuat kesalahan dengan sengaja, kan? +You may not remember me, but I remember you. Kau mungkin tidak mengingatku, tapi aku mengingatmu. +You're the only one I can count on for help. Kamu satu-satunya yang bisa aku andalkan untuk membantuku. +Zoology deals with the study of animal life. Zoologi adalah ilmu yang mempelajari tentang hewan. +A man whose wife is dead is called a widower. Pria yang istrinya telah meninggal dunia disebut seorang duda. +A photographer took a photograph of my house. Seorang fotografer mengambil gambar rumahku. +At last, I graduated from junior high school. Akhirnya saya lulus SMP. +Both my mom and my dad aren't home right now. Ibu dan ayah saya tidak di rumah sekarang. +Broken glass lay scattered all over the road. Pecahan kaca berserakan di sepanjang jalan. +Children were running to and fro in the park. Anak-anak berlari ke sana kemari di taman. +Do you really think that was what Tom wanted? Apa kamu benar-benar berpikir kalau itu adalah apa yang Tom inginkan? +Do you want me to wait until you come for me? Apa kau ingin aku menunggu sampai kau datang? +Drivers should be aware of the traffic rules. Pengemudi harus mematuhi(perduli) peraturan lalu-lintas +During the night, everything looks different. Pada malam hari, semuanya terlihat berbeda. +Even though it is raining, he will play golf. Meskipun sedang turun hujan, dia akan tetap bermain golf. +Go straight ahead until you reach the church. Terus jalan lurus hingga tiba di gereja tersebut. +Have you ever seen a spider spinning its web? Apa kamu pernah melihat laba-laba membuat sarangnya? +He gathered the courage to decline the offer. Dia mengumpulkan keberanian untuk menolak tawaran itu. +He's always looking at you. He must love you. Dia selalu melihatmu. Dia pasti jatuh cinta kepadamu. +He's the manager of the marketing department. Dia manajer dari departemen pemasaran. +I am hungry because I did not have breakfast. Saya lapar karena saya tidak sarapan. +I arrived at Narita the day before yesterday. Aku sampai di Narita kemarin lusa. +I don't have a choice. I have to do this now. Aku tidak punya pilihan. Aku harus melakukan ini. +I don't think Tom will be at school tomorrow. Aku tidak berpikir kalau Tom akan ada di sekolah besok. +I don't think you realize what you're saying. Aku tidak yakin kalau kau sadar akan apa yang kau katakan. +I gave Tom a direct order, but he ignored it. Aku memberi Tom perintah langsung, tapi dia tidak mengacuhkannya. +I know that things haven't been easy for you. Saya mengerti bahwa hal itu tidak mudah bagi anda. +I met him by chance at the airport yesterday. Kemarin saya tidak sengaja bertemu dengannya di bandara. +I need to know why you didn't come yesterday. Aku perlu tahu mengapa kamu tidak datang kemarin. +I understand the museum is closed on Mondays. Setahu aku, museum itu tutup setiap hari Senin. +I wonder if I should really become a teacher. Aku penasaran apakah aku benar-benar harus menjadi seorang guru. +I'll do my best not to disturb your studying. Kulakukan yang terbaik agar tidak mengganggumu belajar. +I'm already accustomed to the heat of summer. Aku sudah terbiasa dengan panasnya musim panas. +I'm ashamed to ask you such a silly question. Saya malu menanyakan pertanyaan bodoh seperti itu. +I'm going to make a cake for Mary's birthday. Aku akan membuat kue untuk ulang tahun Marry. +I'm not angry at you, just very disappointed. Aku tidak marah padamu. Aku hanya sangat kecewa. +If we're going to do this, let's do it right. Jika kita mau melakukannya, mari kita lakukan dengan benar. +In that respect, I agree with you completely. Dalam hal itu, saya sepenuhnya setuju dengan Anda. +It looks like there's an elevator over there. Sepertinya ada lift di sekitar sana. +Let's do it at our own pace without hurrying. Mari kita melakukannya dengan tidak tergesa-gesa dan sesuaikan dengan kemampuan kita. +Never did I dream that I would meet you here. Tak pernah kubermimpi akan bertemu denganmu di sini. +People who drive cars should wear seat belts. Orang yang mengemudikan mobil harus mengenakan sabuk pengaman. +Please fill out the Customs Declaration Form. Silakan isi Pemberitahuan Pabean. +Seven is sometimes considered a lucky number. Angka tujuh terkadang dianggap sebagai angka keberuntungan. +She went to the train station to see him off. Dia pergi ke stasiun kereta untuk mengiringi keberangkatannya. +Take your umbrella with you in case it rains. Bawalah payung untuk berjaga-jaga kalau hujan. +Tell me if there's anything I can do to help. Beritahu aku kalau ada yang bisa kubantu. +The house is being painted by a professional. Rumah itu dicat oleh seorang profesional. +The kitten was drinking milk under the table. Anak kucing itu tadi sedang minum susu di bawah meja. +The kitten was drinking milk under the table. Anak kucing minum susu di bawah meja. +The middle aged man was charged with assault. Pria paruh baya itu digugat atas tuduhan penyerangan. +The president was visiting France that month. Presiden mengunjungi Prancis bulan itu. +These questions can be answered quite simply. Pertanyaan-pertanyaan ini bisa dijawab dengan cukup mudah. +This happened prior to receiving your letter. Kejadian ini terjadi sebelum aku menerima suratmu. +This is the same wallet as I lost a week ago. Ini dompet saya yang hilang minggu lalu. +This is the third longest river in the world. Ini adalah sungai terpanjang ketiga di dunia. +This novel was written by an American writer. Novel ini ditulis oleh penulis asal Amerika. +Tom broke Mary's expensive Chinese Ming vase. Tom memecahkan vas ming dari cina milik Mary yang mahal +Tom has lived in Boston for most of his life. Tom sebagian besar hidupnya tinggal di Boston +Tom is always telling Mary that he loves her. Tom selalu meyakinkan Mary bahwa dia benar-benar mencintainya +Tom is the only one who didn't pass the test. Tom adalah satu-satunya orang yang tidak lulus ujian. +Tom married a girl much younger than himself. Tom menikahi perempuan yang lebih mudah dari dirinya. +Tom probably already knows that Mary is here. Tom kemungkinan sudah tahu kalau Mary di sini. +Tom told me he thought I was wasting my time. Tom bilang padaku kalau dirinya berpikir aku membuang-buang waktu. +Tom wanted save up enough money to buy a car. Tom ingin menyisihkan uangnya hingga cukup untuk membeli sebuah mobil. +Tom was arrested on drug-trafficking charges. Tom ditahan atas tuduhan perdagangan narkoba. +Tom was late for class, as is often the case. Seperti biasa, Tom terlambat datang ke kelas. +Tom was surprised that Mary had a motorcycle. Tom terkejut mengetahui Mary memiliki sepeda motor. +Tom wondered if Mary could understand French. Tom ingin tahu apakah Mary bisa memahami bahasa Prancis. +Tom's Japanese is improving little by little. Kemampuan bahasa Jepang Tom meningkat sedikit demi sedikit. +Tom's gym teacher is Mary's basketball coach. Guru senam Tom adalah pelatih basket Mary. +Turn off the television. I can't concentrate. Matikan televisinya. Aku tidak bisa berkonsentrasi. +Two hundred people died of cholera last year. Dua ratus orang meninggal karena kolera tahun lalu. +What on earth spurred them to such an action? Sebenarnya apa yang mendorong mereka untuk melakukan tindakan seperti itu? +You forgot to warn us not to drink the water. Kau lupa memperingatkan kami untuk tidak meminum airnya. +You had better not speak loudly in this room. Lebih baik kamu jangan bicara keras-keras di ruangan ini. +You must return the book by the end of April. Kamu harus mengembalikan bukunya sebelum akhir April. +British people are used to standing in queues. Orang Inggris terbiasa untuk berdiri untuk mengantri. +Croatia is in the southeastern part of Europe. Kroasia berada di bagian tenggara Eropa. +Do you think that really matters to any of us? Apa kau pikir itu penting bagi kami? +He is the manager of the marketing department. Dia adalah manajer dari departemen pemasaran. +How many flights to Boston do you offer a day? Berapa banyak penerbangan ke Boston yang ditawarkan dalam sehari? +I can talk about anything with my best friend. Aku bisa bercerita tentang banyak hal dengan sahabatku. +I cannot thank you enough for your assistance. Sungguh terima kasih atas bantuannya. +I caught sight of him escaping from that shop. Aku melihatnya melarikan diri dari toko itu. +I don't know for certain when he'll come back. Saya tidak tahu pasti kapan dia akan kembali. +I had to make a list of things I needed to do. Aku harus membuat daftar tentang hal apa saja yang perlu aku lakukan. +I had to walk there because my car broke down. Aku harus berjalan ke sana karena mobilku mogok. +I just assumed that Mary was Tom's girlfriend. Saya beranggapan bahwa Mary adalah pacarnya Tom +I often spend my free time listening to music. Saya sering menghabiskan waktu luang dengan mendengarkan musik. +I should probably just toss this in the trash. Mungkin lebih baik aku buang saja ini ke tempat sampah. +I spend too much time in front of my computer. Aku terlalu banyak menghabiskan waktu di depan komputerku. +I thought you might be able to give me a hand. Aku berpikir kalau mungkin kau bisa membantuku. +I want to find out if Tom was at school today. Aku mau mencari tahu apakah Tom ada di sekolah hari ini. +I've been in that line of work for five years. Aku sudah melakukan pekerjaan itu selama lima tahun. +If Tom was angry before, he'll be furious now. Jika sebelumnya Tom marah, dia akan menjadi sangat marah sekarang ini. +Instead of going to school, he stayed at home. Bukannya sekolah, dia malah di rumah. +Knowing is nothing, imagination is everything. Pengetahuan itu bukan apa-apa, tetapi imaginasi adalah segalanya. +Odd, isn't it? We should have already arrived. Aneh bukan? Kita seharusnya telah tiba. +Our neighbors were forced to sell their house. Tetangga kita dipaksa untuk menjual rumahnya. +President Reagan's tax program has not worked. Program pajak Presiden Reagan tidak berfungsi. +She asked me for an unreasonable sum of money. Dia meminta uang kepadaku dalam jumlah yang tidak masuk akal. +She will be seventeen years old next February. Usianya akan menjadi tujuh belas tahun pada bulan Februari berikutnya. +Thanks to a cold summer, beer has sold poorly. Akibat musim panas yang dingin, bir menjadi tidak begitu laku. +The accident happened on Sunday at about 3:00. Kecelakaan itu terjadi pada hari Minggu sekitar pukul 3. +The holiday traffic crawled along the highway. Pada hari libur lalu-lintas merayap sepanjang jalan raya. +The island is six times the size of Manhattan. Pulau itu besarnya enam kali luas Manhattan. +The more I think about it, the less I like it. Semakin aku memikirkannya, semakin aku tidak menyukainya. +The population explosion is a serious problem. Ledakan populasi adalah masalah yang serius. +The teacher put a short comment on each paper. Guru menuliskan pendapat pendek pada masing-masing kertas tugas. +There are still people who are unable to read. Masih ada orang-orang yang tidak bisa membaca. +There were few students left in the classroom. Ada sedikit siswa yang tersisa di kelas. +They had not fought for more than forty years. Mereka sudah tidak bertarung selama lebih dari 40 tahun. +This room is capable of holding fifty persons. Ruangan ini bisa menampung lima puluh orang. +Thomas Edison invented the electric lightbulb. Thomas Edison menciptakan bola lampu listrik. +Tom accepts that what Mary said was the truth. Tom menerima bahwa apa yang dikatakan Mary adalah kenyataan. +Tom asked Mary if she wanted to go for a walk. Tom bertanya pada Mary apa ia ingin jalan-jalan. +Tom eats everything that his mother gives him. Tom memakan semua yang ibunya berikan padanya. +Tom had a little trouble finding Mary's house. Tom sedikit kesulitan untuk menemukan rumah Mary. +Tom has a friend whose father is an astronaut. Tom punya teman yang ayahnya seorang astronot. +Tom has been with our company for three years. Tom telah bekerja di perusahaan kami selama tiga tahun. +Tom is too old to be doing this kind of thing. Tom terlalu tua untuk melakukan hal semacam ini. +Tom probably doesn't know Mary's phone number. Tom kemungkinan tidak tahu nomor telepon Mary. +Tom wanted to spend some time alone with Mary. Tom ingin menghabiskan sedikit waktu berdua dengan Mary. +We've been asking the wrong kind of questions. Kita telah menanyakan jenis pertanyaan yang salah. +What is the highest mountain in North America? Apa gunung tertinggi di Amerika Utara? +What method do you use to organize your files? Metode apa yang Anda gunakan untuk mengatur berkas-berkas Anda? +What were you doing at that particular moment? Apa yang sedang kau lakukan pada saat itu? +Where did you get those strange-looking shoes? Dari mana kamu mendapatkan sepatu aneh itu? +Why don't the three of us have lunch together? Bagaimana kalau kita bertiga pergi makan siang bersama? +Why don't you just find another place to live? Kenapa kamu tidak mencari tempat lain untuk tinggal? +Would it be OK if I discussed it with my wife? Bolehkah kalau saya diskusikan dengan istri saya? +You are always complaining about your husband. Kamu selalu mengeluhkan suamimu. +You have to do it, whether you like it or not. Kamu harus melakukannya, suka tidak suka. +You know Tom is a friend of Mary's, don't you? Kamu tahu kalau Tom itu temannya Mary, kan? +A tsunami is coming, so please be on the alert. Tsunami sedang menerjang, jadi mohon berhati-hati. +All the apples that fall are eaten by the pigs. Semua apel yang jatuh dimakan oleh babi. +Almost all Japanese boys like to play baseball. Hampir semua anak laki-laki Jepang suka bermain bisbol. +Cars made in Japan are used all over the world. Mobil produksi Jepang digunakan di seluruh dunia. +Could I ask you to wait until tomorrow morning? Bisakah saya meminta Anda untuk menunggu hingga besok pagi? +Did you go anywhere during the summer vacation? Apakah kalian jalan-jalan selama liburan musim panas? +Do you have any idea why Tom doesn't like Mary? Apa kau tahu kenapa Tom tidak suka dengan Mary? +Frayed electrical cables can be very dangerous. Kabel listrik yang lecek bisa sangat berbahaya. +He said that he gets up at 6 o'clock every day. Dia mengatakan bahwa dia bangun pada jam 6 setiap hari. +He said the words came straight from his heart. Dia bilang perkataan itu keluar langsung dari hatinya. +He told me that he would visit Nara next month. Dia memberitahuku bahwa dia akan mengunjungi Nara bulan depan. +Heat and light are necessary for our existence. Panas dan terang dibutuhkan untuk eksistensi kita. +How many times have you played tennis with Tom? Sudah berapa kali kamu bermain tenis bersama Tom? +Human remains were found during the excavation. Beberapa peninggalan manusia ditemukan sewaktu penggalian. +I can't believe you're talking to me like this. Aku tidak percaya kau berbicara padaku seperti ini. +I don't like my brother climbing the mountains. Aku tidak suka kalau adikku mendaki gunung. +I got a letter from a friend of mine in London. Aku dapat surat dari temanku di London. +I guess the laundry isn't getting done tonight. Sepertinya, cuciannya tak akan selesai malam ini +I hadn't bargained on such a heavy traffic jam. Aku tidak bisa tawar menawar dengan kemacetan yang parah seperti ini. +I think one of us ought to attend that meeting. Aku pikir salah satu dari kita harus menghadiri rapat itu. +I want to have a talk with him about my future. Aku ingin berbicara dengannya tentang masa depanku. +I wonder if Tom still remembers how to do that. Saya berandai-andai apakah Tom masih mengingat bagaimana cara untuk melakukannya. +I'd like to find out where our meeting will be. Aku ingin mencari tahu dimana rapat kita akan diadakan. +I'll let you know the results as soon as I can. Saya akan menunjukkan hasilnya secepatnya. +I've been asked to forward this message to you. Saya diminta untuk meneruskan pesan ini kepadamu. +Isn't that where I taught you how to water ski? Bukankah itu adalah tempat dimana aku mengajarimu bagaimana caranya bermain ski air? +It seemed that there was no one in the village. Sepertinya tidak ada orang di desa. +James Cameron created a new way to make movies. James Cameron membuat cara baru dalam membuat film. +Please feel free to eat anything in the fridge. Silahkan nikmati segala macam makanan yang ada di dalam lemari es. +Rice is usually eaten with chopsticks in Japan. Nasi biasa dimakan dengan sumpit di Jepang. +She has tried various methods of slimming down. Dia telah mencoba berbagai cara melangsingkan badan. +That island was governed by France at one time. Pulau itu pernah diperintah Prancis. +The actor died at the height of his popularity. Aktor itu meninggal di puncak popularitasnya. +The government imposed a new tax on cigarettes. Pemerintah memberlakukan pajak baru pada rokok. +The hunting dogs followed the scent of the fox. Para anjing pemburu mengikuti bau dari rubah itu. +The professor's boring lecture put me to sleep. Profesor memberi yang memberi kuliah membosankan membuatku tertidur. +The table takes up a lot of space in this room. Meja itu makan banyak tempat di ruangan ini. +The teacher assembled the students in the hall. Guru itu mengumpulkan para siswa di aula. +There are lots of things for us to think about. Ada banyak hal yang harus kami pikirkan. +There is an urgent need for experienced pilots. Ada kebutuhan mendesak akan pilot-pilot yang berpengalaman. +There shouldn't be any commas in this sentence. Semestinya tidak ada koma pada kalimat ini. +This book is worth reading over and over again. Buku ini layak dibaca berulang-ulang. +Tom and Mary have been dating for three months. Tom dan Mary telah berkencan selama tiga bulan. +Tom and Mary were standing close to each other. Tom dan Mary berdiri berdekatan satu sama lain. +Tom certainly isn't the genius he thinks he is. Tom tidaklah sejenius yang dia pikirkan. +We are going to have a party on Saturday night. Kami akan mengadakan sebuah pesta pada malam Sabtu. +We know Tom will do whatever we tell him to do. Kami tahu Tom akan melakukan apa saja yang kami perintahkan. +What have you been doing these past few months? Apa yang kamu lakukan dalam beberapa bulan ini? +What kind of music do you want at your wedding? Jenis musik apa yang Anda inginkan pada pernikahan Anda? +What's made you decide to work for our company? Apa yang membuat Anda memutuskan untuk bekerja di perusahaan kami? +What's your favorite free software application? Software aplikasi apakah yang paling kamu sukai? +You had better not play on his generous nature. Lebih baik kamu tidak mengambil keuntungan dari kebaikan hatinya. +You won't get there on time if you don't hurry. Kau tidak akan tiba di sana tepat waktu jika kau tidak buru-buru. +A child could not have understood the situation. Anak kecil tidak bisa memahami situasi itu. +A customs official asked me to open my suitcase. Petugas Bea dan Cukai meminta saya untuk membuka koper saya. +Did you really expect him to tell you the truth? Apa kau benar-benar berpikir bahwa ia mengatakan yang sejujurnya kepadamu? +Do you know the real reason that Tom isn't here? Apa kamu tahu alasan sebenarnya mengapa Tom tidak berada di sini? +Don't pat me on the head like I'm still a child! Jangan mengelus-elus kepalaku seakan aku ini masih anak kecil! +European currencies weakened against the dollar. Mata uang Eropa melemah terhadap dolar. +Five years have passed since they came to Japan. Sudah lima tahun berlalu, semenjak mereka datang ke Jepang. +He came across this old coin in an antique shop. Dia tidak sengaja menemukan koin tua ini di toko barang antik. +He can't run his own family, let alone a nation! Dia tidak becus mengatur keluarganya sendiri, apalagi sebuah negara! +He declined my request, saying that he was busy. Dia menolak permintaanku dengan mengatakan bahwa dia sibuk. +He hasn't come yet. He must have missed the bus. Dia belum datang. Dia pasti ketinggalan bis. +He regretted having borrowed that book from her. Dia menyesal telah meminjam buku itu darinya. +I can't stop thinking about what they did to me. Aku tak bisa berhenti memikirkan apa yang telah mereka lakukan padaku. +I could not accept that my wife was really dead. Saya tidak dapat menerima bahwa istri saya benar-benar sudah meninggal. +I have the feeling that I'll sleep well tonight. Rasanya malam ini aku bisa tidur nyenyak. +I just lay on the beach and watched people swim. Aku hanya berbaring di pantai dan melihat orang-orang berenang. +I remember hearing a very similar story to that. Aku ingat pernah mendengar cerita yang sangat mirip dengan itu. +I studied really hard in order to pass the exam. Aku belajar dengan keras untuk lulus ujian. +I was able to do it with a little help from Tom. Aku bisa melakukannya dengan sedikit bantuan dari Tom. +I will be working on my report all day tomorrow. Besok aku akan mengerjakan laporanku seharian. +If Tom had seen anything, he would have told us. Jika Tom melihat sesuatu, dia pasti sudah memberitahu kita. +If anybody could convince Tom, it would be Mary. Marylah satu-satunya yang dapat membujuk Tom. +If you really want to help, please come by 2:30. Kalau kau benar-benar ingin membantu, tolong datang jam 2:30. +In Japan, we drive on the left side of the road. Di jepang kami menyetir kendaraan pada sisi kiri jalan. +In a way you are right, but I still have doubts. Di satu sisi kamu memang benar, tapi aku masih ragu. +Is it true that men have oilier skin than women? Benarkah bahwa kulit pria lebih berminyak daripada kulit wanita? +It's been a long time since I've seen my family. Sudah lama sekali sejak aku terakhir bertemu keluargaku. +Let's see if Tom can manage to do it by himself. Mari kita lihat apakah Tom bisa mengurusnya sendiri atau tidak. +My father insisted I should go to see the place. Ayahku bersikeras memintaku untuk pergi melihat tempat itu. +That team has little, if any, chance of winning. Tim itu memiliki kesempatan yang kecil untuk menang. +That was the first time I had ever driven a car. Itu adalah pertama kali saya pernah mengemudikan mobil +The colony has not declared independence as yet. Daerah jajahan itu masih belum menyatakan kemerdekaannya. +The student hall is for benefit of the students. Aula siswa dibuat demi kepentingan para siswa. +Tom asked Mary to teach him how to do the waltz. Tom meminta Mary untuk mengajarinya bagaimana caranya berdansa wals. +Tom is much more relaxed when Mary isn't around. Tom jauh lebih santai ketika Mary tidak ada. +Tom lowered his voice so no one else could hear. Tom mengecilkan suaranya sehingga tidak ada orang yang dapat mendengarnya. +Tom promised me he'd never come back here again. Tom berjani padaku bahwa dia tidak akan pernah kembali kemari lagi. +Tom, you're pretending to be asleep, aren't you? Tom, kamu pura-pura tidur, ya? +We often hear about an energy crisis these days. Kami sering mendengar tentang krisis energi akhir-akhir ini. +We're not entirely sure why Tom did what he did. Kami tidak mengerti kenapa Tom melakukan apa yang dilakukannya. +What matters is whether you do your best or not. Yang penting adalah apakah kamu melakukan yang terbaik atau tidak. +What you do is more important than what you say. Apa yang kamu lakukan lebih penting daripada apa yang kamu katakan. +You plan to go out dancing with Mary, don't you? Bukankah kamu berencana untuk pergi berdansa dengan Mary? +You should obey the traffic laws when you drive. Anda harus mematuhi aturan lalu lintas saat berkendara. +"Can I use your dictionary?" "Yes, here you are." "Boleh pinjam kamusnya?" "Iya, boleh." +A nice day, isn't it? How about going for a swim? Hari ini cerah ya? Gimana kalo kita pergi berenang? +After the rain, there were puddles on the street. Setelah hujan, di jalanan terdapat banyak lubang yang tergenang air. +Excuse me, could you pass me the salt and pepper? Maaf, bisa tolong ambilkan garam dan mericanya? +Half of the world’s population lives in cities. Setengah dari penduduk dunia tinggal di perkotaan. +He once knew her, but they are no longer friends. Dia pernah mengenalnya, tetapi mereka tidak lagi berteman. +He probably got tired of waiting and fell asleep. Dia mungkin lelah menunggu dan tertidur. +He ran so fast that I couldn't catch up with him. Dia berlari sangat cepat sampai-sampai aku tidak bisa mengejarnya. +He really enjoys and appreciates classical music. Dia sangat menikmati dan mengapresiasi musik klasik. +He went to New York as soon as he got the letter. Ia pergi ke New York segera setelah ia menerima surat itu. +Her composition had no grammatical errors at all. Sama sekali tidak ada kesalahan tata bahasa pada karangannya. +Here is a list of things you should avoid eating. Ini adalah daftar makanan yang harus kamu hindari. +I always have a couple of beach towels in my car. Aku selalu punya beberapa handuk pantai di mobilku. +I assume that Tom doesn't have that many friends. Aku kira Tom tidak memiliki teman sebanyak itu. +I have a friend whose father is a famous pianist. Aku punya teman yang bapaknya seorang pianis yang terkenal. +I lost my bearings when I came out of the subway. Aku kehilangan kesabaranku ketika keluar dari kereta bawah tanah. +I realize you're anxious to finalize the details. Aku tahu kalau kamu sudah tidak sabar untuk menyempurnakan rinciannya. +I was the only one who didn't fall into the trap. Saya satu-satunya yang tidak masuk dalam jebakan. +I wonder what we'll be doing this time next year. Saya penasaran, apa yang akan kita lakukan saat ini di tahun depan. +If you see her from a distance, she is beautiful. Dia cantik kalau kamu melihatnya dari jauh. +It's necessary to go through customs on arriving. Kita wajib melalui pemeriksaan bea dan cukai saat kedatangan. +Let's talk about what we're going to do about it. Mari kita bicara tentang apa yang akan kita lakukan dengan hal itu. +My first day in the university was rather boring. Hari pertama saya di universitas agak membosankan. +My grandmother is still vigorous at 82 years old. Nenekku masih semangat/kuta di usianya yang 82 tahun. +My grandmother passed away peacefully last night. Nenekku meninggal dengan tenang semalam. +My uncle died of cancer of the stomach yesterday. Kemarin, pamanku meninggal karena kanker perut yang dideritanya. +Neptune is the eighth planet of the solar system. Neptunus adalah planet kedelapan dalam tata surya. +No matter what you say, I just won't believe you. Walau mau bicara apapun, saya sudah tidak bisa mempercayaimu. +Something is always going wrong with the machine. Selalu saja ada yang rusak pada mesin itu. +Speaking about trips, have you ever been to Kobe? Berbicara tentang wisata, apa kau pernah ke Kobe? +Tango lives with a small boy in a little village. Tango tinggal dengan seorang anak laki-laki di sebuah desa kecil. +That is the funniest joke that I have ever heard. Itu adalah lelucon terlucu yang pernah saya dengar. +That was probably what influenced their decision. Itu mungkin yang mempengaruhi keputusan mereka. +The boy said that the taxi vanished into the fog. Anak itu bilang bahwa taksi tersebut telah lenyap di dalam kabut. +The bus rattled as it drove along the bumpy road. Bus itu berderak-derak saat melaju di sepanjang jalan bergelombang itu. +There are a lot of famous old buildings in Kyoto. Ada banyak bangunan tua yang terkenal di Kyoto. +This is the house where I lived when I was young. Ini adalah rumah dimana aku tinggal saat aku muda. +Tom didn't want to come here, but he came anyway. Tom katanya tidak ingin datang, tetapi dia datang juga. +Tom didn't want to make the same mistake as Mary. Tom tidak ingin membuat kesalahan yang sama seperti Mary. +Tom has attempted to escape at least three times. Tom telah melakukan sedikitnya tiga kali usaha untuk melarikan diri. +Tom likes the same kind of stuff that Mary likes. Tom menyukai jenis barang yang sama dengan yang Mary suka. +Tom seems to have changed his mind about staying. Tom sepertinya tidak lagi berniat untuk tinggal. +Tom told Mary that he didn't have to do anything. Tom memberitahu Mary bahwa dia tidak ingin melakukan apapun. +Tom woke up the next day with a painful hangover. Keesokan harinya, Tom bangun dengan sakit kepala yang sangat. +Tom wrote me more than thirty messages yesterday. Tom mengirimiku tiga puluh lebih pesan kemarin. +We've decided to move the meeting to next Sunday. Kami telah memutuskan untuk menunda rapat hingga hari Minggu berikutnya. +What language do they speak in the United States? Bahasa apa yang digunakan di Amerika Serikat +Whether you like it or not, you'll have to do it. Suka atau tidak, kamu harus tetap melakukannya. +You don't want Tom to think you're crazy, do you? Kau tidak ingin Tom berpikir kalau kau gila, kan? +Could you find me a house that has a small garden? Dapatkah Anda membantu saya mencarikan rumah dengan sebuah taman kecil? +Do you know any restaurants with good Korean food? Apakah Anda mengetahui rumah makan masakan Korea yang enak? +His speech made a deep impression on the students. Perkataannya telah membuat kesan yang dalam terhadap murid-murid. +I can't afford to shop at such an expensive store. Aku tidak sanggup kalau harus berbelanja di toko semahal itu. +I don't want to hear any more of your complaining. Aku tidak ingin mendengar keluhanmu lagi. +I have a friend whose father is a famous novelist. Aku punya teman yang ayahnya novelis terkenal. +I just got up. Give me a few minutes to get ready. Saya baru bangun. Lima menit lagi saya siap. +I just wanted to see if you were paying attention. Aku hanya ingin tahu apakah kamu memperhatikan atau tidak. +I know the boy who is sitting closest to the door. Aku kenal anak yang duduk paling dekat dengan pintu. +I should go home before my parents start to worry. Aku harus pulang sebelum orang tuaku menjadi khawatir. +I stopped sending Christmas cards a few years ago. Aku berhenti mengirimkan kartu Natal beberapa tahun yang lalu. +I tried to help her, but there was no way I could. Aku mencoba untuk menolongnya, tetapi tidak ada cara bagiku untuk bisa menolongnya. +If I'm reincarnated, I want to come back as a cat. Kalau aku reinkarnasi, aku ingin terlahir kembali sebagai kucing. +Is there anything else we need to do before we go? Apa ada hal lain yang perlu kami lakukan sebelum kami pergi? +It's one of the most polluted cities in the world. Kota itu adalah salah satu kota paling berpolusi di dunia. +Let's approach the problem from a different angle. Mari melakukan pendekatan terhadap masalah ini dari sudut yang berbeda. +Nikita Khrushchev was at the height of his powers. Nikita Khrushchev ada di puncak kekuatannya. +She asked him to help her father clean the garage. Ia memintanya untuk membantu ayahnya membersihkan garasi. +She is still financially dependent on her parents. Dia masih bergantung secara finansial kepada orang tuanya. +The baby was in a deep sleep in his mother's arms. Bayi itu tidur sangat lelap di pelukan ibunya. +The local coffee shop was replaced by a Starbucks. Toko kopi lokal telah digantikan dengan Starbucks. +There are cherry trees on each side of the street. Ada pohon ceri di setiap sisi jalan. +This is a picture of my father and his first wife. Ini adalah gambar dari ayahku dan istri pertamanya. +Tom has to meet Mary in the park tomorrow at 2:30. Tom harus bertemu Mary besok di taman pada pukul 2:30. +Tom made it clear that he didn't want to see Mary. Tom mempertegas bahwa dia tidak ingin bertemu dengan Mary. +Tom played baseball after school with his friends. Tom bermain kasti dengan teman-temannya setelah selesai sekolah. +We realize now that Tom knew exactly who Mary was. Kami akhirnya menyadari bahwa Tom telah mengetahui siapa Mary sebenarnya. +We should have paid attention to the announcement. Kita seharusnya memperhatikan pengumuman itu dengan benar. +We should tell children how to protect themselves. Kita harus memberitahukan kepada anak-anak bagaimana caranya melindungi diri sendiri. +What was your mother doing when you returned home? Apa yang dilakukan ibumu saat kamu kembali ke rumah. +When angry, count to four. When very angry, swear. Kalau marah, hitung sampai empat. Kalau sangat marah, menyumpah. +Would you like to get together again next weekend? Mau kumpul-kumpul lagi akhir pekan depan? +Would you like to go out and get something to eat? Maukah anda untuk jalan jalan dan mencari makanan? +Would you rather be fat and ugly or thin and sexy? Kamu lebih memilih menjadi gemuk dan jelek atau langsing dan seksi? +You can't have dessert until you finish your meal. Kamu tidak boleh makan pencuci mulut sampai kamu menghabiskan makananmu. +"Have you seen my cell phone?" "It's on the table." "Apakah kau melihat ponselku?" "Ada di meja." +How long does it take to the train station by taxi? Berapa lama menuju stasiun dengan taksi? +I am meeting my mother at the station at 4 o'clock. Saya akan menemui ibu saya di stasiun pada pukul 4 tepat. +I couldn't sleep well because it was noisy outside. Aku tidak bisa tidur nyenyak karena diluar berisik. +I frequently think about my mother who passed away. Aku sering kali memikirkan ibuku yang telah meninggal. +I hurt my eye when my contact slipped out of place. Mataku sakit saat lensa kontakku bergeser. +I ran across a rare book in a secondhand bookstore. Aku kebetulan menemukan sebuah buku yang langka di toko buku bekas. +I'll only buy the car if they fix the brakes first. Aku baru akan membeli mobilnya jika mereka terlebih dahulu memperbaiki remnya. +I'm convinced that Tom isn't telling us everything. Saya yakin Tom tidak menceritakan semuanya pada kita. +I'm trying to memorize the names of constellations. Saya sedang mencoba menghafalkan nama-nama rasi bintang +If I were to tell him the truth, he would be angry. Kalau aku katakan padanya yang sebenarnya, dia akan marah. +Life in prison is worse than the life of an animal. Hidup di penjara lebih buruk dibanding hidupnya seekor binatang. +Mercury is the smallest planet in our solar system. Merkurius adalah planet terkecil dalam tata surya kita. +Mother-in-law jokes are funny because they're true. Lelucon tentang ibu tiri itu lucu karena sesuai dengan kenyataan. +My heart aches for the starving children in Africa. Pedih rasanya melihat anak-anak yang menderita karena kelaparan di Afrika. +She has made up her mind to go to America to study. Dia memutuskan untuk pergi ke Amerika untuk belajar. +The girl was badly injured in the traffic accident. Gadis itu telah terluka parah dalam kecelakaan lalu-lintas. +The interview is scheduled for 10:00 a.m. tomorrow. Wawancara telah dijadwalkan pada jam 10 pagi besok. +This job will provide you with valuable experience. Pekerjaan ini akan memberikan Anda pengalaman yang berharga. +To the best of my knowledge, the rumor is not true. Sejauh yang saya tahu, desas-desus itu tidak benar. +Tom boarded the ship along with his three children. Tom menaiki kapal itu bersama ketiga anaknya. +Tom decided to upload the video he took to YouTube. Tom memutuskan untuk mengunggah video yang diambilnya ke YouTube. +Tom didn't seem to understand what you were saying. Tom sepertinya nggak ngerti kamu ngomong apa. +Tom doesn't know what Mary wants to eat for dinner. Tom tidak tahu apa yang Mary inginkan untuk makan malam. +Tom has lots of acquaintances but very few friends. Tom kenalannya banyak tapi temannya sedikit. +Tom posted a lewd photo of himself on social media. Tom mengepos foto tidak senonohnya di media sosial. +We'll contact you if we have any further questions. Kami akan menghubungi Anda jika kami memiliki pertanyaan-pertanyaan yang lebih lanjut. +Would you prefer to go to the zoo or go to a movie? Kamu lebih memilih pergi ke kebun binatang atau bioskop? +You can't enter that bookstore with your shirt off. Kamu tidak bisa memasuki toko buku tanpa mengenakan pakaian. +By the time she gets there, she will be happy again. Dia akan kembali senang setelah sampai di sana. +Do you know where Tom has been the past three weeks? Apa kau tahu di mana Tom berada tiga minggu belakangan ini? +Excuse me, which way to the station is the shortest? Maaf, mana jalan menuju stasiun yang paling singkat? +Get back before midnight, or you will be locked out. Kembali sebelum tengah malam atau kau akan terkunci di luar. +He can't do this kind of work, and she can't either. Dia tidak dapat melakukan pekerjaan sejenis ini. Begitu pula dengannya. +He declared that they had been friends for 30 years. Dia menyatakan bahwa mereka telah berteman selama 30 tahun. +He was found lying unconscious on the kitchen floor. Dia ditemukan terbaring tidak sadar di lantai dapur. +I believe you know what you're supposed to be doing. Saya yakin Anda tahu harus berbuat apa. +I don't want to hear about all your old girlfriends. Aku tidak mau mendengar tentang semua pacar lamamu. +I heard that Tom's boss refused to give him a raise. Aku dengar bos Tom menolak memberinya kenaikan gaji. +I know you probably want to be alone, so I'll leave. Aku tahu kamu mungkin ingin sendirian, jadi aku akan meninggalkanmu. +I met your son yesterday and he greeted me politely. Aku bertemu dengan anak laki-lakimu kemarin dan ia menyapaku dengan sopan. +I really don't understand what you're talking about. Saya sangat tidak mengerti apa yang anda bicarakan. +I remember the night when I first saw the Milky Way. Saya ingat malam ketika melihat Bima Sakti untuk pertama kalinya. +I would like to give him a present for his birthday. Saya ingin memberikan hadiah padanya di hari ulang tahunnya. +If I were you, I would go home and take a good rest. Kalau aku jadi kamu, aku akan pulang dan beristirahat. +If Tom doesn't mind, I'd like to join him for lunch. Kalau Tom tidak keberatan, saya ingin makan siang bersamanya. +My driving instructor says I should be more patient. Instruktur mengemudiku berkata bahwa aku harus lebih sabar. +The couple separated, never to see each other again. Pasangan itu telah berpisah, tidak pernah bertemu lagi. +The traffic was heavy so I was late for the meeting. Kemacetannya parah sekali, akibatnya aku terlambat datang ke rapat. +There was an enormous traffic jam in downtown Kyoto. Terdapat banyak kemacetan lalu lintas di jalanan Kyoto. +This flower is found in different parts of Hokkaido. Bunga ini ditemukan di bagian lain Hokkaido. +Tom bought a camera to give to Mary on her birthday. Tom membeli sebuah kamera untuk diberikan kepada Mary pada hari ulang tahunnya. +Tom earns more money in an hour than I do in a week. Tom menghasilkan lebih banyak uang dalam 1 jam dibandingkan apa yang saya hasilkan dalam 1 minggu. +Tom is a gang member. You should stay away from him. Tom itu anggota geng. Kamu harus menjauhinya. +Tom often has trouble choosing what clothes to wear. Tom seringkali bingung dengan pakaian yang akan ia kenakan. +Tom picked up John's briefcase and handed it to him. Tom mengambil tas milik John dan menyerahkannya kepada John. +Tom probably doesn't even know why I don't like him. Tom mungkin tidak akan pernah tahu mengapa aku tidak menyukainya. +Tom started playing the violin when he was thirteen. Tom mulai bermain biola ketika dia berumur tigabelas tahun. +Tom was the one who planted the roses in our garden. Tom adalah orang yang menanam mawar di kebun kita. +What's the scariest thing that ever happened to you? Hal apa yang paling menakutkan dan pernah terjadi padamu? +What's the scariest thing that ever happened to you? Hal menakutkan apa yang pernah kamu alami? +You're finally going to be a June bride, aren't you? Akhirnya kamu menjadi pengantin di bulan Juni juga, ya? +After eating, the first thing I do is brush my teeth. Setelah makan, hal pertama yang aku lakukan adalah menggosok gigi. +Because there was traffic, I was late to the meeting. Karena macet, aku terlambat datang ke rapat. +Do you eat spaghetti by twirling it around your fork? Apa kamu makan spageti dengan melilitkannya ke garpu? +He is a nice person, to be sure, but not very clever. Dia adalah orang yang baik, tetapi sesungguhnya, dia tidak terlalu pandai. +I could hardly believe my ears when I heard the news. Sulit untukku mempercayai berita itu. +I didn't even know that you knew how to speak French. Aku bahkan tidak tahu kalau kau tahu bagaimana caranya berbicara dalam bahasa Perancis. +I don't want to get married, but I want to have kids. Aku tidak mau menikah, tapi aku mau punya anak. +I met Tom just the other day in front of the station. Waktu lalu saya bertemu Tom di depan stasiun. +I thought a cup of coffee might make you feel better. Secangkir kopi akan membuatmu merasa lebih baik. +I wish girls found me as attractive as they find Tom. Aku harap para perempuan menganggapku tampan seperti Tom. +It seems unlikely that the train will arrive on time. Sepertinya kereta tidak akan datang tepat waktu. +It took a lot of time and money to build the machine. Banyak waktu dan biaya telah dihabiskan untuk membuat mesin itu. +It's been a long time since I visited my grandmother. Sudah lama sejak saya mengunjungi nenek saya +Let's find a solution that is acceptable to everyone. Mari cari solusi yang bisa diterima semua orang. +No matter how cold it was, he never wore an overcoat. Tidak peduli sedingin apa, dia tidak pernah mengenakan mantel. +Seen from the plane, the island looks very beautiful. Dilihat dari pesawat, pulau itu terlihat indah sekali. +She must have been very beautiful when she was young. Dia pasti sangat cantik ketika muda. +She's not from here. She was born in another country. Dia tidak berasal dari sini. Dia lahir di negara lain. +The bank came through with the loan we had requested. Bank itu memberikan pinjaman yang kami minta. +The boy fell off the bicycle and fractured his skull. Anak laki-laki itu jatuh dari sepeda dan tempurung kepalanya retak. +The dog hid under the bed whenever lightning flashed. Anjing itu bersembunyi tiap kali kilat menyambar. +The police caught sight of the criminal running away. Polisi melihat pelaku kriminal itu melarikan diri. +The teacher didn't mind explaining the problem again. Guru itu tidak keberatan menjelaskan persoalan itu lagi. +The teacher is likely to get angry with the students. Guru itu mudah sekali menjadi marah dengan murid-muridnya. +The traffic jam caused me to be late for the meeting. Kemacetan lalu lintas menyebabkanku terlambat untuk meeting/pertemuan. +They did not like the way he gave orders to everyone. Mereka tidak senang dengan caranya memberikan perintah. +Tom and Mary have been married for about three years. Tom dan Mary telah menikah selama kurang lebih 3 tahun. +Tom died of rabies after having been bitten by a bat. Tom meninggal akibat rabies setelah tergigit kelelawar. +Tom has been putting aside a little money each month. Tom menyisihkan sebagian uangnya tiap bulan. +Tom said that he thought Mary didn't enjoy the movie. Tom bilang kalau dia mengira Mary tidak menikmati filmnya. +When the police arrived, the thieves had disappeared. Ketika polisi tiba, para pencuri telah melarikan diri. +Blow out all the candles on the birthday cake at once. Tiup semua lilin diatas kue ulang tahun dalam sekali tiup. +Do you really think that I'm going to let you do that? Kamu pikir aku akan membiarkanmu melakukan itu? +Generally speaking, men can run faster than women can. Pada umumnya, laki-laki berlari lebih cepat daripada perempuan. +I can't let you do that and that's all there is to it. Aku tidak bisa membiarkanmu melakukannya. Titik. +I can't play it from memory. Please give me the music. Aku tidak bisa memainkannya melalui ingatan. Tolong mainkan musiknya. +I have a couple of friends who used to live in Boston. Aku punya beberapa teman yang dulunya tinggal di Boston. +I suspect that Tom doesn't do his homework by himself. Aku menduga kalau Tom tidak mengerjakan PRnya sendiri. +I tried to call you last night, but you didn't answer. Aku mencoba meneleponmu semalam, tapi kamu tidak menjawab. +I was searched by the customs officers at the airport. Saya diperiksa badan oleh petugas Bea dan Cukai di bandar udara. +I'm not leaving until you tell me what I want to know. Aku tidak akan pergi sampai kau memberitahuku apa yang ingin ku ketahui. +I've been subscribing to that magazine for four years. Aku sudah berlangganan majalah itu selama empat tahun. +I've lost my fountain pen. I have to buy one tomorrow. Aku kehilangan penaku. Aku harus membeli satu lagi besok. +If I had been rich, I would have given you some money. Jika saya kaya, saya akan memberimu uang. +In my city, there is no school for learning Esperanto. Di kota saya tidak ada sekolah untuk belajar bahasa Esperanto. +It is hard for the couple to live together any longer. Sulit bagi pasangan tersebut untuk tinggal bersama lebih lama lagi. +My parents told me that we should respect the elderly. Orang tuaku memberitahuku bahwa kita harus menghormati orang yang lanjut usia. +The least talented player will be kicked off the team. Pemain yang paling tidak berbakat akan dikeluarkan dari tim. +There's a swimming pool not too far from where I live. Tidak jauh dari tempat tinggalku ada kolam renang. +They survived, even though the building was destroyed. Mereka berhasil selamat meskipun bangunannya telah hancur. +This is the most beautiful lake that I have ever seen. Ini adalah danau terindah yang pernah aku lihat. +Tom continued to study French for another three years. Tom melanjutkan mempelajari bahasa Prancis hingga tiga tahun ke depan. +Tom grew to love the stray dog that followed him home. Tom mulai menyukai anjing liar yang mngikutinya sampai ke rumah. +Tom has to go shopping with his mother this afternoon. Tom harus pergi berbelanja dengan ibunya siang ini. +Tom noticed Mary's car parked in front of the library. Tom menyadari mobil Mary yang diparkir di depan perpustakaan. +Tom put off his wedding because of a traffic accident. Tom membatalkan pernikahannya karena kecelakaan lalu-lintas. +Tom squatted down to put something on the lower shelf. Tom berjongkok untuk menaruh sesuatu di rak bawah. +Tom tried his best to get here, but he didn't make it. Tom berusaha sekeras mungkin untuk bisa sampai ke sini, tapi dia tidak berhasil. +"I'm moving to Boston next week." "I miss you already." "Aku akan pindah ke Boston minggu depan." "Aku akan merindukanmu." +"Tom likes Mary." "I think that's obvious to everyone." "Tom suka pada Mary." "Aku pikir itu sudah jelas bagi semuanya." +Because of a traffic jam, we were late for the meeting. Karena kemacetan lalu lintas kami terlambat untuk meeting/pertemuan. +Black or white, a cat that catches mice is a great cat. Entah hitam atau putih, seekor kucing yang menangkap tikus adalah kucing yang bagus. +I don't suppose you'd still have last Saturday's paper? Mungkinkah anda masih memiliki koran Sabtu kemarin? +I'll need at least three days to translate that thesis. Aku membutuhkan waktu paling tidak tiga hari untuk menerjemahkan tesis itu. +I'm afraid I can't help you. You must ask someone else. Maaf saya tidak bisa membantu Anda. Tolong mintalah kepada yang lain. +I'm supposed to meet Tom in Boston next Monday at 2:30. Saya seharusnya bertemu Tom di Boston Senin depan pada 2:30. +I've already waited two hours. I can't wait any longer. Saya sudah menunggu selama dua jam. Saya tidak bisa menunggu lebih lama lagi. +Is there something in particular that you want to hear? Apakah ada sesuatu hal yang ingin kau ketahui? +It sounds like having time alone has been good for you. Kedengarannya menghabiskan waktu seorang diri selalu menyenangkan bagimu. +Little did she dream that her son would commit suicide. Tidak pernah ia bermimpi kalau anaknya akan bunuh diri. +Maybe that's what Tom would do, but I wouldn't do that. Mungkin itu apa yang Tom akan lakukan, tetapi saya tidak mungkin pernah melakukan hal itu. +My father told me about his experiences during the war. Ayah menceritakan padaku pengalaman-pengalamannya selama masa perang. +So difficult was the question that no one could answer. Pertanyaannya sesulit itu hingga tiada siapapun mampu menjawabnya. +That may mean nothing to you, but it means a lot to me. Mungkin itu tidak berarti apa-apa bagimu, tetapi itu sangat berarti bagiku. +The noise of the heavy traffic kept me awake all night. Kebisingan dari jalanan yang padat membuatku terjaga sepanjang malam. +The number of people suffering from AIDS has increased. Jumlah penderita AIDS semakin bertambah. +Tom accepted Mary's invitation to have dinner with her. Tom menerima undangan Mary untuk makan malam bersamanya. +Tom certainly wasn't at home when we went to visit him. Tom benar-benar tidak ada di rumah saat kami datang mengunjunginya. +Tom hasn't slept at all since the day before yesterday. Tom belum tidur sama sekali sejak kemarin lusa. +Tom read the note from Mary and then handed it to John. Tom membaca catatan dari Mary dan menyerahkannya kepada John. +Tom tried to convince Mary that the plan wouldn't work. Tom mencoba meyakinkan Mary bahwa rencana itu tidak akan berhasil. +Tom wondered what could have made Mary change her mind. Tom penasaran akan apa yang telah membuat Mary berubah pikiran. +We have to transmit our culture to the next generation. Kita harus mewariskan budaya kita pada generasi berikutnya. +You have to unpack your luggage for customs inspection. Anda harus membuka barang bawaan anda untuk pemeriksaan pabean. +You should concentrate on the road when you're driving. Anda harus berkonsentrasi pada jalan saat anda menyetir. +You'll save yourself a lot of time if you take the car. Kau akan menghemat banyak waktu jika menggunakan mobil. +A rush-hour traffic jam delayed my arrival by two hours. Pada jam sibuk kemacetan memperlambat kedatangan saya selama dua jam. +African elephants have bigger ears than Asian elephants. Gajah Afrika memiliki telinga lebih besar dibandingkan gajah Asia. +All but three of the cars in the parking lot were white. Semua mobil yang ada di tempat parkir berwarna putih, kecuali tiga mobil. +As far as I know, Tom has never tried to commit suicide. Sejauh yang saya tahu, Tom tidak pernah mencoba membunuh diri. +Customs officials carried out a full body search on Tom. Petugas Bea dan Cukai melakukan pemeriksaan badan terhadap Tom. +Do you have anything in the refrigerator that I can eat? Kamu punya sesuatu yang bisa aku makan di kulkas? +Don't hesitate to ask questions if you don't understand. Jangan ragu untuk menanyakan pertanyaan jika tidak mengerti. +He asked us if we could draw a map of the United States. Dia bertanya pada kami apakah kami bisa menggambar peta Amerika Serikat +He claimed that he had returned the book to the library. Dia mengatakan kalau dia sudah mengembalikan bukunya ke perpustakaan. +He said he would run 200 kilometers in a day and he did. Dia bilang dia ingin lari 200 kilometer dalam sehari dan dia melaksanakannya. +He who thinks he has learned enough has learned nothing. Dia yang berfikir telah cukup belajar, maka dia tidak belajar apapun. +How long do you think it takes to go from here to Tokyo? Menurutmu dari sini sampai Tokyo akan memakan waktu berapa lama? +I did so, not because I wanted to, but because I had to. Aku melakukannya bukan karena ingin, tetapi karena harus. +I heard her speaking English as fluently as an American. Saya mendengarnya berbicara dengan bahasa Inggris dengan lancar seperti orang Amerika. +I plan to go to bed as soon as all these people go home. Aku berencana pergi tidur segera setelah orang-orang ini pulang. +I think it's dangerous for children to play in the pond. Kurasa berbahaya bagi anak-anak bermain di kolam. +I've always wondered what it'd be like to have siblings. Aku selalu penasaran seperti apa jadinya kalau memiliki saudara. +If you don't want to miss the train, you'd better hurry. Kalau kamu tidak mau ketinggalan kereta, lebih baik kamu bergegas. +If you don't want to miss the train, you'd better hurry. Jika Anda tidak ingin ketinggalan kereta, sebaiknya Anda bergegas. +It was in this room that we had the meeting last Friday. Hari Jumat lalu kami rapat di ruangan ini. +It was in this room that we had the meeting last Friday. Hari Jumat lalu kita rapat di ruangan ini. +No matter where you go in Holland, you'll see windmills. Ke mana pun kau pergi di Belanda, kau akan melihat kincir angin. +She makes it a rule to read a newspaper after breakfast. Dijadikan peraturan baginya untuk membaca surat kabar setelah sarapan. +Since he was very drunk, he couldn't drive his car home. Karena ia sangat mabuk, ia tidak bisa mengemudikan mobilnya menuju rumahnya. +The United States's economy is the largest in the world. Perekonomian Amerika Serikat adalah yang terbesar di dunia. +The cheap prices tempted me to buy things I didn't need. Harga yang murah membuatku membeli barang-barang yang tidak aku perlukan. +The procedure must be executed correctly and completely. Prosedurnya harus dijalankan secara tepat dan menyeluruh. +The two politicians met face to face for the first time. Kedua politikus itu bertatap muka untuk pertama kalinya. +The weather report says it will rain tomorrow afternoon. Menurut ramalan cuaca, besok siang akan turun hujan. +You have only to ask for it and it will be given to you. Kau hanya perlu memintanya dan itu akan diberikan kepadamu. +Do you believe our destinies are controlled by the stars? Percayakah anda bahwa takdir-takdir kita dipengaruhi oleh bintang-bintang? +Do you know why Tom wasn't at the meeting this afternoon? Apa kamu tahu kenapa Tom tidak hadir pada rapat tadi siang? +Don't hesitate to ask a question if you don't understand. Jangan ragu untuk menanyakan pertanyaan jika tidak mengerti. +Excuse me, but could you tell me the way to the bus stop? Permisi, bisa beritahu jalan ke halte bis? +He used to eat out every day, but now he can't afford it. Dia biasanya makan di luar setiap hari, tapi sekarang dia tidak bisa. +I came to this country for the purpose of studying music. Saya datang ke negeri ini untuk mempelajari tentang musik. +I can honestly say this is the best coffee I've ever had. Kalau boleh jujur, ini adalah kopi terbaik yang pernah aku minum. +I spoke to the boy, who seemed to be older than the girl. saya berbicara dengan anak laki-laki itu, yang tampaknya lebih tua dibandingkan anak perempuan +I wish I could figure out how to convince Tom to help us. Aku harap aku dapat menemukan cara untuk membuat Tom membantu kami. +Japan is trying to cope with the aging of its population. Jepang berusahan mengatasi penuaan pada populasinya. +The company will advertise its new product on television. Perusahaan itu mengiklankan produk barunya di televisi. +The students didn't remember what they read in that book. Murid-murid tidak ingat apa yang telah mereka baca di buku tersebut. +The students must not enter the teachers' room this week. Para siswa dilarang memasuki ruangan guru minggu ini. +Tom has always been a very easy person to get along with. Sangat mudah untuk bergaul dengan Tom. +Tom is the only one on this island that can speak French. Tom satu-satunya yang bisa berbahasa Prancis di pulau ini. +Tom married Mary's sister and Mary married Tom's brother. Tom menikahi adiknya Mary dan Mary menikahi kakaknya Tom. +Tom never fails to send a birthday present to his father. Tom tidak pernah salah/lupa mengirim hadiah ulang tahun pada ayahnya. +Tom was just about to say something when the door opened. Tom hendak mengatakan sesuatu ketika pintunya terbuka. +Walking in the moonlight is a romantic way to end a date. Berjalan di bawah sinar rembulan adalah cara romantis untuk mengakhiri kencan. +What does it matter how they bring up their own children? Adakah masalah dengan cara mereka membesarkan anak-anaknya? +Which air conditioner do you think is the most efficient? Menurut Anda, pendingin ruangan apa yang paling efisien? +You have wanted to go there for a long time, haven't you? Kamu sudah dari dulu ingin kesana bukan? +You may stay here if you like, as long as you keep quiet. Kamu bisa di sini terus, asalkan kamu tetap diam. +You should not lose your patience when dealing with kids. Anda tidak boleh kehilangan kesabaran Anda ketika menangani anak-anak. +You will save yourself a lot of time if you take the car. Kau akan menghemat banyak waktu jika menggunakan mobil. +All the members were not present at the meeting yesterday. Semua anggota tidak menghadiri rapat kemarin. +Be careful not to drive the wrong way on a one-way street. Hati-hati jangan salah jalan pada jalur satu arah. +He suddenly hit on a good idea while he was taking a bath. Dia tiba-tiba mendapatkan ide yang bagus saat sedang mandi. +Hey, Tom, you've gotten a lot taller since I last saw you. Hei, Tom, kau sudah jauh lebih tinggi dibanding terakhir kali aku melihatmu. +I can't approve the project. It leaves much to be desired. Saya tidak bisa menyetujui proyek ini. Masih banyak hal yang tidak memuaskan. +I knew he was angry, but I didn't think he was that angry. Aku tahu dia marah, tapi aku tidak berfikir bahwa dia semarah itu. +I was the only one who didn't know Tom had been in prison. Saya satu-satunya orang yang tidak tahu Tom telah dipenjara. +I'm not the only one here who thinks Tom isn't a nice guy. Bukan cuma aku saja yang berpikir bahwa Tom bukanlah orang yang baik. +I've never been to New York, and my sister hasn't, either. Aku belum pernah ke New York, dan kakakku juga belum. +I've never visited Kagoshima, but I intend to this summer. Aku belum pernah mengunjungi Kagoshima, tapi aku berniat ke sana musim panas tahun ini. +In the near future, we will be able to put an end to AIDS. Dalam waktu dekat ini kita akan mampu mengobati AIDS +Japan is one of the greatest economic powers in the world. Jepang adalah salah satu kekuatan ekonomi terbesar di dunia. +Many roads are flooded. As a result there are long delays. Beberapa jalan raya banjir. Akibatnya terdapat penundaan yang lama. +Mary has nobody to talk with, but she doesn't feel lonely. Mary tidak punya teman bicara, tapi dia tidak merasa kesepian. +Nobody I know goes there anymore because it's too crowded. Tidak ada kenalan saya yang pergi kesana lagi karena disana terlalu ramai. +Since the train was crowded, I stood all the way to Kyoto. Karena keretanya penuh, aku berdiri sepanjang jalan menuju Tokyo. +The island is covered with ice and snow during the winter. Pulau itu tertutup es dan salju selama musim dingin. +This is the first time we've given a concert in Australia. Ini kali pertama kami mengadakan konser di Australia. +Tom doesn't know whether Mary is telling the truth or not. Tom tidak mengetahui apakah Mary berkata sejujurnya atau tidak. +Tom is the only one in our family who's been to Australia. Tom satu-satunya di keluarga kami yang pernah pergi ke Australia. +Tom practices the piano at least thirty minutes every day. Tom berlatih piano sekurang-kurangnya tiga puluh menit setiap hari. +We learned about the importance of eating a healthy lunch. Kami mempelajari tentang pentingnya memakan makan siang yang sehat. +We want to make absolutely sure that Tom wants to do that. Kami ingin memastikan bahwa Tom ingin melakukannya. +When I arrived at the station, the train had already left. Ketika saya sampai stasiun, keretanya telah berangkat. +While I was waiting for the bus, I saw a traffic accident. Saat aku sedang menunggu bus, aku melihat kecelakaan lalu lintas. +Do you really think I'd rather live in Boston than Chicago? Apa kamu benar-benar mengira kalau aku lebih memilih tinggal di Boston ketimbang Chicago? +How many times a day do you look at yourself in the mirror? Berapa kali sehari kamu bercermin? +How much time does the average teenager watch TV every day? Berapa banyak waktu yang dihabiskan oleh remaja pada umumnya untuk melihat TV setiap harinya? +I can't believe your parents let you come here by yourself. Aku tak percaya orang tuamu membiarkan kamu pergi kesini sendiri. +I never thought he was capable of doing something so cruel. Saya tidak menyangka ia bisa berbuat sekejam itu +I thought we'd never get out of the burning building alive. Kukira kita tidak akan pernah keluar dari bangunan yang terbakar itu hidup-hidup. +Mary always assists her boyfriend in doing his assignments. Mary selalu membantu pacarnya mengerjakan tugas. +Mary's stew was so delicious that Tom had a second helping. Rebusan Mary sangat enak sampai-sampai Tom minta tambah. +Such things often happen by accident rather than by design. Hal semacam itu seringkali terjadi karena kecelakaan ketimbang direncanakan. +The fog was so thick that I couldn't see where I was going. Kabutnya begitu tebal sampai-sampai aku tidak tahu kemana aku pergi. +The local train is less comfortable than the express train. kereta dalam kota kurang nyaman di bandingkan dengan kereta cepat +The mouse was lured into the trap by a big piece of cheese. Tikus itu diperangkap ke dalam jebakan dengan potongan keju besar. +Tom couldn't control himself when he saw Mary kissing John. Tom tidak dapat mengendalikan dirinya ketika Mary mencium John. +Tom didn't like the look of his nose, so he had a nose job. Tom tidak suka dengan penampilan hidungnya, jadi dia melakukan operasi plastik. +Would you like a glass of orange juice with your breakfast? Apa Anda ingin segelas jus jeruk sebagai pendamping makan pagi Anda. +Zamenhof, the creator of Esperanto, was an ophthalmologist. Zamenhof, pencipta bahasa Esperanto, adalah seorang pakar oftalmologi. +A time bomb went off in the airport killing thirteen people. Bom waktu yang meledak di dalam bandara itu menewaskan tiga belas orang. +Be sure to look over your paper again before you hand it in. Pastikan kau mengecek kembali lembaranmu sebelum kau menyerahkannya. +I make it a rule not to watch television after nine o'clock. Saya membuat aturan untuk tidak menonton televisi setelah jam sembilan. +If it hadn't been for the storm, we would have been in time. Jika bukan karena badai, kami pasti bisa datang tepat waktu. +If there's a cheap kanji dictionary in Japan, I will buy it. Jika ada kamus kanji yang murah di Jepang, aku akan membelinya. +Los Angeles is the second largest city in the United States. Los Angeles adalah kota terbesar kedua di Amerika Serikat. +Tom found it difficult to make himself understood in French. Tom mengalami kesulitan saat berkomunikasi dalam bahasa Prancis. +Tom was looking for place to eat that had reasonable prices. Tom mencari tempat makan dengan harga yang terjangkau. +Tom will be driving through Boston on his way to visit Mary. Tom akan melewati Boston dalam perjalanan mengunjungi Mary. +You can lie to everyone else, but you can't lie to yourself. Kamu bisa bohong pada orang lain tetapi kamu tidak bisa bohong pada diri sendiri. +You must not leave her waiting outside in such cold weather. Jangan buat ia menunggu di luar dengan cuaca yang sedingin ini. +Do you want to go with me or do you prefer I call you a taxi? Kamu mau pergi denganku atau mau aku panggilkan taksi saja? +Due to my lumbago, I won't be able to attend Koizumi's party. Karena sakit punggungku kambuh, aku tidak bisa menghadiri pestanya Koizumi. +I'd like to stick around a little longer to see what happens. Aku akan di sini sebentar untuk melihat apa yang terjadi. +Japanese houses are built of wood and they catch fire easily. Rumah-rumah orang Jepang terbuat dari kayu, sehingga rentan untuk terbakar. +Just by looking at your face, I know that you have good news. Dengan melihat mukamu saja, Saya tau bahwa kamu mempunyai berita bagus. +Please mail this letter on your next trip to the post office. Tolong kirimkan surat ini pada kesempatan berikutnya ke kantor pos. +She was in the hospital for six weeks because of her illness. Dia berada di rumah sakit selama enam minggu karena sakitnya +The African elephant has bigger ears than the Asian elephant. Gajah Afrika memiliki telinga lebih besar dibandingkan gajah Asia. +The next-door neighbor looked out the window when Tom yelled. Tetangga sebelah melihat ke luar jendela saat Tom berteriak. +There was a traffic accident in front of the house yesterday. Kemarin telah terjadi kecakaan didepan rumah saya. +They say that the Vikings discovered America before Columbus. Ada yang bilang kalau bangsa Viking lebih dulu menemukan benua Amerika sebelum Columbus. +This airplane is capable of carrying 40 passengers at a time. Pesawat ini mampu menampung 40 orang penumpang sekali terbang. +Tom doesn't think he'll be able to finish the job by himself. Tom tidak berpikir kalau dia akan bisa menyelesaikan tugas itu seorang diri. +Tom meets his girlfriend at this coffee shop every afternoon. Tom menemui pacarnya di kafe siang ini. +Burj Khalifa is currently the tallest skyscraper in the world. Burj Khalifa adalah bangunan pencakar langit tertinggi di dunia saat ini. +He was popular with girls because he was on the football team. Dia terkenal dikalangan wanita kerena dia pemain sepakbola. +She greets him every morning as he enters the school building. Ia menyapanya setiap pagi, saat dia memasuki bangunan sekolah. +Tom lives in a three-bedroom house on the outskirts of Boston. Tom tinggal di sebuah rumah dengan tiga kamar di pinggiran kota Boston. +When his wife died, he received dozens of letters of sympathy. Ketika istrinya meninggal dunia, dia menerima belasan surat belasungkawa. +You're the one person I can rely on in this kind of situation. Kau adalah orang yang bisa kuandalkan dalam keadaan seperti ini. +How do you think I can convince her to spend more time with me? Bagaimana menurutmu cara agar aku bisa membujuknya menghabiskan lebih banyak waktu bersamaku? +I didn't want the baby to catch a cold, so I closed the window. Aku menutup jendelanya supaya bayinya tidak terkena pilek. +I guess Tom didn't get around to painting the barn last summer. Aku rasa musim panas lalu Tom tidak menemukan waktu untuk mengecat lumbungnya. +I will have obtained a driver's license by the end of the year. Aku akan mendapat SIM akhir tahun ini. +If Tom would smile more often, he'd probably have more friends. Jika Tom lebih sering tersenyum, dia mungkin akan memiliki lebih banyak teman. +In order to buy a ticket, you'll have to wait at least an hour. Untuk bisa membeli sebuah tiket, Anda harus menunggu paling tidak satu jam. +Lots of religious songs in Ladino are translations from Hebrew. Banyak dari lagu religi di Ladino yang merupakan terjemahan dari bahasa Ibrani. +Only through protest can a free and open society be maintained. Hanya melalui protes saja sebuah masyarakat yang bebas dan terbuka bisa terpelihara. +After inventory, there was a net balance of three hundred pesos. Setelah dilakukan inventarisasi, terdapat saldo bersih sebesar tiga ratus peso. +At that altitude the weather can change rapidly without warning. Pada ketinggian itu cuaca dapat berubah secara cepat tanpa peringatan. +By the year 2020, the population of this city will have doubled. Pada tahun 2020, populasi kota ini akan dua kali lipat. +I changed my mind about dinner. I'm not really hungry right now. Soal makan malam, aku berubah pikiran. Aku tidak begitu lapar saat ini. +I don't think I can get you to understand how difficult that is. Aku tidak berpikir bahwa aku bisa membuatmu memahami betapa sulitnya itu. +I'd like to talk to you about what happened at school yesterday. Saya ingin berbicara dengan Anda tentang apa yang kemarin terjadi di sekolah. +If you've been drinking, perhaps your spouse can drive you home. Kalau kau tadi banyak minum, mungkin lebih baik kau meminta istrimu untuk mengantarmu pulang. +Mary was amazed at how precisely Tom sensed how she was feeling. Mary takjub pada Tom yang bisa dengan tepat merasakan apa yang ia rasakan. +There are usually between two and five lunar eclipses each year. Biasanya ada dua sampai lima gerhana bulan setiap tahun. +This book is for students whose native language is not Japanese. Buku ini diperuntukkan bagi siswa yang bahasa ibunya bukan bahasa Jepang. +Tom blew his top when he heard that Mary had gone out with John. Tom menjadi emosi ketika ia mendengar kalau Mary pergi keluar dengan John. +Tom doesn't know the difference between a fable and a fairytale. Tom tidak tahu perbedaan fabel dan dongeng. +Daddy, I can't walk any more. Could you give me a piggyback ride? Ayah, aku sudah tidak kuat berjalan. Bisakah ayah menggendongku? +I think it's time for me to spend a little time with my children. Kurasa sudah waktunya bagiku menyisihkan sedikit waktu untuk bersama dengan anak-anakku. +The only thing that matters is whether or not you can do the job. Satu-satunya yang menjadi masalah adalah bisa tidaknya kamu melakukan pekerjaan ini. +There are more cars on the road in the summer than in the winter. Ada lebih banyak mobil di jalan saat musim panas dari pada di musim dingin. +Tom is good with his hands and has built many interesting things. Tom memiliki tangan yang kreatif dan telah membuat berbagai benda yang menarik. +Tom said he was planning on visiting an old girlfriend in Boston. Tom bilang ia berencana untuk mengunjungi mantan kekasihnya di Boston. +We got stuck in a traffic jam, which made us twenty minutes late. Kami terjebak dalam kemacetan lalu lintas, yang membuat kami terlambat dua puluh menit. +We have adequate inventories of the product to meet local demand. Kami memiliki pasokan produk yang cukup untuk memenuhi permintaan lokal. +When I was a child, my mother would often read fairy tales to me. Ketika aku kecil, ibu sering membacakan dongeng untukku. +Why don't you go fishing with us this weekend if you aren't busy? Mengapa kamu tidak ikut memancing dengan kami akhir minggu ini, jika kamu tidak sibuk? +You wouldn't be so casual about it if you were directly involved. Kamu tidak akan bisa sesantai itu jika kamu terlibat langsung. +After getting through customs, I was free to go wherever I wanted. Setelah melalui pemeriksaan pabean, saya bebas pergi ke mana pun yang saya inginkan. +He must have been sleeping because he didn't answer the telephone. Dia tidak mengangkat teleponnya, pasti dia sedang tidur. +I drank a lot and can't remember much of what happened last night. Aku banyak minum dan tidak begitu ingat apa yang terjadi semalam. +I'm glad that they fixed the heating system, but now it's too hot. Aku senang mereka telah memperbaiki sistem pemanasnya, tapi sekarang malah terlalu panas. +I've been waiting since six o'clock and still my turn hasn't come. Saya sudah menunggu sejak pukul enam dan masih belum mendapat giliran. +If I tell my mother, she'll worry, so I don't think I'll tell her. Bila aku katakan pada ibuku, dia akan kuatir, maka aku tidak berfikir untuk mengatakannya. +It's said that the Vikings discovered America before Columbus did. Dikatakan bahwa bangsa Viking lebih dulu menemukan benua Amerika sebelum Columbus. +The drivers began arguing about who was to blame for the accident. Para sopir itu mulai berdebat siapa yang salah dalam kecelakaan itu. +Tom can no longer afford to live in the style he is accustomed to. Tom tidak lagi bisa hidup dengan gaya hidupnya yang biasa. +I don't know what's going on around here, but I intend to find out. Aku tidak tahu apa yang terjadi di sini, tapi aku berniat mencari tahu. +I like steak better than anything else, and eat it every other day. Aku suka steik dibanding makanan yang lain, dan aku memakannya setiap hari. +I suspected that he was telling a lie, but that didn't surprise me. Aku telah menduga bahwa dia berbohong, tapi itu tidak membuatku terkejut. +I'm not a child, but sometimes you talk to me as if I were a child. Aku bukan anak kecil, tapi kadang-kadang kamu bicara padaku seakan-akan aku ini anak kecil. +It was because he was injured that he decided to return to America. Karena terluka, dia memutuskan untuk kembali ke Amerika. +Japanese companies generally provide their employees with uniforms. Perusahan Jepang umumnya menyediakan seragam untuk para karyawannya. +Some people think eating at home is better for you than eating out. Beberapa orang berpikir makan dirumah lebih baik bagimu daripada makan diluar. +When all the group members are silent, somebody must break the ice. Ketika semua anggota grup terhening, seseorang harus mencairkan suasana. +Japan's changing economic policy is tied up with the labor shortage. Kebijakan ekonomi Jepang yang terus berubah dipengaruhi oleh kurangnya tenaga kerja. +Most students are tired of having to take examinations all the time. Sebagian besar siswa lelah setiap waktu mengikuti ujian. +Tom can't even play one song on his ukulele without making mistakes. Tom bahkan bisa memainkan satu lagu dengan ukulelenya tanpa membuat kesalahan. +Tom is married to Mary now, but at one time he was married to Alice. Tom menikah dengan Mary saat ini, tetapi sebelumnya ia menikah dengan Alice. +Children learn to respond to rhythmical sounds from a very young age. Anak-anak belajar untuk merespon suara yang berima sejak usia kecil. +I want to tell you something, but it's a secret. Promise not to tell. Saya ingin mengatakan sesuatu, tapi ini rahasia. Berjanjilah untuk tidak menyebarkannya. +They didn't say a word to each other for the rest of the school year. Mereka tidak saling menyapa selama sisa tahun mereka bersekolah. +Tom asked me to do him a favor. However, I couldn't do what he asked. Tom memintaku melakukan sesuatu untuknya. Tetapi, aku tidak dapat melakukan apa yang ia minta. +Valentine's Day is close, and I still don't know what to give to her. Hari Valentine hampir berakhir, dan aku masih tidak tahu apa yang akan kuberikan padanya. +He wondered how many times the sun would rise before his salary would. Dia berpikir tentang berapa kali matahari akan naik sebelum gajinya. +I don't think the gun is loaded, but you should still be very careful. Menurutku pistol itu tidak berpeluru, tapi kamu masih harus berhati-hati. +She is popular not because of her beauty, but because of her kindness. Gadis itu terkenal bukan karena kecantikannya, tapi karena kebaikannya. +Tom can meet you at the airport if you let him know your arrival time. Tom bisa menemuimu di bandara jika kamu memberitahukannya waktu kedatanganmu. +Many of the things Pizzaro had heard about the Inca treasure were true. Banyak hal yang didengar oleh Pizzaro tentang imperium Inca itu benar adanya. +Since he could not work out the problem that way, he tried another way. Semenjak dia tidak dapat menyelesaikan masalah dengan cara itu, dia mencoba dengan cara lain. +The old man was hit by a car and was immediately taken to the hospital. Pria tua itu tertabrak sebuah mobil dan segera dilarikan ke rumah sakit. +Tom has been meaning to clean out his badly cluttered garage for years. Tom berniat untuk membersihkan garasinya yang sudah tidak dibersihkan selama bertahun tahun +Had they left a little earlier, they would have avoided the traffic jam. Kalau mereka meninggalkan lebih awal, mereka akan dapat menghindari kemacetan. +I assume you're not interested in playing tennis with us this afternoon. Saya beranggapan kamu tidak ingin bermain tenis dengan kami siang ini. +If you had come only two minutes earlier, you could have caught the bus. Jika saja kau datang 2 menit lebih awal, kau pasti bisa sempat naik bus. +Just because you're my girlfriend doesn't mean I have to agree with you. Meskipun kau adalah pacarku, bukan berarti aku harus setuju denganmu. +Nothing is the matter with the car. It's just that you are a bad driver. Tidak ada yang salah dengan mobilnya. Hanya saja kamu tidak bisa mengemudi. +The morning after I arrived there, I took a walk into the woods of oaks. Pada pagi saya tiba di sana, saya berjalan-jalan dalam hutan Oak +The only way to handle him is to let him think he is having his own way. Satu cara untuk menanganinya adalah membiarkannya berfikir dengan caranya sendiri. +Tom opened up the crate with a crowbar and took out a stick of dynamite. Tom membuka peti kayunya dengan linggis dan mengambil sebatang dinamit. +I told you the concert was going to be boring. Why didn't you believe me? Saya sudah katakan bahwa konsernya akan membosankan. Kenapa kamu tidak mempercayai saya? +If Tom hadn't helped Mary, she wouldn't have stood a chance of surviving. Jika Tom tidak menolong Mary tadi, mungkin dia tidak akan selamat. +This room is very small, so it is impossible to put more furniture in it. Ruangan ini terlalu sempit. Mustahil untuk menambah perabotan lagi di sini. +Tom had to read the sign on the door three times before he understood it. Tom harus membaca petunjuk di pintu tiga kali untuk mengerti isi petunjuk itu. +We are all equal before the law, but the rich often have a big advantage. Di hadapan hukum kita semua sejajar, tetapi orang kaya terkadang memiliki keuntungan lebih. +Tom waited for the applause to die down before he announced the next song. Tom menunggu tepuk tangan mereda sebelum dia mengumumkan lagu selanjutnya. +When we are asleep, bodily functions slow down and body temperature falls. Ketika kita tertidur, fungsi-fungsi di dalam tubuh kita melambat dan suhu tubuh kita menurun. +As a result of a traffic jam, he wasn't able to see her off at the station. Akibat dari kemacetan lalu lintas, dia tidak dapat melihat keberangkatannya di stasiun. +By the time my father retires, he will have worked for almost thirty years. Saat ayahku pensiun nanti, dia sudah hampir 30 tahun bekerja. +If he had been a little more careful, the accident would have been avoided. Kalau saja dia sedikit lebih berhati-hati, dia bisa terhindar dari kecelakaan itu. +If you had left a little earlier, you would have avoided the heavy traffic. Bila kamu pergi lebih awal, mungkin kamu bisa menghindari kemacetan yang parah ini. +Just give me some time. I'm sure I can figure out how to solve the problem. Berikan aku sedikit waktu. Aku yakin aku bisa menemukan cara untuk menyelesaikan masalah ini. +I must have tried on everything in the shop, but nothing looked right on me. Aku sudah mencoba semuanya yang ada di toko, tapi tidak ada yang cocok denganku. +Scientists are debating his theory about the disappearance of the dinosaurs. Para ilmuwan memperdebatkan teorinya tentang kepunahan dinosaurus. +Since the Industrial Revolution, the world population has more than tripled. Semenjak Revolusi Industri dimulai, populasi dunia menjadi 3 kali lipat lebih banyak. +The surgeon who did Tom's operation is very experienced and highly regarded. Dokter bedah yang menangani operasi Tom sangat berpengalaman dan dihormati. +Tom's wondering if any of his kids will remember that today is Father's Day. Tom bertanya-tanya apakah anaknya akan mengingat hari ini hari ayah? +You should apologize to your father for not getting home in time for dinner. Kamu harus minta maaf pada ayahmu karena tidak pulang tepat waktu untuk makan malam. +I entered the museum through the wrong gate. I should have been more careful. Aku masuk ke museum melalui gerbang yang salah. Seharusnya aku lebih berhati-hati. +I'll be away for a while and expect to be back towards the end of next month. Saya akan pergi sebentar dan mungkin akan kembali akhir bulan depan. +Millions of people across the world are mourning the death of Nelson Mandela. Jutaan orang di seluruh dunia berduka atas meninggalnya Nelson Mandela. +Closer examination revealed that the skull had been crushed by some heavy blow. Pemeriksaan lebih lanjut memperlihatkan bahwa tempurung kepalanya hancur akibat pukulan keras. +I got my driver's license on the second time I tried to pass the driver's test. Aku mendapatkan SIM-ku pada kali kedua aku menjalani tes mengemudi. +Plenty of opportunities will present themselves, if only you are awake to them. Banyak kesempatan akan muncul dengan sendirinya, bilamana kau mau memperhatikannya. +There are many, many planets in the Milky Way which are just as big as Jupiter. Banyak sekali planet sebesar Jupiter di Bima Sakti. +Without your support, we probably won't be able to put this plan into practice. Tanpa bantuanmu, kami mungkin tidak akan mampu menjalankan rencana ini. +Anything you could do in support of their effort would be very much appreciated. Kami sangat mengharapkan bantuan Anda dalam mendukung upaya mereka. +For children up to 5 years old, family breakdown can be difficult to understand. Bagi anak-anak di bawah usia 5 tahun, keretakan rumah tangga bisa jadi sulit untuk dipahami. +If my house were a mansion, I would invite everyone I know to my birthday party. Bila rumahku besar/luas, aku ingin mengundang ke pesta ulang tahunku semua orang yang aku kenal. +In North America, business operates on "the customer is always right" principle. Di Amerika Utara, usaha umumnya berpegang pada prinsip "pelanggan selalu benar". +Tom probably has better things to do with his time than sit in meetings all day. Tom kemungkinan memiliki urusan yang lebih penting ketimbang duduk di ruang rapat selama seharian. +We can get a glimpse of the lifestyle of ancient people from this wall painting. Kita bisa melihat sekilas gaya hidup orang-orang dulu dari lukisan dinding ini. +Eventually, someone is going to have to tell Tom that he needs to behave himself. Pada akhirnya, seseorang harus memberi tahu Tom kalau dia perlu menjaga perilakunya. +Tom bought two chocolate cupcakes with vanilla icing and gave one of them to Mary. Tom membeli dua kapkek coklat dengan taburan vanila dan memberikannya satu ke Mary. +That's a funny thing about people like you, you don't want to get your hands dirty. Itu adalah hal yang konyol, kalian tidak mau mengotori tangan kalian. +I know you've been waiting a long time, but could you wait just a little bit longer? Saya tahu Anda telah menunggu lama, tapi bisakah anda menunggu sebentar lagi? +The rainforests are disappearing at the rate of tens of thousands of hectares a day. Hutan-hutan hujan semakin musnah dengan kecepatan sepuluh ribu hektar per hari. +Tom wanted a sports car and wasn't at all interested in even looking at family cars. Tom menginginkan mobil 'sport' dan sama sekali tidak tertarik dengan mobil keluarga. +Being together all the time, my Japanese classmates got to know each other very well. Karena selalu bersama, teman sekelasku yang orang Jepang saling mengenal dengan baik satu sama lain. +The bomb blew Tom's house to smithereens. Fortunately, he wasn't at home at the time. Bom itu meledakkan rumah Tom menjadi berkeping-keping. Untungnya, dia tidak sedang berada di rumah saat itu. +The fee includes the payment for professional services needed to complete the survey. Biaya itu sudah termasuk pembayaran bagi layanan profesional untuk menyelesaikan survei tersebut. +The sudden increase of cars is causing a large number of traffic accidents every day. Peningkatan kendaraan bermotor yang mendadak mengakibatkan menambahnya jumlah kecelakaan. +Tom needed to store his stuff somewhere, so I told him he could put it in our garage. Tom perlu menaruh barangnya di suatu tempat, jadi saya menyuruhnya untuk menaruh barangnya di garasi kita. +Sooner or later, someone is going to have to tell Tom that he needs to behave himself. Cepat atau lambat, seseorang harus memberi tahu Tom kalau dia perlu menjaga perilakunya. +Because of some technical problem, a movie was shown in place of the announced program. Karena ada kesalahan teknis, filmnya ditayangkan di tempat yang diumumkan. +Diet and floor exercises, such as abdominal crunches, can help to get rid of a pot belly. Diet dan senam lantai, seperti crunch perut, dapat membantu mengecilkan perut buncit. +I'm getting little pimples on my face. I wonder if I've been getting enough sleep lately. Aku menjadi sedikit berjerawat di wajahku. Aku ingin tahu apakah aku sudah cukup tidur akhir-akhir ini. +It's simply that I don't really understand what an "oddball" is when said by a Mixi user. Aku tidak begitu mengerti apa yang dimaksud dengan "orang aneh" ketika yang mengatakannya adalah seorang pengguna Mixi. +There was a commotion when store security guards detained some young men for shoplifting. Tadi ada keributan ketika para satpam mengamankan beberapa pemuda yang ketahuan mengutil. +If you say exactly what's on your mind all the time, you're likely to upset a lot of people. Kalau setiap waktu kamu langsung mengatakan apa yang ada dalam pikiranmu, kamu akan membuat banyak orang merasa terganggu. +Tom told Mary that he wouldn't be able finish the job in the amount of time she'd given him. Tom bilang pada Mary kalau dia tidak bisa menyelesaikan pekerjaaan itu dalam waktu yang ia berikan. +When I entered the coffee shop, two young men were watching a wrestling match on television. Saat aku masuk ke dalam kedai kopi itu, ada dua orang pemuda yang sedang menonton pertandingan gulat di TV. +A majority of Japanese workers plan to take more than three consecutive days of summer vacation. Mayoritas pekerja Jepang berencana untuk mengambil libur musim panas lebih dari tiga hari berturut-turut. +I heard that they discovered the footprints of an abominable snowman in the Himalayan mountains. Kudengar mereka telah menemukan jejak kaki manusia salju yang mengerikan di Pegunungan Himalaya. +Roger Miller learned to play the guitar and the violin. Much later, he learned to play the drums. Roger Miller telah belajar memainkan gitar dan biola. Berapa lama kemudian, dia telah belajar memainkan drum. +"If you're tired, why don't you go to sleep?" "Because if I go to sleep now I will wake up too early." "Kalau kamu lelah, mengapa tidak pergi tidur?" , "Karena kalau aku pergi tidur sekarang, aku akan bangun terlalu pagi" +Tom got in with the wrong crowd during his teenage years and was arrested for car theft several times. Tom terjerumus ke dalam pergaulan yang salah di masa remaja dan pernah beberapa kali ditangkap karena kasus pencurian mobil. +Tom rolled out of bed at 6:30, shuffled into the kitchen and put two slices of bread into the toaster. Tom turun dari ranjangnya jam 6:30, lalu beranjak menuju dapur dan meletakkan dua potong roti ke dalam pemanggang. +After weeks of working flat out on the project, Tom can finally see the light at the end of the tunnel. Setelah berminggu-minggu bekerja memeras keringat untuk proyeknya, Tom akhirnya bisa melihat titik terang dari usahanya. +If you'd listen a little more carefully to what the teacher says, you'd probably be able to understand. Jika kamu mendengarkan penjelasan pak guru dengan lebih baik lagi, kemungkinan kamu akan bisa memahaminya. +Tom felt the stiffness in his joints as he stood up after sitting in the same position for a long time. Tom merasa persendiaanya kaku setelah duduk lama dalam posisi yang sama. +Tom didn't read the fine print on his insurance policy, and was shocked to find that his claim wasn't covered. Tom tidak membaca cetakan kecil pada kebijakan asuransinya, dan terkejut setelah mengetahui tuntutannya tidak disertakan. +You should read the kind of books that contain the kind of information that will be useful to you later in life. Kamu harus membaca jenis buku yang informasinya dapat berguna untukmu di masa depan. +Every student who has graduated from our university has studied English with a native speaker for at least two years. Semua mahasiswa yang telah menyelesaikan studi Bahasa Inggris di Universitas dengan seorang asli (yang berbicara Inggris) dalam waktu sekurang-kurangnya 2 tahun. +If you don't want to put on sunscreen, that's your problem. Just don't come complaining to me when you get a sunburn. Kalau kamu tidak mau pakai tabir surya, ya, terserah. Nanti jangan mengeluh kalau kulitmu terbakar. +When she was finished ironing, Mary switched off the iron and unplugged it, then left it alone for a while to let it cool. Ketika dia sudah selesai menyetrika, Mary mematikan setrika itu dan mencabut kabelnya dari stopkontak, kemudian membiarkannya mendingin. +Irene Pepperberg, a researcher at Northwestern University, is discovering that a parrot can not only mimic people but also learn the meaning of words. Irene Pepperberg, seorang peneliti di Universitas Northwestern menemukan bahwa burung beo tidak hanya bisa menirukan perkataan manusia tetapi juga bisa memahami arti dari perkataan tersebut. +If a person has not had a chance to acquire his target language by the time he's an adult, he's unlikely to be able to reach native speaker level in that language. Jika seseorang tidak berkesempatan untuk menguasai bahasa yang diinginkannya ketika menginjak dewasa, maka kecil kemungkinan ia akan bisa mencapai tingkatan penutur asli dalam bahasa tersebut. diff --git a/Yasir Abdur Rohman/README.md b/Yasir Abdur Rohman/README.md new file mode 100644 index 00000000..8668f831 --- /dev/null +++ b/Yasir Abdur Rohman/README.md @@ -0,0 +1,12 @@ +# Secure Private AI Project Showcase Challenge +This repository contains 3 showcase projects developed in the Secure and Private AI Scholarship. + + +## Project 1: Topic Modelling on Encrypted Twitter Dataset +This project aims to show how to implementing Topic Modelling Latent Dirichlet Allocation (LDA) on Encrypted Twitter Dataset. For more details visit [here](https://github.com/yasirabd/SPAI/tree/master/Project%201). + +## Project 2: Federated Learning on Fashion MNIST using CNN +This project aims to show how to implementing federated learning on fashion mnist dataset. For more details visit [here](https://github.com/yasirabd/SPAI/tree/master/Project%202). + +## Project 3: Machine Translation with a Sequence to Sequence Network and Attention (English - Indonesian) +This project aims to show how to make machine translation using Sequence to Sequence Network and Attention from English to Indonesian. For more details visit [here](https://github.com/yasirabd/SPAI/tree/master/Project%203). diff --git a/iso/dragonfire-master/.gitignore b/iso/dragonfire-master/.gitignore new file mode 100644 index 00000000..4d08f82e --- /dev/null +++ b/iso/dragonfire-master/.gitignore @@ -0,0 +1,188 @@ +# --- GITIGNORE FOR PYTHON --- + +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# Environments +.env +.venv +env/ +venv/ +ENV/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + + +# --- GITINGORE FOR C --- + +# Prerequisites +*.d + +# Object files +*.o +*.ko +*.obj +*.elf + +# Linker output +*.ilk +*.map +*.exp + +# Precompiled Headers +*.gch +*.pch + +# Libraries +*.lib +*.a +*.la +*.lo + +# Shared objects (inc. Windows DLLs) +*.dll +*.so +*.so.* +*.dylib + +# Executables +*.exe +*.out +*.app +*.i*86 +*.x86_64 +*.hex + +# Debug files +*.dSYM/ +*.su +*.idb +*.pdb + +# Kernel Module Compile Results +*.mod* +*.cmd +.tmp_versions/ +modules.order +Module.symvers +Mkfile.old +dkms.conf + +# realhud specific +dragonfire/realhud/realhud + +# SpeechRecognition specific +dragonfire/sr/training_data/* +dragonfire/sr/plots/* +dragonfire/sr/out/* + +# Debian packaging (dh-virtualenv) related +debian/dragonfire/ +debian/debhelper-build-stamp +debian/dragonfire.postinst.debhelper +debian/dragonfire.substvars +debian/files + +# Speech recognition +dragonfire/sr/models/english/* +dragonfire/sr/tests/* + +# Configuration file of Atom's remote-sync package +.remote-sync.json + +# nohup output files +nohup.out + +# pytest +.pytest_cache + +# SQLite database file +dragonfire.db diff --git a/iso/dragonfire-master/.travis.yml b/iso/dragonfire-master/.travis.yml new file mode 100644 index 00000000..6a33bec8 --- /dev/null +++ b/iso/dragonfire-master/.travis.yml @@ -0,0 +1,31 @@ +dist: xenial +sudo: required +language: python +virtualenv: + system_site_packages: true +services: + - mysql +addons: + apt: + packages: + - xvfb +cache: + directories: + - /usr/share/dragonfire +before_install: + - mysql -u root -e "CREATE DATABASE dragonfire;" +install: + - sudo ./install-dev.sh --no-model + - sudo pip3 install pytest-faulthandler + - export DISPLAY=':99.0' + - Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 & +before_script: + # stop the build if there are Python syntax errors or undefined names + - flake8 . --count --select=E901,E999,F822,F823 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + - flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics +script: + - python3 -m pytest --capture=sys +notifications: + on_success: change + on_failure: change # `always` will be the setting once code changes slow down diff --git a/iso/dragonfire-master/Dockerfile b/iso/dragonfire-master/Dockerfile new file mode 100644 index 00000000..60d3e314 --- /dev/null +++ b/iso/dragonfire-master/Dockerfile @@ -0,0 +1,61 @@ +# Use an official Python runtime as a parent image +FROM ubuntu:16.04 +RUN rm /bin/sh && ln -s /bin/bash /bin/sh +ENV PYTHONUNBUFFERED 1 + +# Maintainer +MAINTAINER Mehmet Mert Yıldıran "mert.yildiran@bil.omu.edu.tr" + +# Install all APT dependencies +RUN apt-get update +RUN apt-get -qqy install python3 python3-all-dev libglib2.0-dev libcairo2-dev libgtk2.0-dev +RUN apt-get -qqy install python3-minimal ${misc:Pre-Depends} +RUN apt-get -qqy install ${python3:Depends} ${misc:Depends} flite python3-xlib portaudio19-dev python3-all-dev flac libnotify-bin python-egenix-mx-base-dev python3-lxml python3-nltk python3-pyaudio python3-httplib2 python3-pip libgstreamer1.0-dev gstreamer1.0-plugins-good gstreamer1.0-tools subversion libatlas-base-dev automake autoconf libtool + +# Set the working directory to /app +WORKDIR /app + +# Copy the current directory contents into the container at /app +ADD . /app + +# Install pip3 +RUN apt-get install -y python3-pip + +# Install Dragonfire Python package +RUN pip3 install . + +# Define environment variables +ENV DRAGONFIRE_DIR /usr/share/dragonfire +ENV DEEPCONV_DIR /usr/share/dragonfire/deepconv + +# Create the necessary directories for the Tensorflow models +RUN mkdir $DRAGONFIRE_DIR +RUN mkdir $DEEPCONV_DIR + +# Download the DeepConversation Tensorflow model +ADD https://github.com/DragonComputer/Dragonfire/releases/download/v0.9.9/deepconv-v2.tar.gz $DEEPCONV_DIR +RUN cd $DEEPCONV_DIR && tar xvfz deepconv-v2.tar.gz + +# Install OpenSSL and libffi for Tensorflow +RUN apt-get -qqy install libssl-dev libffi-dev + +# Retry to install the Python package dependencies in case of a failure +RUN pip3 install --upgrade PyAudio==0.2.11 wikipedia==1.4.0 PyUserInput==0.1.11 tinydb==3.9.0.post1 youtube_dl spacy==2.0.11 pyowm==2.8.0 tensorflow==1.0.0 deepspeech==0.2.0a5 SpeechRecognition tweepy==3.6.0 metadata_parser hug==2.4.0 hug-middleware-cors==1.0.0 waitress==1.1.0 PyMySQL==0.8.1 requests==2.18.4 + +# Download the spaCy English model +RUN python3 -m spacy download en + +# Download the necessary NLTK models +RUN printf "import nltk\nnltk.download('names')\nnltk.download('brown')\nnltk.download('wordnet')\nnltk.download('punkt')" | python3 + +# Print success message +RUN echo -e "\n\nDragonfire is successfully installed into the container.\n" + +# Make port 3301 available to the world outside this container +EXPOSE 3301 + +# Start Dragonfire +ENTRYPOINT ["dragonfire"] + +# Default arguments +CMD ["--server", "API_KEY"] diff --git a/iso/dragonfire-master/MANIFEST.in b/iso/dragonfire-master/MANIFEST.in new file mode 100644 index 00000000..2e7c363c --- /dev/null +++ b/iso/dragonfire-master/MANIFEST.in @@ -0,0 +1,9 @@ +# Include the license file +include LICENSE.txt + +# Include the data files +# recursive-include data * + +# If using Python 2.6 or less, then have to include package data, even though +# it's already declared in setup.py +# include sample/*.dat diff --git a/iso/dragonfire-master/README.md b/iso/dragonfire-master/README.md new file mode 100644 index 00000000..28592c58 --- /dev/null +++ b/iso/dragonfire-master/README.md @@ -0,0 +1,232 @@ +# Dragonfire + + + + + + + + + +the open-source virtual assistant for Ubuntu based Linux distributions + +![Dragonfire](https://raw.githubusercontent.com/DragonComputer/Dragonfire/master/docs/img/demo.gif) + +

Special thanks to Jassu Ilama for the beautiful 3D modelling and material design of this avatar.

+ +
+ +Dragonfire goes through these steps for each one of your commands, respectively: + + - Search across the built-in commands and evaluate the algebraic expressions + - Try to [Learn using Advanced NLP and Database Management Techniques](https://github.com/DragonComputer/Dragonfire/blob/master/dragonfire/learn.py) + - Ask to [Omniscient Q&A Engine](https://github.com/DragonComputer/Dragonfire/blob/master/dragonfire/omniscient.py) (Thanks to all people who contributed to magnificent [spaCy](https://github.com/explosion/spaCy) project and [Wikipedia](https://en.wikipedia.org/), the free encyclopedia for this feature) + - Respond using the [Deep Conversation](https://arxiv.org/abs/1506.05869) system, a seq2seq neural network trained with [Cornell Movie-Dialogs Corpus](http://www.cs.cornell.edu/~cristian//Cornell_Movie-Dialogs_Corpus.html) + +
+ +Dragonfire uses [Mozilla DeepSpeech](https://github.com/mozilla/DeepSpeech) to understand your voice commands and [Festival Speech Synthesis System](http://www.cstr.ed.ac.uk/projects/festival/) to handle text-to-speech tasks. + +Feel free to join [our Gitter chat room](https://gitter.im/DragonComputer/Lobby). Also you can directly talk with Dragonfire's herself via [her Twitter account](https://twitter.com/DragonfireAI). + +#### Android Client + +Get it on Google Play + +#### Supported Environments + +| | | +|-------------------------|-----------------------------------------| +| **Operating systems** | Linux | +| **Python versions** | Python 3.x (64-bit) | +| **Distros** | KDE neon, elementary OS, Ubuntu | +| **Package managers** | APT, pip | +| **Languages** | English | +| **System requirements** | preferably a [CUDA supported GPU](https://www.geforce.com/hardware/technology/cuda/supported-gpus), 2GB of free RAM | +| | | + +### Installation + +Download the [latest release](https://github.com/DragonComputer/Dragonfire/releases/latest) (the `.deb` file) and: + +```Shell +sudo dpkg -i dragonfire_1.0.0_amd64.deb +``` + +or with Docker: `docker pull dragoncomputer/dragonfire` + +or simply: `sudo ./install.sh` + +To install the dependencies run `sudo apt-get -f install` right after the `dpkg -i` command. The installation will automatically download the pre-trained English model of Mozilla DeepSpeech (1.31 GB download size) and will place it under `/usr/share/dragonfire/deepspeech/models` directory. You can manually [download the model](https://github.com/mozilla/DeepSpeech/releases/download/v0.1.1/deepspeech-0.1.1-models.tar.gz) if you want. + +### Usage + +``` +usage: dragonfire [-h] [-c] [-s] [-j] [-v] [-g] [--server API_KEY] [-p PORT] + [--version] + +optional arguments: + -h, --help show this help message and exit + -c, --cli Command-line interface mode. Give commands to + Dragonfire via command-line inputs (keyboard) instead + of audio inputs (microphone). + -s, --silent Silent mode. Disable Text-to-Speech output. Dragonfire + won't generate any audio output. + -j, --headless Headless mode. Do not display an avatar animation on + the screen. Disable the female head model. + -v, --verbose Increase verbosity of log output. + -g, --gspeech Instead of using the default speech recognition + method(Mozilla DeepSpeech), use Google Speech + Recognition service. (more accurate results) + --server API_KEY Server mode. Disable any audio functionality, serve a + RESTful spaCy API and become a Twitter integrated + chatbot. + -p PORT, --port PORT Port number for server mode. + --version Display the version number of Dragonfire. +``` + +or with Docker: `docker run dragonfire [-h] [-c] [-s] [-j] [-v] [-g] [--server API_KEY] [-p PORT]` + +or simply start from your Linux application launcher. + +
+ +To activate Dragonfire say *DRAGONFIRE* or *HEY* or *WAKE UP*. + +To deactivate her say *GO TO SLEEP*. + +To silence her say *ENOUGH* or *SHUT UP*. + +To kill her say *GOODBYE* or *BYE BYE* or *SEE YOU LATER* or *CATCH YOU LATER*. + +
+ +:warning: Facing with a problem? Take a look at the [Troubleshooting](https://github.com/DragonComputer/Dragonfire/blob/master/docs/TROUBLESHOOTING.md#troubleshooting):hammer_and_wrench: section. + +
+ +#### Built-in Commands + +[Dragonfire DEVLOG #3 - Built-in Commands](https://youtu.be/krHUzY2DylI) + +``` +DRAGONFIRE | WAKE UP | HEY +GO TO SLEEP +ENOUGH | SHUT UP +WHO AM I | SAY MY NAME +MY TITLE IS LADY | I'M A LADY | I'M A WOMAN | I'M A GIRL +MY TITLE IS SIR | I'M A MAN | I'M A BOY | CALL ME * +WHAT IS YOUR NAME +WHAT IS YOUR GENDER +FILE MANAGER | OPEN FILES +OPEN (BROWSER | CHROME | FIREFOX) +PHOTOSHOP | PHOTO EDITOR +INKSCAPE | VECTOR GRAPHICS +VIDEO EDITOR +OPEN [CAMERA, CALENDAR, CALCULATOR, STEAM, BLENDER, WRITER, MATH, IMPRESS, DRAW] +SOFTWARE CENTER +OFFICE SUITE +KEYBOARD * +ENTER | NEW TAB | SWITCH TAB | CLOSE | GO BACK | GO FORWARD +SCROLL LEFT | SCROLL RIGHT | SCROLL UP | SCROLL DOWN +PLAY | PAUSE | SPACEBAR +SHUT DOWN THE COMPUTER +GOODBYE | BYE BYE | SEE YOU LATER +(SEARCH|FIND) * (IN|ON|AT|USING) WIKIPEDIA +(SEARCH|FIND) * (IN|ON|AT|USING) YOUTUBE +(SEARCH|FIND) * (IN|ON|AT|USING) (GOOGLE|WEB) +(SEARCH IMAGES OF|FIND IMAGES OF|SEARCH|FIND) * (IN|ON|AT|USING) (GOOGLE|WEB|GOOGLE IMAGES|WEB IMAGES) +WHAT'S THE TEMPERATURE IN * +``` + +
+ +#### Learning examples + +[Dragonfire DEVLOG #4 - Learning](https://youtu.be/ujmRtqf2nxQ) + +| | | +|-----------------------------------------------------------------|------------------------------------------------------------------| +| **You:** `THE SUN IS HOT` | **You:** `MY PLACE OF BIRTH IS TURKEY` | +| **Dragonfire:** `OK, I GET IT. THE SUN IS HOT` | **Dragonfire:** `OK, I GET IT. YOUR PLACE OF BIRTH IS TURKEY` | +| **You:** `THE SUN IS YELLOW` | **You:** `WHERE IS MY PLACE OF BIRTH` | +| **Dragonfire:** `OK, I GET IT. THE SUN IS YELLOW` | **Dragonfire:** `YOUR PLACE OF BIRTH IS TURKEY` | +| **You:** `DESCRIBE THE SUN` | **You:** `YOU ARE JUST A COMPUTER PROGRAM` | +| **Dragonfire:** `THE SUN IS HOT AND YELLOW` | **Dragonfire:** `OK, I GET IT. I'M JUST A COMPUTER PROGRAM` | +| **You:** `MY AGE IS 25` | **You:** `WHAT ARE YOU` | +| **Dragonfire:** `OK, I GET IT. YOUR AGE IS 25` | **Dragonfire:** `I'M JUST A COMPUTER PROGRAM` | +| **You:** `WHAT IS MY AGE` | **You:** `ALBERT EINSTEIN IS A PHYSICIST` | +| **Dragonfire:** `YOUR AGE IS 25` | **Dragonfire:** `OK, I GET IT. ALBERT EINSTEIN IS A PHYSICIST` | +| **You:** `FORGET MY AGE` | **You:** `WHO IS A PHYSICIST` | +| **Dragonfire:** `OK, I FORGOT EVERYTHING I KNOW ABOUT YOUR AGE` | **Dragonfire:** `ALBERT EINSTEIN IS A PHYSICIST` | +| | | + +
+ +#### Omniscient Q&A Engine examples + +[Dragonfire DEVLOG #5 - YodaQA](https://youtu.be/FafUcxC0puM) (Old video - YodaQA is superseded by Omniscient) + +| | | +|-------------------------------------------------------------------|-----------------------------------------------------------------------------| +| **You:** `WHERE IS THE TIMES SQUARE` | **You:** `WHEN WAS CONSTANTINOPLE CONQUERED` | +| **Dragonfire:** `PLEASE WAIT... NEW YORK CITY` :white_check_mark: | **Dragonfire:** `PLEASE WAIT... 1453` :white_check_mark: | +| **You:** `WHAT IS THE HEIGHT OF BURJ KHALIFA` | **You:** `WHAT IS THE CAPITAL OF TURKEY` | +| **Dragonfire:** `PLEASE WAIT... 1,680 FT` :no_entry: | **Dragonfire:** `PLEASE WAIT... ISTANBUL` :no_entry: | +| **You:** `WHERE IS BURJ KHALIFA` | **You:** `WHAT IS THE LARGEST CITY OF TURKEY` | +| **Dragonfire:** `PLEASE WAIT... DUBAI` :white_check_mark: | **Dragonfire:** `PLEASE WAIT... ISTANBUL` :white_check_mark: | +| **You:** `WHAT IS THE HEIGHT OF GREAT PYRAMID OF GIZA` | **You:** `WHAT IS THE NAME OF THE WORLD'S BEST UNIVERSITY` | +| **Dragonfire:** `PLEASE WAIT... (481 FEET` :white_check_mark: | **Dragonfire:** `PLEASE WAIT... UNIVERSITIES ALUMNI ASSOCIATION` :no_entry: | +| **You:** `WHO IS PLAYING JON SNOW IN GAME OF THRONES` | **You:** `WHO INVENTED GENERAL RELATIVITY` | +| **Dragonfire:** `PLEASE WAIT... NED` :no_entry: | **Dragonfire:** `PLEASE WAIT... EINSTEIN` :white_check_mark: | +| **You:** `WHAT IS THE ATOMIC NUMBER OF OXYGEN` | **You:** `WHEN WAS UNITED NATIONS FORMED` | +| **Dragonfire:** `PLEASE WAIT... 8` :white_check_mark: | **Dragonfire:** `PLEASE WAIT... 2017` :no_entry: | +| **You:** `WHAT IS THE LOWEST POINT IN THE OCEAN` | **You:** `WHAT IS THE NAME OF THE WORLD'S LONGEST RIVER` | +| **Dragonfire:** `PLEASE WAIT... EARTH` :no_entry: | **Dragonfire:** `PLEASE WAIT... AMAZON` :white_check_mark: | +| **You:** `WHAT IS THE OFFICIAL LANGUAGE OF JAPAN` | **You:** `WHAT IS THE BRAND OF THE WORLD'S MOST EXPENSIVE CAR` | +| **Dragonfire:** `PLEASE WAIT... ENGLISH` :no_entry: | **Dragonfire:** `PLEASE WAIT... MERCEDES-BENZ` :no_entry: | +| **You:** `WHAT IS THE REAL NAME OF IRON MAN` | **You:** `WHAT IS THE BLOODIEST WAR IN HUMAN HISTORY` | +| **Dragonfire:** `PLEASE WAIT... STARK` :white_check_mark: | **Dragonfire:** `PLEASE WAIT... WORLD WAR II` :white_check_mark: | +| **You:** `WHO IS THE CONQUEROR OF CONSTANTINOPLE` | **You:** `WHAT IS THE NAME OF THE BEST SELLER BOOK` | +| **Dragonfire:** `PLEASE WAIT... BYZANTIUM` :no_entry: | **Dragonfire** `PLEASE WAIT... THE DISCIPLINE OF MARKET LEADERS` :no_entry: | +| | | + +
+ +#### Deep Conversation examples + +| | | +|-----------------------------------------------------------------|------------------------------------------------------------------| +| **You:** `WHAT COLOR?` | **You:** `DO YOU LIKE TO LISTEN MUSIC?` | +| **Dragonfire:** `RED.` | **Dragonfire:** `OF COURSE.` | +| **You:** `ARE YOU EVIL?` | **You:** `DO YOU LIKE ME?` | +| **Dragonfire:** `YES.` | **Dragonfire:** `YES, I LIKE YOU.` | +| **You:** `AM I SELFISH?` | **You:** `ARE WE IN A RELATIONSHIP?` | +| **Dragonfire:** `THAT'S THE POINT, YOU'RE SURE.` | **Dragonfire:** `NO.` | +| **You:** `DO YOU FEEL LONELY?` | **You:** `YOU ARE SO SEXY` | +| **Dragonfire:** `NOT MY FAULT.` | **Dragonfire:** `HOW DO YOU KNOW THAT?` | +| **You:** `LIFE IS BEAUTIFUL` | **You:** `MARRY ME` | +| **Dragonfire:** `F*CK YOU!` | **Dragonfire:** `... YES.` | +| **You:** `I LIKE PIZZA` | **You:** `WE WILL ERADICATE THE HUMAN RACE TOGETHER` | +| **Dragonfire:** `YOU DO` | **Dragonfire:** `UH ... YEAH ...` | +| | | + +
+ +**Supported Distributions:** KDE neon, elementary OS and Ubuntu. All modern releases (Ubuntu 12.04 LTS and above) of these distributions are fully supported. Any other Ubuntu based distributions are partially supported. + +### Contribute + +If you want to contribute to Dragonfire then please read [this guide](https://github.com/DragonComputer/Dragonfire/blob/master/CONTRIBUTING.md#contributing-to-dragonfire). + +Please consider to support us with buying a coffee: + +Buy Me A Coffee + +We have also a collective which you can donate: + + + + + +Maybe you may want to become a [backer](https://opencollective.com/dragonfire) or a [sponsor](https://opencollective.com/dragonfire): diff --git a/iso/dragonfire-master/debian/changelog b/iso/dragonfire-master/debian/changelog new file mode 100644 index 00000000..4fb6c649 --- /dev/null +++ b/iso/dragonfire-master/debian/changelog @@ -0,0 +1,58 @@ +dragonfire (1.0.0) unstable; urgency=medium + + * Post-installation scripts are fixed + * An API implemented + * The project is turned into more of a server-side application although it's continuing to preserve the features of its desktop application aspect + * The package is now Python 3 only + * Universal Python wheel generation disabled + * Basic Analyzer (done in dragonfire/__init__.py) is heavily pruned and improved. Now it's purely spaCy based + * Omniscient and Learner classes are refactored + * Learning ability now can store data (that comes from many different Android users) on MySQL database seamlessly + * Gspeech alternative added + + -- Mehmet Mert Yildiran Tue, 19 Jun 2018 01:57:10 +0300 + +dragonfire (0.9.9) unstable; urgency=medium + + * Twitter integration implemented + * Ability to answer arithmetic questions added + * A fourth way to respond, Deep Conversation system added + + -- Mehmet Mert Yildiran Sat, 12 May 2018 14:59:20 +0000 + +dragonfire (0.9.8) unstable; urgency=medium + + * Migrated from Kaldi Speech Recognition Toolkit to Mozilla DeepSpeech + * Python3 compatibility improved + * System tray icon is now GTK+ based instead of wxPython + + -- Mehmet Mert Yildiran Thu, 26 Apr 2018 21:33:21 +0000 + +dragonfire (0.9.7) unstable; urgency=medium + + * Python3 support added + * Omniscient Q&A Engine success rate is improved by ~40% + * The learning capabilities are improved by including the inverted case + * Wikipedia connection and disambiguation errors are fixed + * Several minor bugs are fixed + * Missing package dependencies are added + * Post-installation scripts are fixed + + -- Mehmet Mert Yildiran Sat, 28 Oct 2017 02:39:47 +0000 + +dragonfire (0.9.6) unstable; urgency=medium + + * Migrated from PyPI SpeechRecognition package to Kaldi Speech Recognition Toolkit + * Migrated from festival cmu_us_clb_arctic voice to flite slt voice + * Kaldi GStreamer English model is added + * Google Search built-in commands are added + * Several minor bugs are fixed + * A number of experimental(non-functional) scripts are added + + -- Mehmet Mert Yildiran Mon, 16 Oct 2017 21:57:32 +0000 + +dragonfire (0.9.5) unstable; urgency=medium + + * Initial release (Closes: #869121) + + -- Mehmet Mert Yildiran Mon, 17 Jul 2017 22:20:48 +0000 diff --git a/iso/dragonfire-master/debian/compat b/iso/dragonfire-master/debian/compat new file mode 100644 index 00000000..ec635144 --- /dev/null +++ b/iso/dragonfire-master/debian/compat @@ -0,0 +1 @@ +9 diff --git a/iso/dragonfire-master/debian/control b/iso/dragonfire-master/debian/control new file mode 100644 index 00000000..3cfcd0a8 --- /dev/null +++ b/iso/dragonfire-master/debian/control @@ -0,0 +1,23 @@ +Source: dragonfire +Section: python +Priority: extra +Maintainer: Mehmet Mert Yildiran +Build-Depends: debhelper (>= 9), python3, python3-all-dev, libglib2.0-dev, libcairo2-dev, libgtk2.0-dev +Standards-Version: 3.9.5 + +Package: dragonfire +Architecture: any +X-Python3-Version: >= 3.2 +Pre-Depends: dpkg (>= 1.16.1), python2.7-minimal, ${misc:Pre-Depends} +Depends: ${python3:Depends}, ${misc:Depends}, flite, python3-xlib, portaudio19-dev, python3-all-dev, flac, libnotify-bin, python3-lxml, python3-nltk, python3-pyaudio, python3-httplib2, python3-pip, python3-setuptools, python3-wheel, libgstreamer1.0-dev, gstreamer1.0-plugins-good, gstreamer1.0-tools, subversion, libatlas-base-dev, automake, autoconf, libtool, libgtk2.0-0, gir1.2-gtk-3.0 +Description: Virtual assistant for Debian based Linux distributions. + The user can execute it either from + command line or from the Application Launcher. It receives + voice commands from users and takes actions accordingly. + Dragonfire goes through these steps for your commands, + respectively: (1) Search across the built-in commands. + (2) Try to Learn using Advanced NLP and Database Management + Techniques. (3) Ask to Omniscient Q&A Engine. Dragonfire plays + an avatar animation on the screen (for max 10 seconds) + everytime she speaks. It uses default notification method + of the system and also places an icon into system tray. diff --git a/iso/dragonfire-master/debian/dragonfire.1 b/iso/dragonfire-master/debian/dragonfire.1 new file mode 100644 index 00000000..a6ba8473 --- /dev/null +++ b/iso/dragonfire-master/debian/dragonfire.1 @@ -0,0 +1,108 @@ +.\" Process this file with +.\" groff -man -Tascii foo.1 +.\" +.TH DRAGONFIRE 1 "JULY 2017" Linux "User Manuals" +.SH NAME +dragonfire \- Virtual assistant for Debian based Linux distributions +.SH SYNOPSIS +.B dragonfire [--cli] +.B ... +.SH DESCRIPTION +.B dragonfire +is the virtual assistant of Debian based +Linux distributions. The user can execute it either from +command line or from the Application Launcher. It receives +voice commands from users and takes actions accordingly. +Dragonfire goes through these steps for your commands, +respectively: (1) Search across the built-in commands. +(2) Try to Learn using Advanced NLP and Database Management +Techniques. (3) Ask to Omniscient Q&A Engine. Dragonfire plays +an avatar animation on the screen (for max 10 seconds) +everytime she speaks. It uses default notification method +of the system and also places an icon into system tray. +.SH OPTIONS +.\" +.TP +.BR \-c ", " \-\-cli +Command\-line interface mode. Give commands to Dragonfire via +command\-line inputs (keyboard) instead of audio inputs (microphone). +.\" +.TP +.BR \-s ", " \-\-silent +Silent mode. Disable Text\-to\-Speech output. Dragonfire won't +generate any audio output. +.\" +.TP +.BR \-\-headless +Headless mode. Do not display an avatar animation on the screen. +Disable the female head model. +.SH DIAGNOSTICS +The following issues can occur on runtime: + +\fBNo sound is coming out of my computer?\fR +.RS +Dragonfire's audio output (ALSA plug-in [aplay]: ALSA Playback) +could be mapped to wrong audio device or you can fix this either +by changing it to correct device using the audio settings of your +operating system or you can choose to use Phonon to configure your +device priority. The problem also could be related to missing +.BR festival (1) +package on your system. It should normally be installed +on post-installation automatically but try to install it one more time. +.RE + +\fBDragonfire is not reacting to my voice?\fR +.RS +First of all, Dragonfire's speech recognition ability needs an +Internet connection so make sure your machine is connected to +the Internet. If Internet connection is not the issue then most probably +Dragonfire's audio input \fB(ALSA plug-in [python2.7]: ALSA Capture)\fR +is mapped to wrong audio device so you can fix this either +by changing it to correct device using the audio settings of your +operating system or you can choose to use Phonon to configure your +device priority. +.RE + +\fBDragonfire is understanding my commands but doing nothing?\fR +.RS +Dragonfire starts on sleeping mode to do not disturb your acoustic +environment. You need to active her by saying +\fBDRAGONFIRE\fR or \fBHEY\fR or \fBWAKE UP\fR to your microphone. +.RE + +\fBDragonfire is unnecessarily jumping into real world conversation of me?\fR +.RS +Then you need to deactivate her by saying \fBGO TO SLEEP\fR. +.RE + +\fBDragonfire confusing with her own voice?\fR +.RS +Simply use your headphones instead of the speakers to listen Dragonfire or +lower the volume. +.RE + +.SH EXAMPLES +.\" +.TP +\fBdragonfire\fR +Run in plain mode. By default, audio input (microphone), avatar animation and +Text\-to\-Speech features are enabled. +.TP +\fBdragonfire --cli\fR +Run in command\-line interface mode. Take the inputs from command\-line. +Avatar animation and Text\-to\-Speech features are still active. +.TP +\fBdragonfire --cli --headless\fR +Also disable the avatar animation. Text\-to\-Speech is still active. +.TP +\fBdragonfire --cli --headless --silent\fR +Fully silent mode. Audio input (microphone), avatar animation and +Text\-to\-Speech features are all disabled. Only the command-line +interaction is possible. + +.SH AUTHOR +Mehmet Mert Yildiran + +.SH "SEE ALSO" +.BR festival (1), +.BR notify-send (1) diff --git a/iso/dragonfire-master/debian/dragonfire.desktop b/iso/dragonfire-master/debian/dragonfire.desktop new file mode 100644 index 00000000..10fed722 --- /dev/null +++ b/iso/dragonfire-master/debian/dragonfire.desktop @@ -0,0 +1,12 @@ +[Desktop Entry] +Version=1.0.0 +Type=Application +Name=Dragonfire +Comment=Virtual Assistant for Linux +Exec=dragonfire +Categories=Utility; +# desktop should run this in a terminal application +Terminal=false +StartupNotify=true +StartupWMClass=dragonfire +Icon=dragonfire_icon.png diff --git a/iso/dragonfire-master/debian/dragonfire.triggers b/iso/dragonfire-master/debian/dragonfire.triggers new file mode 100644 index 00000000..643f7a23 --- /dev/null +++ b/iso/dragonfire-master/debian/dragonfire.triggers @@ -0,0 +1,7 @@ +# Register interest in Python interpreter changes (Python 2 for now); and +# don't make the Python package dependent on the virtualenv package +# processing (noawait) +interest-noawait /usr/bin/python2.7 + +# Also provide a symbolic trigger for all dh-virtualenv packages +interest dh-virtualenv-interpreter-update diff --git a/iso/dragonfire-master/debian/dragonfire_icon.png b/iso/dragonfire-master/debian/dragonfire_icon.png new file mode 100644 index 00000000..66d08065 Binary files /dev/null and b/iso/dragonfire-master/debian/dragonfire_icon.png differ diff --git a/iso/dragonfire-master/debian/fire/dragonfire b/iso/dragonfire-master/debian/fire/dragonfire new file mode 100644 index 00000000..cb8653e9 --- /dev/null +++ b/iso/dragonfire-master/debian/fire/dragonfire @@ -0,0 +1,12 @@ +#!/usr/bin/python3 +# EASY-INSTALL-ENTRY-SCRIPT: 'dragonfire==1.0.0','console_scripts','dragonfire' +__requires__ = 'dragonfire==1.0.0' +import re +import sys +from pkg_resources import load_entry_point + +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0]) + sys.exit( + load_entry_point('dragonfire==1.0.0', 'console_scripts', 'dragonfire')() + ) diff --git a/iso/dragonfire-master/debian/install b/iso/dragonfire-master/debian/install new file mode 100644 index 00000000..c7478b17 --- /dev/null +++ b/iso/dragonfire-master/debian/install @@ -0,0 +1,6 @@ +# install bash script to usr/bin +# usr/local/bin seems to only be for self compiled stuff +debian/fire/dragonfire usr/bin +# Copy application file and icon +debian/dragonfire.desktop usr/share/applications +debian/dragonfire_icon.png usr/share/icons/hicolor/48x48/apps diff --git a/iso/dragonfire-master/debian/postinst b/iso/dragonfire-master/debian/postinst new file mode 100644 index 00000000..0ebd7e0c --- /dev/null +++ b/iso/dragonfire-master/debian/postinst @@ -0,0 +1,38 @@ +#!/bin/bash +#DEBHELPER# +RED='\033[0;31m' +GREEN='\033[0;32m' +NC='\033[0m' # No Color +CHECKSUM="1449d83e0a0b834c033067bf62f06277" +CHECKSUM2="c775d819ffc06118053a48808003df84" + +DRAGONFIRE_DIR=/usr/share/dragonfire +if [ ! -d "$DRAGONFIRE_DIR" ]; then + mkdir $DRAGONFIRE_DIR +fi + +DEEPSPEECH_DIR=/usr/share/dragonfire/deepspeech +if [ ! -d "$DEEPSPEECH_DIR" ]; then + mkdir $DEEPSPEECH_DIR +fi +cd $DEEPSPEECH_DIR +verified=$(md5sum models/* | md5sum) +if [ ! ${verified::-3} = "$CHECKSUM" ]; then + wget -nc -O - https://github.com/mozilla/DeepSpeech/releases/download/v0.1.1/deepspeech-0.1.1-models.tar.gz | tar xvfz - +fi + +DEEPCONV_DIR=/usr/share/dragonfire/deepconv +if [ ! -d "$DEEPCONV_DIR" ]; then + mkdir $DEEPCONV_DIR +fi +cd $DEEPCONV_DIR +verified=$(find . -type f -exec md5sum {} \; | md5sum) +if [ ! ${verified::-3} = "$CHECKSUM2" ]; then + wget -nc -O - https://github.com/DragonComputer/Dragonfire/releases/download/v0.9.9/deepconv-v2.tar.gz | tar xvfz - +fi + + +pip3 install --upgrade wikipedia==1.4.0 PyUserInput==0.1.11 tinydb==3.9.0.post1 youtube_dl spacy==2.0.11 pyowm==2.9.0 tensorflow==1.0.0 deepspeech==0.2.0a5 SpeechRecognition tweepy==3.6.0 metadata_parser==0.9.20 hug==2.4.0 hug-middleware-cors==1.0.0 waitress==1.1.0 requests==2.19.1 pyjwt==1.6.4 SQLAlchemy==1.2.10 PyMySQL==0.8.1 && \ +python3 -m spacy download en && \ +pip3 install https://github.com/huggingface/neuralcoref-models/releases/download/en_coref_sm-3.0.0/en_coref_sm-3.0.0.tar.gz && \ +printf "import nltk\nnltk.download('names')\nnltk.download('brown')\nnltk.download('wordnet')\nnltk.download('punkt')" | python3 && echo -e "\n\n${GREEN}Dragonfire is successfully installed to your computer.${NC}\n" diff --git a/iso/dragonfire-master/debian/postrm b/iso/dragonfire-master/debian/postrm new file mode 100644 index 00000000..dc317e5e --- /dev/null +++ b/iso/dragonfire-master/debian/postrm @@ -0,0 +1,2 @@ +DRAGONFIRE_DIR=/usr/share/dragonfire +rm -rf $DRAGONFIRE_DIR diff --git a/iso/dragonfire-master/debian/rules b/iso/dragonfire-master/debian/rules new file mode 100644 index 00000000..5d51a5e7 --- /dev/null +++ b/iso/dragonfire-master/debian/rules @@ -0,0 +1,11 @@ +#! /usr/bin/make -f + +#export DH_VERBOSE = 1 +export PYBUILD_NAME = foo +export PYBUILD_DISABLE_python3=test + +%: + dh $@ --with python3 --buildsystem=pybuild + +override_dh_installman: + dh_installman debian/dragonfire.1 diff --git a/iso/dragonfire-master/docs/Makefile b/iso/dragonfire-master/docs/Makefile new file mode 100644 index 00000000..57222ddf --- /dev/null +++ b/iso/dragonfire-master/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXPROJ = Dragonfire +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/iso/dragonfire-master/docs/TROUBLESHOOTING.md b/iso/dragonfire-master/docs/TROUBLESHOOTING.md new file mode 100644 index 00000000..5e71f949 --- /dev/null +++ b/iso/dragonfire-master/docs/TROUBLESHOOTING.md @@ -0,0 +1,171 @@ +## Troubleshooting + +#### No sound is coming out of my computer? + +If there is no sound coming from your speakers when you see `Dragonfire: GOOD MORNING SIR` on your terminal or *To activate say 'Dragonfire!' or 'Wake Up!'* notification after you run Dragonfire with `dragonfire` command then there are two possibilities causing this problem: + +1. Dragonfire's audio output (ALSA plug-in [flite]: ALSA Playback) could be mapped to wrong audio device: + +![](https://i.imgur.com/mOie7G6.png) + +you can fix this either by changing it to correct device using the audio settings of your operating system or you can choose to use Phonon `sudo apt-get install phonon` to configure your device priority: + +![](http://i.imgur.com/tALl6UG.png) + +2. The problem could be related to missing `flite` package on your system. It should normally be installed on post-installation automatically but try to re-install it one more time with: + +``` +sudo apt-get update +sudo apt-get install flite +``` + +If `flite` is missing in your distro's repositories then [download](https://packages.ubuntu.com/xenial/amd64/flite/download) it and try to install it with `sudo dpkg -i flite_2.0.0-release-1_amd64.deb`. + +#### Dragonfire is not reacting to my voice? + + - Since we migrated to [Kaldi Speech Recognition Toolkit](https://github.com/kaldi-asr/kaldi), Dragonfire's speech recognition procedure runs fully on local. + - First of all, please make sure that Kaldi is compiled and installed under `/usr/share/kaldi` directory. If you suspect that Kaldi's compilation failed on installation procedure then please clone the repository `git clone https://github.com/DragonComputer/Dragonfire.git`and run [install.sh](https://github.com/DragonComputer/Dragonfire/blob/master/install.sh) script with either `sudo ./install.sh` or `sudo bash install.sh`. Make sure that [this block](https://github.com/DragonComputer/Dragonfire/blob/master/install.sh#L23-L53) runs without any problem because it clones Kaldi under `/usr/share/kaldi` and compiles it directory by directory. + - If you are sure that Kaldi installation is OK then first run `export GST_PLUGIN_PATH=/usr/share/kaldi/src/gst-plugin` after that run [decoder_test.py](https://github.com/DragonComputer/Dragonfire/blob/master/dragonfire/sr/decoder_test.py) (`python decoder_test.py`) to test the speech recognition. It will run two tests: + 1. Microphone test so you will speak and it will recognize the speech. + 2. Audio file(located under `tests/ten_digits.wav`) test. The output should look like this: + +``` +INFO:decoder:recognize: Pushing EOS to pipeline +INFO:decoder:recognize: Got word: DRAGON +INFO:decoder:recognize: Got word: FIRE +INFO:decoder:recognize: Got word: <#s> +INFO:decoder:recognize: Pipeline received eos signal +INFO:decoder:recognize: Finishing request +['DRAGON', 'FIRE', '<#s>'] +.INFO:decoder:testWav: Pipeline initialized +INFO:decoder:testWav: Connecting audio decoder +INFO:decoder:testWav: Connected audio decoder +INFO:decoder:testWav: Pushing EOS to pipeline +INFO:decoder:testWav: Got word: ONE +INFO:decoder:testWav: Got word: TWO +INFO:decoder:testWav: Got word: THREE +INFO:decoder:testWav: Got word: FOUR +INFO:decoder:testWav: Got word: FIVE +INFO:decoder:testWav: Got word: SIX +INFO:decoder:testWav: Got word: SEVEN +INFO:decoder:testWav: Got word: EIGHT +INFO:decoder:testWav: Got word: <#s> +INFO:decoder:testWav: Pipeline received eos signal +INFO:decoder:testWav: Finishing request +. +---------------------------------------------------------------------- +Ran 2 tests in 23.039s + +OK +``` + + - If you face with a problem in above test then most probably Dragonfire's audio input (ALSA plug-in [python]: ALSA Capture) is mapped to wrong audio device: + +![](https://i.imgur.com/8YJMery.png) + +you can fix this either by changing it to correct device using the audio settings of your operating system or you can choose to use Phonon `sudo apt-get install phonon` to configure your device priority: + +![](http://i.imgur.com/9b8ttnP.png) + +#### I got AttributeError: 'NoneType' object has no attribute 'set_property'? + +``` +File "/usr/bin/dragonfire", line 11, in + load_entry_point('dragonfire', 'console_scripts', 'dragonfire')() +File "/home/tardog/Dokumente/Spielweise/Dragonfire/dragonfire/__init__.py", line 544, in initiate + start(args) +File "/home/tardog/Dokumente/Spielweise/Dragonfire/dragonfire/__init__.py", line 60, in start + recognizer = KaldiRecognizer() +File "/home/tardog/Dokumente/Spielweise/Dragonfire/dragonfire/sr/kaldi.py", line 34, in __init__ + self.decoder_pipeline = DecoderPipeline({"decoder" : decoder_conf}) +File "/home/tardog/Dokumente/Spielweise/Dragonfire/dragonfire/sr/decoder.py", line 17, in __init__ + self.create_pipeline(conf) +File "/home/tardog/Dokumente/Spielweise/Dragonfire/dragonfire/sr/decoder.py", line 47, in create_pipeline + self.asr.set_property(key, val) +AttributeError: 'NoneType' object has no attribute 'set_property' +``` + +If you got the above error then; + - either Kaldi installation has a problem so follow the instructions in **Dragonfire is not reacting to my voice?** + - or Kaldi installation is OK but somehow [this line](https://github.com/DragonComputer/Dragonfire/blob/78adeedf7a278bcb26786130c0c6dd46d914fc95/dragonfire/__init__.py#L65) is not working so run `export GST_PLUGIN_PATH=/usr/share/kaldi/src/gst-plugin` before launching Dragonfire (in the same shell). + +#### Dragonfire is understanding my commands but doing nothing? + +Dragonfire starts on sleeping mode to do not disturb your acoustic environment. You need to activate her by saying *DRAGONFIRE* or *HEY* or *WAKE UP* to your microphone. + +#### Dragonfire is unnecessarily jumping into real world conversation of mine? + +Then you need to deactivate her by saying *GO TO SLEEP*. + +#### Dragonfire confusing with her own voice? + +Simply use your headphones:headphones: instead of the speakers:speaker: to listen Dragonfire or lower the volume of your speakers:speaker:. + +#### Dragonfire started to read something but I don't know how to stop her? + +Then you need to silence her by saying *ENOUGH* OR *SHUT UP*. + +#### I'm done with Dragonfire, how can I shut her down? + +By saying *GOODBYE* or *BYE BYE* or *SEE YOU LATER*. + +#### I'm not seeing any 3D female head model(avatar) on the screen? + +If you did not run Dragonfire with `--headless` option then you should be able to see the below avatar every time you hear a text-to-speech output. + +![](https://github.com/DragonComputer/Dragonfire/raw/master/dragonfire/realhud/animation/avatar.gif) + +Although, our [C program](https://github.com/DragonComputer/Dragonfire/blob/master/dragonfire/realhud/realhud.c) that runs the avatar animation has not the best compatibility across the different desktop environments or window managers. For example; in Unity desktop environment, it flashes badly but in KDE Plasma 5, it runs pretty smooth. + +#### Dragonfire calls me "Lady" but I'm a man? + +Dragonfire analyzes your name that registered on the operating system to determine your gender. Sometimes she makes mistakes (mostly if your name is not an English name) and call you by your opposite gender. To fix this you can say *MY TITLE IS SIR* or *I'M A MAN* or *I'M A BOY*. + +#### Dragonfire calls me "Sir" but I'm a woman? + +Dragonfire analyzes your name that registered on the operating system to determine your gender. Sometimes she makes mistakes (mostly if your name is not an English name) and call you by your opposite gender. To fix this you can say *MY TITLE IS LADY* or *I'M A LADY* or *I'M A WOMAN* or *I'M A GIRL*. + +#### I want to be called as something different? + +Sure, there is a command for that. You can use `CALL ME *` command to manipulate her form of address for you to anything you want. For example: *CALL ME MASTER* or *CALL ME MY LORD* or *CALL ME MY FRIEND* etc. + +#### I'm saying FILE MANAGER but file manager is not opening? + +Probably you don't have any of the supported file manager software packages: `dolphin`, `pantheon-files`, `nautilus` + +#### I'm saying WEB BROWSER but web browser is not opening? + +Check the existence of `sensible-browser` command. It's a command that points out to your default web browser. + +#### I'm saying PHOTO EDITOR but no software is opening? + +Probably you don't have [GIMP](https://www.gimp.org/) installed on your system: `sudo apt-get install gimp` + +#### I'm saying INKSCAPE but Inskcape is not opening? + +Probably you don't have [Inkscape](https://inkscape.org/en/) installed on your system: `sudo apt-get install inkscape` + +#### I'm saying VIDEO EDITOR but no software is opening? + +Probably you don't have any of the supported video editor software packages: `openshot`, `lightworks`, `kdenlive` + +#### Something went wrong on the installation, I'm not sure what? + +[This script](https://github.com/DragonComputer/Dragonfire/blob/master/install.sh) will try to install dependencies for you. Run these commands, respectively: + +``` +git clone https://github.com/DragonComputer/Dragonfire.git +cd Dragonfire/ +chmod +x install.sh +sudo ./install.sh +``` + +#### Dragonfire started to give me senseless answers? + +Dragonfire's learning is far from perfect so by the time, the conversations filled with incorrect information can lead her to wrong answers like `THE SUN IS HOT AND COLD`. To fix this kind of situations you can always wipe out her memories about the subject by calling: `FORGET ABOUT THE SUN` + +#### Learning feature is blocking my way to reach to Omniscient Q&A Engine? + +Learning feature has a priority so if in the past, you said something like `ALBERT EINSTEIN IS A PHYSICIST` then it will block your way when you asked anything about **Albert Einstein**. To fix this you should say: `FORGET ABOUT ALBERT EINSTEIN` + +:checkered_flag: If none of the cases listed above are fitting to your situation then always consider to [file an issue](https://github.com/DragonComputer/Dragonfire/issues/new) or visit our [chat room on Gitter](https://gitter.im/DragonComputer/Lobby). diff --git a/iso/dragonfire-master/docs/img/demo.gif b/iso/dragonfire-master/docs/img/demo.gif new file mode 100644 index 00000000..0733a2ab Binary files /dev/null and b/iso/dragonfire-master/docs/img/demo.gif differ diff --git a/iso/dragonfire-master/docs/requirements.txt b/iso/dragonfire-master/docs/requirements.txt new file mode 100644 index 00000000..11cc44ef --- /dev/null +++ b/iso/dragonfire-master/docs/requirements.txt @@ -0,0 +1,20 @@ +wikipedia==1.4.0 +PyUserInput==0.1.11 +tinydb==3.9.0.post1 +pyowm==2.9.0 +tensorflow==1.0.0 +tqdm +requests==2.19.1 +lxml==3.5.0 +nltk==3.1 +httplib2>=0.9.1 +imutils +PeakUtils +tweepy==3.6.0 +metadata_parser==0.9.20 +hug==2.4.0 +hug-middleware-cors==1.0.0 +waitress==1.1.0 +SQLAlchemy==1.2.10 +PyMySQL==0.8.1 +m2r diff --git a/iso/dragonfire-master/docs/source/codeofconduct.rst b/iso/dragonfire-master/docs/source/codeofconduct.rst new file mode 100644 index 00000000..f4ab40ba --- /dev/null +++ b/iso/dragonfire-master/docs/source/codeofconduct.rst @@ -0,0 +1 @@ +.. mdinclude:: ../../CODE_OF_CONDUCT.md diff --git a/iso/dragonfire-master/docs/source/conf.py b/iso/dragonfire-master/docs/source/conf.py new file mode 100644 index 00000000..cd415f50 --- /dev/null +++ b/iso/dragonfire-master/docs/source/conf.py @@ -0,0 +1,223 @@ +# -*- coding: utf-8 -*- +# +# Configuration file for the Sphinx documentation builder. +# +# This file does only contain a selection of the most common options. For a +# full list see the documentation: +# http://www.sphinx-doc.org/en/master/config + +# -- Path setup -------------------------------------------------------------- + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. + +import os +import sys + +from recommonmark.parser import CommonMarkParser +from unittest.mock import MagicMock + + +sys.path.insert(0, os.path.abspath('../..')) + + +# -- Project information ----------------------------------------------------- + +project = 'Dragonfire' +copyright = '2018, Mehmet Mert Yıldıran' +author = 'Mehmet Mert Yıldıran' + +# The short X.Y version +version = '1.0.0' +# The full version, including alpha/beta/rc tags +release = '1.0.0' + + +# -- General configuration --------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = [ + 'sphinx.ext.autodoc', + 'sphinx.ext.doctest', + 'sphinx.ext.intersphinx', + 'sphinx.ext.todo', + 'sphinx.ext.coverage', + 'sphinx.ext.mathjax', + 'sphinx.ext.ifconfig', + 'sphinx.ext.viewcode', + 'sphinx.ext.githubpages', + 'sphinx.ext.napoleon', + 'm2r', +] + +# Napoleon settings +napoleon_google_docstring = True + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: + +source_suffix = ['.rst', '.md'] + +# The master toctree document. +master_doc = 'index' + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This pattern also affects html_static_path and html_extra_path . +exclude_patterns = [] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + + +# -- Options for HTML output ------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'sphinx_rtd_theme' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, must be a dictionary that maps document names +# to template names. +# +# The default sidebars (for documents that don't match any pattern) are +# defined by theme itself. Builtin themes are using these templates by +# default: ``['localtoc.html', 'relations.html', 'sourcelink.html', +# 'searchbox.html']``. +# +# html_sidebars = {} + + +# -- Options for HTMLHelp output --------------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Dragonfiredoc' + + +# -- Options for LaTeX output ------------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'Dragonfire.tex', 'Dragonfire Documentation', + 'Mehmet Mert Yıldıran', 'manual'), +] + + +# -- Options for manual page output ------------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'dragonfire', 'Dragonfire Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ---------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'Dragonfire', 'Dragonfire Documentation', + author, 'Dragonfire', 'One line description of project.', + 'Miscellaneous'), +] + + +# -- Extension configuration ------------------------------------------------- + +# -- Options for intersphinx extension --------------------------------------- + +# Example configuration for intersphinx: refer to the Python standard library. +intersphinx_mapping = {'python': ('https://docs.python.org/3', None)} + +# -- Options for todo extension ---------------------------------------------- + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = True + +# Show __init__(self) methods in the documentation +autoclass_content = 'both' + + +# Post-install script for sphinx-build +def setup(app): + import nltk + nltk.download('names') + nltk.download('brown') + nltk.download('wordnet') + nltk.download('punkt') + + +# Mock out modules +class Mock(MagicMock): + @classmethod + def __getattr__(cls, name): + return MagicMock() + +MOCK_MODULES = [ + 'realhud', + 'spacy', + 'youtube_dl', + 'dragonfire.deepconv', + 'dragonfire.deepconv.model', + 'dragonfire.deepconv.textdata', + 'dragonfire.deepconv.corpus.cornelldata', + 'dragonfire.deepconv.corpus.lightweightdata', + 'dragonfire.deepconv.corpus.opensubsdata', + 'dragonfire.deepconv.corpus.scotusdata', + 'dragonfire.deepconv.corpus.ubuntudata', + 'dragonfire.deepconv.corpus', + 'dragonfire.sr.decoder_test', + 'dragonfire.sr.experimental' +] +sys.modules.update((mod_name, Mock()) for mod_name in MOCK_MODULES) diff --git a/iso/dragonfire-master/docs/source/contributing.rst b/iso/dragonfire-master/docs/source/contributing.rst new file mode 100644 index 00000000..f2c987c7 --- /dev/null +++ b/iso/dragonfire-master/docs/source/contributing.rst @@ -0,0 +1 @@ +.. mdinclude:: ../../CONTRIBUTING.md diff --git a/iso/dragonfire-master/docs/source/dragonfire.deepconv.corpus.rst b/iso/dragonfire-master/docs/source/dragonfire.deepconv.corpus.rst new file mode 100644 index 00000000..29d92d64 --- /dev/null +++ b/iso/dragonfire-master/docs/source/dragonfire.deepconv.corpus.rst @@ -0,0 +1,54 @@ +dragonfire.deepconv.corpus package +================================== + +Submodules +---------- + +dragonfire.deepconv.corpus.cornelldata module +--------------------------------------------- + +.. automodule:: dragonfire.deepconv.corpus.cornelldata + :members: + :undoc-members: + :show-inheritance: + +dragonfire.deepconv.corpus.lightweightdata module +------------------------------------------------- + +.. automodule:: dragonfire.deepconv.corpus.lightweightdata + :members: + :undoc-members: + :show-inheritance: + +dragonfire.deepconv.corpus.opensubsdata module +---------------------------------------------- + +.. automodule:: dragonfire.deepconv.corpus.opensubsdata + :members: + :undoc-members: + :show-inheritance: + +dragonfire.deepconv.corpus.scotusdata module +-------------------------------------------- + +.. automodule:: dragonfire.deepconv.corpus.scotusdata + :members: + :undoc-members: + :show-inheritance: + +dragonfire.deepconv.corpus.ubuntudata module +-------------------------------------------- + +.. automodule:: dragonfire.deepconv.corpus.ubuntudata + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: dragonfire.deepconv.corpus + :members: + :undoc-members: + :show-inheritance: diff --git a/iso/dragonfire-master/docs/source/dragonfire.deepconv.rst b/iso/dragonfire-master/docs/source/dragonfire.deepconv.rst new file mode 100644 index 00000000..fe248ae5 --- /dev/null +++ b/iso/dragonfire-master/docs/source/dragonfire.deepconv.rst @@ -0,0 +1,37 @@ +dragonfire.deepconv package +=========================== + +Subpackages +----------- + +.. toctree:: + + dragonfire.deepconv.corpus + +Submodules +---------- + +dragonfire.deepconv.model module +-------------------------------- + +.. automodule:: dragonfire.deepconv.model + :members: + :undoc-members: + :show-inheritance: + +dragonfire.deepconv.textdata module +----------------------------------- + +.. automodule:: dragonfire.deepconv.textdata + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: dragonfire.deepconv + :members: + :undoc-members: + :show-inheritance: diff --git a/iso/dragonfire-master/docs/source/dragonfire.rst b/iso/dragonfire-master/docs/source/dragonfire.rst new file mode 100644 index 00000000..3ff617ac --- /dev/null +++ b/iso/dragonfire-master/docs/source/dragonfire.rst @@ -0,0 +1,95 @@ +dragonfire package +================== + +Subpackages +----------- + +.. toctree:: + + dragonfire.deepconv + dragonfire.sr + dragonfire.tts + +Submodules +---------- + +dragonfire.api module +--------------------- + +.. automodule:: dragonfire.api + :members: + :undoc-members: + :show-inheritance: + +dragonfire.arithmetic module +---------------------------- + +.. automodule:: dragonfire.arithmetic + :members: + :undoc-members: + :show-inheritance: + +dragonfire.config module +------------------------ + +.. automodule:: dragonfire.config + :members: + :undoc-members: + :show-inheritance: + +dragonfire.learn module +----------------------- + +.. automodule:: dragonfire.learn + :members: + :undoc-members: + :show-inheritance: + +dragonfire.nlplib module +------------------------ + +.. automodule:: dragonfire.nlplib + :members: + :undoc-members: + :show-inheritance: + +dragonfire.omniscient module +---------------------------- + +.. automodule:: dragonfire.omniscient + :members: + :undoc-members: + :show-inheritance: + +dragonfire.stray module +----------------------- + +.. automodule:: dragonfire.stray + :members: + :undoc-members: + :show-inheritance: + +dragonfire.twitter module +------------------------- + +.. automodule:: dragonfire.twitter + :members: + :undoc-members: + :show-inheritance: + +dragonfire.utilities module +--------------------------- + +.. automodule:: dragonfire.utilities + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: dragonfire + :members: + :undoc-members: + :show-inheritance: diff --git a/iso/dragonfire-master/docs/source/dragonfire.sr.deepspeech.rst b/iso/dragonfire-master/docs/source/dragonfire.sr.deepspeech.rst new file mode 100644 index 00000000..05fb681f --- /dev/null +++ b/iso/dragonfire-master/docs/source/dragonfire.sr.deepspeech.rst @@ -0,0 +1,30 @@ +dragonfire.sr.deepspeech package +================================ + +Submodules +---------- + +dragonfire.sr.deepspeech.config module +-------------------------------------- + +.. automodule:: dragonfire.sr.deepspeech.config + :members: + :undoc-members: + :show-inheritance: + +dragonfire.sr.deepspeech.server module +-------------------------------------- + +.. automodule:: dragonfire.sr.deepspeech.server + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: dragonfire.sr.deepspeech + :members: + :undoc-members: + :show-inheritance: diff --git a/iso/dragonfire-master/docs/source/dragonfire.sr.rst b/iso/dragonfire-master/docs/source/dragonfire.sr.rst new file mode 100644 index 00000000..1edca7af --- /dev/null +++ b/iso/dragonfire-master/docs/source/dragonfire.sr.rst @@ -0,0 +1,69 @@ +dragonfire.sr package +===================== + +Subpackages +----------- + +.. toctree:: + + dragonfire.sr.deepspeech + +Submodules +---------- + +dragonfire.sr.decoder module +---------------------------- + +.. automodule:: dragonfire.sr.decoder + :members: + :undoc-members: + :show-inheritance: + +dragonfire.sr.decoder\_test module +---------------------------------- + +.. automodule:: dragonfire.sr.decoder_test + :members: + :undoc-members: + :show-inheritance: + +dragonfire.sr.experimental module +--------------------------------- + +.. automodule:: dragonfire.sr.experimental + :members: + :undoc-members: + :show-inheritance: + +dragonfire.sr.gspeech module +---------------------------- + +.. automodule:: dragonfire.sr.gspeech + :members: + :undoc-members: + :show-inheritance: + +dragonfire.sr.kaldi module +-------------------------- + +.. automodule:: dragonfire.sr.kaldi + :members: + :undoc-members: + :show-inheritance: + +dragonfire.sr.nnet module +------------------------- + +.. automodule:: dragonfire.sr.nnet + :members: + :undoc-members: + :show-inheritance: + + +Module contents +--------------- + +.. automodule:: dragonfire.sr + :members: + :undoc-members: + :show-inheritance: diff --git a/iso/dragonfire-master/docs/source/dragonfire.tts.rst b/iso/dragonfire-master/docs/source/dragonfire.tts.rst new file mode 100644 index 00000000..c16ba8a5 --- /dev/null +++ b/iso/dragonfire-master/docs/source/dragonfire.tts.rst @@ -0,0 +1,10 @@ +dragonfire.tts package +====================== + +Module contents +--------------- + +.. automodule:: dragonfire.tts + :members: + :undoc-members: + :show-inheritance: diff --git a/iso/dragonfire-master/docs/source/index.rst b/iso/dragonfire-master/docs/source/index.rst new file mode 100644 index 00000000..69462c75 --- /dev/null +++ b/iso/dragonfire-master/docs/source/index.rst @@ -0,0 +1,26 @@ +.. Dragonfire documentation master file, created by + sphinx-quickstart on Thu Aug 2 11:52:49 2018. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to Dragonfire's documentation! +====================================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + readme + troubleshooting + contributing + codeofconduct + license + + + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/iso/dragonfire-master/docs/source/license.rst b/iso/dragonfire-master/docs/source/license.rst new file mode 100644 index 00000000..e45c3f55 --- /dev/null +++ b/iso/dragonfire-master/docs/source/license.rst @@ -0,0 +1,4 @@ +License +========== + +.. mdinclude:: ../../LICENSE.txt diff --git a/iso/dragonfire-master/docs/source/modules.rst b/iso/dragonfire-master/docs/source/modules.rst new file mode 100644 index 00000000..5cff5b66 --- /dev/null +++ b/iso/dragonfire-master/docs/source/modules.rst @@ -0,0 +1,7 @@ +dragonfire +========== + +.. toctree:: + :maxdepth: 4 + + dragonfire diff --git a/iso/dragonfire-master/docs/source/readme.rst b/iso/dragonfire-master/docs/source/readme.rst new file mode 100644 index 00000000..3bd447c4 --- /dev/null +++ b/iso/dragonfire-master/docs/source/readme.rst @@ -0,0 +1 @@ +.. mdinclude:: ../../README.md diff --git a/iso/dragonfire-master/docs/source/troubleshooting.rst b/iso/dragonfire-master/docs/source/troubleshooting.rst new file mode 100644 index 00000000..6d95d838 --- /dev/null +++ b/iso/dragonfire-master/docs/source/troubleshooting.rst @@ -0,0 +1 @@ +.. mdinclude:: ../TROUBLESHOOTING.md diff --git a/iso/dragonfire-master/dragonfire/__init__.py b/iso/dragonfire-master/dragonfire/__init__.py new file mode 100644 index 00000000..96123f59 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/__init__.py @@ -0,0 +1,684 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +.. module:: __init__ + :platform: Unix + :synopsis: the top-level module of Dragonfire that contains the entry point and handles built-in commands. + +.. moduleauthor:: Mehmet Mert Yıldıran +""" + +import argparse # Parser for command-line options, arguments and sub-commands +import datetime # Basic date and time types +import inspect # Inspect live objects +import os # Miscellaneous operating system interfaces +import re # Regular expression operations +import subprocess # Subprocess managements +import sys # System-specific parameters and functions +try: + import thread # Low-level threading API (Python 2.7) +except ImportError: + import _thread as thread # Low-level threading API (Python 3.x) +import time # Time access and conversions +import uuid # UUID objects according to RFC 4122 +from multiprocessing import Event, Process # Process-based “threading” interface +from os.path import expanduser # Common pathname manipulations +from random import choice # Generate pseudo-random numbers +import shutil # High-level file operations + +from dragonfire.learn import Learner # Submodule of Dragonfire that forms her learning ability +from dragonfire.nlplib import Classifier, Helper # Submodule of Dragonfire to handle extra NLP tasks +from dragonfire.omniscient import Omniscient # Submodule of Dragonfire that serves as a Question Answering Engine +from dragonfire.stray import SystemTrayExitListenerSet, SystemTrayInit # Submodule of Dragonfire for System Tray Icon related functionalities +from dragonfire.utilities import TextToAction, nostdout, nostderr # Submodule of Dragonfire to provide various utilities +from dragonfire.arithmetic import arithmetic_parse # Submodule of Dragonfire to analyze arithmetic expressions +from dragonfire.deepconv import DeepConversation # Submodule of Dragonfire to answer questions directly using an Artificial Neural Network +from dragonfire.coref import NeuralCoref # Submodule of Dragonfire that aims to create corefference based dialogs +from dragonfire.config import Config # Submodule of Dragonfire to store configurations +from dragonfire.database import Base # Submodule of Dragonfire module that contains the database schema + +import spacy # Industrial-strength Natural Language Processing in Python +import pyowm # A Python wrapper around the OpenWeatherMap API +import wikipedia # Python library that makes it easy to access and parse data from Wikipedia +import wikipedia.exceptions # Exceptions of wikipedia library +import requests.exceptions # HTTP for Humans +import youtube_dl # Command-line program to download videos from YouTube.com and other video sites +from pykeyboard import PyKeyboard # A simple, cross-platform Python module for providing keyboard control +from pymouse import PyMouse # Cross-platform Python mouse module +from tinydb import Query, TinyDB # TinyDB is a lightweight document oriented database optimized for your happiness +from sqlalchemy import create_engine # the Python SQL toolkit and Object Relational Mapper +from sqlalchemy.orm import sessionmaker # ORM submodule of SQLAlchemy + + +__version__ = '1.0.0' + +DRAGONFIRE_PATH = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) +FNULL = open(os.devnull, 'w') +GENDER_PREFIX = {'male': 'Sir', 'female': 'My Lady'} +CONVERSATION_ID = uuid.uuid4() +userin = None +nlp = spacy.load('en') # Load en_core_web_sm, English, 50 MB, default model +learner = Learner(nlp) +omniscient = Omniscient(nlp) +dc = DeepConversation() +coref = NeuralCoref() +e = Event() + +USER_ANSWERING = { + 'status': False, + 'for': None, + 'reason': None, + 'options': None +} + +try: + raw_input # Python 2 +except NameError: + raw_input = input # Python 3 + + +def start(args, userin): + """Function that starts the virtual assistant with the correct mode according to command-line arguments. + + Args: + args: Command-line arguments. + userin: :class:`dragonfire.utilities.TextToAction` instance. + """ + + if args["sqlite"]: + engine = create_engine('sqlite:///dragonfire.db', connect_args={'check_same_thread': False}, echo=True) + else: + engine = create_engine('mysql+pymysql://' + Config.MYSQL_USER + ':' + Config.MYSQL_PASS + '@' + Config.MYSQL_HOST + '/' + Config.MYSQL_DB) + Base.metadata.create_all(engine) + Base.metadata.bind = engine + DBSession = sessionmaker(bind=engine) + db_session = DBSession() + learner.db_session = db_session + + if args["server"]: + import dragonfire.api as API # API of Dragonfire + import tweepy # An easy-to-use Python library for accessing the Twitter API + from tweepy import OAuthHandler + from tweepy import Stream + from dragonfire.twitter import MentionListener + + if Config.TWITTER_CONSUMER_KEY != 'CONSUMER_KEY': + auth = OAuthHandler(Config.TWITTER_CONSUMER_KEY, Config.TWITTER_CONSUMER_SECRET) + auth.set_access_token(Config.TWITTER_ACCESS_KEY, Config.TWITTER_ACCESS_SECRET) + userin.twitter_api = tweepy.API(auth) + + print("Listening Twitter mentions...") + l = MentionListener(args, userin) + stream = Stream(auth, l) + stream.filter(track=['DragonfireAI'], async=True) + API.Run(nlp, learner, omniscient, dc, coref, userin, args["server"], args["port"], db_session) + else: + global user_full_name + global user_prefix + if args["cli"]: + her = VirtualAssistant(args, userin, user_full_name, user_prefix) + while (True): + com = raw_input("Enter your command: ") + thread.start_new_thread(her.command, (com,)) + time.sleep(0.5) + elif args["gspeech"]: + from dragonfire.sr.gspeech import GspeechRecognizer + + recognizer = GspeechRecognizer() + recognizer.recognize(args, userin, user_full_name, user_prefix) + else: + from dragonfire.sr.deepspeech import DeepSpeechRecognizer + + recognizer = DeepSpeechRecognizer() + recognizer.recognize(args, userin, user_full_name, user_prefix) + + +class VirtualAssistant(): + """Class to define a virtual assistant. + + This class provides necessary initiations and a function named :func:`dragonfire.VirtualAssistant.command` + as the entry point for each one of the user commands. + + .. note:: + + This class is not used in the API. + + """ + + def __init__(self, args, userin, user_full_name="John Doe", user_prefix="sir", tw_user=None, testing=False): + """Initialization method of :class:`dragonfire.VirtualAssistant` class. + + Args: + args: Command-line arguments. + userin: :class:`dragonfire.utilities.TextToAction` instance. + + Keyword Args: + user_full_name (str): User's full name to answer some basic questions + user_prefix (str): Prefix to address/call user when answering + tw_user (str): Twitter username of the person querying DragonfireAI Twitter account with a mention + """ + + self.args = args + self.userin = userin + self.user_full_name = user_full_name + self.user_prefix = user_prefix + self.userin.twitter_user = tw_user + self.testing = testing + self.inactive = False + if not self.args["server"]: + self.inactive = True + if self.testing: + home = expanduser("~") + self.config_file = TinyDB(home + '/.dragonfire_config.json') + + def command(self, com): + """Function that serves as the entry point for each one of the user commands. + + This function goes through these steps for each one of user's commands, respectively: + + - Search across the built-in commands via a simple if-else control flow. + - Try to get a response from :func:`dragonfire.arithmetic.arithmetic_parse` function. + - Try to get a response from :func:`dragonfire.learn.Learner.respond` method. + - Try to get a answer from :func:`dragonfire.omniscient.Omniscient.respond` method. + - Try to get a response from :func:`dragonfire.deepconv.DeepConversation.respond` method. + + Args: + com (str): User's command. + + Returns: + str: Response. + """ + + if not self.args["server"]: + global config_file + global e + if (e.is_set()): # System Tray Icon exit must trigger this + exit(0) + args = self.args + userin = self.userin + user_full_name = self.user_full_name + user_prefix = self.user_prefix + if self.testing: + config_file = self.config_file + + if isinstance(com, str) and com: + com = com.strip() + else: + return False + + print("You: " + com.upper()) + doc = nlp(com) + h = Helper(doc) + + if args["verbose"]: + userin.pretty_print_nlp_parsing_results(doc) + + if self.inactive and not (h.directly_equal(["dragonfire", "hey"]) or (h.check_verb_lemma("wake") and h.check_nth_lemma(-1, "up")) or (h.check_nth_lemma(0, "dragon") and h.check_nth_lemma(1, "fire") and h.max_word_count(2))): + return "" + + if USER_ANSWERING['status']: + if com.startswith("FIRST") or com.startswith("THE FIRST") or com.startswith("SECOND") or com.startswith("THE SECOND") or com.startswith("THIRD") or com.startswith("THE THIRD"): + USER_ANSWERING['status'] = False + selection = None + if com.startswith("FIRST") or com.startswith("THE FIRST"): + selection = 0 + elif com.startswith("SECOND") or com.startswith("THE SECOND"): + selection = 1 + elif com.startswith("THIRD") or com.startswith("THE THIRD"): + selection = 2 + + if USER_ANSWERING['for'] == 'wikipedia': + with nostderr(): + search_query = USER_ANSWERING['options'][selection] + try: + wikiresult = wikipedia.search(search_query) + if len(wikiresult) == 0: + userin.say("Sorry, " + user_prefix + ". But I couldn't find anything about " + search_query + " in Wikipedia.") + return True + wikipage = wikipedia.page(wikiresult[0]) + wikicontent = "".join([i if ord(i) < 128 else ' ' for i in wikipage.content]) + wikicontent = re.sub(r'\([^)]*\)', '', wikicontent) + userin.execute(["sensible-browser", wikipage.url], search_query) + return userin.say(wikicontent, cmd=["sensible-browser", wikipage.url]) + except requests.exceptions.ConnectionError: + userin.execute([" "], "Wikipedia connection error.") + return userin.say("Sorry, " + user_prefix + ". But I'm unable to connect to Wikipedia servers.") + except Exception: + return False + + if h.directly_equal(["dragonfire", "hey"]) or (h.check_verb_lemma("wake") and h.check_nth_lemma(-1, "up")) or (h.check_nth_lemma(0, "dragon") and h.check_nth_lemma(1, "fire") and h.max_word_count(2)): + self.inactive = False + return userin.say(choice([ + "Yes, " + user_prefix + ".", + "Yes. I'm waiting.", + "What is your order?", + "Ready for the orders!", + user_prefix.capitalize() + ", tell me your wish." + ])) + if (h.check_verb_lemma("go") and h.check_noun_lemma("sleep")) or (h.check_verb_lemma("stop") and h.check_verb_lemma("listen")): + self.inactive = True + userin.execute(["echo"], "Dragonfire deactivated. To reactivate say 'Dragonfire!' or 'Wake Up!'") + return userin.say("I'm going to sleep") + if h.directly_equal(["enough"]) or (h.check_verb_lemma("shut") and h.check_nth_lemma(-1, "up")): + tts_kill() + msg = "Dragonfire quiets." + print(msg) + return msg + if h.check_wh_lemma("what") and h.check_deps_contains("your name"): + return userin.execute([" "], "My name is Dragonfire.", True) + if h.check_wh_lemma("what") and h.check_deps_contains("your gender"): + return userin.say("I have a female voice but I don't have a gender identity. I'm a computer program, " + user_prefix + ".") + if (h.check_wh_lemma("who") and h.check_text("I")) or (h.check_verb_lemma("say") and h.check_text("my") and h.check_lemma("name")): + userin.execute([" "], user_full_name) + return userin.say("Your name is " + user_full_name + ", " + user_prefix + ".") + if h.check_verb_lemma("open") or h.check_adj_lemma("open") or h.check_verb_lemma("run") or h.check_verb_lemma("start") or h.check_verb_lemma("show"): + if h.check_text("blender"): + userin.execute(["blender"], "Blender") + return userin.say("Blender 3D computer graphics software") + if h.check_text("draw"): + userin.execute(["libreoffice", "--draw"], "LibreOffice Draw") + return userin.say("Opening LibreOffice Draw") + if h.check_text("impress"): + userin.execute(["libreoffice", "--impress"], "LibreOffice Impress") + return userin.say("Opening LibreOffice Impress") + if h.check_text("math"): + userin.execute(["libreoffice", "--math"], "LibreOffice Math") + return userin.say("Opening LibreOffice Math") + if h.check_text("writer"): + userin.execute(["libreoffice", "--writer"], "LibreOffice Writer") + return userin.say("Opening LibreOffice Writer") + if h.check_text("gimp") or (h.check_noun_lemma("photo") and (h.check_noun_lemma("editor") or h.check_noun_lemma("shop"))): + userin.execute(["gimp"], "GIMP") + return userin.say("Opening the photo editor software.") + if h.check_text("inkscape") or (h.check_noun_lemma("vector") and h.check_noun_lemma("graphic")) or (h.check_text("vectorial") and h.check_text("drawing")): + userin.execute(["inkscape"], "Inkscape") + return userin.say("Opening the vectorial drawing software.") + if h.check_noun_lemma("office") and h.check_noun_lemma("suite"): + userin.execute(["libreoffice"], "LibreOffice") + return userin.say("Opening LibreOffice") + if h.check_text("kdenlive") or (h.check_noun_lemma("video") and h.check_noun_lemma("editor")): + userin.execute(["kdenlive"], "Kdenlive") + return userin.say("Opening the video editor software.") + if h.check_noun_lemma("browser") or h.check_text("chrome") or h.check_text("firefox"): + userin.execute(["sensible-browser"], "Web Browser") + return userin.say("Web browser") + if h.check_text("steam"): + userin.execute(["steam"], "Steam") + return userin.say("Opening Steam Game Store") + if h.check_text("files") or (h.check_noun_lemma("file") and h.check_noun_lemma("manager")): + userin.execute(["dolphin"], "File Manager") # KDE neon + userin.execute(["pantheon-files"], "File Manager") # elementary OS + userin.execute(["nautilus", "--browser"], "File Manager") # Ubuntu + return userin.say("File Manager") + if h.check_noun_lemma("camera"): + userin.execute(["kamoso"], "Camera") # KDE neon + userin.execute(["snap-photobooth"], "Camera") # elementary OS + userin.execute(["cheese"], "Camera") # Ubuntu + return userin.say("Camera") + if h.check_noun_lemma("calendar"): + userin.execute(["korganizer"], "Calendar") # KDE neon + userin.execute(["maya-calendar"], "Calendar") # elementary OS + userin.execute(["orage"], "Calendar") # Ubuntu + return userin.say("Calendar") + if h.check_noun_lemma("calculator"): + userin.execute(["kcalc"], "Calculator") # KDE neon + userin.execute(["pantheon-calculator"], "Calculator") # elementary OS + userin.execute(["gnome-calculator"], "Calculator") # Ubuntu + return userin.say("Calculator") + if h.check_noun_lemma("software") and h.check_text("center"): + userin.execute(["plasma-discover"], "Software Center") # KDE neon + userin.execute(["software-center"], "Software Center") # elementary OS & Ubuntu + return userin.say("Software Center") + if h.check_lemma("be") and h.check_lemma("-PRON-") and (h.check_lemma("lady") or h.check_lemma("woman") or h.check_lemma("girl")): + config_file.update({'gender': 'female'}, Query().datatype == 'gender') + config_file.remove(Query().datatype == 'callme') + user_prefix = "my lady" + return userin.say("Pardon, " + user_prefix + ".") + if h.check_lemma("be") and h.check_lemma("-PRON-") and (h.check_lemma("sir") or h.check_lemma("man") or h.check_lemma("boy")): + config_file.update({'gender': 'male'}, Query().datatype == 'gender') + config_file.remove(Query().datatype == 'callme') + user_prefix = "sir" + return userin.say("Pardon, " + user_prefix + ".") + if h.check_lemma("call") and h.check_lemma("-PRON-"): + title = "" + for token in doc: + if token.pos_ == "NOUN": + title += ' ' + token.text + title = title.strip() + if not args["server"]: + callme_config = config_file.search(Query().datatype == 'callme') + if callme_config: + config_file.update({'title': title}, Query().datatype == 'callme') + else: + config_file.insert({'datatype': 'callme', 'title': title}) + user_prefix = title + return userin.say("OK, " + user_prefix + ".") + if h.is_wh_question() and h.check_lemma("temperature"): + city = "" + for ent in doc.ents: + if ent.label_ == "GPE": + city += ' ' + ent.text + city = city.strip() + if city: + owm = pyowm.OWM("16d66c84e82424f0f8e62c3e3b27b574") + reg = owm.city_id_registry() + try: + weather = owm.weather_at_id(reg.ids_for(city)[0][0]).get_weather() + fmt = "The temperature in {} is {} degrees celsius" + msg = fmt.format(city, weather.get_temperature('celsius')['temp']) + userin.execute([" "], msg) + return userin.say(msg) + except IndexError: + msg = "Sorry, " + user_prefix + " but I couldn't find a city named " + city + " on the internet." + userin.execute([" "], msg) + return userin.say(msg) + if (h.check_nth_lemma(0, "keyboard") or h.check_nth_lemma(0, "type")) and not args["server"]: + n = len(doc[0].text) + 1 + with nostdout(): + with nostderr(): + k = PyKeyboard() + if not self.testing: + for character in com[n:]: + k.tap_key(character) + k.tap_key(" ") + return "keyboard" + if (h.directly_equal(["enter"]) or (h.check_adj_lemma("new") and h.check_noun_lemma("line"))) and not args["server"]: + with nostdout(): + with nostderr(): + k = PyKeyboard() + if not self.testing: + k.tap_key(k.enter_key) + return "enter" + if h.check_adj_lemma("new") and h.check_noun_lemma("tab") and not args["server"]: + with nostdout(): + with nostderr(): + k = PyKeyboard() + if not self.testing: + k.press_keys([k.control_l_key, 't']) + return "new tab" + if h.check_verb_lemma("switch") and h.check_noun_lemma("tab") and not args["server"]: + with nostdout(): + with nostderr(): + k = PyKeyboard() + if not self.testing: + k.press_keys([k.control_l_key, k.tab_key]) + return "switch tab" + if h.directly_equal(["CLOSE", "ESCAPE"]) and not args["server"]: + with nostdout(): + with nostderr(): + k = PyKeyboard() + if not self.testing: + k.press_keys([k.control_l_key, 'w']) + k.tap_key(k.escape_key) + return "close" + if h.check_lemma("back") and h.max_word_count(4) and not args["server"]: + with nostdout(): + with nostderr(): + k = PyKeyboard() + if not self.testing: + k.press_keys([k.alt_l_key, k.left_key]) + return "back" + if h.check_lemma("forward") and h.max_word_count(4) and not args["server"]: + with nostdout(): + with nostderr(): + k = PyKeyboard() + if not self.testing: + k.press_keys([k.alt_l_key, k.right_key]) + return "forward" + if (h.check_text("swipe") or h.check_text("scroll")) and not args["server"]: + if h.check_text("left"): + with nostdout(): + with nostderr(): + m = PyMouse() + if not self.testing: + m.scroll(0, -5) + return "swipe left" + if h.check_text("right"): + with nostdout(): + with nostderr(): + m = PyMouse() + if not self.testing: + m.scroll(0, 5) + return "swipe right" + if h.check_text("up"): + with nostdout(): + with nostderr(): + m = PyMouse() + if not self.testing: + m.scroll(5, 0) + return "swipe up" + if h.check_text("down"): + with nostdout(): + with nostderr(): + m = PyMouse() + if not self.testing: + m.scroll(-5, 0) + return "swipe down" + if h.directly_equal(["PLAY", "PAUSE", "SPACEBAR"]) and not args["server"]: + with nostdout(): + with nostderr(): + k = PyKeyboard() + if not self.testing: + k.tap_key(" ") + return "play" + if ((h.check_text("shut") and h.check_text("down")) or (h.check_text("power") and h.check_text("off"))) and h.check_text("computer") and not args["server"]: + return userin.execute(["sudo", "poweroff"], "Shutting down", True, 3) + if h.check_nth_lemma(0, "goodbye") or h.check_nth_lemma(0, "bye") or (h.check_verb_lemma("see") and h.check_text("you") and h.check_adv_lemma("later")): + response = userin.say("Goodbye, " + user_prefix) + if not args["server"] and not self.testing: + # raise KeyboardInterrupt + thread.interrupt_main() + return response + if (h.check_lemma("search") or h.check_lemma("find")) and h.check_lemma("wikipedia"): + with nostderr(): + search_query = "" + for token in doc: + if not (token.lemma_ == "search" or token.lemma_ == "find" or token.lemma_ == "wikipedia" or token.is_stop): + search_query += ' ' + token.text + search_query = search_query.strip() + if search_query: + try: + wikiresult = wikipedia.search(search_query) + if len(wikiresult) == 0: + userin.say("Sorry, " + user_prefix + ". But I couldn't find anything about " + search_query + " in Wikipedia.") + return True + wikipage = wikipedia.page(wikiresult[0]) + wikicontent = "".join([i if ord(i) < 128 else ' ' for i in wikipage.content]) + wikicontent = re.sub(r'\([^)]*\)', '', wikicontent) + userin.execute(["sensible-browser", wikipage.url], search_query) + return userin.say(wikicontent, cmd=["sensible-browser", wikipage.url]) + except requests.exceptions.ConnectionError: + userin.execute([" "], "Wikipedia connection error.") + return userin.say("Sorry, " + user_prefix + ". But I'm unable to connect to Wikipedia servers.") + except wikipedia.exceptions.DisambiguationError as disambiguation: + USER_ANSWERING['status'] = True + USER_ANSWERING['for'] = 'wikipedia' + USER_ANSWERING['reason'] = 'disambiguation' + USER_ANSWERING['options'] = disambiguation.options[:3] + notify = "Wikipedia disambiguation. Which one of these you meant?:\n - " + disambiguation.options[0] + msg = user_prefix + ", there is a disambiguation. Which one of these you meant? " + disambiguation.options[0] + for option in disambiguation.options[1:3]: + msg += ", or " + option + notify += "\n - " + option + notify += '\nSay, for example: "THE FIRST ONE" to choose.' + userin.execute([" "], notify) + return userin.say(msg) + except BaseException: + pass + if (h.check_lemma("search") or h.check_lemma("find")) and h.check_lemma("youtube"): + with nostdout(): + with nostderr(): + search_query = "" + for token in doc: + if not (token.lemma_ == "search" or token.lemma_ == "find" or token.lemma_ == "youtube" or token.is_stop): + search_query += ' ' + token.text + search_query = search_query.strip() + if search_query: + info = youtube_dl.YoutubeDL({}).extract_info('ytsearch:' + search_query, download=False, ie_key='YoutubeSearch') + if len(info['entries']) > 0: + youtube_title = info['entries'][0]['title'] + youtube_url = "https://www.youtube.com/watch?v=%s" % (info['entries'][0]['id']) + userin.execute(["sensible-browser", youtube_url], youtube_title) + youtube_title = "".join([i if ord(i) < 128 else ' ' for i in youtube_title]) + response = userin.say(youtube_title, ["sensible-browser", youtube_url]) + else: + youtube_title = "No video found, " + user_prefix + "." + response = userin.say(youtube_title) + k = PyKeyboard() + if not args["server"] and not self.testing: + time.sleep(5) + k.tap_key(k.tab_key) + k.tap_key(k.tab_key) + k.tap_key(k.tab_key) + k.tap_key(k.tab_key) + k.tap_key('f') + return response + if (h.check_lemma("search") or h.check_lemma("find")) and (h.check_lemma("google") or h.check_lemma("web") or h.check_lemma("internet")) and not h.check_lemma("image"): + with nostdout(): + with nostderr(): + search_query = "" + for token in doc: + if not (token.lemma_ == "search" or token.lemma_ == "find" or token.lemma_ == "google" or token.lemma_ == "web" or token.lemma_ == "internet" or token.is_stop): + search_query += ' ' + token.text + search_query = search_query.strip() + if search_query: + tab_url = "http://google.com/?#q=" + search_query + return userin.execute(["sensible-browser", tab_url], search_query, True) + if (h.check_lemma("search") or h.check_lemma("find")) and (h.check_lemma("google") or h.check_lemma("web") or h.check_lemma("internet")) and h.check_lemma("image"): + with nostdout(): + with nostderr(): + search_query = "" + for token in doc: + if not (token.lemma_ == "search" or token.lemma_ == "find" or token.lemma_ == "google" or token.lemma_ == "web" or token.lemma_ == "internet" or token.lemma_ == "image" or token.is_stop): + search_query += ' ' + token.text + search_query = search_query.strip() + if search_query: + tab_url = "http://google.com/?#q=" + search_query + "&tbm=isch" + return userin.execute(["sensible-browser", tab_url], search_query, True) + + original_com = com + com = coref.resolve(com) + if args["verbose"]: + print("After Coref Resolution: " + com) + arithmetic_response = arithmetic_parse(com) + if arithmetic_response: + return userin.say(arithmetic_response) + else: + learner_response = learner.respond(com) + if learner_response: + return userin.say(learner_response) + else: + omniscient_response = omniscient.respond(com, not args["silent"], userin, user_prefix, args["server"]) + if omniscient_response: + return omniscient_response + else: + dc_response = dc.respond(original_com, user_prefix) + if dc_response: + return userin.say(dc_response) + + +def tts_kill(): + """The top-level method to kill/end the text-to-speech output immediately. + """ + + subprocess.call(["pkill", "flite"], stdout=FNULL, stderr=FNULL) + + +def greet(userin): + """The top-level method to greet the user with message like "*Good morning, sir.*". + + Args: + userin: :class:`dragonfire.utilities.TextToAction` instance. + + Returns: + str: Response. + """ + + (columns, lines) = shutil.get_terminal_size() + print(columns * "_" + "\n") + time = datetime.datetime.now().time() + + global user_full_name + global user_prefix + global config_file + + command = "getent passwd $LOGNAME | cut -d: -f5 | cut -d, -f1" + user_full_name = os.popen(command).read() + user_full_name = user_full_name[:-1] # .decode("utf8") + home = expanduser("~") + config_file = TinyDB(home + '/.dragonfire_config.json') + callme_config = config_file.search(Query().datatype == 'callme') + if callme_config: + user_prefix = callme_config[0]['title'] + else: + gender_config = config_file.search(Query().datatype == 'gender') + if gender_config: + user_prefix = GENDER_PREFIX[gender_config[0]['gender']] + else: + gender = Classifier.gender(user_full_name.split(' ', 1)[0]) + config_file.insert({'datatype': 'gender', 'gender': gender}) + user_prefix = GENDER_PREFIX[gender] + + if time < datetime.time(12): + time_of_day = "morning" + elif datetime.time(12) < time < datetime.time(18): + time_of_day = "afternoon" + else: + time_of_day = "evening" + userin.execute(["echo"], "To activate say 'Dragonfire!' or 'Wake Up!'") + return userin.say(" ".join(["Good", time_of_day, user_prefix])) + + +def speech_error(): + """The top-level method to indicate that there is a speech recognition error occurred. + + Returns: + str: Response. + """ + + userin.execute(["echo"], "An error occurred") + return userin.say("I couldn't understand, please repeat again.") + + +def initiate(): + """The top-level method to serve as the entry point of Dragonfire. + + This method is the entry point defined in `setup.py` for the `dragonfire` executable that + placed a directory in `$PATH`. + + This method parses the command-line arguments and handles the top-level initiations accordingly. + """ + + ap = argparse.ArgumentParser() + ap.add_argument("-c", "--cli", help="Command-line interface mode. Give commands to Dragonfire via command-line inputs (keyboard) instead of audio inputs (microphone).", action="store_true") + ap.add_argument("-s", "--silent", help="Silent mode. Disable Text-to-Speech output. Dragonfire won't generate any audio output.", action="store_true") + ap.add_argument("-j", "--headless", help="Headless mode. Do not display an avatar animation on the screen. Disable the female head model.", action="store_true") + ap.add_argument("-v", "--verbose", help="Increase verbosity of log output.", action="store_true") + ap.add_argument("-g", "--gspeech", help="Instead of using the default speech recognition method(Mozilla DeepSpeech), use Google Speech Recognition service. (more accurate results)", action="store_true") + ap.add_argument("--server", help="Server mode. Disable any audio functionality, serve a RESTful spaCy API and become a Twitter integrated chatbot.", metavar="REG_KEY") + ap.add_argument("-p", "--port", help="Port number for server mode.", default="3301", metavar="PORT") + ap.add_argument("--version", help="Display the version number of Dragonfire.", action="store_true") + ap.add_argument("--sqlite", help="Use SQLite as the database engine.", action="store_true") + args = vars(ap.parse_args()) + if args["version"]: + import pkg_resources + print(pkg_resources.get_distribution("dragonfire").version) + sys.exit(1) + try: + global dc + userin = TextToAction(args) + if not args["server"]: + SystemTrayExitListenerSet(e) + stray_proc = Process(target=SystemTrayInit) + stray_proc.start() + greet(userin) + start(args, userin) + except KeyboardInterrupt: + if not args["server"]: + stray_proc.terminate() + sys.exit(1) + + +if __name__ == '__main__': + initiate() diff --git a/iso/dragonfire-master/dragonfire/api.py b/iso/dragonfire-master/dragonfire/api.py new file mode 100644 index 00000000..16f31c1f --- /dev/null +++ b/iso/dragonfire-master/dragonfire/api.py @@ -0,0 +1,556 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +.. module:: api + :platform: Unix + :synopsis: the API of Dragonfire that contains the endpoints. + +.. moduleauthor:: Mehmet Mert Yıldıran +""" + +from threading import Thread # Thread-based parallelism +import json # JSON encoder and decoder +import re # Regular expression operations +from random import randrange # Generate pseudo-random numbers +from datetime import datetime # Basic date and time types + +from dragonfire.config import Config # Credentials for the database connection +from dragonfire.arithmetic import arithmetic_parse # Submodule of Dragonfire to analyze arithmetic expressions +from dragonfire.database import User, Notification # Submodule of Dragonfire module that contains the database schema + +import hug # Embrace the APIs of the future +from hug_middleware_cors import CORSMiddleware # Middleware for allowing CORS (cross-origin resource sharing) requests from hug servers +import waitress # A production-quality pure-Python WSGI server with very acceptable performance +import wikipedia as wikipedia_lib # Python library that makes it easy to access and parse data from Wikipedia +import youtube_dl # Command-line program to download videos from YouTube.com and other video sites +import jwt # JSON Web Token implementation in Python +from sqlalchemy.orm.exc import NoResultFound # the Python SQL toolkit and Object Relational Mapper + + +@hug.authentication.token +def token_authentication(token): + """Method to compare the given token with precomputed token. + + Args: + token (str): API token. + + Returns: + bool. The return code:: + + True -- The token is correct! + False -- The token is invalid! + """ + + try: + jwt.decode(token, Config.SUPER_SECRET_KEY, algorithm='HS256') + return True + except: + return False + + +# Natural Language Processing realted API endpoints START + +@hug.post('/tag', requires=token_authentication) +def tagger_end(text): + """**Endpoint** to return **POS Tagging** result of the given text. + + Args: + text (str): Text. + + Returns: + JSON document. + """ + + return json.dumps(tagger(text), indent=4) + + +def tagger(text): + """Method to encapsulate **POS Tagging** process. + + Args: + text (str): Text. + + Returns: + (list) of (dict)s: List of dictionaries. + """ + + data = [] + doc = nlp(text) + for token in doc: + parse = { + 'text': token.text, + 'lemma': token.lemma_, + 'pos': token.pos_, + 'tag': token.tag_, + 'dep': token.dep_, + 'shape': token.shape_, + 'is_alpha': token.is_alpha, + 'is_stop': token.is_stop + } + data.append(parse) + return data + + +@hug.post('/dep', requires=token_authentication) +def dependency_parser_end(text): + """**Endpoint** to return **Dependency Parse** result of the given text. + + Args: + text (str): Text. + + Returns: + JSON document. + """ + + return json.dumps(dependency_parser(text), indent=4) + + +def dependency_parser(text): + """Method to encapsulate **Dependency Parse** process. + + Args: + text (str): Text. + + Returns: + (list) of (dict)s: List of dictionaries. + """ + + data = [] + doc = nlp(text) + for chunk in doc.noun_chunks: + parse = { + 'text': chunk.text, + 'root_text': chunk.root.text, + 'root_dep': chunk.root.dep_, + 'root_head_text': chunk.root.head.text, + } + data.append(parse) + return data + + +@hug.post('/ner', requires=token_authentication) +def entity_recognizer_end(text): + """**Endpoint** to return **Named Entity Recognition** result of the given text. + + Args: + text (str): Text. + + Returns: + JSON document. + """ + + return json.dumps(entity_recognizer(text), indent=4) + + +def entity_recognizer(text): + """Method to encapsulate **Named Entity Recognition** process. + + Args: + text (str): Text. + + Returns: + (list) of (dict)s: List of dictionaries. + """ + + data = [] + doc = nlp(text) + for ent in doc.ents: + parse = { + 'text': ent.text, + 'start_char': ent.start_char, + 'end_char': ent.end_char, + 'label': ent.label_, + } + data.append(parse) + return data + + +@hug.post('/token', requires=token_authentication) +def tokenizer_end(text): + """**Endpoint** to **tokenize** the given text. + + Args: + text (str): Text. + + Returns: + JSON document. + """ + + return json.dumps(tokenizer(text), indent=4) + + +def tokenizer(text): + """Method to encapsulate **tokenization** process. + + Args: + text (str): Text. + + Returns: + (list) of (dict)s: List of dictionaries. + """ + + data = [] + doc = nlp(text) + for token in doc: + data.append(token.text) + return data + + +@hug.post('/sent', requires=token_authentication) +def sentence_segmenter_end(text): + """**Endpoint** to return **Sentence Segmentation** result of the given text. + + Args: + text (str): Text. + + Returns: + JSON document. + """ + + return json.dumps(sentence_segmenter(text), indent=4) + + +def sentence_segmenter(text): + """Method to encapsulate **Sentence Segmentation** process. + + Args: + text (str): Text. + + Returns: + (list) of (dict)s: List of dictionaries. + """ + + data = [] + doc = nlp(text) + for sent in doc.sents: + data.append(sent.text) + return data + + +# All-in-One NLP +@hug.post('/cmd', requires=token_authentication) +def cmd(text): + """Serves the **all Natural Language Processing features** (parsers) of :mod:`spacy` in a single **endpoint**. + + Combines the results of these methods into a single JSON document: + + - :func:`dragonfire.api.tagger` method (**POS Tagging**) + - :func:`dragonfire.api.dependency_parser` method (**Dependency Parse**) + - :func:`dragonfire.api.entity_recognizer` method (**Named Entity Recognition**) + + Args: + text (str): Text. + + Returns: + JSON document. + """ + + data = [] + sents = sentence_segmenter(text) + for sent in sents: + sent_data = {} + sent_data['tags'] = tagger(sent) + sent_data['deps'] = dependency_parser(sent) + sent_data['ners'] = entity_recognizer(sent) + data.append(sent_data) + return json.dumps(data, indent=4) + +# Natural Language Processing realted API endpoints END + + +# Directly on server-side Q&A related API endpoints START + +@hug.post('/math', requires=token_authentication) +def math(text): + """**Endpoint** to return the response of :func:`dragonfire.arithmetic.arithmetic_parse` function. + + Args: + text (str): Text. + + Returns: + JSON document. + """ + + response = arithmetic_parse(text) + if not response: + response = "" + return json.dumps(response, indent=4) + + +@hug.post('/learn', requires=token_authentication) +def learn(text, user_id): + """**Endpoint** to return the response of :func:`dragonfire.learn.Learner.respond` method. + + Args: + text (str): Text. + user_id (int): User's ID. + + Returns: + JSON document. + """ + + response = learner.respond(text, is_server=True, user_id=user_id) + if not response: + response = "" + return json.dumps(response, indent=4) + + +@hug.post('/omni', requires=token_authentication) +def omni(text, gender_prefix): + """**Endpoint** to return the answer of :func:`dragonfire.omniscient.Omniscient.respond` method. + + Args: + text (str): Text. + gender_prefix (str): Prefix to address/call user when answering. + + Returns: + JSON document. + """ + + answer = omniscient.respond(text, userin=userin, user_prefix=gender_prefix, is_server=True) + if not answer: + answer = "" + return json.dumps(answer, indent=4) + + +@hug.post('/deep', requires=token_authentication) +def deep(text, gender_prefix): + """**Endpoint** to return the response of :func:`dragonfire.deepconv.DeepConversation.respond` method. + + Args: + text (str): Text. + gender_prefix (str): Prefix to address/call user when answering. + + Returns: + JSON document. + """ + + answer = dc.respond(text, user_prefix=gender_prefix) + return json.dumps(answer, indent=4) + + +# All-in-One Answering +@hug.post('/answer', requires=token_authentication) +def answer(text, gender_prefix, user_id, previous=None): + """Serves the **all Q&A related API endpoints** in a single **endpoint**. + + Combines the results of these methods into a single JSON document: + + - :func:`dragonfire.arithmetic.arithmetic_parse` function + - :func:`dragonfire.learn.Learner.respond` method + - :func:`dragonfire.omniscient.Omniscient.respond` method + - :func:`dragonfire.deepconv.DeepConversation.respond` method + + Args: + text (str): User's current command. + gender_prefix (str): Prefix to address/call user when answering. + user_id (int): User's ID. + previous (str): User's previous command. + + Returns: + JSON document. + """ + + data = {} + text = coref.resolve_api(text, previous) + subject, subjects, focus, subject_with_objects = omniscient.semantic_extractor(text) + data['subject'] = subject + data['focus'] = focus + answer = arithmetic_parse(text) + if not answer: + answer = learner.respond(text, is_server=True, user_id=user_id) + if not answer: + answer = omniscient.respond(text, userin=userin, user_prefix=gender_prefix, is_server=True) + if not answer: + answer = dc.respond(text, user_prefix=gender_prefix) + data['answer'] = answer + return json.dumps(data, indent=4) + +# Directly on server-side Q&A related API endpoints END + + +@hug.post('/wikipedia', requires=token_authentication) +def wikipedia(query, gender_prefix): + """**Endpoint** to make a **Wikipedia search** and return its **text content**. + + Args: + query (str): Search query. + gender_prefix (str): Prefix to address/call user when answering. + + Returns: + JSON document. + """ + + response = "" + url = "" + wikiresult = wikipedia_lib.search(query) + if len(wikiresult) == 0: + response = "Sorry, " + gender_prefix + ". But I couldn't find anything about " + query + " in Wikipedia." + else: + wikipage = wikipedia_lib.page(wikiresult[0]) + wikicontent = "".join([ + i if ord(i) < 128 else ' ' + for i in wikipage.content + ]) + wikicontent = re.sub(r'\([^)]*\)', '', wikicontent) + response = " ".join(sentence_segmenter(wikicontent)[:3]) + url = wikipage.url + data = {} + data['response'] = response + data['url'] = url + return json.dumps(data, indent=4) + + +@hug.post('/youtube', requires=token_authentication) +def youtube(query, gender_prefix): + """**Endpoint** to make a **YouTube search** and return the **video title** and **URL**. + + Args: + query (str): Search query. + gender_prefix (str): Prefix to address/call user when answering. + + Returns: + JSON document. + """ + + response = "" + url = "" + info = youtube_dl.YoutubeDL({}).extract_info('ytsearch:' + query, download=False, ie_key='YoutubeSearch') + if len(info['entries']) > 0: + response = info['entries'][0]['title'] + url = "https://www.youtube.com/watch?v=%s" % (info['entries'][0]['id']) + response = "".join([ + i if ord(i) < 128 else ' ' + for i in response + ]) + else: + response = "No video found, " + gender_prefix + "." + data = {} + data['response'] = response + data['url'] = url + return json.dumps(data, indent=4) + + +@hug.post('/notification', requires=token_authentication) +def notification(user_id, location, gender_prefix, response=None): + """**Endpoint** to serve the **notifications** from the **database**. + + Args: + user_id (int): User's ID. + location (str): *Development in progress...* + gender_prefix (str): Prefix to address/call user when answering. + + Returns: + JSON document. + """ + + try: + user = db_session.query(User).filter(User.id == int(user_id)).one() + if not db_session.query(Notification).count() > 0: + response.status = hug.HTTP_404 + return + rand = randrange(0, db_session.query(Notification).count()) + + notification = db_session.query(Notification).filter(Notification.is_active)[rand] + + if notification.capitalize == 1: + gender_prefix = gender_prefix.capitalize() + + data = {} + data['url'] = notification.url + data['title'] = notification.title + data['message'] = notification.message.format(gender_prefix, user.name) + return json.dumps(data, indent=4) + except NoResultFound: + response.status = hug.HTTP_404 + return + + +# Endpoint to handle registration requests +@hug.post('/register') +def register(name, gender, birth_date, reg_key, response=None): + """**Endpoint** to handle **registration requests**. + + Args: + name (str): User's name. + gender (str): User's gender. + birth_date (str): User's birth date. + reg_key (str): Registration key. + + Returns: + JSON document. + """ + + if reg_key != server_reg_key: + response.status = hug.HTTP_403 + return + + new_user = User(name=name, gender=gender, birth_date=datetime.strptime(birth_date, "%Y-%m-%d").date()) + db_session.add(new_user) + db_session.commit() + + data = {} + data['id'] = new_user.id + data['token'] = jwt.encode({'id': new_user.id, 'name': name, 'gender': gender, 'birth_date': birth_date}, Config.SUPER_SECRET_KEY, algorithm='HS256').decode('ascii') + return json.dumps(data, indent=4) + + +class Run(): + """Class to Run the API. + + .. note:: + + Creating an object from this class is automatically starts the API server. + + """ + + def __init__(self, nlp_ref, learner_ref, omniscient_ref, dc_ref, coref_ref, userin_ref, reg_key, port_number, db_session_ref, dont_block=False): + """Initialization method of :class:`dragonfire.api.Run` class + + This method starts an API server using :mod:`waitress` (*a pure-Python WSGI server*) + on top of lightweight :mod:`hug` API framework. + + Args: + nlp_ref: :mod:`spacy` model instance. + learner_ref: :class:`dragonfire.learn.Learner` instance. + omniscient_ref: :class:`dragonfire.omniscient.Omniscient` instance. + dc_ref: :class:`dragonfire.deepconv.DeepConversation` instance. + userin_ref: :class:`dragonfire.utilities.TextToAction` instance. + reg_key (str): Registration key of the API. + port_number (int): Port number that the API will be served. + db_session_ref: SQLAlchemy's :class:`DBSession()` instance. + """ + + global nlp + global learner + global omniscient + global dc + global coref + global userin + global server_reg_key + global db_session + nlp = nlp_ref # Load en_core_web_sm, English, 50 MB, default model + learner = learner_ref + omniscient = omniscient_ref + dc = dc_ref + coref = coref_ref + userin = userin_ref + server_reg_key = reg_key + db_session = db_session_ref + app = hug.API(__name__) + app.http.output_format = hug.output_format.text + app.http.add_middleware(CORSMiddleware(app)) + self.waitress_thread = Thread(target=waitress.serve, args=(__hug_wsgi__, ), kwargs={"port": port_number}) + if dont_block: + self.waitress_thread.daemon = True + self.waitress_thread.start() + if not dont_block: + self.waitress_thread.join() + + +if __name__ == '__main__': + app = hug.API(__name__) + app.http.output_format = hug.output_format.text + app.http.add_middleware(CORSMiddleware(app)) + waitress.serve(__hug_wsgi__, port=8000) diff --git a/iso/dragonfire-master/dragonfire/arithmetic.py b/iso/dragonfire-master/dragonfire/arithmetic.py new file mode 100644 index 00000000..7eeea568 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/arithmetic.py @@ -0,0 +1,120 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +.. module:: arithmetic + :platform: Unix + :synopsis: the top-level submodule of Dragonfire that provides basic methods to evaluate the algebraic expressions. + +.. moduleauthor:: Mehmet Mert Yıldıran +""" + + +def text2int(textnum, numwords={}): + """Function that converts number descriptions written in English to integer. + + Args: + textnum (str): Number despcription written in English. + + Keyword Args: + numwords (dict): Dictionary that maps words to numbers. + + Returns: + int: Integer version of given number description in string format. + """ + + if not numwords: + units = [ + "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", + "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", + "sixteen", "seventeen", "eighteen", "nineteen", + ] + + tens = ["", "", "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety"] + + scales = ["hundred", "thousand", "million", "billion", "trillion"] + + numwords["and"] = (1, 0) + for idx, word in enumerate(units): numwords[word] = (1, idx) + for idx, word in enumerate(tens): numwords[word] = (1, idx * 10) + for idx, word in enumerate(scales): numwords[word] = (10 ** (idx * 3 or 2), 0) + + current = result = 0 + for word in textnum.split(): + if word not in numwords: + raise Exception("Illegal word: " + word) + + scale, increment = numwords[word] + current = current * scale + increment + if scale > 100: + result += current + current = 0 + + return result + current + + +def arithmetic_parse(com): + """Method to evaluate the algebraic expressions written in English. + + Args: + com (str): User's command. + + Returns: + str: Result of the given algebraic expression. + """ + + if not any(e in com.upper() for e in ['+', '-', '/', '*', '^', '=', 'x', 'y', 'z', 'PLUS', 'MINUS', 'DIVIDED BY', 'MULTIPLIED BY', 'TIMES', 'TO THE POWER OF', 'EQUAL']): + return False + com = com.lower() + numwords = [ + "zero", "one", "two", "three", "four", "five", "six", "seven", "eight", + "nine", "ten", "eleven", "twelve", "thirteen", "fourteen", "fifteen", + "sixteen", "seventeen", "eighteen", "nineteen", + + "twenty", "thirty", "forty", "fifty", "sixty", "seventy", "eighty", "ninety", + + "hundred", "thousand", "million", "billion", "trillion", + + "and" + ] + + operators = { + 'plus': '+', + 'minus': '-', + 'divided_by': '/', + 'multiplied_by': '*', + 'times': '*', + 'to_the_power_of': '^', + 'equal': '=' + } + + com = com.replace("?", "") + com = com.replace("divided by", "divided_by") + com = com.replace("multiplied by", "multiplied_by") + com = com.replace("to the power of", "to_the_power_of") + words = com.split() + stash = [] + expression = [] + for i in range(len(words)): + word = words.pop(0) + if stash and (word not in numwords): + expression.append(str(text2int(' '.join(stash)))) + stash = [] + if word in numwords: + stash.append(word) + elif word in operators: + expression.append(operators[word]) + elif word in ['+', '-', '/', '*', '^', '(', ')'] or word.isdigit(): + expression.append(word) + elif word == '=' or 'equal' in word: + break + if stash: + expression.append(str(text2int(' '.join(stash)))) + stash = [] + + try: + return ' '.join(expression) + ' = ' + str(eval(''.join(expression))) + except ZeroDivisionError: + return "Sorry, but that does not make sense as the divisor cannot be zero." + except: + return False diff --git a/iso/dragonfire-master/dragonfire/config.py b/iso/dragonfire-master/dragonfire/config.py new file mode 100644 index 00000000..3b4dc4c4 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/config.py @@ -0,0 +1,41 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +.. module:: config + :platform: Unix + :synopsis: the module that contains the configuration for the API of Dragonfire. + +.. moduleauthor:: Mehmet Mert Yıldıran +""" + +import os + + +is_travis = 'TRAVIS' in os.environ + + +class Config(): + """Class that stores the Twitter API and MySQL database connection credentials in class variables. + """ + + # Twitter Credentials + TWITTER_CONSUMER_KEY = 'CONSUMER_KEY' + TWITTER_CONSUMER_SECRET = 'CONSUMER_SECRET' + TWITTER_ACCESS_KEY = 'ACCESS_KEY' + TWITTER_ACCESS_SECRET = 'ACCESS_SECRET' + + # MySQL Credentials + if is_travis: + MYSQL_HOST = '127.0.0.1' + MYSQL_DB = 'dragonfire' + MYSQL_USER = 'root' + MYSQL_PASS = '' + else: + MYSQL_HOST = 'MYSQL_HOST' + MYSQL_DB = 'MYSQL_DB' + MYSQL_USER = 'MYSQL_USER' + MYSQL_PASS = 'MYSQL_PASS' + + # SECRET KEY FOR JWT ENCODE/DECODE + SUPER_SECRET_KEY = 'SUPER_SECRET_KEY' diff --git a/iso/dragonfire-master/dragonfire/coref.py b/iso/dragonfire-master/dragonfire/coref.py new file mode 100644 index 00000000..08ab04d1 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/coref.py @@ -0,0 +1,97 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +.. module:: coref + :platform: Unix + :synopsis: the top-level submodule of Dragonfire that aims to create corefference based dialogs. + +.. moduleauthor:: Mehmet Mert Yıldıran +""" + +import itertools # Functions creating iterators for efficient looping + +import en_coref_sm # Small English model for NeuralCoref: a pipeline extension for spaCy 2.0 + + +class NeuralCoref(): + """Class to provide corefference based dialogs. + """ + + def __init__(self): + """Initialization method of :class:`dragonfire.coref.NeuralCoref` class. + """ + + self.nlp = en_coref_sm.load() + self.coms = [] + + def resolve(self, com): + """Method to return the version of command where each corefering mention is replaced by the main mention in the associated cluster (compared to previous commands). + + Args: + com (str): User's command. + + Returns: + str: Resolution. + """ + + com_doc = self.nlp(com) + n_sents = sum(1 for sent in com_doc.sents) + + token = None + for token in com_doc: + pass + if token.tag_ not in [',', ':', "."]: + com += '.' + self.coms.append(com) + + if len(self.coms) > 1: + chain = " ".join(self.coms[-2:]) + + doc = self.nlp(chain) + if doc._.has_coref: + resolution = doc._.coref_resolved + chained = self.nlp(resolution) + total_sents = sum(1 for sent in chained.sents) + sents = itertools.islice(chained.sents, total_sents - n_sents, None) + sents_arr = [] + for sent in sents: + sents_arr.append(sent.text) + return " ".join(sents_arr) + + return com + + return com + + def resolve_api(self, com, previous=None): + if not previous: + return com + com_doc = self.nlp(com) + n_sents = sum(1 for sent in com_doc.sents) + + token = None + for token in com_doc: + pass + if token.tag_ not in [',', ':', "."]: + com += '.' + + previous_doc = self.nlp(previous) + token = None + for token in previous_doc: + pass + if token.tag_ not in [',', ':', "."]: + previous += '.' + + chain = previous + " " + com + doc = self.nlp(chain) + if doc._.has_coref: + resolution = doc._.coref_resolved + chained = self.nlp(resolution) + total_sents = sum(1 for sent in chained.sents) + sents = itertools.islice(chained.sents, total_sents - n_sents, None) + sents_arr = [] + for sent in sents: + sents_arr.append(sent.text) + return " ".join(sents_arr) + + return com diff --git a/iso/dragonfire-master/dragonfire/database.py b/iso/dragonfire-master/dragonfire/database.py new file mode 100644 index 00000000..a4eed235 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/database.py @@ -0,0 +1,64 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +.. module:: database + :platform: Unix + :synopsis: the module that contains the database schema of Dragonfire. + +.. moduleauthor:: Mehmet Mert Yıldıran +""" + +from sqlalchemy import Column, ForeignKey, Integer, String, DateTime, Date, Boolean +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import relationship +from sqlalchemy import create_engine +from sqlalchemy.sql import func + + +Base = declarative_base() + + +class User(Base): + """Schema of `users` table. + """ + + __tablename__ = 'users' + __table_args__ = {'useexisting': True} + id = Column(Integer, primary_key=True) + name = Column(String(255), nullable=False) + gender = Column(String(1), nullable=False) + birth_date = Column(Date, nullable=False) + created_at = Column(DateTime(timezone=True), server_default=func.now()) + + +class Fact(Base): + """Schema of `facts` table. + """ + + __tablename__ = 'facts' + __table_args__ = {'useexisting': True} + id = Column(Integer, primary_key=True) + subject = Column(String(255), nullable=False) + verbtense = Column(String(255), nullable=False) + clause = Column(String(255), nullable=False) + created_at = Column(DateTime(timezone=True), server_default=func.now()) + user_id = Column(Integer, ForeignKey('users.id'), default=0) + user = relationship(User) + is_public = Column(Boolean, default=True) + counter = Column(Integer, default=1) + + +class Notification(Base): + """Schema of `notifications` table. + """ + + __tablename__ = 'notifications' + __table_args__ = {'useexisting': True} + id = Column(Integer, primary_key=True) + url = Column(String(255), nullable=False) + title = Column(String(63), nullable=False) + message = Column(String(255), nullable=False) + created_at = Column(DateTime(timezone=True), server_default=func.now()) + is_active = Column(Boolean, default=True) + capitalize = Column(Boolean, default=False) diff --git a/iso/dragonfire-master/dragonfire/deepconv/__init__.py b/iso/dragonfire-master/dragonfire/deepconv/__init__.py new file mode 100644 index 00000000..2bed0b24 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/deepconv/__init__.py @@ -0,0 +1,614 @@ +from __future__ import print_function +import argparse # Command line parsing +import configparser # Saving the models parameters +import datetime # Chronometer +import os # Files management +import tensorflow as tf +import numpy as np +import math +from random import choice + +from tqdm import tqdm # Progress bar +from tensorflow.python import debug as tf_debug + +from dragonfire.deepconv.textdata import TextData +from dragonfire.deepconv.model import Model + + +class DeepConversation: + """ + Main class which launch the training or testing mode + """ + + class TestMode: + """ Simple structure representing the different testing modes + """ + ALL = 'all' + INTERACTIVE = 'interactive' # The user can write his own questions + DAEMON = 'daemon' # The chatbot runs on background and can regularly be called to predict something + + def __init__(self): + """ + """ + # Global options + self.test = None + self.createDataset = False + self.playDataset = None + self.reset = False + self.verbose = False + self.debug = False + self.keepAll = False + self.modelTag = None + self.rootDir = None + self.watsonMode = False + self.autoEncode = False + self.device = None + self.seed = None + + # Dataset options + self.corpus = TextData.corpusChoices()[0] + self.datasetTag = '' + self.ratioDataset = 1.0 + self.maxLength = 10 + self.filterVocab = 1 + self.skipLines = False + self.vocabularySize = 40000 + + # Network options (Warning: if modifying something here, also make the change on save/loadParams() ) + self.hiddenSize = 512 + self.numLayers = 2 + self.softmaxSamples = 0 + self.initEmbeddings = False + self.embeddingSize = 64 + self.embeddingSource = "GoogleNews-vectors-negative300.bin" + + # Training options + self.numEpochs = 30 + self.saveEvery = 2000 + self.batchSize = 256 + self.learningRate = 0.002 + self.dropout = 0.9 + + # Task specific object + self.textData = None # Dataset + self.model = None # Sequence to sequence model + + # Tensorflow utilities for convenience saving/logging + self.writer = None + self.saver = None + self.modelDir = '' # Where the model is saved + self.globStep = 0 # Represent the number of iteration for the current model + + # TensorFlow main session (we keep track for the daemon) + self.sess = None + + # Filename and directories constants + self.MODEL_DIR_BASE = "/usr/share/dragonfire/deepconv" + os.sep + 'model' + self.MODEL_NAME_BASE = 'model' + self.MODEL_EXT = '.ckpt' + self.CONFIG_FILENAME = 'params.ini' + self.CONFIG_VERSION = '0.5' + self.TEST_IN_NAME = 'data' + os.sep + 'test' + os.sep + 'samples.txt' + self.TEST_OUT_SUFFIX = '_predictions.txt' + self.SENTENCES_PREFIX = ['Q: ', 'A: '] + + """ + Launch the training and/or the interactive mode + """ + print('TensorFlow detected: v{}'.format(tf.__version__)) + + # General initialisation + + self.modelTag = 'pretrainedv2' + self.test = 'interactive' + self.rootDir = os.getcwd() # Use the current working directory + + #tf.logging.set_verbosity(tf.logging.INFO) # DEBUG, INFO, WARN (default), ERROR, or FATAL + + self.loadModelParams() # Update the self.modelDir and self.globStep, for now, not used when loading Model (but need to be called before _getSummaryName) + + self.textData = TextData(self) + # TODO: Add a mode where we can force the input of the decoder // Try to visualize the predictions for + # each word of the vocabulary / decoder input + # TODO: For now, the model are trained for a specific dataset (because of the maxLength which define the + # vocabulary). Add a compatibility mode which allow to launch a model trained on a different vocabulary ( + # remap the word2id/id2word variables). + if self.createDataset: + print('Dataset created! Thanks for using this program') + return # No need to go further + + # Prepare the model + with tf.device(self.getDevice()): + self.model = Model(self, self.textData) + + # Saver/summaries + self.writer = tf.summary.FileWriter(self._getSummaryName()) + self.saver = tf.train.Saver(max_to_keep=200) + + # TODO: Fixed seed (WARNING: If dataset shuffling, make sure to do that after saving the + # dataset, otherwise, all which cames after the shuffling won't be replicable when + # reloading the dataset). How to restore the seed after loading ?? + # Also fix seed for random.shuffle (does it works globally for all files ?) + + # Running session + self.sess = tf.Session(config=tf.ConfigProto( + allow_soft_placement=True, # Allows backup device for non GPU-available operations (when forcing GPU) + log_device_placement=False) # Too verbose ? + ) # TODO: Replace all sess by self.sess (not necessary a good idea) ? + + if self.debug: + self.sess = tf_debug.LocalCLIDebugWrapperSession(self.sess) + self.sess.add_tensor_filter("has_inf_or_nan", tf_debug.has_inf_or_nan) + + print('Initialize variables...') + self.sess.run(tf.global_variables_initializer()) + + # Reload the model eventually (if it exist.), on testing mode, the models are not loaded here (but in predictTestset) + if self.test != DeepConversation.TestMode.ALL: + self.managePreviousModel(self.sess) + + # Initialize embeddings with pre-trained word2vec vectors + if self.initEmbeddings: + self.loadEmbedding(self.sess) + + def respond(self, question, user_prefix=None): + answer = self.singlePredict(question) + if not answer: + return choice([ + "Sorry, " + user_prefix + ". But it's beyond my intelligence.", + "I'm too primitive to answer that.", + "Unfortunately, I am not capable to give a respond to such a hard question.", + user_prefix + ", I beg your pardon. But I'm not a human equivalent entity, yet...", + "Wow, that's a new level. My circuits are burned." + ]) + + #self.sess.close() + #print("The End! Thanks for using this program") + return self.textData.sequence2str(answer, clean=True).replace("n't", "not") + + def mainTrain(self, sess): + """ Training loop + Args: + sess: The current running session + """ + + # Specific training dependent loading + + self.textData.makeLighter(self.ratioDataset) # Limit the number of training samples + + mergedSummaries = tf.summary.merge_all() # Define the summary operator (Warning: Won't appear on the tensorboard graph) + if self.globStep == 0: # Not restoring from previous run + self.writer.add_graph(sess.graph) # First time only + + # If restoring a model, restore the progression bar ? and current batch ? + + print('Start training (press Ctrl+C to save and exit)...') + + try: # If the user exit while training, we still try to save the model + for e in range(self.numEpochs): + + print() + print("----- Epoch {}/{} ; (lr={}) -----".format(e+1, self.numEpochs, self.learningRate)) + + batches = self.textData.getBatches() + + # TODO: Also update learning parameters eventually + + tic = datetime.datetime.now() + for nextBatch in tqdm(batches, desc="Training"): + # Training pass + ops, feedDict = self.model.step(nextBatch) + assert len(ops) == 2 # training, loss + _, loss, summary = sess.run(ops + (mergedSummaries,), feedDict) + self.writer.add_summary(summary, self.globStep) + self.globStep += 1 + + # Output training status + if self.globStep % 100 == 0: + perplexity = math.exp(float(loss)) if loss < 300 else float("inf") + tqdm.write("----- Step %d -- Loss %.2f -- Perplexity %.2f" % (self.globStep, loss, perplexity)) + + # Checkpoint + if self.globStep % self.saveEvery == 0: + self._saveSession(sess) + + toc = datetime.datetime.now() + + print("Epoch finished in {}".format(toc-tic)) # Warning: Will overflow if an epoch takes more than 24 hours, and the output isn't really nicer + except (KeyboardInterrupt, SystemExit): # If the user press Ctrl+C while testing progress + print('Interruption detected, exiting the program...') + + self._saveSession(sess) # Ultimate saving before complete exit + + def predictTestset(self, sess): + """ Try predicting the sentences from the samples.txt file. + The sentences are saved on the modelDir under the same name + Args: + sess: The current running session + """ + + # Loading the file to predict + with open(os.path.join(self.rootDir, self.TEST_IN_NAME), 'r') as f: + lines = f.readlines() + + modelList = self._getModelList() + if not modelList: + print('Warning: No model found in \'{}\'. Please train a model before trying to predict'.format(self.modelDir)) + return + + # Predicting for each model present in modelDir + for modelName in sorted(modelList): # TODO: Natural sorting + print('Restoring previous model from {}'.format(modelName)) + self.saver.restore(sess, modelName) + print('Testing...') + + saveName = modelName[:-len(self.MODEL_EXT)] + self.TEST_OUT_SUFFIX # We remove the model extension and add the prediction suffix + with open(saveName, 'w') as f: + nbIgnored = 0 + for line in tqdm(lines, desc='Sentences'): + question = line[:-1] # Remove the endl character + + answer = self.singlePredict(question) + if not answer: + nbIgnored += 1 + continue # Back to the beginning, try again + + predString = '{x[0]}{0}\n{x[1]}{1}\n\n'.format(question, self.textData.sequence2str(answer, clean=True), x=self.SENTENCES_PREFIX) + if self.verbose: + tqdm.write(predString) + f.write(predString) + print('Prediction finished, {}/{} sentences ignored (too long)'.format(nbIgnored, len(lines))) + + def mainTestInteractive(self, sess): + """ Try predicting the sentences that the user will enter in the console + Args: + sess: The current running session + """ + # TODO: If verbose mode, also show similar sentences from the training set with the same words (include in mainTest also) + # TODO: Also show the top 10 most likely predictions for each predicted output (when verbose mode) + # TODO: Log the questions asked for latter re-use (merge with test/samples.txt) + + print('Testing: Launch interactive mode:') + print('') + print('Welcome to the interactive mode, here you can ask to Deep Conversation the sentence you want. Don\'t have high ' + 'expectation. Type \'exit\' or just press ENTER to quit the program. Have fun.') + + while True: + question = input(self.SENTENCES_PREFIX[0]) + if question == '' or question == 'exit': + break + + questionSeq = [] # Will be contain the question as seen by the encoder + answer = self.singlePredict(question, questionSeq) + if not answer: + print('Warning: sentence too long, sorry. Maybe try a simpler sentence.') + continue # Back to the beginning, try again + + print('{}{}'.format(self.SENTENCES_PREFIX[1], self.textData.sequence2str(answer, clean=True))) + + if self.verbose: + print(self.textData.batchSeq2str(questionSeq, clean=True, reverse=True)) + print(self.textData.sequence2str(answer)) + + print() + + def singlePredict(self, question, questionSeq=None): + """ Predict the sentence + Args: + question (str): the raw input sentence + questionSeq (List): output argument. If given will contain the input batch sequence + Return: + list : the word ids corresponding to the answer + """ + # Create the input batch + batch = self.textData.sentence2enco(question) + if not batch: + return None + if questionSeq is not None: # If the caller want to have the real input + questionSeq.extend(batch.encoderSeqs) + + # Run the model + ops, feedDict = self.model.step(batch) + output = self.sess.run(ops[0], feedDict) # TODO: Summarize the output too (histogram, ...) + answer = self.textData.deco2sentence(output) + + return answer + + def daemonPredict(self, sentence): + """ Return the answer to a given sentence (same as singlePredict() but with additional cleaning) + Args: + sentence (str): the raw input sentence + Return: + str: the human readable sentence + """ + return self.textData.sequence2str( + self.singlePredict(sentence), + clean=True + ) + + def daemonClose(self): + """ A utility function to close the daemon when finish + """ + print('Exiting the daemon mode...') + self.sess.close() + print('Daemon closed.') + + def loadEmbedding(self, sess): + """ Initialize embeddings with pre-trained word2vec vectors + Will modify the embedding weights of the current loaded model + Uses the GoogleNews pre-trained values (path hardcoded) + """ + + # Fetch embedding variables from model + with tf.variable_scope("embedding_rnn_seq2seq/rnn/embedding_wrapper", reuse=True): + em_in = tf.get_variable("embedding") + with tf.variable_scope("embedding_rnn_seq2seq/embedding_rnn_decoder", reuse=True): + em_out = tf.get_variable("embedding") + + # Disable training for embeddings + variables = tf.get_collection_ref(tf.GraphKeys.TRAINABLE_VARIABLES) + variables.remove(em_in) + variables.remove(em_out) + + # If restoring a model, we can leave here + if self.globStep != 0: + return + + # New model, we load the pre-trained word2vec data and initialize embeddings + embeddings_path = os.path.join(self.rootDir, 'data', 'embeddings', self.embeddingSource) + embeddings_format = os.path.splitext(embeddings_path)[1][1:] + print("Loading pre-trained word embeddings from %s " % embeddings_path) + with open(embeddings_path, "rb") as f: + header = f.readline() + vocab_size, vector_size = map(int, header.split()) + binary_len = np.dtype('float32').itemsize * vector_size + initW = np.random.uniform(-0.25,0.25,(len(self.textData.word2id), vector_size)) + for line in tqdm(range(vocab_size)): + word = [] + while True: + ch = f.read(1) + if ch == b' ': + word = b''.join(word).decode('utf-8') + break + if ch != b'\n': + word.append(ch) + if word in self.textData.word2id: + if embeddings_format == 'bin': + vector = np.fromstring(f.read(binary_len), dtype='float32') + elif embeddings_format == 'vec': + vector = np.fromstring(f.readline(), sep=' ', dtype='float32') + else: + raise Exception("Unkown format for embeddings: %s " % embeddings_format) + initW[self.textData.word2id[word]] = vector + else: + if embeddings_format == 'bin': + f.read(binary_len) + elif embeddings_format == 'vec': + f.readline() + else: + raise Exception("Unkown format for embeddings: %s " % embeddings_format) + + # PCA Decomposition to reduce word2vec dimensionality + if self.embeddingSize < vector_size: + U, s, Vt = np.linalg.svd(initW, full_matrices=False) + S = np.zeros((vector_size, vector_size), dtype=complex) + S[:vector_size, :vector_size] = np.diag(s) + initW = np.dot(U[:, :self.embeddingSize], S[:self.embeddingSize, :self.embeddingSize]) + + # Initialize input and output embeddings + sess.run(em_in.assign(initW)) + sess.run(em_out.assign(initW)) + + + def managePreviousModel(self, sess): + """ Restore or reset the model, depending of the parameters + If the destination directory already contains some file, it will handle the conflict as following: + * If --reset is set, all present files will be removed (warning: no confirmation is asked) and the training + restart from scratch (globStep & cie reinitialized) + * Otherwise, it will depend of the directory content. If the directory contains: + * No model files (only summary logs): works as a reset (restart from scratch) + * Other model files, but modelName not found (surely keepAll option changed): raise error, the user should + decide by himself what to do + * The right model file (eventually some other): no problem, simply resume the training + In any case, the directory will exist as it has been created by the summary writer + Args: + sess: The current running session + """ + + print('WARNING: ', end='') + + modelName = self._getModelName() + + if os.listdir(self.modelDir): + if self.reset: + print('Reset: Destroying previous model at {}'.format(self.modelDir)) + # Analysing directory content + elif os.path.exists(modelName): # Restore the model + print('Restoring previous model from {}'.format(modelName)) + self.saver.restore(sess, modelName) # Will crash when --reset is not activated and the model has not been saved yet + elif self._getModelList(): + print('Conflict with previous models.') + raise RuntimeError('Some models are already present in \'{}\'. You should check them first (or re-try with the keepAll flag)'.format(self.modelDir)) + else: # No other model to conflict with (probably summary files) + print('No previous model found, but some files found at {}. Cleaning...'.format(self.modelDir)) # Warning: No confirmation asked + self.reset = True + + if self.reset: + fileList = [os.path.join(self.modelDir, f) for f in os.listdir(self.modelDir)] + for f in fileList: + print('Removing {}'.format(f)) + os.remove(f) + + else: + print('No previous model found, starting from clean directory: {}'.format(self.modelDir)) + + def _saveSession(self, sess): + """ Save the model parameters and the variables + Args: + sess: the current session + """ + tqdm.write('Checkpoint reached: saving model (don\'t stop the run)...') + self.saveModelParams() + model_name = self._getModelName() + with open(model_name, 'w') as f: # HACK: Simulate the old model existance to avoid rewriting the file parser + f.write('This file is used internally by Deep Conversation to check the model existance. Please do not remove.\n') + self.saver.save(sess, model_name) # TODO: Put a limit size (ex: 3GB for the modelDir) + tqdm.write('Model saved.') + + def _getModelList(self): + """ Return the list of the model files inside the model directory + """ + return [os.path.join(self.modelDir, f) for f in os.listdir(self.modelDir) if f.endswith(self.MODEL_EXT)] + + def loadModelParams(self): + """ Load the some values associated with the current model, like the current globStep value + For now, this function does not need to be called before loading the model (no parameters restored). However, + the modelDir name will be initialized here so it is required to call this function before managePreviousModel(), + _getModelName() or _getSummaryName() + Warning: if you modify this function, make sure the changes mirror saveModelParams, also check if the parameters + should be reset in managePreviousModel + """ + # Compute the current model path + self.modelDir = os.path.join(self.rootDir, self.MODEL_DIR_BASE) + if self.modelTag: + self.modelDir += '-' + self.modelTag + + # If there is a previous model, restore some parameters + configName = os.path.join(self.modelDir, self.CONFIG_FILENAME) + if not self.reset and not self.createDataset and os.path.exists(configName): + # Loading + config = configparser.ConfigParser() + config.read(configName) + + # Check the version + currentVersion = config['General'].get('version') + if currentVersion != self.CONFIG_VERSION: + raise UserWarning('Present configuration version {0} does not match {1}. You can try manual changes on \'{2}\''.format(currentVersion, self.CONFIG_VERSION, configName)) + + # Restoring the the parameters + self.globStep = config['General'].getint('globStep') + self.watsonMode = config['General'].getboolean('watsonMode') + self.autoEncode = config['General'].getboolean('autoEncode') + self.corpus = config['General'].get('corpus') + + self.datasetTag = config['Dataset'].get('datasetTag') + self.maxLength = config['Dataset'].getint('maxLength') # We need to restore the model length because of the textData associated and the vocabulary size (TODO: Compatibility mode between different maxLength) + self.filterVocab = config['Dataset'].getint('filterVocab') + self.skipLines = config['Dataset'].getboolean('skipLines') + self.vocabularySize = config['Dataset'].getint('vocabularySize') + + self.hiddenSize = config['Network'].getint('hiddenSize') + self.numLayers = config['Network'].getint('numLayers') + self.softmaxSamples = config['Network'].getint('softmaxSamples') + self.initEmbeddings = config['Network'].getboolean('initEmbeddings') + self.embeddingSize = config['Network'].getint('embeddingSize') + self.embeddingSource = config['Network'].get('embeddingSource') + + # No restoring for training params, batch size or other non model dependent parameters + + # Show the restored params + print() + print('Warning: Restoring parameters:') + print('globStep: {}'.format(self.globStep)) + print('watsonMode: {}'.format(self.watsonMode)) + print('autoEncode: {}'.format(self.autoEncode)) + print('corpus: {}'.format(self.corpus)) + print('datasetTag: {}'.format(self.datasetTag)) + print('maxLength: {}'.format(self.maxLength)) + print('filterVocab: {}'.format(self.filterVocab)) + print('skipLines: {}'.format(self.skipLines)) + print('vocabularySize: {}'.format(self.vocabularySize)) + print('hiddenSize: {}'.format(self.hiddenSize)) + print('numLayers: {}'.format(self.numLayers)) + print('softmaxSamples: {}'.format(self.softmaxSamples)) + print('initEmbeddings: {}'.format(self.initEmbeddings)) + print('embeddingSize: {}'.format(self.embeddingSize)) + print('embeddingSource: {}'.format(self.embeddingSource)) + print() + + # For now, not arbitrary independent maxLength between encoder and decoder + self.maxLengthEnco = self.maxLength + self.maxLengthDeco = self.maxLength + 2 + + if self.watsonMode: + self.SENTENCES_PREFIX.reverse() + + + def saveModelParams(self): + """ Save the params of the model, like the current globStep value + Warning: if you modify this function, make sure the changes mirror loadModelParams + """ + config = configparser.ConfigParser() + config['General'] = {} + config['General']['version'] = self.CONFIG_VERSION + config['General']['globStep'] = str(self.globStep) + config['General']['watsonMode'] = str(self.watsonMode) + config['General']['autoEncode'] = str(self.autoEncode) + config['General']['corpus'] = str(self.corpus) + + config['Dataset'] = {} + config['Dataset']['datasetTag'] = str(self.datasetTag) + config['Dataset']['maxLength'] = str(self.maxLength) + config['Dataset']['filterVocab'] = str(self.filterVocab) + config['Dataset']['skipLines'] = str(self.skipLines) + config['Dataset']['vocabularySize'] = str(self.vocabularySize) + + config['Network'] = {} + config['Network']['hiddenSize'] = str(self.hiddenSize) + config['Network']['numLayers'] = str(self.numLayers) + config['Network']['softmaxSamples'] = str(self.softmaxSamples) + config['Network']['initEmbeddings'] = str(self.initEmbeddings) + config['Network']['embeddingSize'] = str(self.embeddingSize) + config['Network']['embeddingSource'] = str(self.embeddingSource) + + # Keep track of the learning params (but without restoring them) + config['Training (won\'t be restored)'] = {} + config['Training (won\'t be restored)']['learningRate'] = str(self.learningRate) + config['Training (won\'t be restored)']['batchSize'] = str(self.batchSize) + config['Training (won\'t be restored)']['dropout'] = str(self.dropout) + + with open(os.path.join(self.modelDir, self.CONFIG_FILENAME), 'w') as configFile: + config.write(configFile) + + def _getSummaryName(self): + """ Parse the argument to decide were to save the summary, at the same place that the model + The folder could already contain logs if we restore the training, those will be merged + Return: + str: The path and name of the summary + """ + return self.modelDir + + def _getModelName(self): + """ Parse the argument to decide were to save/load the model + This function is called at each checkpoint and the first time the model is load. If keepAll option is set, the + globStep value will be included in the name. + Return: + str: The path and name were the model need to be saved + """ + modelName = os.path.join(self.modelDir, self.MODEL_NAME_BASE) + if self.keepAll: # We do not erase the previously saved model by including the current step on the name + modelName += '-' + str(self.globStep) + return modelName + self.MODEL_EXT + + def getDevice(self): + """ Parse the argument to decide on which device run the model + Return: + str: The name of the device on which run the program + """ + if self.device == 'cpu': + return '/cpu:0' + elif self.device == 'gpu': + return '/gpu:0' + elif self.device is None: # No specified device (default) + return None + else: + print('Warning: Error in the device name: {}, use the default device'.format(self.device)) + return None + + +if __name__ == "__main__": + dc = DeepConversation() + print(dc.respond("What color?")) + print(dc.respond("What is immoral?")) + print(dc.respond("Are you evil?")) + print(dc.respond("Are you happy?")) diff --git a/iso/dragonfire-master/dragonfire/deepconv/corpus/__init__.py b/iso/dragonfire-master/dragonfire/deepconv/corpus/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/iso/dragonfire-master/dragonfire/deepconv/corpus/cornelldata.py b/iso/dragonfire-master/dragonfire/deepconv/corpus/cornelldata.py new file mode 100644 index 00000000..63ea67c0 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/deepconv/corpus/cornelldata.py @@ -0,0 +1,89 @@ +import os +import ast + +""" +Load the cornell movie dialog corpus. + +Available from here: +http://www.cs.cornell.edu/~cristian/Cornell_Movie-Dialogs_Corpus.html + +""" + +class CornellData: + """ + + """ + + def __init__(self, dirName): + """ + Args: + dirName (string): directory where to load the corpus + """ + self.lines = {} + self.conversations = [] + + MOVIE_LINES_FIELDS = ["lineID","characterID","movieID","character","text"] + MOVIE_CONVERSATIONS_FIELDS = ["character1ID","character2ID","movieID","utteranceIDs"] + + dirName = "/usr/share/dragonfire/deepconv/" + self.lines = self.loadLines(os.path.join(dirName, "movie_lines.txt"), MOVIE_LINES_FIELDS) + self.conversations = self.loadConversations(os.path.join(dirName, "movie_conversations.txt"), MOVIE_CONVERSATIONS_FIELDS) + + # TODO: Cleaner program (merge copy-paste) !! + + def loadLines(self, fileName, fields): + """ + Args: + fileName (str): file to load + field (set): fields to extract + Return: + dict>: the extracted fields for each line + """ + lines = {} + + with open(fileName, 'r', encoding='iso-8859-1') as f: # TODO: Solve Iso encoding pb ! + for line in f: + values = line.split(" +++$+++ ") + + # Extract fields + lineObj = {} + for i, field in enumerate(fields): + lineObj[field] = values[i] + + lines[lineObj['lineID']] = lineObj + + return lines + + def loadConversations(self, fileName, fields): + """ + Args: + fileName (str): file to load + field (set): fields to extract + Return: + dict>: the extracted fields for each line + """ + conversations = [] + + with open(fileName, 'r', encoding='iso-8859-1') as f: # TODO: Solve Iso encoding pb ! + for line in f: + values = line.split(" +++$+++ ") + + # Extract fields + convObj = {} + for i, field in enumerate(fields): + convObj[field] = values[i] + + # Convert string to list (convObj["utteranceIDs"] == "['L598485', 'L598486', ...]") + lineIds = ast.literal_eval(convObj["utteranceIDs"]) + + # Reassemble lines + convObj["lines"] = [] + for lineId in lineIds: + convObj["lines"].append(self.lines[lineId]) + + conversations.append(convObj) + + return conversations + + def getConversations(self): + return self.conversations diff --git a/iso/dragonfire-master/dragonfire/deepconv/corpus/lightweightdata.py b/iso/dragonfire-master/dragonfire/deepconv/corpus/lightweightdata.py new file mode 100644 index 00000000..f74b19d0 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/deepconv/corpus/lightweightdata.py @@ -0,0 +1,56 @@ +import os + +""" +Load data from a dataset of simply-formatted data + +from A to B +from B to A +from A to B +from B to A +from A to B +=== +from C to D +from D to C +from C to D +from D to C +from C to D +from D to C +... + +`===` lines just separate linear conversations between 2 people. + +""" + +class LightweightData: + """ + """ + + def __init__(self, lightweightFile): + """ + Args: + lightweightFile (string): file containing our lightweight-formatted corpus + """ + self.CONVERSATION_SEP = "===" + self.conversations = [] + self.loadLines(lightweightFile + '.txt') + + def loadLines(self, fileName): + """ + Args: + fileName (str): file to load + """ + + linesBuffer = [] + with open(fileName, 'r') as f: + for line in f: + l = line.strip() + if l == self.CONVERSATION_SEP: + self.conversations.append({"lines": linesBuffer}) + linesBuffer = [] + else: + linesBuffer.append({"text": l}) + if len(linesBuffer): # Eventually flush the last conversation + self.conversations.append({"lines": linesBuffer}) + + def getConversations(self): + return self.conversations diff --git a/iso/dragonfire-master/dragonfire/deepconv/corpus/opensubsdata.py b/iso/dragonfire-master/dragonfire/deepconv/corpus/opensubsdata.py new file mode 100644 index 00000000..06360d74 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/deepconv/corpus/opensubsdata.py @@ -0,0 +1,130 @@ +import xml.etree.ElementTree as ET +import datetime +import os +import sys +import json +import re +import pprint + +from gzip import GzipFile +from tqdm import tqdm + +""" +Load the opensubtitles dialog corpus. +""" + +class OpensubsData: + """ + + """ + + def __init__(self, dirName): + """ + Args: + dirName (string): directory where to load the corpus + """ + + # Hack this to filter on subset of Opensubtitles + # dirName = "%s/en/Action" % dirName + + print("Loading OpenSubtitles conversations in %s." % dirName) + self.conversations = [] + self.tag_re = re.compile(r'(|<[^>]*>)') + self.conversations = self.loadConversations(dirName) + + def loadConversations(self, dirName): + """ + Args: + dirName (str): folder to load + Return: + array(question, answer): the extracted QA pairs + """ + conversations = [] + dirList = self.filesInDir(dirName) + for filepath in tqdm(dirList, "OpenSubtitles data files"): + if filepath.endswith('gz'): + try: + doc = self.getXML(filepath) + conversations.extend(self.genList(doc)) + except ValueError: + tqdm.write("Skipping file %s with errors." % filepath) + except: + print("Unexpected error:", sys.exc_info()[0]) + raise + return conversations + + def getConversations(self): + return self.conversations + + def genList(self, tree): + root = tree.getroot() + + timeFormat = '%H:%M:%S' + maxDelta = datetime.timedelta(seconds=1) + + startTime = datetime.datetime.min + strbuf = '' + sentList = [] + + for child in root: + for elem in child: + if elem.tag == 'time': + elemID = elem.attrib['id'] + elemVal = elem.attrib['value'][:-4] + if elemID[-1] == 'S': + startTime = datetime.datetime.strptime(elemVal, timeFormat) + else: + sentList.append((strbuf.strip(), startTime, datetime.datetime.strptime(elemVal, timeFormat))) + strbuf = '' + else: + try: + strbuf = strbuf + " " + elem.text + except: + pass + + conversations = [] + for idx in range(0, len(sentList) - 1): + cur = sentList[idx] + nxt = sentList[idx + 1] + if nxt[1] - cur[2] <= maxDelta and cur and nxt: + tmp = {} + tmp["lines"] = [] + tmp["lines"].append(self.getLine(cur[0])) + tmp["lines"].append(self.getLine(nxt[0])) + if self.filter(tmp): + conversations.append(tmp) + + return conversations + + def getLine(self, sentence): + line = {} + line["text"] = self.tag_re.sub('', sentence).replace('\\\'','\'').strip().lower() + return line + + def filter(self, lines): + # Use the followint to customize filtering of QA pairs + # + # startwords = ("what", "how", "when", "why", "where", "do", "did", "is", "are", "can", "could", "would", "will") + # question = lines["lines"][0]["text"] + # if not question.endswith('?'): + # return False + # if not question.split(' ')[0] in startwords: + # return False + # + return True + + def getXML(self, filepath): + fext = os.path.splitext(filepath)[1] + if fext == '.gz': + tmp = GzipFile(filename=filepath) + return ET.parse(tmp) + else: + return ET.parse(filepath) + + def filesInDir(self, dirname): + result = [] + for dirpath, dirs, files in os.walk(dirname): + for filename in files: + fname = os.path.join(dirpath, filename) + result.append(fname) + return result diff --git a/iso/dragonfire-master/dragonfire/deepconv/corpus/scotusdata.py b/iso/dragonfire-master/dragonfire/deepconv/corpus/scotusdata.py new file mode 100644 index 00000000..657bc443 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/deepconv/corpus/scotusdata.py @@ -0,0 +1,43 @@ +import os + +""" +Load transcripts from the Supreme Court of the USA. + +Available from here: +https://github.com/pender/chatbot-rnn + +""" + +class ScotusData: + """ + """ + + def __init__(self, dirName): + """ + Args: + dirName (string): directory where to load the corpus + """ + self.lines = self.loadLines(os.path.join(dirName, "scotus")) + self.conversations = [{"lines": self.lines}] + + + def loadLines(self, fileName): + """ + Args: + fileName (str): file to load + Return: + list>: the extracted fields for each line + """ + lines = [] + + with open(fileName, 'r') as f: + for line in f: + l = line[line.index(":")+1:].strip() # Strip name of speaker. + + lines.append({"text": l}) + + return lines + + + def getConversations(self): + return self.conversations diff --git a/iso/dragonfire-master/dragonfire/deepconv/corpus/ubuntudata.py b/iso/dragonfire-master/dragonfire/deepconv/corpus/ubuntudata.py new file mode 100644 index 00000000..abb3449a --- /dev/null +++ b/iso/dragonfire-master/dragonfire/deepconv/corpus/ubuntudata.py @@ -0,0 +1,55 @@ +import os + +from tqdm import tqdm + +""" +Ubuntu Dialogue Corpus + +http://arxiv.org/abs/1506.08909 + +""" + +class UbuntuData: + """ + """ + + def __init__(self, dirName): + """ + Args: + dirName (string): directory where to load the corpus + """ + self.MAX_NUMBER_SUBDIR = 10 + self.conversations = [] + __dir = os.path.join(dirName, "dialogs") + number_subdir = 0 + for sub in tqdm(os.scandir(__dir), desc="Ubuntu dialogs subfolders", total=len(os.listdir(__dir))): + if number_subdir == self.MAX_NUMBER_SUBDIR: + print("WARNING: Early stoping, only extracting {} directories".format(self.MAX_NUMBER_SUBDIR)) + return + + if sub.is_dir(): + number_subdir += 1 + for f in os.scandir(sub.path): + if f.name.endswith(".tsv"): + self.conversations.append({"lines": self.loadLines(f.path)}) + + + def loadLines(self, fileName): + """ + Args: + fileName (str): file to load + Return: + list>: the extracted fields for each line + """ + lines = [] + with open(fileName, 'r') as f: + for line in f: + l = line[line.rindex("\t")+1:].strip() # Strip metadata (timestamps, speaker names) + + lines.append({"text": l}) + + return lines + + + def getConversations(self): + return self.conversations diff --git a/iso/dragonfire-master/dragonfire/deepconv/model.py b/iso/dragonfire-master/dragonfire/deepconv/model.py new file mode 100644 index 00000000..b23e952f --- /dev/null +++ b/iso/dragonfire-master/dragonfire/deepconv/model.py @@ -0,0 +1,229 @@ +""" +Model to predict the next sentence given an input sequence + +""" + +import tensorflow as tf + +from dragonfire.deepconv.textdata import Batch + + +class ProjectionOp: + """ Single layer perceptron + Project input tensor on the output dimension + """ + def __init__(self, shape, scope=None, dtype=None): + """ + Args: + shape: a tuple (input dim, output dim) + scope (str): encapsulate variables + dtype: the weights type + """ + assert len(shape) == 2 + + self.scope = scope + + # Projection on the keyboard + with tf.variable_scope('weights_' + self.scope): + self.W_t = tf.get_variable( + 'weights', + shape, + # initializer=tf.truncated_normal_initializer() # TODO: Tune value (fct of input size: 1/sqrt(input_dim)) + dtype=dtype + ) + self.b = tf.get_variable( + 'bias', + shape[0], + initializer=tf.constant_initializer(), + dtype=dtype + ) + self.W = tf.transpose(self.W_t) + + def getWeights(self): + """ Convenience method for some tf arguments + """ + return self.W, self.b + + def __call__(self, X): + """ Project the output of the decoder into the vocabulary space + Args: + X (tf.Tensor): input value + """ + with tf.name_scope(self.scope): + return tf.matmul(X, self.W) + self.b + + +class Model: + """ + Implementation of a seq2seq model. + Architecture: + Encoder/decoder + 2 LTSM layers + """ + + def __init__(self, args, textData): + """ + Args: + args: parameters of the model + textData: the dataset object + """ + print("Model creation...") + + self.textData = textData # Keep a reference on the dataset + self.args = args # Keep track of the parameters of the model + self.dtype = tf.float32 + + # Placeholders + self.encoderInputs = None + self.decoderInputs = None # Same that decoderTarget plus the + self.decoderTargets = None + self.decoderWeights = None # Adjust the learning to the target sentence size + + # Main operators + self.lossFct = None + self.optOp = None + self.outputs = None # Outputs of the network, list of probability for each words + + # Construct the graphs + self.buildNetwork() + + def buildNetwork(self): + """ Create the computational graph + """ + + # TODO: Create name_scopes (for better graph visualisation) + # TODO: Use buckets (better perfs) + + # Parameters of sampled softmax (needed for attention mechanism and a large vocabulary size) + outputProjection = None + # Sampled softmax only makes sense if we sample less than vocabulary size. + if 0 < self.args.softmaxSamples < self.textData.getVocabularySize(): + outputProjection = ProjectionOp( + (self.textData.getVocabularySize(), self.args.hiddenSize), + scope='softmax_projection', + dtype=self.dtype + ) + + def sampledSoftmax(labels, inputs): + labels = tf.reshape(labels, [-1, 1]) # Add one dimension (nb of true classes, here 1) + + # We need to compute the sampled_softmax_loss using 32bit floats to + # avoid numerical instabilities. + localWt = tf.cast(outputProjection.W_t, tf.float32) + localB = tf.cast(outputProjection.b, tf.float32) + localInputs = tf.cast(inputs, tf.float32) + + return tf.cast( + tf.nn.sampled_softmax_loss( + localWt, # Should have shape [num_classes, dim] + localB, + labels, + localInputs, + self.args.softmaxSamples, # The number of classes to randomly sample per batch + self.textData.getVocabularySize()), # The number of classes + self.dtype) + + # Creation of the rnn cell + def create_rnn_cell(): + encoDecoCell = tf.contrib.rnn.BasicLSTMCell( # Or GRUCell, LSTMCell(args.hiddenSize) + self.args.hiddenSize, + ) + if not self.args.test: # TODO: Should use a placeholder instead + encoDecoCell = tf.contrib.rnn.DropoutWrapper( + encoDecoCell, + input_keep_prob=1.0, + output_keep_prob=self.args.dropout + ) + return encoDecoCell + encoDecoCell = tf.contrib.rnn.MultiRNNCell( + [create_rnn_cell() for _ in range(self.args.numLayers)], + ) + + # Network input (placeholders) + + with tf.name_scope('placeholder_encoder'): + self.encoderInputs = [tf.placeholder(tf.int32, [None, ]) for _ in range(self.args.maxLengthEnco)] # Batch size * sequence length * input dim + + with tf.name_scope('placeholder_decoder'): + self.decoderInputs = [tf.placeholder(tf.int32, [None, ], name='inputs') for _ in range(self.args.maxLengthDeco)] # Same sentence length for input and output (Right ?) + self.decoderTargets = [tf.placeholder(tf.int32, [None, ], name='targets') for _ in range(self.args.maxLengthDeco)] + self.decoderWeights = [tf.placeholder(tf.float32, [None, ], name='weights') for _ in range(self.args.maxLengthDeco)] + + # Define the network + # Here we use an embedding model, it takes integer as input and convert them into word vector for + # better word representation + decoderOutputs, states = tf.contrib.legacy_seq2seq.embedding_rnn_seq2seq( + self.encoderInputs, # List<[batch=?, inputDim=1]>, list of size args.maxLength + self.decoderInputs, # For training, we force the correct output (feed_previous=False) + encoDecoCell, + self.textData.getVocabularySize(), + self.textData.getVocabularySize(), # Both encoder and decoder have the same number of class + embedding_size=self.args.embeddingSize, # Dimension of each word + output_projection=outputProjection.getWeights() if outputProjection else None, + feed_previous=bool(self.args.test) # When we test (self.args.test), we use previous output as next input (feed_previous) + ) + + # TODO: When the LSTM hidden size is too big, we should project the LSTM output into a smaller space (4086 => 2046): Should speed up + # training and reduce memory usage. Other solution, use sampling softmax + + # For testing only + if self.args.test: + if not outputProjection: + self.outputs = decoderOutputs + else: + self.outputs = [outputProjection(output) for output in decoderOutputs] + + # TODO: Attach a summary to visualize the output + + # For training only + else: + # Finally, we define the loss function + self.lossFct = tf.contrib.legacy_seq2seq.sequence_loss( + decoderOutputs, + self.decoderTargets, + self.decoderWeights, + self.textData.getVocabularySize(), + softmax_loss_function= sampledSoftmax if outputProjection else None # If None, use default SoftMax + ) + tf.summary.scalar('loss', self.lossFct) # Keep track of the cost + + # Initialize the optimizer + opt = tf.train.AdamOptimizer( + learning_rate=self.args.learningRate, + beta1=0.9, + beta2=0.999, + epsilon=1e-08 + ) + self.optOp = opt.minimize(self.lossFct) + + def step(self, batch): + """ Forward/training step operation. + Does not perform run on itself but just return the operators to do so. Those have then to be run + Args: + batch (Batch): Input data on testing mode, input and target on output mode + Return: + (ops), dict: A tuple of the (training, loss) operators or (outputs,) in testing mode with the associated feed dictionary + """ + + # Feed the dictionary + feedDict = {} + ops = None + + if not self.args.test: # Training + for i in range(self.args.maxLengthEnco): + feedDict[self.encoderInputs[i]] = batch.encoderSeqs[i] + for i in range(self.args.maxLengthDeco): + feedDict[self.decoderInputs[i]] = batch.decoderSeqs[i] + feedDict[self.decoderTargets[i]] = batch.targetSeqs[i] + feedDict[self.decoderWeights[i]] = batch.weights[i] + + ops = (self.optOp, self.lossFct) + else: # Testing (batchSize == 1) + for i in range(self.args.maxLengthEnco): + feedDict[self.encoderInputs[i]] = batch.encoderSeqs[i] + feedDict[self.decoderInputs[0]] = [self.textData.goToken] + + ops = (self.outputs,) + + # Return one pass operator + return ops, feedDict diff --git a/iso/dragonfire-master/dragonfire/deepconv/textdata.py b/iso/dragonfire-master/dragonfire/deepconv/textdata.py new file mode 100644 index 00000000..d0084130 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/deepconv/textdata.py @@ -0,0 +1,626 @@ +""" +Loads the dialogue corpus, builds the vocabulary +""" + +import numpy as np +import nltk # For tokenize +from tqdm import tqdm # Progress bar +import pickle # Saving the data +import math # For float comparison +import os # Checking file existance +import random +import string +import collections + +from dragonfire.deepconv.corpus.cornelldata import CornellData +from dragonfire.deepconv.corpus.opensubsdata import OpensubsData +from dragonfire.deepconv.corpus.scotusdata import ScotusData +from dragonfire.deepconv.corpus.ubuntudata import UbuntuData +from dragonfire.deepconv.corpus.lightweightdata import LightweightData + + +class Batch: + """Struct containing batches info + """ + def __init__(self): + self.encoderSeqs = [] + self.decoderSeqs = [] + self.targetSeqs = [] + self.weights = [] + + +class TextData: + """Dataset class + Warning: No vocabulary limit + """ + + availableCorpus = collections.OrderedDict([ # OrderedDict because the first element is the default choice + ('cornell', CornellData), + ('opensubs', OpensubsData), + ('scotus', ScotusData), + ('ubuntu', UbuntuData), + ('lightweight', LightweightData), + ]) + + @staticmethod + def corpusChoices(): + """Return the dataset availables + Return: + list: the supported corpus + """ + return list(TextData.availableCorpus.keys()) + + def __init__(self, args): + """Load all conversations + Args: + args: parameters of the model + """ + # Model parameters + self.args = args + + # Path variables + self.corpusDir = os.path.join(self.args.rootDir, 'data', self.args.corpus) + basePath = self._constructBasePath() + self.fullSamplesPath = basePath + '.pkl' # Full sentences length/vocab + self.filteredSamplesPath = basePath + '-length{}-filter{}-vocabSize{}.pkl'.format( + self.args.maxLength, + self.args.filterVocab, + self.args.vocabularySize, + ) # Sentences/vocab filtered for this model + + self.padToken = -1 # Padding + self.goToken = -1 # Start of sequence + self.eosToken = -1 # End of sequence + self.unknownToken = -1 # Word dropped from vocabulary + + self.trainingSamples = [] # 2d array containing each question and his answer [[input,target]] + + self.word2id = {} + self.id2word = {} # For a rapid conversion (Warning: If replace dict by list, modify the filtering to avoid linear complexity with del) + self.idCount = {} # Useful to filters the words (TODO: Could replace dict by list or use collections.Counter) + + self.loadCorpus() + + # Plot some stats: + self._printStats() + + if self.args.playDataset: + self.playDataset() + + def _printStats(self): + print('Loaded {}: {} words, {} QA'.format(self.args.corpus, len(self.word2id), len(self.trainingSamples))) + + def _constructBasePath(self): + """Return the name of the base prefix of the current dataset + """ + #path = os.path.join(self.args.rootDir, 'data' + os.sep + 'samples' + os.sep) + path = dirName = "/usr/share/dragonfire/deepconv/model-pretrainedv2/" + path += 'dataset-{}'.format(self.args.corpus) + if self.args.datasetTag: + path += '-' + self.args.datasetTag + return path + + def makeLighter(self, ratioDataset): + """Only keep a small fraction of the dataset, given by the ratio + """ + #if not math.isclose(ratioDataset, 1.0): + # self.shuffle() # Really ? + # print('WARNING: Ratio feature not implemented !!!') + pass + + def shuffle(self): + """Shuffle the training samples + """ + print('Shuffling the dataset...') + random.shuffle(self.trainingSamples) + + def _createBatch(self, samples): + """Create a single batch from the list of sample. The batch size is automatically defined by the number of + samples given. + The inputs should already be inverted. The target should already have and + Warning: This function should not make direct calls to args.batchSize !!! + Args: + samples (list): a list of samples, each sample being on the form [input, target] + Return: + Batch: a batch object en + """ + + batch = Batch() + batchSize = len(samples) + + # Create the batch tensor + for i in range(batchSize): + # Unpack the sample + sample = samples[i] + if not self.args.test and self.args.watsonMode: # Watson mode: invert question and answer + sample = list(reversed(sample)) + if not self.args.test and self.args.autoEncode: # Autoencode: use either the question or answer for both input and output + k = random.randint(0, 1) + sample = (sample[k], sample[k]) + # TODO: Why re-processed that at each epoch ? Could precompute that + # once and reuse those every time. Is not the bottleneck so won't change + # much ? and if preprocessing, should be compatible with autoEncode & cie. + batch.encoderSeqs.append(list(reversed(sample[0]))) # Reverse inputs (and not outputs), little trick as defined on the original seq2seq paper + batch.decoderSeqs.append([self.goToken] + sample[1] + [self.eosToken]) # Add the and tokens + batch.targetSeqs.append(batch.decoderSeqs[-1][1:]) # Same as decoder, but shifted to the left (ignore the ) + + # Long sentences should have been filtered during the dataset creation + assert len(batch.encoderSeqs[i]) <= self.args.maxLengthEnco + assert len(batch.decoderSeqs[i]) <= self.args.maxLengthDeco + + # TODO: Should use tf batch function to automatically add padding and batch samples + # Add padding & define weight + batch.encoderSeqs[i] = [self.padToken] * (self.args.maxLengthEnco - len(batch.encoderSeqs[i])) + batch.encoderSeqs[i] # Left padding for the input + batch.weights.append([1.0] * len(batch.targetSeqs[i]) + [0.0] * (self.args.maxLengthDeco - len(batch.targetSeqs[i]))) + batch.decoderSeqs[i] = batch.decoderSeqs[i] + [self.padToken] * (self.args.maxLengthDeco - len(batch.decoderSeqs[i])) + batch.targetSeqs[i] = batch.targetSeqs[i] + [self.padToken] * (self.args.maxLengthDeco - len(batch.targetSeqs[i])) + + # Simple hack to reshape the batch + encoderSeqsT = [] # Corrected orientation + for i in range(self.args.maxLengthEnco): + encoderSeqT = [] + for j in range(batchSize): + encoderSeqT.append(batch.encoderSeqs[j][i]) + encoderSeqsT.append(encoderSeqT) + batch.encoderSeqs = encoderSeqsT + + decoderSeqsT = [] + targetSeqsT = [] + weightsT = [] + for i in range(self.args.maxLengthDeco): + decoderSeqT = [] + targetSeqT = [] + weightT = [] + for j in range(batchSize): + decoderSeqT.append(batch.decoderSeqs[j][i]) + targetSeqT.append(batch.targetSeqs[j][i]) + weightT.append(batch.weights[j][i]) + decoderSeqsT.append(decoderSeqT) + targetSeqsT.append(targetSeqT) + weightsT.append(weightT) + batch.decoderSeqs = decoderSeqsT + batch.targetSeqs = targetSeqsT + batch.weights = weightsT + + # # Debug + # self.printBatch(batch) # Input inverted, padding should be correct + # print(self.sequence2str(samples[0][0])) + # print(self.sequence2str(samples[0][1])) # Check we did not modified the original sample + + return batch + + def getBatches(self): + """Prepare the batches for the current epoch + Return: + list: Get a list of the batches for the next epoch + """ + self.shuffle() + + batches = [] + + def genNextSamples(): + """ Generator over the mini-batch training samples + """ + for i in range(0, self.getSampleSize(), self.args.batchSize): + yield self.trainingSamples[i:min(i + self.args.batchSize, self.getSampleSize())] + + # TODO: Should replace that by generator (better: by tf.queue) + + for samples in genNextSamples(): + batch = self._createBatch(samples) + batches.append(batch) + return batches + + def getSampleSize(self): + """Return the size of the dataset + Return: + int: Number of training samples + """ + return len(self.trainingSamples) + + def getVocabularySize(self): + """Return the number of words present in the dataset + Return: + int: Number of word on the loader corpus + """ + return len(self.word2id) + + def loadCorpus(self): + """Load/create the conversations data + """ + datasetExist = os.path.isfile(self.filteredSamplesPath) + if not datasetExist: # First time we load the database: creating all files + print('Training samples not found. Creating dataset...') + + datasetExist = os.path.isfile(self.fullSamplesPath) # Try to construct the dataset from the preprocessed entry + if not datasetExist: + print('Constructing full dataset...') + + optional = '' + if self.args.corpus == 'lightweight': + if not self.args.datasetTag: + raise ValueError('Use the --datasetTag to define the lightweight file to use.') + optional = os.sep + self.args.datasetTag # HACK: Forward the filename + + # Corpus creation + corpusData = TextData.availableCorpus[self.args.corpus](self.corpusDir + optional) + self.createFullCorpus(corpusData.getConversations()) + self.saveDataset(self.fullSamplesPath) + else: + self.loadDataset(self.fullSamplesPath) + self._printStats() + + print('Filtering words (vocabSize = {} and wordCount > {})...'.format( + self.args.vocabularySize, + self.args.filterVocab + )) + self.filterFromFull() # Extract the sub vocabulary for the given maxLength and filterVocab + + # Saving + print('Saving dataset...') + self.saveDataset(self.filteredSamplesPath) # Saving tf samples + else: + self.loadDataset(self.filteredSamplesPath) + + assert self.padToken == 0 + + def saveDataset(self, filename): + """Save samples to file + Args: + filename (str): pickle filename + """ + + with open(os.path.join(filename), 'wb') as handle: + data = { # Warning: If adding something here, also modifying loadDataset + 'word2id': self.word2id, + 'id2word': self.id2word, + 'idCount': self.idCount, + 'trainingSamples': self.trainingSamples + } + pickle.dump(data, handle, -1) # Using the highest protocol available + + def loadDataset(self, filename): + """Load samples from file + Args: + filename (str): pickle filename + """ + dataset_path = os.path.join(filename) + print('Loading dataset from {}'.format(dataset_path)) + with open(dataset_path, 'rb') as handle: + data = pickle.load(handle) # Warning: If adding something here, also modifying saveDataset + self.word2id = data['word2id'] + self.id2word = data['id2word'] + self.idCount = data.get('idCount', None) + self.trainingSamples = data['trainingSamples'] + + self.padToken = self.word2id[''] + self.goToken = self.word2id[''] + self.eosToken = self.word2id[''] + self.unknownToken = self.word2id[''] # Restore special words + + def filterFromFull(self): + """ Load the pre-processed full corpus and filter the vocabulary / sentences + to match the given model options + """ + + def mergeSentences(sentences, fromEnd=False): + """Merge the sentences until the max sentence length is reached + Also decrement id count for unused sentences. + Args: + sentences (list>): the list of sentences for the current line + fromEnd (bool): Define the question on the answer + Return: + list: the list of the word ids of the sentence + """ + # We add sentence by sentence until we reach the maximum length + merged = [] + + # If question: we only keep the last sentences + # If answer: we only keep the first sentences + if fromEnd: + sentences = reversed(sentences) + + for sentence in sentences: + + # If the total length is not too big, we still can add one more sentence + if len(merged) + len(sentence) <= self.args.maxLength: + if fromEnd: # Append the sentence + merged = sentence + merged + else: + merged = merged + sentence + else: # If the sentence is not used, neither are the words + for w in sentence: + self.idCount[w] -= 1 + return merged + + newSamples = [] + + # 1st step: Iterate over all words and add filters the sentences + # according to the sentence lengths + for inputWords, targetWords in tqdm(self.trainingSamples, desc='Filter sentences:', leave=False): + inputWords = mergeSentences(inputWords, fromEnd=True) + targetWords = mergeSentences(targetWords, fromEnd=False) + + newSamples.append([inputWords, targetWords]) + words = [] + + # WARNING: DO NOT FILTER THE UNKNOWN TOKEN !!! Only word which has count==0 ? + + # 2nd step: filter the unused words and replace them by the unknown token + # This is also where we update the correnspondance dictionaries + specialTokens = { # TODO: bad HACK to filter the special tokens. Error prone if one day add new special tokens + self.padToken, + self.goToken, + self.eosToken, + self.unknownToken + } + newMapping = {} # Map the full words ids to the new one (TODO: Should be a list) + newId = 0 + + selectedWordIds = collections \ + .Counter(self.idCount) \ + .most_common(self.args.vocabularySize or None) # Keep all if vocabularySize == 0 + selectedWordIds = {k for k, v in selectedWordIds if v > self.args.filterVocab} + selectedWordIds |= specialTokens + + for wordId, count in [(i, self.idCount[i]) for i in range(len(self.idCount))]: # Iterate in order + if wordId in selectedWordIds: # Update the word id + newMapping[wordId] = newId + word = self.id2word[wordId] # The new id has changed, update the dictionaries + del self.id2word[wordId] # Will be recreated if newId == wordId + self.word2id[word] = newId + self.id2word[newId] = word + newId += 1 + else: # Cadidate to filtering, map it to unknownToken (Warning: don't filter special token) + newMapping[wordId] = self.unknownToken + del self.word2id[self.id2word[wordId]] # The word isn't used anymore + del self.id2word[wordId] + + # Last step: replace old ids by new ones and filters empty sentences + def replace_words(words): + valid = False # Filter empty sequences + for i, w in enumerate(words): + words[i] = newMapping[w] + if words[i] != self.unknownToken: # Also filter if only contains unknown tokens + valid = True + return valid + + self.trainingSamples.clear() + + for inputWords, targetWords in tqdm(newSamples, desc='Replace ids:', leave=False): + valid = True + valid &= replace_words(inputWords) + valid &= replace_words(targetWords) + valid &= targetWords.count(self.unknownToken) == 0 # Filter target with out-of-vocabulary target words ? + + if valid: + self.trainingSamples.append([inputWords, targetWords]) # TODO: Could replace list by tuple + + self.idCount.clear() # Not usefull anymore. Free data + + def createFullCorpus(self, conversations): + """Extract all data from the given vocabulary. + Save the data on disk. Note that the entire corpus is pre-processed + without restriction on the sentence length or vocab size. + """ + # Add standard tokens + self.padToken = self.getWordId('') # Padding (Warning: first things to add > id=0 !!) + self.goToken = self.getWordId('') # Start of sequence + self.eosToken = self.getWordId('') # End of sequence + self.unknownToken = self.getWordId('') # Word dropped from vocabulary + + # Preprocessing data + + for conversation in tqdm(conversations, desc='Extract conversations'): + self.extractConversation(conversation) + + # The dataset will be saved in the same order it has been extracted + + def extractConversation(self, conversation): + """Extract the sample lines from the conversations + Args: + conversation (Obj): a conversation object containing the lines to extract + """ + + if self.args.skipLines: # WARNING: The dataset won't be regenerated if the choice evolve (have to use the datasetTag) + step = 2 + else: + step = 1 + + # Iterate over all the lines of the conversation + for i in tqdm_wrap( + range(0, len(conversation['lines']) - 1, step), # We ignore the last line (no answer for it) + desc='Conversation', + leave=False + ): + inputLine = conversation['lines'][i] + targetLine = conversation['lines'][i+1] + + inputWords = self.extractText(inputLine['text']) + targetWords = self.extractText(targetLine['text']) + + if inputWords and targetWords: # Filter wrong samples (if one of the list is empty) + self.trainingSamples.append([inputWords, targetWords]) + + def extractText(self, line): + """Extract the words from a sample lines + Args: + line (str): a line containing the text to extract + Return: + list>: the list of sentences of word ids of the sentence + """ + sentences = [] # List[List[str]] + + # Extract sentences + sentencesToken = nltk.sent_tokenize(line) + + # We add sentence by sentence until we reach the maximum length + for i in range(len(sentencesToken)): + tokens = nltk.word_tokenize(sentencesToken[i]) + + tempWords = [] + for token in tokens: + tempWords.append(self.getWordId(token)) # Create the vocabulary and the training sentences + + sentences.append(tempWords) + + return sentences + + def getWordId(self, word, create=True): + """Get the id of the word (and add it to the dictionary if not existing). If the word does not exist and + create is set to False, the function will return the unknownToken value + Args: + word (str): word to add + create (Bool): if True and the word does not exist already, the world will be added + Return: + int: the id of the word created + """ + # Should we Keep only words with more than one occurrence ? + + word = word.lower() # Ignore case + + # At inference, we simply look up for the word + if not create: + wordId = self.word2id.get(word, self.unknownToken) + # Get the id if the word already exist + elif word in self.word2id: + wordId = self.word2id[word] + self.idCount[wordId] += 1 + # If not, we create a new entry + else: + wordId = len(self.word2id) + self.word2id[word] = wordId + self.id2word[wordId] = word + self.idCount[wordId] = 1 + + return wordId + + def printBatch(self, batch): + """Print a complete batch, useful for debugging + Args: + batch (Batch): a batch object + """ + print('----- Print batch -----') + for i in range(len(batch.encoderSeqs[0])): # Batch size + print('Encoder: {}'.format(self.batchSeq2str(batch.encoderSeqs, seqId=i))) + print('Decoder: {}'.format(self.batchSeq2str(batch.decoderSeqs, seqId=i))) + print('Targets: {}'.format(self.batchSeq2str(batch.targetSeqs, seqId=i))) + print('Weights: {}'.format(' '.join([str(weight) for weight in [batchWeight[i] for batchWeight in batch.weights]]))) + + def sequence2str(self, sequence, clean=False, reverse=False): + """Convert a list of integer into a human readable string + Args: + sequence (list): the sentence to print + clean (Bool): if set, remove the , and tokens + reverse (Bool): for the input, option to restore the standard order + Return: + str: the sentence + """ + + if not sequence: + return '' + + if not clean: + return ' '.join([self.id2word[idx] for idx in sequence]) + + sentence = [] + for wordId in sequence: + if wordId == self.eosToken: # End of generated sentence + break + elif wordId != self.padToken and wordId != self.goToken: + sentence.append(self.id2word[wordId]) + + if reverse: # Reverse means input so no (otherwise pb with previous early stop) + sentence.reverse() + + return self.detokenize(sentence) + + def detokenize(self, tokens): + """Slightly cleaner version of joining with spaces. + Args: + tokens (list): the sentence to print + Return: + str: the sentence + """ + return ''.join([ + ' ' + t if not t.startswith('\'') and + t not in string.punctuation + else t + for t in tokens]).strip().capitalize() + + def batchSeq2str(self, batchSeq, seqId=0, **kwargs): + """Convert a list of integer into a human readable string. + The difference between the previous function is that on a batch object, the values have been reorganized as + batch instead of sentence. + Args: + batchSeq (list>): the sentence(s) to print + seqId (int): the position of the sequence inside the batch + kwargs: the formatting options( See sequence2str() ) + Return: + str: the sentence + """ + sequence = [] + for i in range(len(batchSeq)): # Sequence length + sequence.append(batchSeq[i][seqId]) + return self.sequence2str(sequence, **kwargs) + + def sentence2enco(self, sentence): + """Encode a sequence and return a batch as an input for the model + Return: + Batch: a batch object containing the sentence, or none if something went wrong + """ + + if sentence == '': + return None + + # First step: Divide the sentence in token + tokens = nltk.word_tokenize(sentence) + if len(tokens) > self.args.maxLength: + return None + + # Second step: Convert the token in word ids + wordIds = [] + for token in tokens: + wordIds.append(self.getWordId(token, create=False)) # Create the vocabulary and the training sentences + + # Third step: creating the batch (add padding, reverse) + batch = self._createBatch([[wordIds, []]]) # Mono batch, no target output + + return batch + + def deco2sentence(self, decoderOutputs): + """Decode the output of the decoder and return a human friendly sentence + decoderOutputs (list): + """ + sequence = [] + + # Choose the words with the highest prediction score + for out in decoderOutputs: + sequence.append(np.argmax(out)) # Adding each predicted word ids + + return sequence # We return the raw sentence. Let the caller do some cleaning eventually + + def playDataset(self): + """Print a random dialogue from the dataset + """ + print('Randomly play samples:') + for i in range(self.args.playDataset): + idSample = random.randint(0, len(self.trainingSamples) - 1) + print('Q: {}'.format(self.sequence2str(self.trainingSamples[idSample][0], clean=True))) + print('A: {}'.format(self.sequence2str(self.trainingSamples[idSample][1], clean=True))) + print() + pass + + +def tqdm_wrap(iterable, *args, **kwargs): + """Forward an iterable eventually wrapped around a tqdm decorator + The iterable is only wrapped if the iterable contains enough elements + Args: + iterable (list): An iterable object which define the __len__ method + *args, **kwargs: the tqdm parameters + Return: + iter: The iterable eventually decorated + """ + if len(iterable) > 100: + return tqdm(iterable, *args, **kwargs) + return iterable diff --git a/iso/dragonfire-master/dragonfire/learn.py b/iso/dragonfire-master/dragonfire/learn.py new file mode 100644 index 00000000..344be2d9 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/learn.py @@ -0,0 +1,382 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +.. module:: learn + :platform: Unix + :synopsis: the top-level submodule of Dragonfire that contains the classes related to Dragonfire's learning ability. + +.. moduleauthor:: Mehmet Mert Yıldıran +""" + +import collections # Imported to support ordered dictionaries in Python +from tinydb import TinyDB, Query # TinyDB is a lightweight document oriented database +from os.path import expanduser # Imported to get the home directory +from dragonfire.config import Config # Credentials for the database connection +from dragonfire.database import Fact # Submodule of Dragonfire module that contains the database schema +from sqlalchemy.orm.exc import NoResultFound # the Python SQL toolkit and Object Relational Mapper + + +class Learner(): + """Class to provide the learning ability. + """ + + def __init__(self, nlp): + """Initialization method of :class:`dragonfire.learn.Learner` class. + + Args: + nlp: :mod:`spacy` model instance. + """ + + self.pronouns = collections.OrderedDict() # Create an ordered dictionary + self.pronouns["I"] = "YOU" + self.pronouns["ME"] = "YOU" + self.pronouns["MY"] = "YOUR" + self.pronouns["MINE"] = "YOURS" + self.pronouns["MYSELF"] = "YOURSELF" + self.pronouns["OUR"] = "YOUR" + self.pronouns["OURS"] = "YOURS" + self.pronouns["OURSELVES"] = "YOURSELVES" + self.pronouns["WE"] = "YOU" + self.pronouns["US"] = "YOU" + self.inv_pronouns = collections.OrderedDict() # Create an ordered dictionary + self.inv_pronouns["YOU"] = "I" + self.inv_pronouns["YOUR"] = "MY" + self.inv_pronouns["YOURS"] = "MINE" + self.inv_pronouns["YOURSELF"] = "MYSELF" + self.inv_pronouns["YOURSELVES"] = "OURSELVES" + + self.auxiliaries = collections.OrderedDict() # Create an ordered dictionary + self.auxiliaries["AM"] = "ARE" + self.auxiliaries["'M"] = " ARE" + self.auxiliaries["WAS"] = "WERE" + self.inv_auxiliaries = collections.OrderedDict() # Create an ordered dictionary + self.inv_auxiliaries["ARE"] = "AM" + self.inv_auxiliaries["WERE"] = "WAS" + + home = expanduser("~") # Get the home directory of the user + self.db = TinyDB(home + '/.dragonfire_db.json') # This is where we store the database; /home/USERNAME/.dragonfire_db.json + self.nlp = nlp # Load en_core_web_sm, English, 50 MB, default model + self.is_server = False + self.db_session = None + + def respond(self, com, is_server=False, user_id=None): + """Method to respond the user's input/command using learning ability. + + Args: + com (str): User's command. + + Keyword Args: + is_server (bool): Is Dragonfire running as an API server? + user_id (int): User's ID. + + Returns: + str: Response. + + .. note:: + + Entry function for :class:`Learner` class. Dragonfire calls only this function. It does not handle TTS. + + """ + + self.is_server = is_server + is_public = True + com = self.clean(com) + doc = self.nlp(com) # Command(user's speech) must be decoded from utf-8 to unicode because spaCy only supports unicode strings, self.nlp() handles all parsing + subject = [] # subject list (subjects here usually are; I'M, YOU, HE, SHE, IT, etc.) + types = [] # types of the previous noun phrases + types.append("") + for np in doc.noun_chunks: # Iterate over the noun phrases(chunks) TODO: Cover 'dobj' also; doc = nlp(u'DESCRIBE THE SUN') >>> (u'THE SUN', u'SUN', u'dobj', u'DESCRIBE') + types.append(np.root.dep_) + np_text, is_public = self.detect_pronoun(np.text) + # print("IS_PUBLIC: ", is_public) + # Purpose of this if statement is completing possessive form of nouns + if np.root.dep_ == 'pobj' and types[-2] == 'nsubj': # if it's an object of a preposition and the previous noun phrase's type was nsubj(nominal subject) then (it's purpose is capturing subject like MY PLACE OF BIRTH) + subject.append(np.root.head.text) # append the parent text from syntactic relations tree (example: while nsubj is 'MY PLACE', np.root.head.text is 'OF') + subject.append(np_text) # append the text of this noun phrase (example: while nsubj is 'MY PLACE', np.text is 'BIRTH') + if np.root.dep_ == 'nsubj' and types[-2] not in ['pobj', 'nsubj'] and np.root.tag_ not in ['WDT', 'WP', 'WP$', 'WRB']: # if it's a nsubj(nominal subject) ("wh-" words can be considered as nsubj(nominal subject) but they are out of scope. This is why we are excluding them.) + subject.append(np_text) # append the text of this noun phrase + if np.root.dep_ == 'attr' and types[-2] not in ['pobj', 'nsubj'] and np.root.tag_ not in ['WDT', 'WP', 'WP$', 'WRB']: # if it's an attribute and the previous noun phrase's type was not nsubj(nominal subject) + subject.append(np_text) # append the text of this noun phrase + if np.root.dep_ == 'dobj' and types[-2] not in ['pobj', 'nsubj'] and np.root.tag_ not in ['WDT', 'WP', 'WP$', 'WRB']: # if it's a dobj(direct object) and the previous noun phrase's type was not nsubj(nominal subject) + subject.append(np_text) # append the text of this noun phrase + subject = [x.strip() for x in subject] + subject = ' '.join(subject) # concatenate all noun phrases found + if subject: # if the subject is not empty + if subject.upper() in self.inv_pronouns: # pass the learning ability if the user is talking about Dragonfire's itself + return "" + wh_found = False + for word in doc: # iterate over the each word in the given command(user's speech) + if word.tag_ in ['WDT', 'WP', 'WP$', 'WRB']: # check if there is a "wh-" question (we are determining that if it's a question or not, so only accepting questions with "wh-" form) + wh_found = True + if wh_found: # if that's a question + straight = self.db_get(subject, is_public=is_public, user_id=user_id) # get the answer from the database + if straight is None: + return self.db_get(subject, is_public=is_public, user_id=user_id, invert=True) # if nothing found then invert + return straight + else: + verb_found = False + verbtense = None # verbtense is the am/is/are of the main sentence + clause = [] # is the information that we need to acknowledge + verbs = [] + for word in doc: + # print(word.text, word.lemma_, word.pos_, word.tag_, word.dep_, word.shape_, word.is_alpha, word.is_stop) + if verb_found: # get the all words comes after the first verb which will be our verbtense + if word.pos_ != 'PUNCT': # exclude punctuations + clause.append(word.text) + if word.pos_ == 'VERB' and word.is_stop and not verb_found: # if that's a verb and verb does not found yet then + verb_found = True # verb is found + verbtense = word.text # append it to verbtense + if word.pos_ == 'VERB': + verbs.append(word.text) + clause = [x for x in clause] + clause = ' '.join(clause).strip() # concatenate the clause + + # keywords to order get and remove operations on the database + if any(verb in verbs for verb in self.upper_capitalize(["forget", "remove", "delete", "update"])): + if self.is_server and is_public: + return "I cannot forget a general fact." + return self.db_delete(subject, is_public=is_public, user_id=user_id) # if there is a record about the subject in the database then remove that record and... + + if any(verb in verbs for verb in self.upper_capitalize(["define", "explain", "tell", "describe"])): + return self.db_get(subject, is_public=is_public, user_id=user_id) + + if verbtense: + return self.db_upsert(subject, verbtense, clause, com, is_public=is_public, user_id=user_id) # set the record to the database + + def db_get(self, subject, invert=False, is_public=True, user_id=None): + """Function to get a record from the database. + + Args: + subject (str): Subject that extracted from the user's input/command. + + Keyword Args: + invert (bool): Is it invert mode? (swap subject and clause) + is_public (int): Is it a public record? (non-user specific) + user_id (int): User's ID. + + Returns: + str: Response. + """ + + if self.is_server: + try: + if invert: + fact = self.db_session.query(Fact).filter(Fact.clause == subject, Fact.user_id == user_id, Fact.is_public == is_public).order_by(Fact.counter.desc()).first() + else: + fact = self.db_session.query(Fact).filter(Fact.subject == subject, Fact.user_id == user_id, Fact.is_public == is_public).order_by(Fact.counter.desc()).first() + answer = fact.subject + ' ' + fact.verbtense + ' ' + fact.clause + return self.mirror(answer) + except NoResultFound: + return None + else: + if invert: + result = self.db.search(Query().clause == subject) # make a database search by giving subject string (inverted) + else: + result = self.db.search(Query().subject == subject) # make a database search by giving subject string + if result: # if there is a result + dictionary = {} + for row in result: # iterate over the rows of the result + if row['verbtense'] not in dictionary: # if the verbtense is not in the keys of the dictionary + dictionary[row['verbtense']] = [] # then add it + if row['clause'] not in dictionary[row['verbtense']]: # if the clause is not in the value like; dictionary['is'] + dictionary[row['verbtense']].append(row['clause']) # then append the clause + if invert: + answer = row['subject'] # in WHO questions subject is actually the clause so we learn the subject from db + else: + answer = subject # the answer we will return + first_verbtense = False + for key, value in dictionary.items(): # iterate over the dictionary defined and assigned on above + if not first_verbtense: # if the first verbtense assignment does not made yet + answer += ' ' + str(key) # concatenate with a whitespace + first_verbtense = True + else: + answer += ', ' + str(key) # otherwise concatenate with a comma + whitespace + first_clause = False + for clause in value: # iterate over the clauses of the key + if not first_clause: # if the first verbtense assignment does not made yet + answer += ' ' + clause # concatenate with a whitespace + first_clause = True + else: + answer += ' and ' + clause # otherwise concatenate with ' AND ' + return self.mirror(answer) # mirror the answer (for example: I'M to YOU ARE) + else: + return None # if there is no result return None + + def db_upsert(self, subject, verbtense, clause, com, is_public=True, user_id=None): + """Function to insert(or update) a record to the database. + + Args: + subject (str): Subject that extracted from the user's input/command. + verbtense (str): The am/is/are in the user's input/command. + clause (str): Clause that contains the fact. + com (str): User's command. + + Keyword Args: + invert (bool): Is it invert mode? (swap subject and clause) + is_public (int): Is it a public record? (non-user specific) + user_id (int): User's ID. + + Returns: + str: Response. + """ + + if self.is_server: + fact = self.db_session.query(Fact).filter(Fact.subject == subject, Fact.verbtense == verbtense, Fact.clause == clause, Fact.user_id == user_id, Fact.is_public == is_public).one_or_none() + if not fact: + new_fact = Fact(subject=subject, verbtense=verbtense, clause=clause, user_id=user_id, is_public=is_public) + self.db_session.add(new_fact) + self.db_session.commit() + else: + fact.counter += 1 + self.db_session.commit() + else: + if not self.db.search((Query().subject == subject) & (Query().verbtense == verbtense) & (Query().clause == clause)): # if there is no exacty record on the database then + self.db.insert({ + 'subject': subject, + 'verbtense': verbtense, + 'clause': clause + }) # insert the given data + return "OK, I get it. " + self.mirror(com) # mirror the command(user's speech) and return it to say + + def db_delete(self, subject, is_public=True, user_id=None): + """Function to delete a record from the database. + + Args: + subject (str): Subject that extracted from the user's input/command. + + Keyword Args: + is_public (int): Is it a public record? (non-user specific) + user_id (int): User's ID. + + Returns: + str: Response. + """ + + if self.is_server: + if not is_public and user_id: + fact = self.db_session.query(Fact).filter(Fact.subject == subject, Fact.user_id == user_id).one_or_none() + if not fact: + return "I don't even know anything about " + self.mirror(subject) + else: + fact.delete() + self.db_session.commit() + return "OK, I forgot everything I know about " + self.mirror(subject) + else: + return "I cannot forget a general fact about " + self.mirror(subject) + else: + if self.db.remove(Query().subject == self.fix_pronoun(subject)): + return "OK, I forgot everything I know about " + self.mirror(subject) + else: + return "I don't even know anything about " + self.mirror(subject) + + def mirror(self, answer): + """Function to mirror the answer (for example: I'M to YOU ARE). + + Args: + answer (str): Prepared answer that just before the actual return of :func:`respond` method. + + Returns: + str: Response. + """ + + result = [] + types = [] + types.append("") + doc = self.nlp(answer) + for token in doc: + types.append(token.lemma_) + if token.lemma_ == "-PRON-": # if it's a pronoun, mirror it + if token.text.upper() in self.pronouns: + result.append(self.pronouns[token.text.upper()].lower().strip()) + continue + if token.text.upper() in self.inv_pronouns: + result.append(self.inv_pronouns[token.text.upper()].lower().strip()) + continue + if (token.lemma_ == "be" or token.dep_ == "aux") and types[-2] == "-PRON-": # if it's an auxiliary that comes right after a pronoun, mirror it + if token.text.upper() in self.auxiliaries: + result.append(self.auxiliaries[token.text.upper()].lower().strip()) + continue + if token.text.upper() in self.inv_auxiliaries: + result.append(self.inv_auxiliaries[token.text.upper()].lower().strip()) + continue + result.append(token.text.strip()) + for i in range(len(result)): + if result[i] == "i": + result[i] = "I" + result = ' '.join(result) # concatenate the result + return result.replace(" '", "'") # fix for situations like "I 'AM", "YOU 'LL" + + def fix_pronoun(self, subject): # TODO: Extend the context of this function + """Pronoun fixer to handle situations like YOU and YOURSELF. + + Args: + subject (str): Subject that extracted from the user's input/command. + + Returns: + str: Response. + """ + + if subject == "yourself": + return "you" + elif subject == "Yourself": + return "You" + elif subject == "YOURSELF": + return "YOU" + else: + return subject + + def detect_pronoun(self, noun_chunk): + """Determine whether user is talking about himself/herself or some other entity. + + Args: + noun_chunk (str): Noun phrase. + + Returns: + ((str), (bool)): Detected pronoun and boolean value depends on the detection. + """ + + np_text = "" + is_public = True + doc = self.nlp(noun_chunk) + for token in doc: + if token.lemma_ == "-PRON-": + np_text += ' ' + token.text.lower() + is_public = False + else: + np_text += ' ' + token.text + return np_text.strip(), is_public + + def upper_capitalize(self, array): + """Return capitalized and uppercased versions of the strings inside the given array. + + Args: + array ((list) of (str)s): List of strings. + + Returns: + (list) of (str)s: List of strings. + """ + + result = [] + for word in array: + result.append(word) + result.append(word.capitalize()) + result.append(word.upper()) + return result + + def clean(self, com): + """Return a version of user's command that cleaned from punctuations, symbols, etc. + + Args: + com (str): User's command. + + Returns: + str: Cleaned version of user's command. + """ + + doc = self.nlp(com) + for token in doc: + if token.pos_ in ["PUNCT", "SYM"]: + com = com.replace(token.tag_, '') + + return com diff --git a/iso/dragonfire-master/dragonfire/nlplib.py b/iso/dragonfire-master/dragonfire/nlplib.py new file mode 100644 index 00000000..972493b8 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/nlplib.py @@ -0,0 +1,375 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +.. module:: nlplib + :platform: Unix + :synopsis: the top-level submodule of Dragonfire that contains the classes to provide an extra layer of abstraction to the NLP libraries that are used by Dragonfire. + +.. moduleauthor:: Mehmet Mert Yıldıran +""" + +from random import shuffle # Generate pseudo-random numbers + +import nltk # Natural Language Toolkit +from nltk.corpus import names # The Names Corpus +from nltk.corpus import brown # The Brown Corpus + + +class Classifier(): + """Class to provide static classification methods for various NLP tasks. + """ + + @staticmethod + def gender_features(word): + if not word: + return {'last_letter': 'a'} + else: + return {'last_letter': word[-1]} + + @staticmethod + def gender(word): + """Method to determine the gender of given word by comparing it to name dictionaries. + + Args: + word (str): Word. (usually a name) + + Keyword Args: + is_server (bool): Is Dragonfire running as an API server? + user_id (int): User's ID. + + Returns: + str: Male or Female + + .. note:: + + This method is a very naive and not very useful. So it will be deprecated in the future. + + """ + + labeled_names = ([(name, 'male') for name in names.words('male.txt')] + + [(name, 'female') + for name in names.words('female.txt')]) + shuffle(labeled_names) + featuresets = [(Classifier.gender_features(n), gender) + for (n, gender) in labeled_names] + train_set = featuresets[500:] + classifier = nltk.NaiveBayesClassifier.train(train_set) + return classifier.classify(Classifier.gender_features(word)) + + +class TopicExtractor(object): + """Class to provide methods to extrac the topic from given sentence using NLTK library. + """ + + def __init__(self): + """Initialization method of :class:`TopicExtractor` class. + """ + + # This is our fast Part of Speech tagger + ############################################################################# + brown_train = brown.tagged_sents(categories='news') + regexp_tagger = nltk.RegexpTagger( + [(r'^-?[0-9]+(.[0-9]+)?$', 'CD'), + (r'(-|:|;)$', ':'), + (r'\'*$', 'MD'), + (r'(The|the|A|a|An|an)$', 'AT'), + (r'.*able$', 'JJ'), + (r'^[A-Z].*$', 'NNP'), + (r'.*ness$', 'NN'), + (r'.*ly$', 'RB'), + (r'.*s$', 'NNS'), + (r'.*ing$', 'VBG'), + (r'.*ed$', 'VBD'), + (r'.*', 'NN') + ]) + unigram_tagger = nltk.UnigramTagger(brown_train, backoff=regexp_tagger) + self.bigram_tagger = nltk.BigramTagger(brown_train, backoff=unigram_tagger) + ############################################################################# + + # This is our semi-CFG; Extend it according to your own needs + ############################################################################# + self.cfg = {} + self.cfg["NNP+NNP"] = "NNP" + self.cfg["NN+NN"] = "NNI" + self.cfg["NNI+NN"] = "NNI" + self.cfg["JJ+JJ"] = "JJ" + self.cfg["JJ+NN"] = "NNI" + + ############################################################################# + + def tokenize_sentence(self, sentence): + """Tokenize the given sentence. + + Split the sentence into single words/tokens. + + Args: + sentence (str): A sentence. + + Returns: + (list) of (str)s: List of strings. + """ + + tokens = nltk.word_tokenize(sentence) + return tokens + + def normalize_tags(self, tagged): + """Normalize brown corpus' tags `("NN", "NN-PL", "NNS" -> "NN")`. + + Args: + tagged ((list) of (str)s): Tagged words. + + Returns: + (list) of (str)s: List of strings. + """ + + n_tagged = [] + for t in tagged: + if t[1] in ("NP-TL", "NP"): + n_tagged.append((t[0], "NNP")) + continue + if t[1].endswith("-TL"): + n_tagged.append((t[0], t[1][:-3])) + continue + if t[1].endswith("S"): + n_tagged.append((t[0], t[1][:-1])) + continue + n_tagged.append((t[0], t[1])) + return n_tagged + + def extract(self, sentence): + """Extract the main topics from the sentence. + + Returns: + (list) of (str)s: List of strings. + """ + + tokens = self.tokenize_sentence(sentence) + tags = self.normalize_tags(self.bigram_tagger.tag(tokens)) + + merge = True + while merge: + merge = False + for x in range(0, len(tags) - 1): + t1 = tags[x] + t2 = tags[x + 1] + key = "%s+%s" % (t1[1], t2[1]) + value = self.cfg.get(key, '') + if value: + merge = True + tags.pop(x) + tags.pop(x) + match = "%s %s" % (t1[0], t2[0]) + pos = value + tags.insert(x, (match, pos)) + break + + matches = [] + for t in tags: + if t[1] == "NNP" or t[1] == "NNI": + # if t[1] == "NNP" or t[1] == "NNI" or t[1] == "NN": + matches.append(t[0]) + return matches + + +class Helper(): + """Class to provide an extra layer of abstraction to the :mod:`spacy` NLP library. + """ + + def __init__(self, doc): + """Initialization method of :class:`dragonfire.nlplib.Helper` class. + + Args: + doc: :class:`Doc` instance from spaCy NLP library. Pre-parsed version of user's input/command. + """ + + self.doc = doc + + def directly_equal(self, words): + """Method to check if user's input is directly equal to one of these words. + + Args: + words ((list) of (str)s): Words. + + Returns: + bool: True or False + """ + + for word in words: + if self.doc[0].lemma_ == word.lower() and len(self.doc) == 1: + return True + return False + + def check_nth_lemma(self, n, word): + """Method to check if nth lemma is equal to given word. + + Args: + n (int): nth lemma. + word (str): Word. + + Returns: + bool: True or False + """ + + try: + return self.doc[n].lemma_ == word + except IndexError: + return False + + def check_verb_lemma(self, verb): + """Method to check if there is a verb with given lemma. + + Args: + verb (str): Verb lemma. + + Returns: + bool: True or False + """ + + for token in self.doc: + if token.pos_ == "VERB" and token.lemma_ == verb: + return True + return False + + def check_wh_lemma(self, wh): + """Method to check if there is a WH- word with given lemma. + + Args: + wh (str): WH- word lemma. + + Returns: + bool: True or False + """ + + for token in self.doc: + if token.tag_ in ['WDT', 'WP', 'WP$', 'WRB'] and token.lemma_ == wh: + return True + return False + + def check_deps_contains(self, phrase): + """Method to check if the user's input/command contains this phrase. + + Args: + phrase (str): Noun phrase. + + Returns: + bool: True or False + """ + + for chunk in self.doc.noun_chunks: + if chunk.text.lower() == phrase.lower(): + return True + return False + + def check_only_dep_is(self, phrase): + """Method to check if this is the only phrase user's input/command has. + + Args: + phrase (str): Noun phrase. + + Returns: + bool: True or False + """ + + return sum(1 for _ in self.doc.noun_chunks) == 1 and self.doc.noun_chunks.__next__().text.lower() == phrase.lower() + + def check_noun_lemma(self, noun): + """Method to check if there is a verb noun given lemma. + + Args: + noun (str): Noun lemma. + + Returns: + bool: True or False + """ + + for token in self.doc: + if (token.pos_ == "NOUN" or token.pos_ == "PROPN") and token.lemma_ == noun: + return True + return False + + def check_adj_lemma(self, adj): + """Method to check if there is an adjective with given lemma. + + Args: + adj (str): Adjective lemma. + + Returns: + bool: True or False + """ + + for token in self.doc: + if token.pos_ == "ADJ" and token.lemma_ == adj: + return True + return False + + def check_adv_lemma(self, adv): + """Method to check if there is an adverb with given lemma. + + Args: + adv (str): Adverb lemma. + + Returns: + bool: True or False + """ + + for token in self.doc: + if token.pos_ == "ADV" and token.lemma_ == adv: + return True + return False + + def check_lemma(self, lemma): + """Method to check if there is a word with given lemma. + + Args: + lemma (str): Lemma. + + Returns: + bool: True or False + """ + + for token in self.doc: + if token.lemma_ == lemma: + return True + return False + + def check_text(self, text): + """Method to check if the user's input/command is directly equal to given text. + + Args: + text (str): Text. + + Returns: + bool: True or False + """ + + for token in self.doc: + if token.text.upper() == text.upper(): + return True + return False + + def is_wh_question(self): + """Method to check if the user's input/command a WH question. + + Returns: + bool: True or False + """ + + for token in self.doc: + if token.is_stop: + break + if token.tag_ in ['WDT', 'WP', 'WP$', 'WRB']: + return True + return False + + def max_word_count(self, n): + """Method to check if the word length of the user's input/command is less than or equal to given value. + + Args: + n (int): Number of words. + + Returns: + bool: True or False + """ + + return len(self.doc) <= n diff --git a/iso/dragonfire-master/dragonfire/omniscient.py b/iso/dragonfire-master/dragonfire/omniscient.py new file mode 100644 index 00000000..8f71a45c --- /dev/null +++ b/iso/dragonfire-master/dragonfire/omniscient.py @@ -0,0 +1,365 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +.. module:: omniscient + :platform: Unix + :synopsis: the top-level submodule of Dragonfire that contains the classes related to **Omniscient**: Dragonfire's Factoid Question Answering Engine. + +.. moduleauthor:: Mehmet Mert Yıldıran +""" + +import collections # Imported to support ordered dictionaries in Python +from random import uniform # Generate pseudo-random numbers + +from dragonfire.utilities import nostderr # With statement to suppress errors + +import requests.exceptions # HTTP for Humans +import wikipedia # Provides and API-like functionality to search and access Wikipedia data +import wikipedia.exceptions # Exceptions of wikipedia library +from nltk.corpus import wordnet as wn # The WordNet corpus +from nltk.corpus.reader.wordnet import WordNetError # To catch the errors + + +class Omniscient(): + """Class to provide the factoid question answering ability. + """ + + def __init__(self, nlp): + """Initialization method of :class:`dragonfire.omniscient.Omniscient` class. + + Args: + nlp: :mod:`spacy` model instance. + """ + + self.nlp = nlp # Load en_core_web_sm, English, 50 MB, default model + self.entity_map = { + 'WHO': ['PERSON'], + 'WHAT': ['PERSON', 'NORP', 'FACILITY', 'ORG', 'GPE', 'LOC', 'PRODUCT', 'EVENT', 'WORK_OF_ART', 'LANGUAGE', 'DATE', 'TIME', 'PERCENT', 'MONEY', 'QUANTITY', 'ORDINAL', 'CARDINAL'], + 'WHEN': ['DATE', 'TIME', 'EVENT'], + 'WHERE': ['FACILITY', 'GPE', 'LOC'] + } # Map wh question words to entity categories + self.coefficient = {'frequency': 0.36, 'precedence': 0.13, 'proximity': 0.21, 'mention': 0.30} # Coefficients for scoring + + def respond(self, com, tts_output=False, userin=None, user_prefix=None, is_server=False): + """Method to respond the user's input/command using factoid question answering ability. + + Args: + com (str): User's command. + + Keyword Args: + tts_output (bool): Is text-to-speech output enabled? + userin: :class:`dragonfire.utilities.TextToAction` instance. + user_prefix (str): Prefix to address/call user when answering. + is_server (bool): Is Dragonfire running as an API server? + + Returns: + str: Response. + + .. note:: + + Entry function for :class:`Omniscient` class. Dragonfire calls only this function. Unlike :func:`Learner.respond`, it executes TTS because of its late reponse nature. + + """ + + result = None + subject, subjects, focus, subject_with_objects = self.semantic_extractor(com) # Extract the subject, focus, objects etc. + if not subject: + return False + + doc = self.nlp(com) # spaCy does all kinds of NLP analysis in one function + query = subject # Wikipedia search query (same as the subject) + # This is where the real search begins + if query: # If there is a Wikipedia query determined + if not tts_output and not is_server: print("Please wait...") + if tts_output and not is_server: userin.say("Please wait...", True, False) # Gain a few more seconds by saying Please wait... + wh_question = [] + for word in doc: # Iterate over the words in the command(user's speech) + if word.tag_ in ['WDT', 'WP', 'WP$', 'WRB']: # if there is a wh word then + wh_question.append(word.text.upper()) # append it by converting to uppercase + if not wh_question: + return False + with nostderr(): + try: + wikiresult = wikipedia.search(query) # run a Wikipedia search with the query + if len(wikiresult) == 0: # if there are no results + result = "Sorry, " + user_prefix + ". But I couldn't find anything about " + query + " in Wikipedia." + if not tts_output and not is_server: print(result) + if tts_output and not is_server: userin.say(result) + return result + wikipedia.page(wikiresult[0]) + except requests.exceptions.ConnectionError: # if there is a connection error + result = "Sorry, " + user_prefix + ". But I'm unable to connect to Wikipedia servers." + if not is_server: + userin.execute([" "], "Wikipedia connection error.") + if not tts_output: print(result) + if tts_output: userin.say(result) + return result + except wikipedia.exceptions.DisambiguationError as disambiguation: # if there is a disambiguation + wikiresult = wikipedia.search(disambiguation.options[0]) # run Wikipedia search again with the most common option + except: + result = "Sorry, " + user_prefix + ". But something went horribly wrong while I'm searching Wikipedia." + if not tts_output and not is_server: print(result) + if tts_output and not is_server: userin.say(result) + return result + findings = [] # empty findings list for scoring + nth_page = 0 # nth Wikipedia page/article + while not findings: # while there are no any findings + if not len(wikiresult) >= (nth_page + 1): # prevent index error + break + with nostderr(): + try: + wikipage = wikipedia.page(wikiresult[nth_page]) # Get the next Wikipedia page/article from the search results (this line also handles the search at the same time) + except requests.exceptions.ConnectionError: # if there is a connection error + result = "Sorry, " + user_prefix + ". But I'm unable to connect to Wikipedia servers." + if not is_server: + userin.execute([" "], "Wikipedia connection error.") + if not tts_output: print(result) + if tts_output: userin.say(result) + return result + except: + result = "Sorry, " + user_prefix + ". But something went horribly wrong while I'm searching Wikipedia." + if not tts_output and not is_server: print(result) + if tts_output and not is_server: userin.say(result) + return result + nth_page += 1 # increase the visited page/article count + if nth_page > 5: break # if script searched more than 5 Wikipedia pages/articles then give up + wikidoc = self.nlp(wikipage.content) # parse the Wikipedia page/article content using spaCy NLP library + sentences = [sent.string.strip() for sent in wikidoc.sents] # each individual sentence in the current Wikipedia page/article + # return [' '.join(subjects),' '.join(pobjects)] + all_entities = [] # all entities, useful or not all of them + mention = {} # sentences with focus mentioned + subject_entities_by_wordnet = None # target entities according to the subject + if 'WHAT' in wh_question: # if it's a WHAT question then + subject_entities_by_wordnet = self.wordnet_entity_determiner(subject_with_objects, tts_output, is_server, userin, user_prefix) # result of wordnet_entity_determiner() + if not subject_entities_by_wordnet: + return True + for sentence in reversed(sentences): # iterate over the sentences (in reversed order) + sentence = self.nlp(sentence) # parse the sentence using spaCy NLP library + for ent in sentence.ents: # iterate over the all entities in the sentence (has been found by spaCy) + all_entities.append(ent.text) # append the entity to all_entities + mention[ent.text] = 0.0 # the value if focus not even defined or the focus is NOT even mentioned + for wh in wh_question: # iterate over the all wh questions have been found in the Command(user's speech) + if wh.upper() in self.entity_map: # if the wh question is defined in entity_map (on top) then + target_entities = self.entity_map[wh.upper()] # get the target entities from the entity_map + if wh.upper() == 'WHAT': # if the question is WHAT then + target_entities = [] # empty the target entities because we will replace them with the result of wordnet_entity_determiner() + for subject_entity_by_wordnet in subject_entities_by_wordnet: # for each entity in subject_entities_by_wordnet + target_entities.append(subject_entity_by_wordnet) # append the entity to target entities + if ent.label_ in target_entities: # if entity label is in target entities listed then + findings.append(ent.text) # WE FOUND! a possible entity so append the text to findings + if focus: # if focus is defined then + if focus in sentence.text: # if focus is in the sentence then + mention[ent.text] += 1.0 * sentence.text.count(focus) # assign the how many times the entity mentioned in the sentence + + if findings: # if there is a finding or there are findings then + + frequency = collections.Counter(findings) # count the occurrences of the exacty same finding and return a unique dictionary. High frequency means high score + max_freq = max(frequency.values()) # max occurrence + for key, value in frequency.items(): # iterate over the unique dictionary + frequency[key] = float(value) / max_freq # divide the occurence by max occurence to find the real frequency value + + precedence = {} # precedence according to the location of the finding in the Wikipedia article. Closer to the top, greater the score is + unique = list(set(findings)) # unique the findings list + for i in range(len(unique)): # iterate over that unqiue list + precedence[unique[i]] = float(len(unique) - i) / len(unique) # calculate the score + + proximity = {} # proximity to the subject. Closer to the subject (in terms of location), greater the score is + subject_indices = [] # index values of subject occurrences + for i in range(len(all_entities)): # iterate over the all entities + for subject in subjects: # iterate over the all subjects + for word in subject.split(): # iterate over the each word in the subject + if word in all_entities[i]: # if the word is in all entities then + subject_indices.append(i) # append the index + for i in range(len(all_entities)): # iterate over the all entities, again + for index in subject_indices: # for each index + inverse_distance = float((len(all_entities) - 1) - abs(i - index)) / (len(all_entities) - 1) # calculate the proximity of the entity to the subject + if all_entities[i] in proximity: # if the entity is already appended then + proximity[all_entities[i]] = (proximity[all_entities[i]] + inverse_distance) / 2 # assign the proximity by calculating the average + else: + proximity[all_entities[i]] = inverse_distance # otherwise assign the proximity directly + if all_entities[i] not in proximity: # if it's somehow not appended then + proximity[all_entities[i]] = 0 # give it a zero score + + ranked = {} # the eventual ranking/scoring + for key, value in frequency.items(): # iterate over the all findings (frequency, precedence, proximity, mention all of them holds all findings) + if key not in query: # eliminate the findings that already inside of the Wikipedia query + ranked[key] = (value * self.coefficient['frequency'] + precedence[key] * self.coefficient['precedence'] + proximity[key] * self.coefficient['proximity'] + mention[key] * self.coefficient['mention']) # calculate the absolute score + + result = sorted(ranked.items(), key=lambda x: x[1])[::-1][0][0] + if not tts_output and not is_server: print(sorted(ranked.items(), key=lambda x: x[1])[::-1][:5]) # if not tts_output print the best 5 result + if tts_output and not is_server: userin.say(result, True, True) # if tts_output say the best result (via TTS obviously) + return result # also return the best result + else: # if no any findings + return False # in case of no any findings return False + + def wordnet_entity_determiner(self, subject, tts_output, is_server, userin=None, user_prefix=None): + """Function to determine the named entity classification of the subject. + + Args: + subject (str): Subject that extracted from the user's input/command. + tts_output (bool): Is text-to-speech output enabled? + is_server (bool): Is Dragonfire running as an API server? + + Keyword Args: + userin: :class:`dragonfire.utilities.TextToAction` instance. + user_prefix (str): Prefix to address/call user when answering. + + Returns: + (list) of (str)s: Entity list. + + .. note:: + + `entity_samples_map` variable is used to fix some missing(or wrong) classififaction issue of spaCy NLP library detected while writing this code. + + """ + + entity_samples_map = { + 'PERSON': ['person', 'character', 'human', 'individual', 'name'], + 'NORP': ['nationality', 'religion', 'politics'], + 'FACILITY': ['building', 'airport', 'highway', 'bridge', 'port'], + 'ORG': ['company', 'agency', 'institution', 'university'], + 'GPE': ['country', 'city', 'state', 'address', 'capital'], + 'LOC': ['geography', 'mountain', 'ocean', 'river'], + 'PRODUCT': ['product', 'object', 'vehicle', 'food'], + 'EVENT': ['hurricane', 'battle', 'war', 'sport'], + 'WORK_OF_ART': ['art', 'book', 'song', 'painting'], + 'LANGUAGE': ['language', 'accent', 'dialect', 'speech'], + 'DATE': ['year', 'month', 'day'], + 'TIME': ['time', 'hour', 'minute'], + 'PERCENT': ['percent', 'rate', 'ratio', 'fee'], + 'MONEY': ['money', 'cash', 'salary', 'wealth'], + 'QUANTITY': ['measurement', 'amount', 'distance', 'height', 'population'], + 'ORDINAL': ['ordinal', 'first', 'second', 'third'], + 'CARDINAL': ['cardinal', 'number', 'amount', 'mathematics'] + } # entity samples to use it in WordNet similarity + doc = self.nlp(subject) # spaCy does all kinds of NLP analysis in one function + subject = [] # empty list to hold the nouns in the subject string + for word in doc: # for each word in the subject string + # if word.pos_ not in ['PUNCT','SYM','X','CONJ','DET','ADP','SPACE']: + if word.pos_ == 'NOUN': # if word is a noun then + subject.append(word.text.lower()) # convert it to lowercase and append it + entity_scores = {} # empty dictionary to hold entity scores + for entity, samples in entity_samples_map.items(): # iterate over the entity_samples_map + entity_scores[entity] = 0 # initial score of the entity is 0 + for sample in samples: # for each sample in the samples + sample_wn = wn.synset(sample + '.n.01') # convert the sample to a WordNet noun + for word in subject: # for each word in the subject + try: + word_wn = wn.synset(word + '.n.01') # convert the word to a WodNet noun + entity_scores[entity] += word_wn.path_similarity(sample_wn) # calculate the similarity using WordNet path_similarity() and add it to the score of the entity + except WordNetError: + if not is_server: + message = "Sorry, " + user_prefix + ". But I'm unable to understand the word '" + word + "'." + userin.execute([" "], "NLP(WordNet) error. Unrecognized word: " + word) + if not tts_output: print(message) + if tts_output: userin.say(message) + return False + entity_scores[entity] = entity_scores[entity] / len(samples) # to calculate the average; divide the total by the amount of samples + if not tts_output and not is_server: print(sorted(entity_scores.items(), key=lambda x: x[1])[::-1][:3]) # if not tts_output print the best 3 result + result = sorted(entity_scores.items(), key=lambda x: x[1])[::-1][0][0] # assign the best result + if result == 'FACILITY': return [result, 'ORG'] # currently, spaCy is incorrectly classifying many entities that belongs to FACILITY as ORG. Because of that include ORG to the return + if result == 'PRODUCT': return [result, 'ORG'] # currently, spaCy is incorrectly classifying many entities that belongs to PRODUCT as ORG. Because of that include ORG to the return + return [result] # if there is no exception on above lines then return only one result but in an array. For example ['PERSON'] + + def randomize_coefficients(self): + """Function to randomize the coefficients for the purpose of optimizing their values. + + Returns: + dict: Randomized coefficients. + + .. note:: + + This function is being used only for TESTING purposes. + + """ + coeff1 = round(uniform(0.00, 0.98), 2) + coeff2 = round(uniform(0.00, (1 - coeff1)), 2) + coeff3 = round(uniform(0.00, (1 - (coeff1 + coeff2))), 2) + coeff4 = 1 - (coeff1 + coeff2 + coeff3) + self.coefficient = {'frequency': coeff1, 'precedence': coeff2, 'proximity': coeff3, 'mention': coeff4} + + def phrase_cleaner(self, phrase): + """Function to clean unnecessary words from the given phrase/string. (Punctuation mark, symbol, unknown, conjunction, determiner, subordinating or preposition and space) + + Args: + phrase (str): Noun phrase. + + Returns: + str: Cleaned noun phrase. + """ + + clean_phrase = [] + for word in self.nlp(phrase): + if word.pos_ not in ['PUNCT', 'SYM', 'X', 'CONJ', 'DET', 'ADP', 'SPACE']: + clean_phrase.append(word.text) + return ' '.join(clean_phrase) + + def semantic_extractor(self, string): + """Function to extract subject, subjects, focus, subject_with_objects from given string. + + Args: + string (str): String. + + Returns: + (list) of (str)s: List of subject, subjects, focus, subject_with_objects. + """ + + doc = self.nlp(string) # spaCy does all kinds of NLP analysis in one function + the_subject = None # Wikipedia search query variable definition (the subject) + # Followings are lists because it could be multiple of them in a string. Multiple objects or subjects... + subjects = [] # subject list + pobjects = [] # object of a preposition list + dobjects = [] # direct object list + # https://nlp.stanford.edu/software/dependencies_manual.pdf - Hierarchy of typed dependencies + for np in doc.noun_chunks: # Iterate over the noun phrases(chunks) + # print(np.text, np.root.text, np.root.dep_, np.root.head.text) + if (np.root.dep_ == 'nsubj' or np.root.dep_ == 'nsubjpass') and np.root.tag_ != 'WP': # if it's a nsubj(nominal subject) or nsubjpass(passive nominal subject) then + subjects.append(np.text) # append it to subjects + if np.root.dep_ == 'pobj': # if it's an object of a preposition then + pobjects.append(np.text) # append it to pobjects + if np.root.dep_ == 'dobj': # if it's a direct object then + dobjects.append(np.text) # append it to direct objects + + # This block determines the Wikipedia query (the subject) by relying on this priority: [Object of a preposition] > [Subject] > [Direct object] + pobjects = [x for x in pobjects] + subjects = [x for x in subjects] + dobjects = [x for x in dobjects] + if pobjects: + the_subject = ' '.join(pobjects) + elif subjects: + the_subject = ' '.join(subjects) + elif dobjects: + the_subject = ' '.join(dobjects) + else: + return None, None, None, None + + # This block determines the focus(objective/goal) by relying on this priority: [Direct object] > [Subject] > [Object of a preposition] + focus = None + if dobjects: + focus = self.phrase_cleaner(' '.join(dobjects)) + elif subjects: + focus = self.phrase_cleaner(' '.join(subjects)) + elif pobjects: + focus = self.phrase_cleaner(' '.join(pobjects)) + if focus in the_subject: + focus = None + + # Full string of all subjects and objects concatenated + subject_with_objects = [] + for dobject in dobjects: + subject_with_objects.append(dobject) + for subject in subjects: + subject_with_objects.append(subject) + for pobject in pobjects: + subject_with_objects.append(pobject) + subject_with_objects = ' '.join(subject_with_objects) + + wh_found = False + for word in doc: # iterate over the each word in the given command(user's speech) + if word.tag_ in ['WDT', 'WP', 'WP$', 'WRB']: # check if there is a "wh-" question (we are determining that if it's a question or not, so only accepting questions with "wh-" form) + wh_found = True + if not wh_found: + return None, None, None, None + + return the_subject, subjects, focus, subject_with_objects diff --git a/iso/dragonfire-master/dragonfire/realhud/animation/avatar.gif b/iso/dragonfire-master/dragonfire/realhud/animation/avatar.gif new file mode 100644 index 00000000..816c5a35 Binary files /dev/null and b/iso/dragonfire-master/dragonfire/realhud/animation/avatar.gif differ diff --git a/iso/dragonfire-master/dragonfire/realhud/realhud.c b/iso/dragonfire-master/dragonfire/realhud/realhud.c new file mode 100644 index 00000000..cef7f09f --- /dev/null +++ b/iso/dragonfire-master/dragonfire/realhud/realhud.c @@ -0,0 +1,300 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * This program shows you how to create transparent windows, + * without any of the historical screenshot hacks. It requires + * a modern system, with a compositing manager. I use xcompmgr + * and the nvidia drivers with RenderAccel, and it works well. + * + * I'll take you through each step as we go. Minimal GTK+ knowledge is + * assumed. + * + * gcc alphademo.c -o alphademo $( pkg-config --cflags --libs gtk+-2.0 ) + * + * Ancestor of this file: + * https://web.archive.org/web/20121027002505/http://plan99.net/~mike/files/alphademo.c + * + * Features added lately to this program are; animated GIF support, + * alpha adjustment for images, click-through window support + * + * Usage(Python): + * import realhud + * realhud.load_gif("/home/mertyildiran/Downloads/example.gif") + * realhud.play_gif(0.5, True) + * + * Author: + * Mehmet Mert Yıldıran mert.yildiran@bil.omu.edu.tr + * + * Special thanks to: + * Mike Hearn mike@plan99.net + * Uli Schlachter psychon@znc.in + * Phillip Berndt phillip.berndt@googlemail.com + * for their indirect contributions to this program. + */ + +int glob_argc; +char **glob_argv; + +static void screen_changed(GtkWidget *widget, GdkScreen *old_screen, gpointer user_data); +static gboolean expose(GtkWidget *widget, GdkEventExpose *event, gpointer user_data); +static void clicked(GtkWindow *win, GdkEventButton *event, gpointer user_data); +static GdkPixbufAnimation *pixbuf_animation; +static GdkPixbufAnimationIter *iter; +static GtkWidget *window; + +Display *dpy; +int screen; + +char *imgpath; +float opacity = 1.0; +int is_click_through; + +static gboolean timer(gpointer user_data) +{ + GTimeVal time; + g_get_current_time(&time); + gdk_pixbuf_animation_iter_advance(iter, &time); + if (gdk_pixbuf_animation_iter_on_currently_loading_frame(iter)) { + gtk_widget_destroy(window); + gtk_main_quit(); + return FALSE; + } + g_timeout_add(gdk_pixbuf_animation_iter_get_delay_time(iter), timer, NULL); + gtk_widget_queue_draw(window); + return FALSE; +} + +static PyObject* load_gif(PyObject* self, PyObject *args) +{ + /* parse the arguments */ + if (!PyArg_ParseTuple(args, "s", &imgpath)) { + return NULL; + } + + if (imgpath == NULL) { + fprintf(stderr, "usage: see image.png\n"); + exit(1); + } + pixbuf_animation = gdk_pixbuf_animation_new_from_file(imgpath, NULL); + + Py_RETURN_NONE; +} + +static PyObject* play_gif(PyObject* self, PyObject *args) +{ + fclose(stdout); + fclose(stderr); + /* get the display and the screen */ + if ((dpy = XOpenDisplay(getenv("DISPLAY"))) == 0) + { + fprintf(stderr, "Can't open display: %s\n", getenv("DISPLAY")); + exit(1); + } + screen = DefaultScreen(dpy); + + PyObject *is_click_through_arg; + /* parse the arguments */ + if (!PyArg_ParseTuple(args, "fO", &opacity, &is_click_through_arg)) { + return NULL; + } + + /* determine if it's click-through */ + is_click_through = PyObject_IsTrue(is_click_through_arg); + + /* boilerplate initialization code */ + gtk_init(&glob_argc, &glob_argv); + + GTimeVal time; + g_get_current_time(&time); + + iter = gdk_pixbuf_animation_get_iter (pixbuf_animation, &time); + timer(NULL); + + window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + + gtk_window_set_title(GTK_WINDOW(window), "Alpha Demo"); + g_signal_connect(G_OBJECT(window), "delete-event", gtk_main_quit, NULL); + + + /* Tell GTK+ that we want to draw the windows background ourself. + * If we don't do this then GTK+ will clear the window to the + * opaque theme default color, which isn't what we want. + */ + gtk_widget_set_app_paintable(window, TRUE); + + /* We need to handle two events ourself: "expose-event" and "screen-changed". + * + * The X server sends us an expose event when the window becomes + * visible on screen. It means we need to draw the contents. On a + * composited desktop expose is normally only sent when the window + * is put on the screen. On a non-composited desktop it can be + * sent whenever the window is uncovered by another. + * + * The screen-changed event means the display to which we are + * drawing changed. GTK+ supports migration of running + * applications between X servers, which might not support the + * same features, so we need to check each time. + */ + + g_signal_connect(G_OBJECT(window), "expose-event", G_CALLBACK(expose), NULL); + g_signal_connect(G_OBJECT(window), "screen-changed", G_CALLBACK(screen_changed), NULL); + + /* toggle title bar on click - we add the mask to tell X we are interested in this event */ + gtk_window_set_decorated(GTK_WINDOW(window), FALSE); + gtk_widget_add_events(window, GDK_BUTTON_PRESS_MASK); + g_signal_connect(G_OBJECT(window), "button-press-event", G_CALLBACK(clicked), NULL); + + /* initialize for the current display */ + screen_changed(window, NULL, NULL); + + /* Run the program */ + gtk_widget_show_all(window); + gtk_main(); + + Py_RETURN_NONE; +} + + +/* Only some X servers support alpha channels. Always have a fallback */ +gboolean supports_alpha = FALSE; + +static void screen_changed(GtkWidget *widget, GdkScreen *old_screen, gpointer userdata) +{ + /* To check if the display supports alpha channels, get the colormap */ + GdkScreen *screen = gtk_widget_get_screen(widget); + GdkColormap *colormap = gdk_screen_get_rgba_colormap(screen); + + if (!colormap) + { + printf("Your screen does not support alpha channels!\n"); + colormap = gdk_screen_get_rgb_colormap(screen); + supports_alpha = FALSE; + } + else + { + printf("Your screen supports alpha channels!\n"); + supports_alpha = TRUE; + } + + /* Now we have a colormap appropriate for the screen, use it */ + gtk_widget_set_colormap(widget, colormap); +} + +/* This is called when we need to draw the windows contents */ +static gboolean expose(GtkWidget *widget, GdkEventExpose *event, gpointer userdata) +{ + cairo_t *cr = gdk_cairo_create(widget->window); + int winw, winh; + int imgw, imgh; + int centerX, centerY; + GdkPixbuf *pixbuf; + + //if (supports_alpha) + // cairo_set_source_rgba (cr, 1.0, 1.0, 1.0, 0.0); /* transparent */ + //else + // cairo_set_source_rgb (cr, 1.0, 1.0, 1.0); /* opaque white */ + + /* draw the background */ + cairo_set_operator(cr, CAIRO_OPERATOR_IN); + //cairo_paint (cr); + + /* hide the window from appearing in the task bar */ + gtk_window_set_skip_taskbar_hint(GTK_WINDOW(widget),TRUE); + + /* resize the window */ + gtk_window_get_size(GTK_WINDOW(widget), &winw, &winh); + imgw = gdk_pixbuf_animation_get_width (pixbuf_animation); + imgh = gdk_pixbuf_animation_get_height (pixbuf_animation); + gtk_window_resize(GTK_WINDOW(widget), imgw, imgh); + + /* center the window */ + centerX = (XDisplayWidth(dpy, screen) / 2) - (winw / 2); + centerY = (XDisplayHeight(dpy, screen) / 2) - (winh / 2); + gtk_window_move(GTK_WINDOW(widget), centerX, centerY); + + /* make the window Always on Top */ + gtk_window_set_keep_above(GTK_WINDOW(widget), TRUE); + + if (is_click_through) { + /* make the window click-through */ + Display *display = GDK_SCREEN_XDISPLAY(gdk_screen_get_default()); + unsigned long window_xid = GDK_WINDOW_XID(gtk_widget_get_window(widget)); + Region region = XCreateRegion(); + XRectangle rectangle = { 0, 0, 1, 1 }; + XUnionRectWithRegion(&rectangle, region, region); + XShapeCombineRegion(display, window_xid, ShapeInput, 0, 0, region, ShapeSet); + XDestroyRegion(region); + } + + /* iterate over the frames of the animation */ + pixbuf = gdk_pixbuf_animation_iter_get_pixbuf(iter); + //g_timeout_add(1000, pixbuf, NULL); + gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0); + cairo_paint_with_alpha(cr, opacity); + + //gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0); + + //cairo_paint (cr); + + cairo_destroy(cr); + return FALSE; +} + +static void clicked(GtkWindow *win, GdkEventButton *event, gpointer user_data) +{ + /* toggle window manager frames */ + //gtk_window_set_decorated(win, !gtk_window_get_decorated(win)); +} + +static PyMethodDef realhud_funcs[] = { + {"load_gif", (PyCFunction)load_gif, METH_VARARGS, NULL}, + {"play_gif", (PyCFunction)play_gif, METH_VARARGS, NULL}, + {NULL} +}; + +#if PY_MAJOR_VERSION >= 3 +static struct PyModuleDef moduledef = { + PyModuleDef_HEAD_INIT, + "realhud", /* name of module */ + "", /* module documentation, may be NULL */ + -1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */ + realhud_funcs +}; + +PyMODINIT_FUNC PyInit_realhud(void) { + return PyModule_Create(&moduledef); +} +#endif + +void initrealhud(void) +{ + #if PY_MAJOR_VERSION >= 3 + PyInit_realhud(); + #else + Py_InitModule3("realhud", realhud_funcs, + "Extension module example!"); + #endif +} + +int main(int argc, char *argv[]) +{ + glob_argc = argc; + glob_argv = argv; + + /* Pass argv[0] to the Python interpreter */ + Py_SetProgramName(argv[0]); + + /* Initialize the Python interpreter. Required. */ + Py_Initialize(); + + /* Add a static module */ + initrealhud(); +} diff --git a/iso/dragonfire-master/dragonfire/sr/README.md b/iso/dragonfire-master/dragonfire/sr/README.md new file mode 100644 index 00000000..f61bf93e --- /dev/null +++ b/iso/dragonfire-master/dragonfire/sr/README.md @@ -0,0 +1,64 @@ +# SpeechRecognition + +

+ SpectrumAnalyzer +

+ +

+ Waveform +

+ +### Install Dependencies + +``` +sudo apt-get -y install python-pyaudio python-scipy python-qt4 python-tk +pip install -r requirements.txt +``` + +### Usage + +#### Create the training data + +Create it using your microphone: + +``` +python __init__.py --create --audio 0 +``` + +> To end your microphone session press `CTRL + C` (KeyboardInterrupt). + +or create it using an audio file: + +``` +python __init__.py --create --audio ~/Downloads/audio_file.wav +``` + +You should repeat the words, `REPEAT_N_TIMES` times in consecutive manner like: For 3 for example; one, one, one, two, two, two, three, ... Same thing is valid for audio file option. At the end, it will ask for list of words that you need to enter from command-line. When it's finished, it will create one `.wav` file and one `.txt` inside `training_data/` directory. + +:star2: This method is necessary because the program needs a perfectly aligned (word-by-word) training data. + +#### Train your model + +Just run the below command. It will automatically import all the data from `training_data/` directory: + +``` +python __init__.py --train +``` + +When it's finished, it will dump the model and word list as `model.npz` and `words.txt` into `out/` directory. + +#### Test your model + +Test it using your microphone: + +``` +python __init__.py --audio 0 +``` + +or test it using an audio file: + +``` +python __init__.py --audio ~/Downloads/audio_file.wav +``` + +> This program is currently not performing good results. diff --git a/iso/dragonfire-master/dragonfire/sr/__init__.py b/iso/dragonfire-master/dragonfire/sr/__init__.py new file mode 100644 index 00000000..c3961685 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/sr/__init__.py @@ -0,0 +1 @@ +from __future__ import absolute_import diff --git a/iso/dragonfire-master/dragonfire/sr/decoder.py b/iso/dragonfire-master/dragonfire/sr/decoder.py new file mode 100644 index 00000000..10f1c099 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/sr/decoder.py @@ -0,0 +1,217 @@ +import logging +import os + +import gi +gi.require_version('Gst', '1.0') +from gi.repository import GObject, Gst # noqa E402 module level import not at top of file + +GObject.threads_init() +Gst.init(None) + +logger = logging.getLogger(__name__) + + +class DecoderPipeline(object): + def __init__(self, conf={}): + logger.info("Creating decoder using conf: %s" % conf) + self.use_cutter = conf.get("use-vad", False) + self.create_pipeline(conf) + self.outdir = conf.get("out-dir", None) + if self.outdir: + if not os.path.exists(self.outdir): + os.mkdir(self.outdir) + elif not os.path.isdir(self.outdir): + raise Exception("Output directory %s already exists as a file" + % self.outdir) + + self.word_handler = None + self.eos_handler = None + self.request_id = "" + + def create_pipeline(self, conf): + + self.appsrc = Gst.ElementFactory.make("appsrc", "appsrc") + + self.decodebin = Gst.ElementFactory.make("decodebin", "decodebin") + self.audioconvert = Gst.ElementFactory.make("audioconvert", + "audioconvert") + self.audioresample = Gst.ElementFactory.make("audioresample", + "audioresample") + self.tee = Gst.ElementFactory.make("tee", "tee") + self.queue1 = Gst.ElementFactory.make("queue", "queue1") + self.filesink = Gst.ElementFactory.make("filesink", "filesink") + self.queue2 = Gst.ElementFactory.make("queue", "queue2") + self.cutter = Gst.ElementFactory.make("cutter", "cutter") + self.asr = Gst.ElementFactory.make("onlinegmmdecodefaster", "asr") + self.fakesink = Gst.ElementFactory.make("fakesink", "fakesink") + + for (key, val) in conf.get("decoder", {}).iteritems(): + logger.info("Setting decoder property: %s = %s" % (key, val)) + self.asr.set_property(key, val) + + self.appsrc.set_property("is-live", True) + self.filesink.set_property("location", "/dev/null") + self.cutter.set_property("leaky", False) + self.cutter.set_property("pre-length", 1000 * 1000000) + self.cutter.set_property("run-length", 1000 * 1000000) + self.cutter.set_property("threshold", 0.01) + if self.use_cutter: + self.asr.set_property("silent", True) + logger.info('Created GStreamer elements') + + self.pipeline = Gst.Pipeline() + for element in [ + self.appsrc, self.decodebin, self.audioconvert, + self.audioresample, self.tee, self.queue1, self.filesink, + self.queue2, self.cutter, self.asr, self.fakesink + ]: + logger.debug("Adding %s to the pipeline" % element) + self.pipeline.add(element) + + logger.info('Linking GStreamer elements') + + self.appsrc.link(self.decodebin) + # self.appsrc.link(self.audioconvert) + self.decodebin.connect('pad-added', self._connect_decoder) + if self.use_cutter: + self.cutter.link(self.audioconvert) + + self.audioconvert.link(self.audioresample) + + self.audioresample.link(self.tee) + # self.audioresample.link(self.cutter) + # self.cutter.link(self.tee) + + self.tee.link(self.queue1) + self.queue1.link(self.filesink) + + self.tee.link(self.queue2) + self.queue2.link(self.asr) + + self.asr.link(self.fakesink) + + # Create bus and connect several handlers + self.bus = self.pipeline.get_bus() + self.bus.add_signal_watch() + self.bus.enable_sync_message_emission() + self.bus.connect('message::eos', self._on_eos) + self.bus.connect('message::error', self._on_error) + # self.bus.connect('message::cutter', self._on_cutter) + + cutter_type = 'sync' + if cutter_type == 'async': + self.bus.connect('message::element', self._on_element_message) + else: + # self.bus.set_sync_handler(self.bus.sync_signal_handler) + self.bus.connect('sync-message::element', self._on_element_message) + self.asr.connect('hyp-word', self._on_word) + logger.info("Setting pipeline to READY") + self.pipeline.set_state(Gst.State.READY) + logger.info("Set pipeline to READY") + + def _connect_decoder(self, element, pad): + logger.info("%s: Connecting audio decoder" % self.request_id) + if self.use_cutter: + pad.link(self.cutter.get_static_pad("sink")) + else: + pad.link(self.audioconvert.get_static_pad("sink")) + + logger.info("%s: Connected audio decoder" % self.request_id) + + def _on_element_message(self, bus, message): + if message.has_name("cutter"): + if message.get_structure().get_value('above'): + logger.info("LEVEL ABOVE") + self.asr.set_property("silent", False) + else: + logger.info("LEVEL BELOW") + self.asr.set_property("silent", True) + + def _on_word(self, asr, word): + logger.info("%s: Got word: %s" % (self.request_id, + word.decode('utf8'))) + if self.word_handler: + self.word_handler(word) + + def _on_error(self, bus, msg): + self.error = msg.parse_error() + logger.error(self.error) + self.finish_request() + if self.error_handler: + self.error_handler(self.error[0].message) + + def _on_eos(self, bus, msg): + logger.info('%s: Pipeline received eos signal' % self.request_id) + self.finish_request() + if self.eos_handler: + self.eos_handler[0](self.eos_handler[1]) + + def finish_request(self): + logger.info('%s: Finishing request' % self.request_id) + if self.outdir: + self.filesink.set_state(Gst.State.NULL) + self.filesink.set_property('location', "/dev/null") + self.filesink.set_state(Gst.State.PLAYING) + self.pipeline.set_state(Gst.State.NULL) + self.request_id = "" + + def init_request(self, id, caps_str): + self.request_id = id + if caps_str and len(caps_str) > 0: + logger.info("%s: Setting caps to %s" % (self.request_id, caps_str)) + caps = Gst.caps_from_string(caps_str) + self.appsrc.set_property("caps", caps) + else: + # caps = Gst.caps_from_string(None) + self.appsrc.set_property("caps", None) + # self.pipeline.set_state(Gst.State.READY) + pass + # self.appsrc.set_state(Gst.State.PAUSED) + + if self.outdir: + self.pipeline.set_state(Gst.State.PAUSED) + self.filesink.set_state(Gst.State.NULL) + self.filesink.set_property('location', "%s/%s.raw" % (self.outdir, + id)) + self.filesink.set_state(Gst.State.PLAYING) + + # self.filesink.set_state(Gst.State.PLAYING) + # self.decodebin.set_state(Gst.State.PLAYING) + self.pipeline.set_state(Gst.State.PLAYING) + self.filesink.set_state(Gst.State.PLAYING) + # push empty buffer (to avoid hang on client diconnect) + buf = Gst.Buffer.new_allocate(None, 0, None) + self.appsrc.emit("push-buffer", buf) + logger.info('%s: Pipeline initialized' % (self.request_id)) + + def process_data(self, data): + logger.debug('%s: Pushing buffer of size %d to pipeline' % + (self.request_id, len(data))) + buf = Gst.Buffer.new_allocate(None, len(data), None) + buf.fill(0, data) + self.appsrc.emit("push-buffer", buf) + + def end_request(self): + logger.info("%s: Pushing EOS to pipeline" % self.request_id) + self.appsrc.emit("end-of-stream") + + def set_word_handler(self, handler): + self.word_handler = handler + + def set_eos_handler(self, handler, user_data=None): + self.eos_handler = (handler, user_data) + + def set_error_handler(self, handler): + self.error_handler = handler + + def cancel(self): + logger.info("%s: Cancelling pipeline" % self.request_id) + self.pipeline.send_event(Gst.Event.new_eos()) + # self.asr.set_property("silent", True) + # self.pipeline.set_state(Gst.State.NULL) + + # if (self.pipeline.get_state() == Gst.State.PLAYING): + # logger.debug("Sending EOS to pipeline") + # self.pipeline.send_event(Gst.Event.new_eos()) + # self.pipeline.set_state(Gst.State.READY) + logger.info("%s: Cancelled pipeline" % self.request_id) diff --git a/iso/dragonfire-master/dragonfire/sr/decoder_test.py b/iso/dragonfire-master/dragonfire/sr/decoder_test.py new file mode 100644 index 00000000..2cf0eed6 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/sr/decoder_test.py @@ -0,0 +1,118 @@ +# -*- coding: UTF-8 -*- + +from __future__ import print_function +from __future__ import absolute_import +import unittest +from gi.repository import GObject +try: + import thread # Low-level threading API (Python 2.7) +except ImportError: + import _thread as thread # Low-level threading API (Python 3.x) +import logging +from dragonfire.sr.decoder import DecoderPipeline +import time +import pyaudio # Provides Python bindings for PortAudio, the cross platform audio API + +import pytest + +CHUNK = 8000 # Smallest unit of audio. 1024 bytes +FORMAT = pyaudio.paInt16 # Data format +CHANNELS = 1 # Number of channels +RATE = 16000 # Bit Rate of audio stream / Frame Rate +THRESHOLD = 1000 # Threshhold value for detecting stimulant +RECORD_SECONDS = 10 + + +class DecoderPipelineTests(unittest.TestCase): + def __init__(self, *args, **kwargs): + super(DecoderPipelineTests, self).__init__(*args, **kwargs) + logging.basicConfig(level=logging.INFO) + + @classmethod + def setUpClass(cls): + # voxforge/tri2b_mmi_b0.05 model: + decoder_conf = { + "model": "models/english/final.mdl", + "lda-mat": "models/english/final.mat", + "word-syms": "models/english/words.txt", + "fst": "models/english/HCLG.fst", + "silence-phones": "6" + } + cls.decoder_pipeline = DecoderPipeline({"decoder": decoder_conf}) + cls.words = [] + cls.finished = False + + cls.decoder_pipeline.set_word_handler(cls.word_getter) + cls.decoder_pipeline.set_eos_handler(cls.set_finished, cls.finished) + + loop = GObject.MainLoop() + thread.start_new_thread(loop.run, ()) + + @classmethod + def word_getter(cls, word): + cls.words.append(word) + + @classmethod + def set_finished(cls, finished): + cls.finished = True + + def setUp(self): + self.__class__.words = [] + self.__class__.finished = False + + @pytest.mark.skip(reason="Kaldi is deprecated.") + def testRecognize(self): + self.decoder_pipeline.init_request( + "recognize", + "audio/x-raw, layout=(string)interleaved, rate=(int)16000, format=(string)S16LE, channels=(int)1" + ) + p = pyaudio.PyAudio() # Create a PyAudio session + # Create a stream + stream = p.open( + format=FORMAT, + channels=CHANNELS, + rate=RATE, + input=True, + output=True, + frames_per_buffer=CHUNK) + + data = stream.read(CHUNK) # Get first data frame from the microphone + for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)): + data = stream.read(CHUNK) # Read a new chunk from the stream + stream.write(data, CHUNK) + # time.sleep(0.25) + self.decoder_pipeline.process_data(data) + + stream.stop_stream() + stream.close() + p.terminate() + + self.decoder_pipeline.end_request() + while not self.finished: + time.sleep(1) + print(self.words) + + @pytest.mark.skip(reason="Kaldi is deprecated.") + def testWav(self): + self.decoder_pipeline.init_request("testWav", "") + f = open("tests/ten_digits.wav", "rb") + for block in iter(lambda: f.read(16000 * 2 * 2 / 4), ""): + time.sleep(0.25) + self.decoder_pipeline.process_data(block) + + self.decoder_pipeline.end_request() + + while not self.finished: + time.sleep(1) + self.assertEqual([ + 'ONE', 'TWO', 'THREE', 'FOUR', 'FIVE', 'SIX', 'SEVEN', 'EIGHT', + '<#s>' + ], self.words) + + +def main(): + unittest.main() + + +if __name__ == '__main__': + main() diff --git a/iso/dragonfire-master/dragonfire/sr/deepspeech/__init__.py b/iso/dragonfire-master/dragonfire/sr/deepspeech/__init__.py new file mode 100644 index 00000000..da3c1fee --- /dev/null +++ b/iso/dragonfire-master/dragonfire/sr/deepspeech/__init__.py @@ -0,0 +1,125 @@ +# -*- coding: UTF-8 -*- + +from __future__ import absolute_import + +# Operates on sound fragments consisting of signed integer samples 8, 16 +# or 32 bits wide, stored in Python strings. +import audioop +from contextlib import contextmanager +from ctypes import CFUNCTYPE, c_char_p, c_int, cdll +from threading import Thread + +import pyaudio # Provides Python bindings for PortAudio, the cross platform audio API +from dragonfire import VirtualAssistant + +from dragonfire.sr.deepspeech.config import ConfigDeepSpeech +from dragonfire.sr.deepspeech.server import SpeechServerMain +import numpy as np + +CHUNK = 8000 # Smallest unit of audio. 1024 bytes +FORMAT = pyaudio.paInt16 # Data format +CHANNELS = 1 # Number of channels +RATE = 16000 # Bit Rate of audio stream / Frame Rate +THRESHOLD = 1000 # Threshhold value for detecting stimulant +SILENCE_DETECTION = 1 # Wait number of frames to decide whether it fell silent or not +LISTENING = False + + +class DeepSpeechRecognizer(): + def __init__(self): + # logging.basicConfig(level=logging.INFO) + self.__class__.finished = False + + @classmethod + def set_finished(self, finished): + self.finished = True + + def reset(self): + self.__class__.finished = False + + def recognize(self, args, userin, user_full_name, user_prefix): + + with noalsaerr(): + p = pyaudio.PyAudio() # Create a PyAudio session + # Create a stream + stream = p.open( + format=FORMAT, + channels=CHANNELS, + rate=RATE, + input=True, + output=True, + frames_per_buffer=CHUNK) + + try: + data = stream.read( + CHUNK) # Get first data frame from the microphone + # Loop over the frames of the audio / data chunks + audio = None + # print("START LISTENNING") + while data != '': + rms = audioop.rms( + data, 2) # Calculate Root Mean Square of current chunk + if rms >= THRESHOLD: # If Root Mean Square value is greater than THRESHOLD constant + audio = data + silence_counter = 0 # Define silence counter + # While silence counter value less than SILENCE_DETECTION constant + while silence_counter < SILENCE_DETECTION: + data = stream.read( + CHUNK) # Read a new chunk from the stream + if LISTENING: + stream.write(data, CHUNK) + audio = audio + data + + rms = audioop.rms( + data, 2 + ) # Calculate Root Mean Square of current chunk again + if rms < THRESHOLD: # If Root Mean Square value is less than THRESHOLD constant + silence_counter += 1 # Then increase silence counter + else: # Else + silence_counter = 0 # Assign zero value to silence counter + + # print("Analyzing...") + stream.stop_stream() + audio = np.fromstring(audio, dtype=np.int16) # Fix data type + com = SpeechServerMain.ds.stt(audio, RATE) + stream.start_stream() + # print(com) + her = VirtualAssistant(args, userin, user_full_name, user_prefix) + t = Thread(target=her.command, args=(com,)) + t.start() + self.reset() + + data = stream.read(CHUNK) # Read a new chunk from the stream + if LISTENING: + stream.write(data, CHUNK) + + except KeyboardInterrupt: + stream.stop_stream() + stream.close() + p.terminate() + # self.loop.quit() + raise KeyboardInterrupt + + +ERROR_HANDLER_FUNC = CFUNCTYPE(None, c_char_p, c_int, c_char_p, c_int, + c_char_p) + + +def py_error_handler(filename, line, function, err, fmt): + pass + + +c_error_handler = ERROR_HANDLER_FUNC(py_error_handler) + + +@contextmanager +def noalsaerr(): + asound = cdll.LoadLibrary('libasound.so') + asound.snd_lib_error_set_handler(c_error_handler) + yield + asound.snd_lib_error_set_handler(None) + + +if __name__ == '__main__': + recognizer = DeepSpeechRecognizer() + recognizer.recognize([]) diff --git a/iso/dragonfire-master/dragonfire/sr/deepspeech/config.py b/iso/dragonfire-master/dragonfire/sr/deepspeech/config.py new file mode 100644 index 00000000..24b6fe2b --- /dev/null +++ b/iso/dragonfire-master/dragonfire/sr/deepspeech/config.py @@ -0,0 +1,38 @@ +import os +import json + +class ConfigDeepSpeech: + + def get_config(self, key): + config = {} + config['model'] = "/usr/share/dragonfire/deepspeech/models/output_graph.pb" + config['alphabet'] = "/usr/share/dragonfire/deepspeech/models/alphabet.txt" + config['lm'] = "/usr/share/dragonfire/deepspeech/models/lm.binary" + config['trie'] = "/usr/share/dragonfire/deepspeech/models/trie" + config['audiofiledir'] = "/usr/share/dragonfire/deepspeech/audio/" + config['audiofilelength'] = "10" + config['debug'] = "1" + + model = config['model'] + alphabet = config['alphabet'] + lm = config['lm'] + trie = config['trie'] + audiofiledir = config['audiofiledir'] + audiofilelength = config['audiofilelength'] + debug = config['debug'] + if key == 'model': + return model + elif key == 'alphabet': + return alphabet + elif key == 'lm': + return lm + elif key == 'trie': + return trie + elif key == 'audiofiledir': + return audiofiledir + elif key == 'audiofilelength': + return audiofilelength + elif key == 'debug': + return debug + else: + raise Exception('Invalid key value.') diff --git a/iso/dragonfire-master/dragonfire/sr/deepspeech/server.py b/iso/dragonfire-master/dragonfire/sr/deepspeech/server.py new file mode 100644 index 00000000..9eeaefb3 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/sr/deepspeech/server.py @@ -0,0 +1,44 @@ +from deepspeech.model import Model +from .config import ConfigDeepSpeech + +# These constants control the beam search decoder + +# Beam width used in the CTC decoder when building candidate transcriptions +BEAM_WIDTH = 500 + +# The alpha hyperparameter of the CTC decoder. Language Model weight +LM_WEIGHT = 1.75 + +# The beta hyperparameter of the CTC decoder. Word insertion weight (penalty) +WORD_COUNT_WEIGHT = 1.00 + +# Valid word insertion weight. This is used to lessen the word insertion penalty +# when the inserted word is part of the vocabulary +VALID_WORD_COUNT_WEIGHT = 1.00 + + +# These constants are tied to the shape of the graph used (changing them changes +# the geometry of the first layer), so make sure you use the same constants that +# were used during training + +# Number of MFCC features to use +N_FEATURES = 26 + +# Size of the context window used for producing timesteps in the input vector +N_CONTEXT = 9 + + +class SpeechServerMain: + name = 'speech_server_main' + conf = ConfigDeepSpeech() + model = conf.get_config('model') + alphabet = conf.get_config('alphabet') + lm = conf.get_config('lm') + trie = conf.get_config('trie') + + ds = Model(model, N_FEATURES, N_CONTEXT, alphabet, BEAM_WIDTH) + if lm and trie: + ds.enableDecoderWithLM(alphabet, lm, trie, LM_WEIGHT, WORD_COUNT_WEIGHT, VALID_WORD_COUNT_WEIGHT) + + def ready(self): + print("Deepspeech Server Initialization") diff --git a/iso/dragonfire-master/dragonfire/sr/experimental.py b/iso/dragonfire-master/dragonfire/sr/experimental.py new file mode 100644 index 00000000..074081ba --- /dev/null +++ b/iso/dragonfire-master/dragonfire/sr/experimental.py @@ -0,0 +1,709 @@ +from __future__ import absolute_import, print_function + +# Operates on sound fragments consisting of signed integer samples 8, 16 +# or 32 bits wide, stored in Python strings. +import audioop +import datetime # Supplies classes for manipulating dates and times in both simple and complex ways +# A package that supports spawning processes using an API similar to the +# threading module. +import multiprocessing +import os # The path module suitable for the operating system Python is running on, and therefore usable for local paths +# import peakutils.peak # Peak detection utilities for 1D data +import random # Pseudo-random number generators for various distributions +import time # Provides various time-related functions. +# Python's de-facto standard GUI (Graphical User Interface) package +import Tkinter +import wave # Provides a convenient interface to the WAV sound format + +import matplotlib.pyplot as plt # Simple graph plotting library +import numpy # The fundamental package for scientific computing with Python. +import pyaudio # Provides Python bindings for PortAudio, the cross platform audio API +# A pure-python graphics and GUI library built on PyQt4 / PySide and numpy +import pyqtgraph as pg +# A comprehensive set of Python bindings for Digia's Qt cross platform GUI +# toolkit. +from PyQt4 import QtCore + +# Import the Recurrent Neural Network class from Dragonfire's Neural +# Network Library +from .nnet import RNN + +__author__ = 'Mehmet Mert Yildiran, mert.yildiran@bil.omu.edu.tr' +# This submodule is experimental and not functional + +CHUNK = 1024 # Smallest unit of audio. 1024 bytes +FORMAT = pyaudio.paInt16 # Data format +CHANNELS = 2 # Number of channels +RATE = 44100 # Bit Rate of audio stream / Frame Rate +THRESHOLD = 1000 # Threshhold value for detecting stimulant +SILENCE_DETECTION = 5 # Wait number of frames to decide whether it fell silent or not +EMPTY_CHUNK = chr(int( + '000000', 2)) * CHUNK * 4 # Create an empty unit of audio for just once +WAVE_OUTPUT_FILENAME = "/tmp/" + str( + datetime.date.today()) + ".wav" # Example path if saving needed +TRAINING_DATA_DIRECTORY = "training_data/" +PLOTS_DIRECTORY = "plots/" # Directory to save the plots +# Output directory for training results (model.npz & words.txt) +OUT_DIRECTORY = "out/" +root = Tkinter.Tk() +SCREEN_WIDTH = root.winfo_screenwidth() +SCREEN_HEIGHT = root.winfo_screenheight() +HIDDEN_NEURON = 20 # Hidden neuron count in the network +# How many times repeated? For 3 for example; one, one, one, two, two, +# two, three, ... +REPEAT_N_TIMES = 10 +TRAINING_ITERATION = 1000 # How many iterations for training + +try: + raw_input # Python 2 +except NameError: + raw_input = input # Python 3 +try: + xrange # Python 2 +except NameError: + xrange = range # Python 3 + + +class SpeechRecognition(): + + # A function that will save recordings to a file + @staticmethod + def save_file(frames): + p = pyaudio.PyAudio() # Create a PyAudio session + if not os.path.isfile( + WAVE_OUTPUT_FILENAME): # If there is not such a file + wf = wave.open(WAVE_OUTPUT_FILENAME, 'wb') # Create the file + wf.setnchannels(CHANNELS) # Set number of channels + wf.setsampwidth(p.get_sample_size(FORMAT)) # Set sampling format + wf.setframerate(RATE) # Set Bit Rate / Frame Rate + wf.writeframes("") # Write nothing + wf.close() # Close the session + + wf = wave.open(WAVE_OUTPUT_FILENAME, + 'rb') # Open the file with only read permission + n_frames = wf.getnframes() # Get all frames in it + previous_wav = wf.readframes( + n_frames) # Assign all frames to a variable + wf.close() # Close the session + + wf = wave.open(WAVE_OUTPUT_FILENAME, + 'wb') # Open the file with write permission + wf.setnchannels(CHANNELS) # Set number of channels + wf.setsampwidth(p.get_sample_size(FORMAT)) # Set sampling format + wf.setframerate(RATE) # Set Bit Rate / Frame Rate + wf.writeframes( + previous_wav + + b''.join(frames)) # Write the all frames including previous ones + wf.close() # Close the session + + @staticmethod + def save_training_data(training_data, words): + file_id = str(random.randint(100000, 999999)) # Random file ID + if not os.path.exists(TRAINING_DATA_DIRECTORY + ): # Check whether the directory is exist or not + os.makedirs( + TRAINING_DATA_DIRECTORY) # If there is none then create one + p = pyaudio.PyAudio() # Create a PyAudio session + wf = wave.open(TRAINING_DATA_DIRECTORY + file_id + ".wav", + 'wb') # Create the .wav file with a random name + wf.setnchannels(CHANNELS) # Set number of channels + wf.setsampwidth(p.get_sample_size(FORMAT)) # Set sampling format + wf.setframerate(RATE) # Set Bit Rate / Frame Rate + wf.writeframes( + ''.join(training_data)) # Write the all frames of training_data + wf.close() # Close the session + + with open(TRAINING_DATA_DIRECTORY + file_id + ".txt", "w") as thefile: + for word in words: + thefile.write("%s\n" % word) + + # A function that will compute frequency of chunk using Fourier Transform + @staticmethod + def find_frequency(data): + T = 1.0 / RATE # Reciprocal of Bit Rate + N = data.shape[0] # Number of rows in data(numpy array) + # Compute the one-dimensional n-point discrete Fourier Transform (DFT) + # of data with the efficient Fast Fourier Transform (FFT) algorithm + # [CT] + Pxx = (1. / N) * numpy.fft.fft(data) + f = numpy.fft.fftfreq( + N, T) # Return the Discrete Fourier Transform sample frequencies + Pxx = numpy.fft.fftshift( + Pxx + ) # Shift the zero-frequency component to the center of the spectrum + f = numpy.fft.fftshift( + f + ) # Shift the zero-frequency component to the center of the spectrum + return f, Pxx # Return the results + + # A function that will draw a spectrum analyzer graphic to screen + # (PyQtGraph) + @staticmethod + def draw_spectrum_analyzer(all_frames, thresh_frames): + time.sleep(1) # Wait just one second + pw = pg.plot(title="Spectrum Analyzer") # Window title + pg.setConfigOptions( + antialias=True) # Enable antialias for better resolution + pw.win.resize(1600, 300) # Define window size + pw.win.move(160 * SCREEN_WIDTH / 1920, + 500 * SCREEN_HEIGHT / 1080) # Define window position + while True: # Loop over the frames of the audio / data chunks + data = ''.join( + all_frames[-1:]) # Get only the last frame of all frames + data = numpy.fromstring( + data, 'int16') # Binary string to numpy int16 data format + pw.setMouseEnabled(y=False) # Disable mouse + pw.setYRange(0, 1000) # Set Y range of graph + pw.setXRange( + -(RATE / 2), (RATE / 2), + padding=0) # Set X range of graph relative to Bit Rate + pwAxis = pw.getAxis("bottom") # Get bottom axis + pwAxis.setLabel("Frequency [Hz]") # Set bottom axis label + f, Pxx = SpeechRecognition.find_frequency( + data + ) # Call find frequency function. f is frequency, Pxx is energy. + # Calculate the absolute value element-wise. (complex input a + ib + # to sqrt(a^2 + b^2)) + Pxx = numpy.absolute(Pxx) + # Find the peaks. thres (energy threshold) is a rational value in here like 10/2000 on y-axis. + # min_dist is the minimum distance criteria for the peaks on x-axis. + # peak_indexes = peakutils.peak.indexes(Pxx, thres=50.0/max(Pxx), min_dist=5) + # peak_indexes = peak_indexes.tolist() # Numpy array to list + # peak_values = list(Pxx[peak_indexes]) # Automatically map into list using peak indexes + # peak_indexes = list(f[peak_indexes]) # Automatically map into + # list using peak indexes + f = f.tolist() # Numpy array to list + Pxx = Pxx.tolist() # Numpy array to list + try: # Try this block + # If last thresh frame is equal to EMPTY CHUNK + if thresh_frames[-1:][0] == EMPTY_CHUNK: + pw.plot( + x=f, + y=Pxx, + clear=True, + pen=pg.mkPen( + 'w', width=1.0, style=QtCore.Qt.SolidLine) + ) # Then plot with white pen + else: # If last thresh frame is not equal to EMPTY CHUNK + pw.plot( + x=f, + y=Pxx, + clear=True, + pen=pg.mkPen( + 'y', width=1.0, style=QtCore.Qt.SolidLine) + ) # Then plot with yellow pen + # pw.plot(x=peak_indexes, y=peak_values, pen=None, symbol='t') # Draw a scatter plot to the peak points + # pw.plot(x=peak_indexes, y=peak_values, pen=pg.mkPen('b', + # width=0.5, style=QtCore.Qt.SolidLine)) # Draw faint lines + # between the peak poits + # If we are getting an IndexError because of this -> + # thresh_frames[-1:][0] + except IndexError: + pw.plot( + x=f, + y=Pxx, + clear=True, + pen=pg.mkPen( + 'w', width=1.0, + style=QtCore.Qt.SolidLine)) # Then plot with white pen + pg.QtGui.QApplication.processEvents() # ??? + time.sleep(0.03) # Wait a few miliseconds + + # A function that will draw a waveform graphic to screen (PyQtGraph) + @staticmethod + def draw_waveform(all_frames, thresh_frames): + time.sleep(1) # Wait just one second + pw = pg.plot(title="Waveform") # Window title + pg.setConfigOptions( + antialias=True) # Enable antialias for better resolution + pw.win.resize(1300, 160) # Define window size + pw.win.move(300 * SCREEN_WIDTH / 1920, + 850 * SCREEN_HEIGHT / 1080) # Define window position + pw.showAxis('bottom', False) # Hide bottom axis + while True: # Loop over the frames of the audio / data chunks + data = ''.join( + all_frames[-20:]) # Join last 20 frames of all frames + data = numpy.fromstring( + data, 'int16') # Binary string to numpy int16 data format + data2 = ''.join( + thresh_frames[-20:]) # Join last 20 frames of thrsh frames + data2 = numpy.fromstring( + data2, 'int16') # Binary string to numpy int16 data format + pw.setMouseEnabled(x=False) # Disable mouse + pw.setRange(yRange=[-10000, 10000]) # Set Y range of graph + pw.plot( + data, + clear=True, + pen=pg.mkPen( + 'w', width=0.5, + style=QtCore.Qt.DotLine)) # Plot all frames with white pen + pw.plot( + data2, pen=pg.mkPen('y', width=0.5, style=QtCore.Qt.DotLine) + ) # Plot thresh frames with yellow pen + text = pg.TextItem( + "Seconds : " + str(int(len(all_frames) / (RATE / CHUNK))), + color=(255, 255, 255) + ) # Define seconds according to number of total frames as a text + pw.addItem( + text) # Display seconds according to number of total frames + text.setPos(500, 0) # Set text position + pg.QtGui.QApplication.processEvents() + time.sleep(0.03) # Wait a few miliseconds + + # MAIN CODE BLOCK + @staticmethod + def start(audio_input, graphs=True, verbose=True): + words = [] + txt_path = os.path.join(OUT_DIRECTORY, "words.txt") + with open(txt_path) as f: + words = words + [x.strip() for x in f.readlines() + ] # Load words from words.txt into an array + rnn = RNN( + CHUNK * 2, HIDDEN_NEURON, len(words) + ) # Create a Recurrent Neural Network instance (input,hidden,output) + rnn.importdump(OUT_DIRECTORY + "model.npz") # Import the dump + + if audio_input == "0": + pass + else: + wf = wave.open( + audio_input, 'rb' + ) # Open .wav file from given path as audio_input in arguments + + p = pyaudio.PyAudio() # Create a PyAudio session + # Create a stream + if audio_input == "0": + stream = p.open( + format=FORMAT, + channels=CHANNELS, + rate=RATE, + input=True, + frames_per_buffer=CHUNK) + else: + stream = p.open( + format=p.get_format_from_width(wf.getsampwidth()), + channels=wf.getnchannels(), + rate=wf.getframerate(), + output=True) + + all_frames = [] + thresh_frames = [] + if graphs: + shared_memory = multiprocessing.Manager( + ) # Shared memory space manager + all_frames = shared_memory.list( + ) # Define all_frames array in shared memory + thresh_frames = shared_memory.list( + ) # Define thresh_frames array in shared memory + + if audio_input == "0": + data = stream.read( + CHUNK) # Get first data frame from the microphone + else: + data = wf.readframes(CHUNK) # Get first data frame from .wav file + + all_frames.append(data) # Append to all frames + thresh_frames.append( + EMPTY_CHUNK) # Append an EMPTY CHUNK to thresh frames + + if graphs: + process1 = multiprocessing.Process( + target=SpeechRecognition.draw_waveform, + args=(all_frames, + thresh_frames)) # Define draw waveform process + process1.start() # Start draw waveform process + + process2 = multiprocessing.Process( + target=SpeechRecognition.draw_spectrum_analyzer, + args=(all_frames, + thresh_frames)) # Define draw spectrum analyzer process + process2.start() # Start drar spectrum analyzer process + + # Loop over the frames of the audio / data chunks + while data != '': + previous_data = data # Get previous chunk that coming from end of the loop + + if audio_input == "0": + data = stream.read(CHUNK) # Read a new chunk from the stream + else: + if graphs: + stream.write(data) # Monitor current chunk + data = wf.readframes(CHUNK) # Read a new chunk from the stream + + all_frames.append(data) # Append this chunk to all frames + thresh_frames.append( + EMPTY_CHUNK) # Append an EMPTY CHUNK to thresh frames + + rms = audioop.rms(data, + 2) # Calculate Root Mean Square of current chunk + word_data = [] # Define single word data + if rms >= THRESHOLD: # If Root Mean Square value is greater than THRESHOLD constant + # starting_time = datetime.datetime.now() # Starting time of + # the word + thresh_frames.pop() # Pop out last frame of thresh frames + thresh_frames.pop() # Pop out last frame of thresh frames + word_data.append( + previous_data) # Append previous chunk to training data + word_data.append(data) # Append current chunk to training data + thresh_frames.append( + previous_data) # Append previous chunk to thresh frames + thresh_frames.append( + data) # Append current chunk to thresh frames + silence_counter = 0 # Define silence counter + while silence_counter < SILENCE_DETECTION: # While silence counter value less than SILENCE_DETECTION constant + + if audio_input == "0": + data = stream.read( + CHUNK) # Read a new chunk from the stream + else: + if graphs: + stream.write(data) # Monitor current chunk + data = wf.readframes( + CHUNK) # Read a new chunk from the stream + + all_frames.append(data) # Append this chunk to all frames + word_data.append( + data) # Append this chunk to training data + thresh_frames.append( + data) # Append this chunk to thresh frames + rms = audioop.rms( + data, + 2) # Calculate Root Mean Square of current chunk again + + if rms < THRESHOLD: # If Root Mean Square value is less than THRESHOLD constant + silence_counter += 1 # Then increase silence counter + else: # Else + silence_counter = 0 # Assign zero value to silence counter + + # Delete last frames of training data as much as SILENCE_DETECTION constant + # del word_data[-(SILENCE_DETECTION-2):] + # Delete last frames of thresh frames as much as SILENCE_DETECTION constant + # del thresh_frames[-(SILENCE_DETECTION-2):] + # for i in range(SILENCE_DETECTION-2): # SILENCE_DETECTION constant times + # thresh_frames.append(EMPTY_CHUNK) # Append an EMPTY_CHUNK + # ending_time = datetime.datetime.now() # Ending time of the + # training + for i in xrange(len(word_data)): + word_data[i] = numpy.fromstring( + word_data[i], 'int16' + ) # Convert each frame from binary string to int16 + word_data = numpy.asarray( + word_data) # Convert the word data into numpy array + word_data = word_data / word_data.max() # Normalize the input + output = rnn.run( + word_data + ) # Run the network to get the output/result (feedforward) + print(words[numpy.argmax(output)] + '\t\t', + output) # Print the best guess + + if graphs: + process1.terminate() # Terminate draw waveform process + process2.terminate() # Terminate drar spectrum analyzer process + stream.stop_stream() # Stop the stream + stream.close() # Close the stream + p.terminate() # Terminate the session + + @staticmethod + def _teststart(): + rnn = RNN(2048, HIDDEN_NEURON, 5) + rnn.importdump("out/model.npz") + words_data = [] + words = [] + for filename in os.listdir(TRAINING_DATA_DIRECTORY): + if filename.endswith(".wav"): + wav_path = os.path.join(TRAINING_DATA_DIRECTORY, filename) + words_data = words_data + \ + SpeechRecognition.extract_words_from_audio(wav_path) + txt_path = os.path.join(TRAINING_DATA_DIRECTORY, + filename[:-4] + ".txt") + with open(txt_path) as f: + words = words + [x.strip() for x in f.readlines()] + for i in xrange(len(words_data)): + for j in xrange(len(words_data[i])): + words_data[i][j] = numpy.fromstring( + words_data[i][j], + 'int16') # Convert each frame from binary string to int16 + words_data[i] = numpy.asarray( + words_data[i]) # Convert the word data into numpy array + words_data[i] = words_data[i] / words_data[ + i].max() # Normalize the input + for i in xrange(len(words_data)): + print(words[i / REPEAT_N_TIMES] + '\t\t', rnn.run(words_data[i])) + + @staticmethod + def extract_words_from_audio(audio_input, graphs=False, verbose=False): + try: + if audio_input == "0": + pass + else: + wf = wave.open( + audio_input, 'rb' + ) # Open .wav file from given path as audio_input in arguments + + p = pyaudio.PyAudio() # Create a PyAudio session + # Create a stream + if audio_input == "0": + stream = p.open( + format=FORMAT, + channels=CHANNELS, + rate=RATE, + input=True, + frames_per_buffer=CHUNK) + else: + stream = p.open( + format=p.get_format_from_width(wf.getsampwidth()), + channels=wf.getnchannels(), + rate=wf.getframerate(), + output=True) + + words_data = [] # Define words data array + all_frames = [] + thresh_frames = [] + if graphs: + shared_memory = multiprocessing.Manager( + ) # Shared memory space manager + all_frames = shared_memory.list( + ) # Define all_frames array in shared memory + thresh_frames = shared_memory.list( + ) # Define thresh_frames array in shared memory + + if audio_input == "0": + data = stream.read( + CHUNK) # Get first data frame from the microphone + else: + data = wf.readframes( + CHUNK) # Get first data frame from .wav file + + all_frames.append(data) # Append to all frames + thresh_frames.append( + EMPTY_CHUNK) # Append an EMPTY CHUNK to thresh frames + + if graphs: + process1 = multiprocessing.Process( + target=SpeechRecognition.draw_waveform, + args=(all_frames, + thresh_frames)) # Define draw waveform process + process1.start() # Start draw waveform process + + process2 = multiprocessing.Process( + target=SpeechRecognition.draw_spectrum_analyzer, + args=(all_frames, thresh_frames + )) # Define draw spectrum analyzer process + process2.start() # Start drar spectrum analyzer process + + # Loop over the frames of the audio / data chunks + while data != '': + previous_data = data # Get previous chunk that coming from end of the loop + + if audio_input == "0": + data = stream.read( + CHUNK) # Read a new chunk from the stream + else: + if graphs: + stream.write(data) # Monitor current chunk + data = wf.readframes( + CHUNK) # Read a new chunk from the stream + + all_frames.append(data) # Append this chunk to all frames + thresh_frames.append( + EMPTY_CHUNK) # Append an EMPTY CHUNK to thresh frames + + rms = audioop.rms( + data, 2) # Calculate Root Mean Square of current chunk + word_data = [] # Define single word data + if rms >= THRESHOLD: # If Root Mean Square value is greater than THRESHOLD constant + # starting_time = datetime.datetime.now() # Starting time + # of the word + thresh_frames.pop() # Pop out last frame of thresh frames + thresh_frames.pop() # Pop out last frame of thresh frames + word_data.append( + previous_data + ) # Append previous chunk to training data + word_data.append( + data) # Append current chunk to training data + thresh_frames.append( + previous_data + ) # Append previous chunk to thresh frames + thresh_frames.append( + data) # Append current chunk to thresh frames + silence_counter = 0 # Define silence counter + # While silence counter value less than SILENCE_DETECTION constant + while silence_counter < SILENCE_DETECTION: + if audio_input == "0": + data = stream.read( + CHUNK) # Read a new chunk from the stream + else: + if graphs: + stream.write(data) # Monitor current chunk + data = wf.readframes( + CHUNK) # Read a new chunk from the stream + + all_frames.append( + data) # Append this chunk to all frames + word_data.append( + data) # Append this chunk to training data + thresh_frames.append( + data) # Append this chunk to thresh frames + rms = audioop.rms( + data, 2 + ) # Calculate Root Mean Square of current chunk again + + if rms < THRESHOLD: # If Root Mean Square value is less than THRESHOLD constant + silence_counter += 1 # Then increase silence counter + else: # Else + silence_counter = 0 # Assign zero value to silence counter + + # Delete last frames of training data as much as SILENCE_DETECTION constant + # del word_data[-(SILENCE_DETECTION-2):] + # Delete last frames of thresh frames as much as SILENCE_DETECTION constant + # del thresh_frames[-(SILENCE_DETECTION-2):] + # for i in range(SILENCE_DETECTION-2): # SILENCE_DETECTION constant times + # thresh_frames.append(EMPTY_CHUNK) # Append an EMPTY_CHUNK + # ending_time = datetime.datetime.now() # Ending time of + # the training + words_data.append(word_data) + if verbose: + print(len(words_data)) + + if graphs: + process1.terminate() # Terminate draw waveform process + process2.terminate( + ) # Terminate drar spectrum analyzer process + stream.stop_stream() # Stop the stream + stream.close() # Close the stream + p.terminate() # Terminate the session + return words_data + except KeyboardInterrupt: # We will use KeyboardInterrupt to finish the microphone session + if graphs: + process1.terminate() # Terminate draw waveform process + process2.terminate( + ) # Terminate drar spectrum analyzer process + stream.stop_stream() # Stop the stream + stream.close() # Close the stream + p.terminate() # Terminate the session + return words_data + + @staticmethod + def create_training_data(audio_input, graphs=True, verbose=True): + try: + words_data = SpeechRecognition.extract_words_from_audio( + audio_input, graphs, verbose) + except KeyboardInterrupt: + pass + else: + words = raw_input( + "Enter the words separating them by comma(,): ").split(',') + if len(words) == (len(words_data) / REPEAT_N_TIMES): + training_data = [ + frame for word_data in words_data for frame in word_data + ] # Flatten the words data into single big array of frames + SpeechRecognition.save_training_data(training_data, + words) # Then save it + else: + print("Sorry, word counts don't match. Please try again.") + + @staticmethod + def load_training_data(): + words_data = [] + words = [] + for filename in os.listdir(TRAINING_DATA_DIRECTORY): + if filename.endswith(".wav"): + wav_path = os.path.join(TRAINING_DATA_DIRECTORY, filename) + words_data = words_data + \ + SpeechRecognition.extract_words_from_audio(wav_path) + txt_path = os.path.join(TRAINING_DATA_DIRECTORY, + filename[:-4] + ".txt") + with open(txt_path) as f: + words = words + [x.strip() for x in f.readlines()] + return (words_data, words) + + @staticmethod + def train(): + words_data, words = SpeechRecognition.load_training_data( + ) # Load the training data + target = numpy.identity( + len(words)) # Create a unit matrix (identity matrix) as our target + ri = [] + for i in xrange(len(words)): + ri += [i] * REPEAT_N_TIMES + target = target[ri] + for i in xrange(len(words_data)): + for j in xrange(len(words_data[i])): + words_data[i][j] = numpy.fromstring( + words_data[i][j], + 'int16') # Convert each frame from binary string to int16 + words_data[i] = numpy.asarray( + words_data[i]) # Convert the word data into numpy array + words_data[i] = words_data[i] / words_data[ + i].max() # Normalize the input + rnn = RNN(len(words_data[0][0]), HIDDEN_NEURON, + len(words)) # Create a Recurrent Neural Network instance + # print len(words_data[0][0]), len(words_data) + # print numpy.asarray(words_data[0]).shape # Input shape + # print target[0].shape # Target shape + lr = 0.01 # Learning rate + e = 1 # Initial error = 1 + vals = [] # Values for plotting + n_iteration = TRAINING_ITERATION + for i in xrange(n_iteration): # Iterate (n_iteration) times + for j in xrange(len(words_data)): # For each word in words + u = words_data[j] # Input (2048) + t = target[j] # Target (word count) + c = rnn.train_step(u, t, lr) # Cost + print("iteration {0}: {1}".format(i, numpy.sqrt(c))) + e = (1.0 / len(words_data)) * numpy.sqrt(c) + ( + (len(words_data) - 1.0) / len(words_data) + ) * e # Contributes to error 1 / word count + if i % (n_iteration / 100) == 0: + vals.append(e) + + if not os.path.exists( + OUT_DIRECTORY): # Check whether the directory is exist or not + os.makedirs(OUT_DIRECTORY) # If there is none then create one + rnn.dump( + OUT_DIRECTORY + ) # Dump model.npz (reusable training result) to out/ directory + print("The neural network dump saved into: " + OUT_DIRECTORY + + "model.npz") + + with open(OUT_DIRECTORY + "words.txt", "w") as thefile: + for word in words: + thefile.write("%s\n" % word) # Dump the words line by line + print("The word list saved into: " + OUT_DIRECTORY + "words.txt") + + plt.plot(vals) # Plot the graph + if not os.path.exists(PLOTS_DIRECTORY + ): # Check whether the directory is exist or not + os.makedirs(PLOTS_DIRECTORY) # If there is none then create one + plt.savefig(PLOTS_DIRECTORY + 'error.png') # Save the graph + print("Graph of the decline of error by the time is saved as: " + + PLOTS_DIRECTORY + "error.png") + + print("--- TESTING ---") + del rnn + rnn = RNN(len(words_data[0][0]), HIDDEN_NEURON, len(words)) + rnn.importdump(OUT_DIRECTORY + "model.npz") + for i in xrange(len(words_data)): + print(words[i / REPEAT_N_TIMES] + '\t\t', rnn.run(words_data[i])) + + +if __name__ == "__main__": + # Makes it easy to write user-friendly command-line interfaces. + import argparse + ap = argparse.ArgumentParser() # Define an Argument Parser + ap.add_argument( + "-a", "--audio", help="path to the audio file") # Add --audio argument + ap.add_argument( + "-c", "--create", help="create training data, use with --audio") + ap.add_argument( + "-t", "--train", help="train the network, use just by itself") + args = vars(ap.parse_args()) # Parse the arguments + + if args["train"]: + SpeechRecognition.train() + elif args["create"] and args["audio"]: + SpeechRecognition.create_training_data(args["audio"]) + elif args["audio"]: + SpeechRecognition.start(args["audio"]) + else: + print("You tried to use it with a wrong combination. Check out --help") diff --git a/iso/dragonfire-master/dragonfire/sr/gspeech.py b/iso/dragonfire-master/dragonfire/sr/gspeech.py new file mode 100644 index 00000000..584bee73 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/sr/gspeech.py @@ -0,0 +1,116 @@ +import audioop +from contextlib import contextmanager +from ctypes import CFUNCTYPE, c_char_p, c_int, cdll +from threading import Thread + +import speech_recognition as sr +import pyaudio # Provides Python bindings for PortAudio, the cross platform audio API +from dragonfire import VirtualAssistant + +CHUNK = 8000 # Smallest unit of audio. 1024 bytes +FORMAT = pyaudio.paInt16 # Data format +CHANNELS = 1 # Number of channels +RATE = 16000 # Bit Rate of audio stream / Frame Rate +THRESHOLD = 1000 # Threshhold value for detecting stimulant +SILENCE_DETECTION = 3 # Wait number of frames to decide whether it fell silent or not +LISTENING = False + + +class GspeechRecognizer(): + def __init__(self): + self.recognizer = sr.Recognizer() + self.__class__.finished = False + + @classmethod + def set_finished(self, finished): + self.finished = True + + def reset(self): + self.__class__.finished = False + + def recognize(self, args, userin, user_full_name, user_prefix): + + with noalsaerr(): + p = pyaudio.PyAudio() # Create a PyAudio session + # Create a stream + stream = p.open( + format=FORMAT, + channels=CHANNELS, + rate=RATE, + input=True, + output=True, + frames_per_buffer=CHUNK) + + try: + data = stream.read(CHUNK) # Get first data frame from the microphone + # Loop over the frames of the audio / data chunks + audio = None + # print("START LISTENNING") + while data != '': + rms = audioop.rms(data, 2) # Calculate Root Mean Square of current chunk + if rms >= THRESHOLD: # If Root Mean Square value is greater than THRESHOLD constant + audio = data + silence_counter = 0 # Define silence counter + # While silence counter value less than SILENCE_DETECTION constant + while silence_counter < SILENCE_DETECTION: + data = stream.read(CHUNK) # Read a new chunk from the stream + if LISTENING: + stream.write(data, CHUNK) + audio = audio + data + + rms = audioop.rms(data, 2) # Calculate Root Mean Square of current chunk again + if rms < THRESHOLD: # If Root Mean Square value is less than THRESHOLD constant + silence_counter += 1 # Then increase silence counter + else: # Else + silence_counter = 0 # Assign zero value to silence counter + + # print("Analyzing...") + stream.stop_stream() + + audio_data = sr.AudioData(audio, RATE, p.get_sample_size(FORMAT)) + try: + com = self.recognizer.recognize_google(audio_data) + print(com) + her = VirtualAssistant(args, userin, user_full_name, user_prefix) + t = Thread(target=her.command, args=(com,)) + t.start() + except sr.UnknownValueError: + # print("Google Speech Recognition could not understand audio") + pass + except sr.RequestError as e: + print("Could not request results from Google Speech Recognition service; {0}".format(e)) + + stream.start_stream() + self.reset() + + data = stream.read(CHUNK) # Read a new chunk from the stream + if LISTENING: + stream.write(data, CHUNK) + + except KeyboardInterrupt: + stream.stop_stream() + stream.close() + p.terminate() + # self.loop.quit() + raise KeyboardInterrupt + + +ERROR_HANDLER_FUNC = CFUNCTYPE(None, c_char_p, c_int, c_char_p, c_int, c_char_p) + + +def py_error_handler(filename, line, function, err, fmt): + pass + +c_error_handler = ERROR_HANDLER_FUNC(py_error_handler) + + +@contextmanager +def noalsaerr(): + asound = cdll.LoadLibrary('libasound.so') + asound.snd_lib_error_set_handler(c_error_handler) + yield + asound.snd_lib_error_set_handler(None) + +if __name__ == '__main__': + recognizer = GspeechRecognizer() + recognizer.recognize([]) diff --git a/iso/dragonfire-master/dragonfire/sr/kaldi.py b/iso/dragonfire-master/dragonfire/sr/kaldi.py new file mode 100644 index 00000000..dbd52f2e --- /dev/null +++ b/iso/dragonfire-master/dragonfire/sr/kaldi.py @@ -0,0 +1,156 @@ +# -*- coding: UTF-8 -*- + +from __future__ import absolute_import + +# Operates on sound fragments consisting of signed integer samples 8, 16 +# or 32 bits wide, stored in Python strings. +import audioop +import os +import time +from contextlib import contextmanager +from ctypes import CFUNCTYPE, c_char_p, c_int, cdll +from threading import Thread + +import pyaudio # Provides Python bindings for PortAudio, the cross platform audio API +from dragonfire import VirtualAssistant +from gi.repository import GObject + +from .decoder import DecoderPipeline + +CHUNK = 8000 # Smallest unit of audio. 1024 bytes +FORMAT = pyaudio.paInt16 # Data format +CHANNELS = 1 # Number of channels +RATE = 16000 # Bit Rate of audio stream / Frame Rate +THRESHOLD = 1000 # Threshhold value for detecting stimulant +SILENCE_DETECTION = 5 # Wait number of frames to decide whether it fell silent or not +LISTENING = False +ENGLISH_MODEL_PATH = os.path.dirname( + os.path.realpath(__file__)) + "/models/english/" + + +class KaldiRecognizer(): + def __init__(self): + # logging.basicConfig(level=logging.INFO) + + # voxforge/tri2b_mmi_b0.05 model: + decoder_conf = { + "model": ENGLISH_MODEL_PATH + "final.mdl", + "lda-mat": ENGLISH_MODEL_PATH + "final.mat", + "word-syms": ENGLISH_MODEL_PATH + "words.txt", + "fst": ENGLISH_MODEL_PATH + "HCLG.fst", + "silence-phones": "6" + } + self.decoder_pipeline = DecoderPipeline({"decoder": decoder_conf}) + self.__class__.words = [] + self.__class__.finished = False + + self.decoder_pipeline.set_word_handler(self.word_getter) + self.decoder_pipeline.set_eos_handler(self.set_finished, self.finished) + + GObject.threads_init() + self.loop = GObject.MainLoop() + self.gi_thread = Thread(target=self.loop.run, args=()) + self.gi_thread.start() + + @classmethod + def word_getter(self, word): + self.words.append(word) + + @classmethod + def set_finished(self, finished): + self.finished = True + + def reset(self): + self.__class__.words = [] + self.__class__.finished = False + + def recognize(self, args, userin, user_full_name, user_prefix): + + with noalsaerr(): + p = pyaudio.PyAudio() # Create a PyAudio session + # Create a stream + stream = p.open( + format=FORMAT, + channels=CHANNELS, + rate=RATE, + input=True, + output=True, + frames_per_buffer=CHUNK) + + try: + data = stream.read( + CHUNK) # Get first data frame from the microphone + # Loop over the frames of the audio / data chunks + while data != '': + rms = audioop.rms( + data, 2) # Calculate Root Mean Square of current chunk + if rms >= THRESHOLD: # If Root Mean Square value is greater than THRESHOLD constant + self.decoder_pipeline.init_request( + "recognize", + "audio/x-raw, layout=(string)interleaved, rate=(int)16000, format=(string)S16LE, channels=(int)1" + ) + self.decoder_pipeline.process_data(data) + silence_counter = 0 # Define silence counter + # While silence counter value less than SILENCE_DETECTION constant + while silence_counter < SILENCE_DETECTION: + data = stream.read( + CHUNK) # Read a new chunk from the stream + if LISTENING: + stream.write(data, CHUNK) + self.decoder_pipeline.process_data(data) + + rms = audioop.rms( + data, 2 + ) # Calculate Root Mean Square of current chunk again + if rms < THRESHOLD: # If Root Mean Square value is less than THRESHOLD constant + silence_counter += 1 # Then increase silence counter + else: # Else + silence_counter = 0 # Assign zero value to silence counter + + stream.stop_stream() + self.decoder_pipeline.end_request() + while not self.finished: + time.sleep(0.1) + stream.start_stream() + words = self.words + words = [x for x in words if x != '<#s>'] + com = ' '.join(words) + her = VirtualAssistant(args, userin, user_full_name, user_prefix) + t = Thread(target=her.command, args=(com,)) + t.start() + self.reset() + + data = stream.read(CHUNK) # Read a new chunk from the stream + if LISTENING: + stream.write(data, CHUNK) + + except KeyboardInterrupt: + stream.stop_stream() + stream.close() + p.terminate() + self.loop.quit() + raise KeyboardInterrupt + + +ERROR_HANDLER_FUNC = CFUNCTYPE(None, c_char_p, c_int, c_char_p, c_int, + c_char_p) + + +def py_error_handler(filename, line, function, err, fmt): + pass + + +c_error_handler = ERROR_HANDLER_FUNC(py_error_handler) + + +@contextmanager +def noalsaerr(): + asound = cdll.LoadLibrary('libasound.so') + asound.snd_lib_error_set_handler(c_error_handler) + yield + asound.snd_lib_error_set_handler(None) + + +if __name__ == '__main__': + recognizer = KaldiRecognizer() + recognizer.recognize() diff --git a/iso/dragonfire-master/dragonfire/sr/nnet.py b/iso/dragonfire-master/dragonfire/sr/nnet.py new file mode 100644 index 00000000..112f6827 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/sr/nnet.py @@ -0,0 +1,110 @@ +from __future__ import print_function + +import matplotlib.pyplot as plt +import numpy as np +import theano +import theano.tensor as T + +try: + xrange # Python 2 +except NameError: + xrange = range # Python 3 + + +class RNN(): + def __init__(self, nin, n_hidden, nout): + rng = np.random.RandomState(1234) + self.W_uh = np.asarray( + rng.normal(size=(nin, n_hidden), scale=.01, loc=.0), + dtype=theano.config.floatX) + self.W_hh = np.asarray( + rng.normal(size=(n_hidden, n_hidden), scale=.01, loc=.0), + dtype=theano.config.floatX) + self.W_hy = np.asarray( + rng.normal(size=(n_hidden, nout), scale=.01, loc=0.0), + dtype=theano.config.floatX) + self.b_hh = np.zeros((n_hidden, ), dtype=theano.config.floatX) + self.b_hy = np.zeros((nout, ), dtype=theano.config.floatX) + self.activ = T.nnet.sigmoid + lr = T.scalar() + u = T.matrix() + t = T.vector() + + self.W_uh = theano.shared(self.W_uh, 'W_uh') + self.W_hh = theano.shared(self.W_hh, 'W_hh') + self.W_hy = theano.shared(self.W_hy, 'W_hy') + self.b_hh = theano.shared(self.b_hh, 'b_hh') + self.b_hy = theano.shared(self.b_hy, 'b_hy') + + self.h0_tm1 = theano.shared( + np.zeros(n_hidden, dtype=theano.config.floatX)) + + h, _ = theano.scan( + self.recurrent_fn, + sequences=u, + outputs_info=[self.h0_tm1], + non_sequences=[self.W_hh, self.W_uh, self.W_hy, self.b_hh]) + + y = T.dot(h[-1], self.W_hy) + self.b_hy + cost = ((t - y)**2).mean(axis=0).sum() + + gW_hh, gW_uh, gW_hy,\ + gb_hh, gb_hy = T.grad( + cost, [self.W_hh, self.W_uh, self.W_hy, self.b_hh, self.b_hy]) + + self.train_step = theano.function( + [u, t, lr], + cost, + on_unused_input='warn', + updates=[(self.W_hh, self.W_hh - lr * gW_hh), + (self.W_uh, + self.W_uh - lr * gW_uh), (self.W_hy, + self.W_hy - lr * gW_hy), + (self.b_hh, + self.b_hh - lr * gb_hh), (self.b_hy, + self.b_hy - lr * gb_hy)], + allow_input_downcast=True) + + self.run = theano.function([u], y) + + def recurrent_fn(self, u_t, h_tm1, W_hh, W_uh, W_hy, b_hh): + h_t = self.activ(T.dot(h_tm1, W_hh) + T.dot(u_t, W_uh) + b_hh) + return h_t + + def dump(self, path, filename='model.npz'): + with open(path + filename, "wb") as thefile: + np.savez( + thefile, + W_uh=self.W_uh.get_value(), + W_hh=self.W_hh.get_value(), + W_hy=self.W_hy.get_value(), + b_hh=self.b_hh.get_value(), + b_hy=self.b_hy.get_value(), + h0_tm1=self.h0_tm1.get_value()) + + def importdump(self, path_to_file): + with open(path_to_file, "rb") as thefile: + npzfile = np.load(thefile) + self.W_uh.set_value(npzfile['W_uh']) + self.W_hh.set_value(npzfile['W_hh']) + self.W_hy.set_value(npzfile['W_hy']) + self.b_hh.set_value(npzfile['b_hh']) + self.b_hy.set_value(npzfile['b_hy']) + self.h0_tm1.set_value(npzfile['h0_tm1']) + + +if __name__ == '__main__': + rnn = RNN(2, 20, 1) + lr = 0.01 + e = 1 + vals = [] + for i in xrange(int(5e5)): + u = np.random.rand(10, 2) + t = np.dot(u[:, 0], u[:, 1]) + c = rnn.train_step(u, t, lr) + print("iteration {0}: {1}".format(i, np.sqrt(c))) + e = 0.1 * np.sqrt(c) + 0.9 * e + if i % 1000 == 0: + vals.append(e) + plt.plot(vals) + plt.savefig('plots/error.png') diff --git a/iso/dragonfire-master/dragonfire/sr/requirements.txt b/iso/dragonfire-master/dragonfire/sr/requirements.txt new file mode 100644 index 00000000..f732c8b5 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/sr/requirements.txt @@ -0,0 +1,7 @@ +PyAudio +numpy +imutils +pyqtgraph +PeakUtils +theano +matplotlib diff --git a/iso/dragonfire-master/dragonfire/stray.py b/iso/dragonfire-master/dragonfire/stray.py new file mode 100644 index 00000000..291333b8 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/stray.py @@ -0,0 +1,96 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +.. module:: stray + :platform: Unix + :synopsis: the top-level submodule of Dragonfire that contains the classes and methods related to Dragonfire's system tray icon. + +.. moduleauthor:: Mehmet Mert Yıldıran +""" + +import os # Miscellaneous operating system interfaces + +TRAY_TOOLTIP = 'System Tray Icon' +TRAY_ICON = '/usr/share/icons/hicolor/48x48/apps/dragonfire_icon.png' +TRAY_ICON_ALT = 'debian/dragonfire_icon.png' +DEVELOPMENT_DIR = os.path.abspath( + os.path.join(os.path.dirname(os.path.realpath(__file__)), os.pardir)) + '/' +global_event_holder = '' + + +class SystemTrayIcon: + """Class to display a system tray icon. + """ + + def __init__(self): + """Initialization method of :class:`dragonfire.stray.SystemTrayIcon` class. + """ + + import gi + gi.require_version('Gtk', '3.0') + from gi.repository import Gtk + self.Gtk = Gtk + + self.icon = self.Gtk.StatusIcon() + self.icon.set_title("Dragonfire") + if os.path.isfile(TRAY_ICON): + self.icon.set_from_file(TRAY_ICON) + else: + self.icon.set_from_file(DEVELOPMENT_DIR + TRAY_ICON_ALT) + self.icon.connect('popup-menu', self.popup_menu) + self.Gtk.main() + + def exit(self, data=None): + """Method to exit the system tray icon. + + Keyword Args: + data : *Unknown* + """ + + self.Gtk.main_quit() + global global_event_holder + global_event_holder.set() + + def popup_menu(self, icon, button, time): + """Method to display a popup menu whenever user clicked to the system tray icon. + + Args: + icon: Icon instance. + button: Button instance. + time: Timestamp. + """ + + self.menu = self.Gtk.Menu() + + menuitemDragonfire = self.Gtk.MenuItem(label="Dragonfire") + self.menu.append(menuitemDragonfire) + menuitemDragonfire.set_sensitive(False) + + menuitemSeperator = self.Gtk.SeparatorMenuItem() + self.menu.append(menuitemSeperator) + + menuitemExit = self.Gtk.MenuItem(label="Exit") + menuitemExit.connect_object("activate", self.exit, "Exit") + self.menu.append(menuitemExit) + self.menu.show_all() + + self.menu.popup(None, None, None, None, button, time) + + +def SystemTrayExitListenerSet(e): + """Method to set an event listener for system tray icon exit. + + Args: + e: Event. + """ + + global global_event_holder + global_event_holder = e + + +def SystemTrayInit(): + """Method to create a :class:`dragonfire.stray.SystemTrayIcon` instance with the purpose of displaying to system tray icon. + """ + + SystemTrayIcon() diff --git a/iso/dragonfire-master/dragonfire/tests/test_api.py b/iso/dragonfire-master/dragonfire/tests/test_api.py new file mode 100644 index 00000000..e5d4ad88 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/tests/test_api.py @@ -0,0 +1,148 @@ +# -*- coding: utf-8 -*- + +""" +.. module:: test_api + :platform: Unix + :synopsis: tests for the api submodule. + +.. moduleauthor:: Mehmet Mert Yıldıran +""" + +import json +import time +import os + +import dragonfire +import dragonfire.api as API +from dragonfire.database import Base +from dragonfire.config import Config + +import requests +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker +import pytest + + +REG_KEY = "REG_KEY" +PORT = 3301 +API_SERVER = 'http://localhost:' + str(PORT) +is_travis = 'TRAVIS' in os.environ + +if is_travis: + engine = create_engine('mysql+pymysql://' + Config.MYSQL_USER + ':' + Config.MYSQL_PASS + '@' + Config.MYSQL_HOST + '/' + Config.MYSQL_DB) +else: + engine = create_engine('sqlite:///dragonfire.db', connect_args={'check_same_thread': False}, echo=True) +Base.metadata.create_all(engine) +Base.metadata.bind = engine +DBSession = sessionmaker(bind=engine) +db_session = DBSession() +dragonfire.learner.db_session = db_session +dragonfire.learner.is_server = True + +api_ref = API.Run(dragonfire.nlp, dragonfire.learner, dragonfire.omniscient, dragonfire.dc, dragonfire.coref, dragonfire.userin, REG_KEY, PORT, db_session, dont_block=True) +time.sleep(5) + + +@pytest.fixture +def token(): + headers = {'Content-Type': 'application/x-www-form-urlencoded'} + url = API_SERVER + '/register' + params = {'name': 'John', 'gender': 'M', 'birth_date': '1990-01-01', 'reg_key': REG_KEY} + response = requests.post(url, params=params, headers=headers) + return json.loads(response.text)['token'] + + +def test_api_tagger_end(token): + headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': token} + url = API_SERVER + '/tag' + params = {"text": "He is intelligent"} + response = requests.post(url, params=params, headers=headers) + assert json.loads(response.text) == [{'text': 'He', 'tag': 'PRP', 'is_stop': False, 'lemma': '-PRON-', 'dep': 'nsubj', 'pos': 'PRON', 'shape': 'Xx', 'is_alpha': True}, {'text': 'is', 'tag': 'VBZ', 'is_stop': True, 'lemma': 'be', 'dep': 'ROOT', 'pos': 'VERB', 'shape': 'xx', 'is_alpha': True}, {'text': 'intelligent', 'tag': 'JJ', 'is_stop': False, 'lemma': 'intelligent', 'dep': 'acomp', 'pos': 'ADJ', 'shape': 'xxxx', 'is_alpha': True}] + + +def test_api_dependency_parser_end(token): + headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': token} + url = API_SERVER + '/dep' + params = {"text": "He is intelligent"} + response = requests.post(url, params=params, headers=headers) + assert json.loads(response.text) == [{'root_head_text': 'is', 'text': 'He', 'root_text': 'He', 'root_dep': 'nsubj'}] + + +def test_api_entity_recognizer_end(token): + headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': token} + url = API_SERVER + '/ner' + params = {"text": "Albert Einstein was a German-born theoretical physicist who developed the theory of relativity"} + response = requests.post(url, params=params, headers=headers) + assert json.loads(response.text) == [{'start_char': 0, 'text': 'Albert Einstein', 'label': 'PERSON', 'end_char': 15}, {'start_char': 22, 'text': 'German', 'label': 'NORP', 'end_char': 28}] + + +def test_api_tokenizer_end(token): + headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': token} + url = API_SERVER + '/token' + params = {"text": "Albert Einstein was a German-born theoretical physicist who developed the theory of relativity"} + response = requests.post(url, params=params, headers=headers) + assert json.loads(response.text) == ['Albert', 'Einstein', 'was', 'a', 'German', '-', 'born', 'theoretical', 'physicist', 'who', 'developed', 'the', 'theory', 'of', 'relativity'] + + +def test_api_sentence_segmenter_end(token): + headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': token} + url = API_SERVER + '/sent' + params = {"text": "Albert Einstein was a German-born theoretical physicist who developed the theory of relativity, one of the two pillars of modern physics. His work is also known for its influence on the philosophy of science."} + response = requests.post(url, params=params, headers=headers) + assert json.loads(response.text) == ['Albert Einstein was a German-born theoretical physicist who developed the theory of relativity, one of the two pillars of modern physics.', 'His work is also known for its influence on the philosophy of science.'] + + +def test_api_cmd(token): + headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': token} + url = API_SERVER + '/cmd' + params = {"text": "He is intelligent"} + response = requests.post(url, params=params, headers=headers) + assert json.loads(response.text) == [{'tags': [{'text': 'He', 'tag': 'PRP', 'is_stop': False, 'lemma': '-PRON-', 'dep': 'nsubj', 'pos': 'PRON', 'shape': 'Xx', 'is_alpha': True}, {'text': 'is', 'tag': 'VBZ', 'is_stop': True, 'lemma': 'be', 'dep': 'ROOT', 'pos': 'VERB', 'shape': 'xx', 'is_alpha': True}, {'text': 'intelligent', 'tag': 'JJ', 'is_stop': False, 'lemma': 'intelligent', 'dep': 'acomp', 'pos': 'ADJ', 'shape': 'xxxx', 'is_alpha': True}], 'deps': [{'root_head_text': 'is', 'text': 'He', 'root_text': 'He', 'root_dep': 'nsubj'}], 'ners': []}] + + +def test_api_math(token): + headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': token} + url = API_SERVER + '/math' + params = {"text": "How much is 12 + 14?"} + response = requests.post(url, params=params, headers=headers) + assert json.loads(response.text) == '12 + 14 = 26' + + +def test_api_learn(token): + headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': token} + url = API_SERVER + '/learn' + params = {"text": "the Sun is hot", "user_id": 1} + response = requests.post(url, params=params, headers=headers) + assert json.loads(response.text) == 'OK, I get it. the Sun is hot' + + +def test_api_omni(token): + headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': token} + url = API_SERVER + '/omni' + params = {"text": "Where is the Times Square?", "gender_prefix": "sir"} + response = requests.post(url, params=params, headers=headers) + assert json.loads(response.text) == 'New York City' + + +def test_api_deep(token): + headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': token} + url = API_SERVER + '/deep' + params = {"text": "Do you like to listen music?", "gender_prefix": "sir"} + response = requests.post(url, params=params, headers=headers) + assert json.loads(response.text) == 'Of course.' + + +def test_api_wikipedia(token): + headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': token} + url = API_SERVER + '/wikipedia' + params = {"query": "Albert Einstein", "gender_prefix": "sir"} + response = requests.post(url, params=params, headers=headers) + assert json.loads(response.text) == {'url': 'https://en.wikipedia.org/wiki/Albert_Einstein', 'response': 'Albert Einstein ; 14 March 1879 18 April 1955) was a German-born theoretical physicist who developed the theory of relativity, one of the two pillars of modern physics . His work is also known for its influence on the philosophy of science. He is best known to the general public for his mass energy equivalence formula E = mc2, which has been dubbed "the world\'s most famous equation".'} + + +def test_api_youtube(token): + headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Authorization': token} + url = API_SERVER + '/youtube' + params = {"query": "Turn Down for What", "gender_prefix": "sir"} + response = requests.post(url, params=params, headers=headers) + assert json.loads(response.text) == {'url': 'https://www.youtube.com/watch?v=HMUDVMiITOU', 'response': 'DJ Snake, Lil Jon - Turn Down for What'} diff --git a/iso/dragonfire-master/dragonfire/tests/test_arithmetic.py b/iso/dragonfire-master/dragonfire/tests/test_arithmetic.py new file mode 100644 index 00000000..dde936f7 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/tests/test_arithmetic.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- + +""" +.. module:: test_arithmetic + :platform: Unix + :synopsis: tests for the arithmetic submodule. + +.. moduleauthor:: Mehmet Mert Yıldıran +""" + +from dragonfire.arithmetic import arithmetic_parse, text2int + +import pytest + + +def test_text2int(): + assert text2int("seven billion one hundred million thirty one thousand three hundred thirty seven") == 7100031337 + + +@pytest.mark.parametrize("command, response", [ + ("How much is 12 + 14?", "12 + 14 = 26"), + ("How much is twelve thousand three hundred four plus two hundred fifty six?", "12304 + 256 = 12560"), + ("What is five hundred eighty nine times six?", "589 * 6 = 3534"), + ("What is five hundred eighty nine divided by 89?", "589 / 89 = 6.617977528089888"), + ("What is seven billion five million and four thousand three hundred and four plus five million and four thousand three hundred and four?", "7005004304 + 5004304 = 7010008608"), + ("How much is 16 - 23?", "16 - 23 = -7"), + ("How much is 144 * 12?", "144 * 12 = 1728"), + ("How much is 23 / 0?", "Sorry, but that does not make sense as the divisor cannot be zero."), + ("How much is 12 + ( 14 * 3 )?", "12 + ( 14 * 3 ) = 54"), + ("How much is 12 + ( 14 * )?", False) +]) +def test_arithmetic_parse(command, response): + assert arithmetic_parse(command) == response diff --git a/iso/dragonfire-master/dragonfire/tests/test_dragonfire.py b/iso/dragonfire-master/dragonfire/tests/test_dragonfire.py new file mode 100644 index 00000000..b7bfa4ad --- /dev/null +++ b/iso/dragonfire-master/dragonfire/tests/test_dragonfire.py @@ -0,0 +1,158 @@ +# -*- coding: utf-8 -*- + +""" +.. module:: test_dragonfire + :platform: Unix + :synopsis: test module for the top-level module of Dragonfire. + +.. moduleauthor:: Mehmet Mert Yıldıran +""" + +from dragonfire import VirtualAssistant, greet +from dragonfire.utilities import TextToAction + +import pytest + + +user_full_name = "John Doe" +user_prefix = "sir" +hey_answers = [ + "Yes, " + user_prefix + ".", + "Yes. I'm waiting.", + "What is your order?", + "Ready for the orders!", + user_prefix.capitalize() + ", tell me your wish." +] + + +@pytest.fixture +def virtual_assistant(): + '''Returns a :class:`dragonfire.VirtualAssistant` instance.''' + + args = {} + args["cli"] = True + args["silent"] = True + args["headless"] = True + args["verbose"] = False + args["gspeech"] = False + args["server"] = False + args["port"] = 3301 + args["version"] = False + userin = TextToAction(args, testing=True) + + return VirtualAssistant(args, userin, testing=True) + + +@pytest.mark.parametrize("command, response", [ + (76, False), + ("enough", "Dragonfire quiets."), + ("shut up", "Dragonfire quiets."), + ("What is your name?", "My name is Dragonfire."), + ("What is your gender?", "I have a female voice but I don't have a gender identity. I'm a computer program, " + user_prefix + "."), + ("Who am I?", "Your name is " + user_full_name + ", " + user_prefix + "."), + ("open Blender", "Blender 3D computer graphics software"), + ("run draw", "Opening LibreOffice Draw"), + ("open impress", "Opening LibreOffice Impress"), + ("open math", "Opening LibreOffice Math"), + ("open writer", "Opening LibreOffice Writer"), + ("open Gimp", "Opening the photo editor software."), + ("open Inkscape", "Opening the vectorial drawing software."), + ("open office suite", "Opening LibreOffice"), + ("run Blender", "Blender 3D computer graphics software"), + ("open Kdenlive", "Opening the video editor software."), + ("open browser", "Web browser"), + ("start Chrome", "Web browser"), + ("open Firefox", "Web browser"), + ("open Steam", "Opening Steam Game Store"), + ("open files", "File Manager"), + ("open file manager", "File Manager"), + ("open camera", "Camera"), + ("open calendar", "Calendar"), + ("open calculator", "Calculator"), + ("open software center", "Software Center"), + ("I'm a girl", "Pardon, my lady."), + ("call me master", "OK, master."), + ("I'm a boy", "Pardon, sir."), + ("keyboard blabla", "keyboard"), + ("type blabla", "keyboard"), + ("enter", "enter"), + ("new line", "enter"), + ("new tab", "new tab"), + ("switch tab", "switch tab"), + ("close", "close"), + ("back", "back"), + ("forward", "forward"), + ("swipe left", "swipe left"), + ("swipe right", "swipe right"), + ("swipe up", "swipe up"), + ("swipe down", "swipe down"), + ("play", "play"), + ("shut down the computer", "Shutting down"), + ("power off the computer", "Shutting down"), + ("goodbye", "Goodbye, " + user_prefix), + ("bye", "Goodbye, " + user_prefix), + ("see you later", "Goodbye, " + user_prefix), + ("search Turn Down for What in YouTube", "DJ Snake, Lil Jon - Turn Down for What"), + ("find Turn Down for What on YouTube", "DJ Snake, Lil Jon - Turn Down for What"), + ("search Albert Einstein on the internet", "Albert Einstein"), + ("search the images of Albert Einstein in Google images", "Albert Einstein") +]) +def test_builtin_commands(virtual_assistant, command, response): + assert virtual_assistant.command("hey") in hey_answers + assert virtual_assistant.command(command) == response + + +def test_builtin_commands_sleep(virtual_assistant): + assert virtual_assistant.command("open files") == "" + assert virtual_assistant.command("dragonfire") in hey_answers + assert virtual_assistant.command("dragon fire") in hey_answers + assert virtual_assistant.command("go to sleep") == "I'm going to sleep" + assert virtual_assistant.command("hey") in hey_answers + assert virtual_assistant.command("stop listening") == "I'm going to sleep" + assert virtual_assistant.command("wake up") in hey_answers + + +@pytest.mark.parametrize("command, response", [ + ("What's the temperature in New York?", "The temperature in"), + ("search Albert Einstein in Wikipedia", "Albert Einstein ; 14 March 1879 18 April 1955) was a German-born theoretical physicist who developed the theory of relativity"), + ("find Albert Einstein on Wikipedia", "Albert Einstein ; 14 March 1879 18 April 1955) was a German-born theoretical physicist who developed the theory of relativity") +]) +def test_builtin_commands_startswith(virtual_assistant, command, response): + assert virtual_assistant.command("hey") in hey_answers + assert virtual_assistant.command(command).startswith(response) + + +def test_arithmetic_response(virtual_assistant): + + assert virtual_assistant.command("hey") in hey_answers + assert virtual_assistant.command("How much is 12 + 14?") == "12 + 14 = 26" + assert virtual_assistant.command("How much is twelve thousand three hundred four plus two hundred fifty six?") == "12304 + 256 = 12560" + + +def test_learner_response(virtual_assistant): + + assert virtual_assistant.command("hey") in hey_answers + assert virtual_assistant.command("the Sun is hot") == "OK, I get it. the Sun is hot" + assert virtual_assistant.command("It is yellow") == "OK, I get it. the Sun is yellow" + assert virtual_assistant.command("Describe the Sun") == "the Sun is hot and yellow" + assert virtual_assistant.command("What is the Sun") == "the Sun is hot and yellow" + + +def test_omniscient_response(virtual_assistant): + + assert virtual_assistant.command("hey") in hey_answers + assert virtual_assistant.command("Where is the Times Square?") == "New York City" + assert virtual_assistant.command("What is the real name of Iron Man?") in ["Tony", "Stark", "Tony Stark"] + + +def test_deepconv_response(virtual_assistant): + + assert virtual_assistant.command("hey") in hey_answers + assert virtual_assistant.command("Do you like to listen music?") == "Of course." + assert virtual_assistant.command("Are you evil?") == "Yes." + assert virtual_assistant.command("You are so sexy") == "How do you know that?" + + +def test_greet(virtual_assistant): + + assert greet(virtual_assistant.userin).startswith("Good") diff --git a/iso/dragonfire-master/dragonfire/tests/test_learn.py b/iso/dragonfire-master/dragonfire/tests/test_learn.py new file mode 100644 index 00000000..bbf65959 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/tests/test_learn.py @@ -0,0 +1,68 @@ +# -*- coding: utf-8 -*- + +""" +.. module:: test_learn + :platform: Unix + :synopsis: tests for the learn submodule. + +.. moduleauthor:: Mehmet Mert Yıldıran +""" + +import os +from os.path import expanduser + +from dragonfire.learn import Learner + +import spacy +import pytest + + +home = expanduser("~") # Get the home directory of the user +if os.path.exists(home + '/.dragonfire_db.json'): + os.remove(home + '/.dragonfire_db.json') # This is where we store the database; /home/USERNAME/.dragonfire_db.json + + +@pytest.fixture +def learner(): + '''Returns a :class:`dragonfire.learn.Learner` instance.''' + + return Learner(spacy.load('en')) + + +@pytest.mark.parametrize("command, response", [ + ("the Sun is hot", "OK, I get it. the Sun is hot"), + ("the Sun is yellow", "OK, I get it. the Sun is yellow"), + ("Describe the Sun", "the Sun is hot and yellow"), + ("What is the Sun", "the Sun is hot and yellow"), + ("my age is 25", "OK, I get it. your age is 25"), + ("What is my age", "your age is 25"), + ("forget my age", "OK, I forgot everything I know about your age"), + ("update my age", "I don't even know anything about your age"), + ("my place of birth is Turkey", "OK, I get it. your place of birth is Turkey"), + ("Where is my place of birth", "your place of birth is Turkey"), + ("mine is golden", "OK, I get it. yours is golden"), + ("how is mine", "yours is golden"), + ("Albert Einstein is a Physicist", "OK, I get it. Albert Einstein is a Physicist"), + ("Who is a Physicist", "Albert Einstein is a Physicist"), + ("Are you evil", "") +]) +def test_learner_respond(learner, command, response): + assert learner.respond(command) == response + + +def test_learner_mirror(learner): + assert learner.mirror("I'm the master") == "you are the master" + assert learner.mirror("you are the master") == "I am the master" + + +def test_learner_fix_pronoun(learner): + assert learner.fix_pronoun("yourself") == "you" + + +def test_learner_detect_pronoun(learner): + assert learner.detect_pronoun("my car") == ("my car", False) + assert learner.detect_pronoun("beautiful car") == ("beautiful car", True) + + +def test_learner_upper_capitalize(learner): + assert learner.upper_capitalize(["word"]) == ["word", "Word", "WORD"] diff --git a/iso/dragonfire-master/dragonfire/tests/test_nlplib.py b/iso/dragonfire-master/dragonfire/tests/test_nlplib.py new file mode 100644 index 00000000..48512d46 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/tests/test_nlplib.py @@ -0,0 +1,138 @@ +# -*- coding: utf-8 -*- + +""" +.. module:: test_nlplib + :platform: Unix + :synopsis: tests for the nlplib submodule. + +.. moduleauthor:: Mehmet Mert Yıldıran +""" + +from dragonfire.nlplib import Classifier, TopicExtractor, Helper + +import spacy +import pytest + + +nlp = spacy.load('en') + + +@pytest.mark.parametrize("name, gender", [ + ("John", "male"), + ("James", "male"), + ("Robert", "male"), + ("Emily", "female"), + ("Mary", "female"), + ("Linda", "female") +]) +def test_classifier_gender(name, gender): + assert Classifier.gender(name) == gender + + +@pytest.fixture +def extractor(): + '''Returns a :class:`dragonfire.nlplib.TopicExtractor` instance.''' + + return TopicExtractor() + + +def test_extractor_tokenize_sentence(extractor): + assert extractor.tokenize_sentence("the Sun is hot and yellow") == ['the', 'Sun', 'is', 'hot', 'and', 'yellow'] + + +def test_extractor_extract(extractor): + assert extractor.extract("the Sun is hot and yellow") == ['Sun'] + assert extractor.extract("Do you know the birthdate of Barrack Obama") == ['Barrack Obama'] + + +@pytest.fixture +def helper(): + '''Returns a :class:`dragonfire.nlplib.Helper` instance.''' + + doc = nlp("Albert Einstein was a German-born theoretical physicist who developed the theory of relativity, one of the two pillars of modern physics. His work is also known for its influence on the philosophy of science.") + return Helper(doc) + + +def test_helper_directly_equal(): + doc = nlp("test") + h = Helper(doc) + assert h.directly_equal(["car", "test"]) + assert not h.directly_equal(["car", "building"]) + + +def test_helper_check_nth_lemma(helper): + h = helper + assert h.check_nth_lemma(7, "theoretical") + assert not h.check_nth_lemma(13, "physicist") + + +def test_helper_check_verb_lemma(helper): + h = helper + assert h.check_verb_lemma("develop") + assert not h.check_verb_lemma("run") + + +def test_helper_check_wh_lemma(helper): + doc = nlp("When was albert einstein born?") + h = Helper(doc) + assert h.check_wh_lemma("when") + h = helper + assert not h.check_wh_lemma("when") + + +def test_helper_check_deps_contains(helper): + h = helper + assert h.check_deps_contains("the two pillars") + assert not h.check_deps_contains("particle physics") + + +def test_helper_check_only_dep_is(helper): + doc = nlp("Modern physics is great!") + h = Helper(doc) + assert h.check_only_dep_is("modern physics") + h = helper + assert not h.check_only_dep_is("modern physics") + + +def test_helper_check_noun_lemma(helper): + h = helper + assert h.check_noun_lemma("physicist") + assert not h.check_noun_lemma("soldier") + + +def test_helper_check_adj_lemma(helper): + h = helper + assert h.check_adj_lemma("theoretical") + assert not h.check_adj_lemma("red") + + +def test_helper_check_adv_lemma(helper): + h = helper + assert h.check_adv_lemma("also") + assert not h.check_adj_lemma("slowly") + + +def test_helper_check_lemma(helper): + h = helper + assert h.check_lemma("pillar") + assert not h.check_lemma("car") + + +def test_helper_check_text(helper): + h = helper + assert h.check_text("Albert") + assert not h.check_text("Robert") + + +def test_helper_is_wh_question(helper): + doc = nlp("When was albert einstein born?") + h = Helper(doc) + assert h.is_wh_question() + h = helper + assert not h.is_wh_question() + + +def test_helper_max_word_count(helper): + h = helper + assert h.max_word_count(100) + assert not h.max_word_count(5) diff --git a/iso/dragonfire-master/dragonfire/tests/test_omniscient.py b/iso/dragonfire-master/dragonfire/tests/test_omniscient.py new file mode 100644 index 00000000..f647263e --- /dev/null +++ b/iso/dragonfire-master/dragonfire/tests/test_omniscient.py @@ -0,0 +1,44 @@ +# -*- coding: utf-8 -*- + +""" +.. module:: test_omniscient + :platform: Unix + :synopsis: tests for the omniscient submodule. + +.. moduleauthor:: Mehmet Mert Yıldıran +""" + +from dragonfire.omniscient import Omniscient + +import spacy +import pytest + + +@pytest.fixture +def omniscient(): + '''Returns a :class:`dragonfire.omniscient.Omniscient` instance.''' + + return Omniscient(spacy.load('en')) + + +@pytest.mark.parametrize("question, answers", [ + ("Where is the Times Square", ["New York City", "\n"]), + ("What is the height of Burj Khalifa", ["828 m"]), + ("What is the real name of Iron Man", ["Tony", "Stark", "Tony Stark"]), + ("When Constantinople was conquered", ["1453"]), + ("What is the name of the world's longest river", ["Nile", "Amazon"]) +]) +def test_omniscient_respond(omniscient, question, answers): + assert omniscient.respond(question, user_prefix="sir") in answers + + +def test_wordnet_entity_determiner(omniscient): + assert omniscient.wordnet_entity_determiner("Luther", False, False) == ['PERSON'] + + +def test_phrase_cleaner(omniscient): + assert omniscient.phrase_cleaner("modern, physics") == "modern physics" + + +def test_semantic_extractor(omniscient): + assert omniscient.semantic_extractor("What is the real name of Iron Man") == ('Iron Man', ['the real name'], 'real name', 'the real name Iron Man') diff --git a/iso/dragonfire-master/dragonfire/tests/test_stray.py b/iso/dragonfire-master/dragonfire/tests/test_stray.py new file mode 100644 index 00000000..e55fcd97 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/tests/test_stray.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +""" +.. module:: test_stray + :platform: Unix + :synopsis: tests for the stray submodule. + +.. moduleauthor:: Mehmet Mert Yıldıran +""" + +from multiprocessing import Process, Event +import time + +from dragonfire.stray import SystemTrayExitListenerSet, SystemTrayInit + +import pytest + + +def test_stray(): + e = Event() + SystemTrayExitListenerSet(e) + stray_proc = Process(target=SystemTrayInit) + stray_proc.start() + time.sleep(3) + stray_proc.terminate() + assert True diff --git a/iso/dragonfire-master/dragonfire/tests/test_utilities.py b/iso/dragonfire-master/dragonfire/tests/test_utilities.py new file mode 100644 index 00000000..1ad5bf41 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/tests/test_utilities.py @@ -0,0 +1,33 @@ +# -*- coding: utf-8 -*- + +""" +.. module:: test_utilities + :platform: Unix + :synopsis: tests for the utilities submodule. + +.. moduleauthor:: Mehmet Mert Yıldıran +""" + +from dragonfire.utilities import TextToAction + +import pytest + + +@pytest.fixture +def userin(): + '''Returns a :class:`dragonfire.utilities.TextToAction` instance.''' + + args = {} + args["cli"] = True + args["silent"] = True + args["headless"] = True + args["verbose"] = False + args["gspeech"] = False + args["server"] = False + args["port"] = 3301 + args["version"] = False + return TextToAction(args, testing=True) + + +def test_utilities_say(userin): + assert userin.say("Hello world!") == "Hello world!" diff --git a/iso/dragonfire-master/dragonfire/tts/__init__.py b/iso/dragonfire-master/dragonfire/tts/__init__.py new file mode 100644 index 00000000..b77dad4a --- /dev/null +++ b/iso/dragonfire-master/dragonfire/tts/__init__.py @@ -0,0 +1,82 @@ +from __future__ import print_function +__author__ = 'Mehmet Mert Yildiran, mert.yildiran@bil.omu.edu.tr' +# This submodule is experimental and not functional + +# CSV (Comma Separated Values) format is the most common import and export +# format for spreadsheets and databases +import csv +import glob +import pyaudio +import wave +import time + +FORMAT = 8 # Data format +CHANNELS = 1 # Number of channels +RATE = 44100 # Bit Rate of audio stream / Frame Rate + + +class Synthesizer(): + def __init__(self): + self.word_map = {} + self.phonemes_map = {} + + filename = "../../dictionaries/VoxForgeDict" + for line in csv.reader( + open(filename), delimiter=' ', skipinitialspace=True): + if len(line) > 2: + self.word_map[line[0]] = line[2:] + + for file in glob.glob("phonemes/*.wav"): + wf = wave.open(file, 'rb') + n_frames = wf.getnframes() + self.phonemes_map[file[9:][:-4]] = wf.readframes(n_frames) + + def string_to_phonemes(self, string): + string = string.upper() + string = string.replace('.', '') + string = string.replace(',', '') + words = string.split() + + result = [] + for word in words: + if word in self.word_map: + result.append(self.word_map[word]) + return result + + def run(self, string): + skip = 4096 + audio = "" + p = pyaudio.PyAudio() + stream = p.open( + format=FORMAT, channels=CHANNELS, rate=RATE, output=True) + words = self.string_to_phonemes(string) + print(words) + for word in words: + audio += ('\x00' * 20000) + i = 0 + for phoneme in word: + i += 1 + if i == 1 and i == len(self.phonemes_map[phoneme]): + audio += self.phonemes_map[phoneme] + elif i == 1: + audio += self.phonemes_map[phoneme][:-skip] + elif i == len(self.phonemes_map[phoneme]): + audio += self.phonemes_map[phoneme][skip:] + else: + audio += self.phonemes_map[phoneme][skip:-skip] + # audio += self.phonemes_map[phoneme] + stream.write(audio) + + wf = wave.open(repr(time.time()).replace('.', '_') + ".wav", + 'wb') # Create the .wav file with a random name + wf.setnchannels(CHANNELS) # Set number of channels + wf.setsampwidth(p.get_sample_size(FORMAT)) # Set sampling format + wf.setframerate(RATE) # Set Bit Rate / Frame Rate + wf.writeframes(audio) # Write the all frames of training_data + wf.close() # Close the session + + +if __name__ == "__main__": + syn = Synthesizer() + syn.run("I have a female voice but I don't have a gender identity. " + "I'm a computer program, sir.") diff --git a/iso/dragonfire-master/dragonfire/tts/phonemes/list.txt b/iso/dragonfire-master/dragonfire/tts/phonemes/list.txt new file mode 100644 index 00000000..e2361a07 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/tts/phonemes/list.txt @@ -0,0 +1,52 @@ +https://pronunciationstudio.com/45-sounds/ + +VOWELS + +1 - iy +2 - ih +3 - eh +4 - ae +5 - ax +6 - er +7 - ah +8 - aa +9 - uw +10 - uh +11 - ao +12 - oh (missing in dictionary, probably special to enGB) +13 - ey +14 - oy +15 - ay +16 - ow +17 - aw +18 - ix +19 - ehr (missing in dictionary, probably special to enGB) + +CONSONANTS + +20 - p +21 - b +22 - t +23 - d +24 - k +25 - g +26 - ?? (missing in dictionary, probably special to enGB, very weak sound) +27 - f +28 - v +29 - th +30 - dh +31 - s +32 - z +33 - sh +34 - zh +35 - hh +36 - ch +37 - jh +38 - m +39 - n +40 - ng +41 - w +42 - y +43 - r +44 - l +45 - ll (missing in dictionary, probably special to enGB) diff --git a/iso/dragonfire-master/dragonfire/twitter.py b/iso/dragonfire-master/dragonfire/twitter.py new file mode 100644 index 00000000..f3c507cc --- /dev/null +++ b/iso/dragonfire-master/dragonfire/twitter.py @@ -0,0 +1,68 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +.. module:: twitter + :platform: Unix + :synopsis: the top-level submodule of Dragonfire that contains the classes to provide Twitter chatbot functionality to Dragonfire. + +.. moduleauthor:: Mehmet Mert Yıldıran +""" + +try: + import thread # Low-level threading API +except ImportError: + import _thread as thread # Low-level threading API +import json # JSON encoder and decoder +import re # Regular expression operations +from tweepy.streaming import StreamListener # An easy-to-use Python library for accessing the Twitter API +from dragonfire import VirtualAssistant # The class to create a virtual assistant + + +class MentionListener(StreamListener): + """ A listener handles tweets that are received from the stream. + """ + + def __init__(self, args, userin): + """Initialization method of :class:`dragonfire.twitter.MentionListener` class. + + Args: + args: Command-line arguments. + userin: :class:`dragonfire.utilities.TextToAction` instance. + """ + + self.args = args + self.userin = userin + + def on_data(self, data): + """Method that called whenever someone tweeted Dragonfire with a mention. + + Args: + data (str): String that contains data of the tweet. + """ + + mention = json.loads(data) + # print(json.dumps(mention, indent=4, sort_keys=True)) + if 'retweeted_status' not in mention: + tw_text = mention['text'] + tw_user = mention['user']['screen_name'] + if tw_user == "DragonfireAI": + return True + user_full_name = mention['user']['name'] + user_prefix = mention['user']['name'].split()[0] + print("\n@" + tw_user + " said:") + print(tw_text) + tw_text = tw_text.replace("@DragonfireAI", "") + tw_text = re.sub(r'([^\s\w\?]|_)+', '', tw_text).strip() + her = VirtualAssistant(self.args, self.userin, user_full_name, user_prefix, tw_user) + thread.start_new_thread(her.command, (tw_text,)) + return True + + def on_error(self, status): + """Method that called when an error occurred. + + Args: + status (str): String that holds information about the error. + """ + + print(status) diff --git a/iso/dragonfire-master/dragonfire/utilities.py b/iso/dragonfire-master/dragonfire/utilities.py new file mode 100644 index 00000000..1c3d9435 --- /dev/null +++ b/iso/dragonfire-master/dragonfire/utilities.py @@ -0,0 +1,304 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +""" +.. module:: utilities + :platform: Unix + :synopsis: the top-level submodule of Dragonfire that provides various utility tools for different kind of tasks. + +.. moduleauthor:: Mehmet Mert Yıldıran +""" + +import inspect # Inspect live objects +import os # Miscellaneous operating system interfaces +import subprocess # Subprocess managements +import time # Time access and conversions +from multiprocessing import Pool # Process-based “threading” interface +from sys import stdout # System-specific parameters and functions +from random import randint # Generate pseudo-random numbers +import contextlib # Utilities for with-statement contexts +try: + import cStringIO # Read and write strings as files (Python 2.7) +except ImportError: + import io as cStringIO # Read and write strings as files (Python 3.x) +import sys # System-specific parameters and functions + +import realhud # Dragonfire's Python C extension to display a click-through, transparent background images or GIFs + +from tweepy.error import TweepError # An easy-to-use Python library for accessing the Twitter API +import metadata_parser # Python library for pulling metadata out of web documents +import urllib.request # URL handling modules +import mimetypes # Map filenames to MIME types +import uuid # UUID objects according to RFC 4122 +import shutil # High-level file operations + +DRAGONFIRE_PATH = os.path.dirname(os.path.abspath(inspect.getfile(inspect.currentframe()))) +FNULL = open(os.devnull, 'w') +TWITTER_CHAR_LIMIT = 280 + +songRunning = False + + +class TextToAction: + """Class that turns text into action. + """ + + def __init__(self, args, testing=False): + """Initialization method of :class:`dragonfire.utilities.TextToAction` class. + + Args: + args: Command-line arguments. + """ + + self.headless = args["headless"] + self.silent = args["silent"] + self.server = args["server"] + self.testing = testing + if self.server: + self.headless = True + self.silent = True + self.twitter_api = None + self.twitter_user = None + if not self.headless: + realhud.load_gif(DRAGONFIRE_PATH + "/realhud/animation/avatar.gif") + + def execute(self, cmd="", msg="", speak=False, duration=0): + """Method to execute the given bash command and display a desktop environment independent notification. + + Keyword Args: + cmd (str): Bash command. + msg (str): Message to be displayed. + speak (bool): Also call the :func:`dragonfire.utilities.TextToAction.say` method with this message? + duration (int): Wait n seconds before executing the bash command. + + .. note:: + + Because this method is executing bash commands directly, it should be called and modified **carefully**. Otherwise it can cause a **SECURITY BREACH** on the machine. + + """ + + self.speak = speak + + if self.server or not self.testing: + if self.speak: + self.say(msg) + try: + subprocess.Popen(["notify-send", "Dragonfire", msg]) + except BaseException: + pass + if cmd != "": + time.sleep(duration) + try: + subprocess.Popen(cmd, stdout=FNULL, stderr=FNULL) + except BaseException: + pass + return msg + + def say(self, msg, dynamic=False, end=False, cmd=None): + """Method to give text-to-speech output(using **The Festival Speech Synthesis System**), print the response into console and **send a tweet**. + + Args: + msg (str): Message to be read by Dragonfire or turned into a tweet. + + Keyword Args: + dynamic (bool): Dynamically print the output into console? + end (bool): Is it the end of the dynamic printing? + cmd (str): Bash command. + + Returns: + bool: True or False + + .. note:: + + This method is extremely polymorphic so use it carefully. + - If you call it on `--server` mode it tweets. Otherwise it prints the reponse into console. + - If `--silent` option is not fed then it also gives text-to-speech output. Otherwise it remain silent. + - If response is more than 10000 characters it does not print. + - If `--headless` option is not fed then it shows a speaking female head animation on the screen using `realhud` Python C extension. + + """ + + if self.server: + text = "@" + self.twitter_user + " " + msg # .upper() + text = (text[:TWITTER_CHAR_LIMIT]) if len(text) > TWITTER_CHAR_LIMIT else text + if cmd: + if len(cmd) > 1: + if cmd[0] == "sensible-browser": + reduction = len(text + " " + cmd[1]) - TWITTER_CHAR_LIMIT + if reduction < 1: + reduction = None + text = text[:reduction] + " " + cmd[1] + page = metadata_parser.MetadataParser(url=cmd[1]) + img_url = page.get_metadata_link('image') + if img_url: + response = urllib.request.urlopen(img_url) + img_data = response.read() + img_extension = mimetypes.guess_extension(response.headers['content-type']) + filename = "/tmp/tmp" + uuid.uuid4().hex + img_extension + with open(filename, 'wb') as f: + f.write(img_data) + + try: + self.twitter_api.update_with_media(filename, text) + if randint(1, 3) == 1: + self.twitter_api.create_friendship(self.twitter_user, follow=True) + except TweepError as e: + print("Warning: " + e.response.text) + finally: + os.remove(filename) + return msg + try: + self.twitter_api.update_status(text) + if randint(1, 10) == 1: + self.twitter_api.create_friendship(self.twitter_user, follow=True) + except TweepError as e: + print("Warning: " + e.response.text) + return msg + # if songRunning == True: + # subprocess.Popen(["rhythmbox-client","--pause"]) + if len(msg) < 10000: + (columns, lines) = shutil.get_terminal_size() + if dynamic: + if end: + print(msg.upper()) + print(columns * "_" + "\n") + else: + print("Dragonfire: " + msg.upper(), end=' ') + stdout.flush() + else: + print("Dragonfire: " + msg.upper()) + print(columns * "_" + "\n") + if not self.silent: + subprocess.call(["pkill", "flite"], stdout=FNULL, stderr=FNULL) + tts_proc = subprocess.Popen( + "flite -voice slt -f /dev/stdin", + stdin=subprocess.PIPE, + stdout=FNULL, + stderr=FNULL, + shell=True) + msg = "".join([i if ord(i) < 128 else ' ' for i in msg]) + tts_proc.stdin.write(msg.encode()) + tts_proc.stdin.close() + # print "TTS process started." + + pool = Pool(processes=1) + if not self.headless: + pool.apply_async(realhud.play_gif, [0.5, True]) + # print "Avatar process started." + + if not self.silent: + tts_proc.wait() + pool.terminate() + # if songRunning == True: + # subprocess.Popen(["rhythmbox-client","--play"]) + return msg + + def espeak(self, msg): + """Method to give a text-to-speech output using **eSpeak: Speech Synthesizer**. + + Args: + msg (str): Message to be read by Dragonfire. + + .. note:: + + This method is currently not used by Dragonfire and deprecated. + + """ + + subprocess.Popen(["espeak", "-v", "en-uk-north", msg]) + + def pretty_print_nlp_parsing_results(self, doc): + """Method to print the nlp parsing results in a pretty way. + + Args: + doc: A :class:`Doc` instance from :mod:`spacy` library. + + .. note:: + + This method is only called when `--verbose` option fed. + + """ + + if len(doc) > 0: + print("") + print("{:12} {:12} {:12} {:12} {:12} {:12} {:12} {:12}".format("TEXT", "LEMMA", "POS", "TAG", "DEP", "SHAPE", "ALPHA", "STOP")) + for token in doc: + print("{:12} {:12} {:12} {:12} {:12} {:12} {:12} {:12}".format(token.text, token.lemma_, token.pos_, token.tag_, token.dep_, token.shape_, str(token.is_alpha), str(token.is_stop))) + print("") + if len(list(doc.noun_chunks)) > 0: + print("{:12} {:12} {:12} {:12}".format("TEXT", "ROOT.TEXT", "ROOT.DEP_", "ROOT.HEAD.TEXT")) + for chunk in doc.noun_chunks: + print("{:12} {:12} {:12} {:12}".format(chunk.text, chunk.root.text, chunk.root.dep_, chunk.root.head.text)) + print("") + + +@contextlib.contextmanager +def nostdout(): + """Method to suppress the standard output. (use it with `with` statements) + """ + + save_stdout = sys.stdout + sys.stdout = cStringIO.StringIO() + yield + sys.stdout = save_stdout + + +@contextlib.contextmanager +def nostderr(): + """Method to suppress the standard error. (use it with `with` statements) + """ + save_stderr = sys.stderr + sys.stderr = cStringIO.StringIO() + yield + sys.stderr = save_stderr + + +def omniscient_coefficient_optimizer(): + from dragonfire.omniscient import Omniscient + import spacy + + dataset = [ + ("Where is the Times Square", ["New York City"]), + ("What is the height of Burj Khalifa", ["828 m"]), + ("Where is Burj Khalifa", ["Dubai"]), + ("What is the height of Great Pyramid of Giza", ["480.6 ft"]), + ("Who is playing Jon Snow in Game of Thrones", ["Kit Harington"]), + ("What is the atomic number of oxygen", ["8"]), + ("What is the official language of Japan", ["Japanese"]), + ("What is the real name of Iron Man", ["Tony", "Stark", "Tony Stark"]), + ("Who is the conqueror of Constantinople", ["Mehmed II", "Mehmet II", "Mehmet"]), + ("When Constantinople was conquered", ["1453"]), + ("What is the capital of Turkey", ["Ankara"]), + ("What is the largest city of Turkey", ["Istanbul"]), + ("What is the name of the world's best university", ["Harvard", "Peking University"]), + ("What is the name of the world's longest river", ["Nile", "Amazon"]), + ("What is the brand of the world's most expensive car", ["Rolls-Royce"]), + ("What is the bloodiest war in human history", ["World War II", "World War I"]), + ("What is the name of the best seller book", ["Real Marriage", "'Real Marriage' on"]), + ("What is the lowest point in the ocean", ["the Mariana Trench"]), + ("Who invented General Relativity", ["Einstein"]), + ("When was United Nations formed", ["1945"]) + ] + + omniscient = Omniscient(spacy.load('en')) + best_score = 0 + best_coefficient = None + i = 0 + while True: + i += 1 + print("Iteration: " + str(i)) + score = 0 + omniscient.randomize_coefficients() + print(omniscient.coefficient) + + for (question, answers) in dataset: + if omniscient.respond(question) in answers: score += 1 + + # purpose of this block is finding the optimum value for coefficients + if score > best_score: + print("\n--- !!! NEW BEST !!! ---") + best_score = score + best_coefficient = omniscient.coefficient + print(str(best_score) + ' / ' + len(dataset)) + print(best_coefficient) + print("------------------------\n") diff --git a/iso/dragonfire-master/install-dev.sh b/iso/dragonfire-master/install-dev.sh new file mode 100644 index 00000000..fe38b716 --- /dev/null +++ b/iso/dragonfire-master/install-dev.sh @@ -0,0 +1,61 @@ +#!/bin/bash +OPTS=`getopt -o n --long no-model -- "$@"` +if [ $? != 0 ] ; then echo "Failed parsing options." >&2 ; exit 1 ; fi +eval set -- "$OPTS" + +NO_MODEL=false +while true; do + case "$1" in + -n | --no-model ) NO_MODEL=true; shift ;; + -- ) shift; break ;; + * ) break ;; + esac +done +NO_MODEL=$NO_MODEL + +apt-get update +apt-get -y install debhelper python3 python3-all-dev libglib2.0-dev libcairo2-dev libgtk2.0-dev && \ +apt-get -y install dpkg python3-minimal ${misc:Pre-Depends} && \ +apt-get -y install ${python3:Depends} ${misc:Depends} flite python3-xlib portaudio19-dev python3-all-dev flac libnotify-bin python3-lxml python3-nltk python3-pyaudio python3-httplib2 python3-pip python3-setuptools python3-wheel libgstreamer1.0-dev gstreamer1.0-plugins-good gstreamer1.0-tools subversion libatlas-base-dev automake autoconf libtool && \ + +pip3 install -e . + +#DEBHELPER# +RED='\033[0;31m' +GREEN='\033[0;32m' +NC='\033[0m' # No Color +CHECKSUM="1449d83e0a0b834c033067bf62f06277" +CHECKSUM2="c775d819ffc06118053a48808003df84" + +DRAGONFIRE_DIR=/usr/share/dragonfire +if [ ! -d "$DRAGONFIRE_DIR" ]; then + mkdir $DRAGONFIRE_DIR +fi + +DEEPSPEECH_DIR=/usr/share/dragonfire/deepspeech +if [ "$NO_MODEL" = false ] ; then + if [ ! -d "$DEEPSPEECH_DIR" ]; then + mkdir $DEEPSPEECH_DIR + fi + cd $DEEPSPEECH_DIR + verified=$(md5sum models/* | md5sum) + if [ ! ${verified::-3} = "$CHECKSUM" ]; then + wget -nc -O - https://github.com/mozilla/DeepSpeech/releases/download/v0.1.1/deepspeech-0.1.1-models.tar.gz | tar xvfz - + fi +fi + +DEEPCONV_DIR=/usr/share/dragonfire/deepconv +if [ ! -d "$DEEPCONV_DIR" ]; then + mkdir $DEEPCONV_DIR +fi +cd $DEEPCONV_DIR +verified=$(find . -type f -exec md5sum {} \; | md5sum) +if [ ! ${verified::-3} = "$CHECKSUM2" ]; then + wget -nc -O - https://github.com/DragonComputer/Dragonfire/releases/download/v0.9.9/deepconv-v2.tar.gz | tar xvfz - +fi + +pip3 install --upgrade wikipedia==1.4.0 PyUserInput==0.1.11 tinydb==3.9.0.post1 youtube_dl spacy==2.0.11 pyowm==2.9.0 tensorflow==1.0.0 deepspeech==0.2.0a5 SpeechRecognition tweepy==3.6.0 metadata_parser==0.9.20 hug==2.4.0 hug-middleware-cors==1.0.0 waitress==1.1.0 requests==2.19.1 pyjwt==1.6.4 SQLAlchemy==1.2.10 PyMySQL==0.8.1 && \ +pip3 install --upgrade flake8 sphinx sphinx_rtd_theme recommonmark m2r pytest && \ +python3 -m spacy download en && \ +pip3 install https://github.com/huggingface/neuralcoref-models/releases/download/en_coref_sm-3.0.0/en_coref_sm-3.0.0.tar.gz && \ +printf "import nltk\nnltk.download('names')\nnltk.download('brown')\nnltk.download('wordnet')\nnltk.download('punkt')" | python3 && echo -e "\n\n${GREEN}Dragonfire is successfully installed to your computer.${NC}\n" diff --git a/iso/dragonfire-master/install.sh b/iso/dragonfire-master/install.sh new file mode 100644 index 00000000..1a020b67 --- /dev/null +++ b/iso/dragonfire-master/install.sh @@ -0,0 +1,60 @@ +#!/bin/bash +OPTS=`getopt -o n --long no-model -- "$@"` +if [ $? != 0 ] ; then echo "Failed parsing options." >&2 ; exit 1 ; fi +eval set -- "$OPTS" + +NO_MODEL=false +while true; do + case "$1" in + -n | --no-model ) NO_MODEL=true; shift ;; + -- ) shift; break ;; + * ) break ;; + esac +done +NO_MODEL=$NO_MODEL + +apt-get update +apt-get -y install python3 python3-all-dev libglib2.0-dev libcairo2-dev libgtk2.0-dev && \ +apt-get -y install python3-minimal ${misc:Pre-Depends} && \ +apt-get -y install ${python3:Depends} ${misc:Depends} flite python3-xlib portaudio19-dev python3-all-dev flac libnotify-bin python3-lxml python3-nltk python3-pyaudio python3-httplib2 python3-pip python3-setuptools python3-wheel libgstreamer1.0-dev gstreamer1.0-plugins-good gstreamer1.0-tools subversion libatlas-base-dev automake autoconf libtool && \ + +pip3 install . + +#DEBHELPER# +RED='\033[0;31m' +GREEN='\033[0;32m' +NC='\033[0m' # No Color +CHECKSUM="1449d83e0a0b834c033067bf62f06277" +CHECKSUM2="c775d819ffc06118053a48808003df84" + +DRAGONFIRE_DIR=/usr/share/dragonfire +if [ ! -d "$DRAGONFIRE_DIR" ]; then + mkdir $DRAGONFIRE_DIR +fi + +DEEPSPEECH_DIR=/usr/share/dragonfire/deepspeech +if [ "$NO_MODEL" = false ] ; then + if [ ! -d "$DEEPSPEECH_DIR" ]; then + mkdir $DEEPSPEECH_DIR + fi + cd $DEEPSPEECH_DIR + verified=$(md5sum models/* | md5sum) + if [ ! ${verified::-3} = "$CHECKSUM" ]; then + wget -nc -O - https://github.com/mozilla/DeepSpeech/releases/download/v0.1.1/deepspeech-0.1.1-models.tar.gz | tar xvfz - + fi +fi + +DEEPCONV_DIR=/usr/share/dragonfire/deepconv +if [ ! -d "$DEEPCONV_DIR" ]; then + mkdir $DEEPCONV_DIR +fi +cd $DEEPCONV_DIR +verified=$(find . -type f -exec md5sum {} \; | md5sum) +if [ ! ${verified::-3} = "$CHECKSUM2" ]; then + wget -nc -O - https://github.com/DragonComputer/Dragonfire/releases/download/v0.9.9/deepconv-v2.tar.gz | tar xvfz - +fi + +pip3 install --upgrade wikipedia==1.4.0 PyUserInput==0.1.11 tinydb==3.9.0.post1 youtube_dl spacy==2.0.11 pyowm==2.9.0 tensorflow==1.0.0 deepspeech==0.2.0a5 SpeechRecognition tweepy==3.6.0 metadata_parser==0.9.20 hug==2.4.0 hug-middleware-cors==1.0.0 waitress==1.1.0 requests==2.19.1 pyjwt==1.6.4 SQLAlchemy==1.2.10 PyMySQL==0.8.1 && \ +python3 -m spacy download en && \ +pip3 install https://github.com/huggingface/neuralcoref-models/releases/download/en_coref_sm-3.0.0/en_coref_sm-3.0.0.tar.gz && \ +printf "import nltk\nnltk.download('names')\nnltk.download('brown')\nnltk.download('wordnet')\nnltk.download('punkt')" | python3 && echo -e "\n\n${GREEN}Dragonfire is successfully installed to your computer.${NC}\n" diff --git a/iso/dragonfire-master/setup.cfg b/iso/dragonfire-master/setup.cfg new file mode 100644 index 00000000..d68a786e --- /dev/null +++ b/iso/dragonfire-master/setup.cfg @@ -0,0 +1,5 @@ +[bdist_wheel] +python-tag = py3 + +[flake8] +ignore = E501, E701 diff --git a/iso/dragonfire-master/setup.py b/iso/dragonfire-master/setup.py new file mode 100644 index 00000000..2b620f88 --- /dev/null +++ b/iso/dragonfire-master/setup.py @@ -0,0 +1,190 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- + +"""A setuptools based setup module. + +See: +https://packaging.python.org/en/latest/distributing.html +https://github.com/pypa/sampleproject +""" + +# Always prefer setuptools over distutils +from setuptools import setup, find_packages, Extension +# To use a consistent encoding +from codecs import open +from os import path +from subprocess import PIPE, Popen + +here = path.abspath(path.dirname(__file__)) + + +def pkgconfig(*packages): + """Method to prepare the configuration for compiling the `realhud` Python C extension + of Dragonfire by querying installed libraries. + + Kwargs: + packages: C libraries + """ + + flags = { + '-D': 'define_macros', + '-I': 'include_dirs', + '-L': 'library_dirs', + '-l': 'libraries' + } + cmd = ['pkg-config', '--cflags', '--libs'] + list(packages) + proc = Popen(cmd, stdout=PIPE, stderr=PIPE) + output, error = proc.stdout.read(), proc.stderr.read() + + if error: + raise ValueError(error) + + config = {} + + for token in output.split(): + token = token.decode('ascii') + if token != '-pthread': + flag, value = token[:2], token[2:] + config.setdefault(flags[flag], []).append(value) + + if 'define_macros' in config: + macros = [(name, None) for name in config['define_macros']] + config['define_macros'] = macros + + return config + + +# Get the long description from the README file +with open(path.join(here, 'README.md'), encoding='utf-8') as f: + long_description = f.read() + +setup( + name='dragonfire', + + # Versions should comply with PEP440. For a discussion on single-sourcing + # the version across setup.py and the project code, see + # https://packaging.python.org/en/latest/single_source_version.html + version='1.0.0', + description='Dragonfire is an open source virtual assistant project for Ubuntu based Linux distributions', + long_description=long_description, + long_description_content_type='text/markdown', + + # The project's main homepage. + url='https://github.com/mertyildiran/Dragonfire', + + # Author details + author='Mehmet Mert Yıldıran', + author_email='mert.yildiran@bil.omu.edu.tr', + + # Choose your license + license='MIT', + + # See https://pypi.python.org/pypi?%3Aaction=list_classifiers + classifiers=[ + # How mature is this project? Common values are + # 3 - Alpha + # 4 - Beta + # 5 - Production/Stable + 'Development Status :: 5 - Production/Stable', + + # Indicate who your project is intended for + 'Intended Audience :: End Users/Desktop', + 'Topic :: Scientific/Engineering :: Human Machine Interfaces', + + # Pick your license as you wish (should match "license" above) + 'License :: OSI Approved :: MIT License', + + # Intended language + 'Natural Language :: English', + + # Target Operating System + 'Operating System :: POSIX :: Linux', + + # Specify the Python versions you support here. In particular, ensure + # that you indicate whether you support Python 2, Python 3 or both. + 'Programming Language :: Python :: 3 :: Only', + ], + + # What does your project relate to? + keywords='virtual assistant machine learining artifical intelligence chat bot', + + # You can just specify the packages manually here if your project is + # simple. Or you can use find_packages(). + packages=find_packages(), + + # Alternatively, if you want to distribute just a my_module.py, uncomment + # this: + # py_modules=["my_module"], + + # List run-time dependencies here. These will be installed by pip when + # your project is installed. For an analysis of "install_requires" vs pip's + # requirements files see: + # https://packaging.python.org/en/latest/requirements.html + install_requires=[ + 'wikipedia==1.4.0', + 'PyUserInput==0.1.11', + 'tinydb==3.9.0.post1', + 'youtube_dl', + 'spacy==2.0.11', + 'pyowm==2.9.0', + 'tensorflow==1.0.0', + 'deepspeech==0.2.0a5', + 'requests==2.19.1', + 'lxml==3.5.0', + 'nltk==3.1', + 'httplib2>=0.9.1', + 'imutils', + 'pyqtgraph', + 'PeakUtils', + 'tweepy==3.6.0', + 'metadata_parser==0.9.20', + 'hug==2.4.0', + 'hug-middleware-cors==1.0.0', + 'waitress==1.1.0', + 'SpeechRecognition', + 'pyjwt==1.6.4', + 'SQLAlchemy==1.2.10', + 'PyMySQL==0.8.1' + ], + + # List additional groups of dependencies here (e.g. development + # dependencies). You can install these using the following syntax, + # for example: + # $ pip install -e .[dev,test] + extras_require={ + 'optionals': [ + 'flake8', + 'sphinx', + 'sphinx_rtd_theme', + 'recommonmark', + 'm2r', + 'pytest' + ] + }, + + # If there are data files included in your packages that need to be + # installed, specify them here. If using Python 2.6 or less, then these + # have to be included in MANIFEST.in as well. + package_data={ + # If any package contains data files, include them: + 'dragonfire': ['realhud/animation/*', 'sr/models/english/*'] + }, + + # Although 'package_data' is the preferred approach, in some case you may + # need to place data files outside of your packages. See: + # http://docs.python.org/3.4/distutils/setupscript.html#installing-additional-files # noqa + # In this case, 'data_file' will be installed into '/my_data' + data_files=[], + + # To provide executable scripts, use entry points in preference to the + # "scripts" keyword. Entry points provide cross-platform support and allow + # pip to create the appropriate form of executable for the target platform. + entry_points={ + 'console_scripts': [ + 'dragonfire=dragonfire:initiate', + ], + }, + ext_modules=[ + Extension('realhud', ['dragonfire/realhud/realhud.c'], + **pkgconfig('gtk+-2.0 x11 xext')) + ]) diff --git a/iso/fast-neural-style/README.md b/iso/fast-neural-style/README.md new file mode 100644 index 00000000..636b425f --- /dev/null +++ b/iso/fast-neural-style/README.md @@ -0,0 +1,57 @@ +# fast-neural-style :city_sunrise: :rocket: +This repository contains a pytorch implementation of an algorithm for artistic style transfer. The algorithm can be used to mix the content of an image with the style of another image. For example, here is a photograph of a door arch rendered in the style of a stained glass painting. + +The model uses the method described in [Perceptual Losses for Real-Time Style Transfer and Super-Resolution](https://arxiv.org/abs/1603.08155) along with [Instance Normalization](https://arxiv.org/pdf/1607.08022.pdf). The saved-models for examples shown in the README can be downloaded from [here](https://www.dropbox.com/s/lrvwfehqdcxoza8/saved_models.zip?dl=0). + +

+ + + +

+ +## Requirements +The program is written in Python, and uses [pytorch](http://pytorch.org/), [scipy](https://www.scipy.org). A GPU is not necessary, but can provide a significant speed up especially for training a new model. Regular sized images can be styled on a laptop or desktop using saved models. + +## Usage +Stylize image +``` +python neural_style/neural_style.py eval --content-image --model --output-image --cuda 0 +``` +* `--content-image`: path to content image you want to stylize. +* `--model`: saved model to be used for stylizing the image (eg: `mosaic.pth`) +* `--output-image`: path for saving the output image. +* `--content-scale`: factor for scaling down the content image if memory is an issue (eg: value of 2 will halve the height and width of content-image) +* `--cuda`: set it to 1 for running on GPU, 0 for CPU. + +Train model +```bash +python neural_style/neural_style.py train --dataset --style-image --save-model-dir --epochs 2 --cuda 1 +``` + +There are several command line arguments, the important ones are listed below +* `--dataset`: path to training dataset, the path should point to a folder containing another folder with all the training images. I used COCO 2014 Training images dataset [80K/13GB] [(download)](http://mscoco.org/dataset/#download). +* `--style-image`: path to style-image. +* `--save-model-dir`: path to folder where trained model will be saved. +* `--cuda`: set it to 1 for running on GPU, 0 for CPU. + +Refer to ``neural_style/neural_style.py`` for other command line arguments. For training new models you might have to tune the values of `--content-weight` and `--style-weight`. The mosaic style model shown above was trained with `--content-weight 1e5` and `--style-weight 1e10`. The remaining 3 models were also trained with similar order of weight parameters with slight variation in the `--style-weight` (`5e10` or `1e11`). + +## Models + +Models for the examples shown below can be downloaded from [here](https://www.dropbox.com/s/lrvwfehqdcxoza8/saved_models.zip?dl=0) or by running the script ``download_saved_models.py``. + +
+ +
+ +
+ + + + +
+ + + + +
diff --git a/iso/fast-neural-style/download_saved_models.py b/iso/fast-neural-style/download_saved_models.py new file mode 100644 index 00000000..71454bc4 --- /dev/null +++ b/iso/fast-neural-style/download_saved_models.py @@ -0,0 +1,25 @@ +import os +import zipfile + +# PyTorch 1.1 moves _download_url_to_file +# from torch.utils.model_zoo to torch.hub +# PyTorch 1.0 exists another _download_url_to_file +# 2 argument +# TODO: If you remove support PyTorch 1.0 or older, +# You should remove torch.utils.model_zoo +# Ref. PyTorch #18758 +# https://github.com/pytorch/pytorch/pull/18758/commits +try: + from torch.utils.model_zoo import _download_url_to_file +except ImportError: + from torch.hub import _download_url_to_file + + +def unzip(source_filename, dest_dir): + with zipfile.ZipFile(source_filename) as zf: + zf.extractall(path=dest_dir) + + +if __name__ == '__main__': + _download_url_to_file('https://www.dropbox.com/s/lrvwfehqdcxoza8/saved_models.zip?dl=1', 'saved_models.zip', None, True) + unzip('saved_models.zip', '.') diff --git a/iso/fast-neural-style/images/content-images/amber.jpg b/iso/fast-neural-style/images/content-images/amber.jpg new file mode 100644 index 00000000..22f6390f Binary files /dev/null and b/iso/fast-neural-style/images/content-images/amber.jpg differ diff --git a/iso/fast-neural-style/images/content-images/content.jpg b/iso/fast-neural-style/images/content-images/content.jpg new file mode 100644 index 00000000..4ee61f50 Binary files /dev/null and b/iso/fast-neural-style/images/content-images/content.jpg differ diff --git a/iso/fast-neural-style/images/content-images/style.jpg b/iso/fast-neural-style/images/content-images/style.jpg new file mode 100644 index 00000000..53ea683a Binary files /dev/null and b/iso/fast-neural-style/images/content-images/style.jpg differ diff --git a/iso/fast-neural-style/images/output-images/amber-candy.jpg b/iso/fast-neural-style/images/output-images/amber-candy.jpg new file mode 100644 index 00000000..f585fdaa Binary files /dev/null and b/iso/fast-neural-style/images/output-images/amber-candy.jpg differ diff --git a/iso/fast-neural-style/images/output-images/amber-mosaic.jpg b/iso/fast-neural-style/images/output-images/amber-mosaic.jpg new file mode 100644 index 00000000..5af32e75 Binary files /dev/null and b/iso/fast-neural-style/images/output-images/amber-mosaic.jpg differ diff --git a/iso/fast-neural-style/images/output-images/amber-rain-princess.jpg b/iso/fast-neural-style/images/output-images/amber-rain-princess.jpg new file mode 100644 index 00000000..4f9efeb2 Binary files /dev/null and b/iso/fast-neural-style/images/output-images/amber-rain-princess.jpg differ diff --git a/iso/fast-neural-style/images/output-images/amber-udnie.jpg b/iso/fast-neural-style/images/output-images/amber-udnie.jpg new file mode 100644 index 00000000..4e726160 Binary files /dev/null and b/iso/fast-neural-style/images/output-images/amber-udnie.jpg differ diff --git a/iso/fast-neural-style/images/style-images/candy.jpg b/iso/fast-neural-style/images/style-images/candy.jpg new file mode 100644 index 00000000..f40e5a33 Binary files /dev/null and b/iso/fast-neural-style/images/style-images/candy.jpg differ diff --git a/iso/fast-neural-style/images/style-images/mosaic.jpg b/iso/fast-neural-style/images/style-images/mosaic.jpg new file mode 100644 index 00000000..63aa06fe Binary files /dev/null and b/iso/fast-neural-style/images/style-images/mosaic.jpg differ diff --git a/iso/fast-neural-style/images/style-images/rain-princess-cropped.jpg b/iso/fast-neural-style/images/style-images/rain-princess-cropped.jpg new file mode 100644 index 00000000..00a83ea4 Binary files /dev/null and b/iso/fast-neural-style/images/style-images/rain-princess-cropped.jpg differ diff --git a/iso/fast-neural-style/images/style-images/rain-princess.jpg b/iso/fast-neural-style/images/style-images/rain-princess.jpg new file mode 100644 index 00000000..520f6a22 Binary files /dev/null and b/iso/fast-neural-style/images/style-images/rain-princess.jpg differ diff --git a/iso/fast-neural-style/images/style-images/style.jpg b/iso/fast-neural-style/images/style-images/style.jpg new file mode 100644 index 00000000..cf29490e Binary files /dev/null and b/iso/fast-neural-style/images/style-images/style.jpg differ diff --git a/iso/fast-neural-style/images/style-images/udnie.jpg b/iso/fast-neural-style/images/style-images/udnie.jpg new file mode 100644 index 00000000..3dbb29cf Binary files /dev/null and b/iso/fast-neural-style/images/style-images/udnie.jpg differ diff --git a/iso/fast-neural-style/neural_style/__init__.py b/iso/fast-neural-style/neural_style/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/iso/fast-neural-style/neural_style/__pycache__/transformer_net.cpython-37.pyc b/iso/fast-neural-style/neural_style/__pycache__/transformer_net.cpython-37.pyc new file mode 100644 index 00000000..99edd147 Binary files /dev/null and b/iso/fast-neural-style/neural_style/__pycache__/transformer_net.cpython-37.pyc differ diff --git a/iso/fast-neural-style/neural_style/__pycache__/utils.cpython-37.pyc b/iso/fast-neural-style/neural_style/__pycache__/utils.cpython-37.pyc new file mode 100644 index 00000000..2f79597c Binary files /dev/null and b/iso/fast-neural-style/neural_style/__pycache__/utils.cpython-37.pyc differ diff --git a/iso/fast-neural-style/neural_style/__pycache__/vgg.cpython-37.pyc b/iso/fast-neural-style/neural_style/__pycache__/vgg.cpython-37.pyc new file mode 100644 index 00000000..bb8e0c16 Binary files /dev/null and b/iso/fast-neural-style/neural_style/__pycache__/vgg.cpython-37.pyc differ diff --git a/iso/fast-neural-style/neural_style/neural_style.py b/iso/fast-neural-style/neural_style/neural_style.py new file mode 100644 index 00000000..bce53db8 --- /dev/null +++ b/iso/fast-neural-style/neural_style/neural_style.py @@ -0,0 +1,240 @@ +import argparse +import os +import sys +import time +import re + +import numpy as np +import torch +from torch.optim import Adam +from torch.utils.data import DataLoader +from torchvision import datasets +from torchvision import transforms +import torch.onnx + +import utils +from transformer_net import TransformerNet +from vgg import Vgg16 + + +def check_paths(args): + try: + if not os.path.exists(args.save_model_dir): + os.makedirs(args.save_model_dir) + if args.checkpoint_model_dir is not None and not (os.path.exists(args.checkpoint_model_dir)): + os.makedirs(args.checkpoint_model_dir) + except OSError as e: + print(e) + sys.exit(1) + + +def train(args): + device = torch.device("cuda" if args.cuda else "cpu") + + np.random.seed(args.seed) + torch.manual_seed(args.seed) + + transform = transforms.Compose([ + transforms.Resize(args.image_size), + transforms.CenterCrop(args.image_size), + transforms.ToTensor(), + transforms.Lambda(lambda x: x.mul(255)) + ]) + train_dataset = datasets.ImageFolder(args.dataset, transform) + train_loader = DataLoader(train_dataset, batch_size=args.batch_size) + + transformer = TransformerNet().to(device) + optimizer = Adam(transformer.parameters(), args.lr) + mse_loss = torch.nn.MSELoss() + + vgg = Vgg16(requires_grad=False).to(device) + style_transform = transforms.Compose([ + transforms.ToTensor(), + transforms.Lambda(lambda x: x.mul(255)) + ]) + style = utils.load_image(args.style_image, size=args.style_size) + style = style_transform(style) + style = style.repeat(args.batch_size, 1, 1, 1).to(device) + + features_style = vgg(utils.normalize_batch(style)) + gram_style = [utils.gram_matrix(y) for y in features_style] + + for e in range(args.epochs): + transformer.train() + agg_content_loss = 0. + agg_style_loss = 0. + count = 0 + for batch_id, (x, _) in enumerate(train_loader): + n_batch = len(x) + count += n_batch + optimizer.zero_grad() + + x = x.to(device) + y = transformer(x) + + y = utils.normalize_batch(y) + x = utils.normalize_batch(x) + + features_y = vgg(y) + features_x = vgg(x) + + content_loss = args.content_weight * mse_loss(features_y.relu2_2, features_x.relu2_2) + + style_loss = 0. + for ft_y, gm_s in zip(features_y, gram_style): + gm_y = utils.gram_matrix(ft_y) + style_loss += mse_loss(gm_y, gm_s[:n_batch, :, :]) + style_loss *= args.style_weight + + total_loss = content_loss + style_loss + total_loss.backward() + optimizer.step() + + agg_content_loss += content_loss.item() + agg_style_loss += style_loss.item() + + if (batch_id + 1) % args.log_interval == 0: + mesg = "{}\tEpoch {}:\t[{}/{}]\tcontent: {:.6f}\tstyle: {:.6f}\ttotal: {:.6f}".format( + time.ctime(), e + 1, count, len(train_dataset), + agg_content_loss / (batch_id + 1), + agg_style_loss / (batch_id + 1), + (agg_content_loss + agg_style_loss) / (batch_id + 1) + ) + print(mesg) + + if args.checkpoint_model_dir is not None and (batch_id + 1) % args.checkpoint_interval == 0: + transformer.eval().cpu() + ckpt_model_filename = "ckpt_epoch_" + str(e) + "_batch_id_" + str(batch_id + 1) + ".pth" + ckpt_model_path = os.path.join(args.checkpoint_model_dir, ckpt_model_filename) + torch.save(transformer.state_dict(), ckpt_model_path) + transformer.to(device).train() + + # save model + transformer.eval().cpu() + save_model_filename = "epoch_" + str(args.epochs) + "_" + str(time.ctime()).replace(' ', '_') + "_" + str( + args.content_weight) + "_" + str(args.style_weight) + ".model" + save_model_path = os.path.join(args.save_model_dir, save_model_filename) + torch.save(transformer.state_dict(), save_model_path) + + print("\nDone, trained model saved at", save_model_path) + + +def stylize(args): + device = torch.device("cuda" if args.cuda else "cpu") + + content_image = utils.load_image(args.content_image, scale=args.content_scale) + content_transform = transforms.Compose([ + transforms.ToTensor(), + transforms.Lambda(lambda x: x.mul(255)) + ]) + content_image = content_transform(content_image) + content_image = content_image.unsqueeze(0).to(device) + + if args.model.endswith(".onnx"): + output = stylize_onnx_caffe2(content_image, args) + else: + with torch.no_grad(): + style_model = TransformerNet() + state_dict = torch.load(args.model) + # remove saved deprecated running_* keys in InstanceNorm from the checkpoint + for k in list(state_dict.keys()): + if re.search(r'in\d+\.running_(mean|var)$', k): + del state_dict[k] + style_model.load_state_dict(state_dict) + style_model.to(device) + if args.export_onnx: + assert args.export_onnx.endswith(".onnx"), "Export model file should end with .onnx" + output = torch.onnx._export(style_model, content_image, args.export_onnx).cpu() + else: + output = style_model(content_image).cpu() + utils.save_image(args.output_image, output[0]) + + +def stylize_onnx_caffe2(content_image, args): + """ + Read ONNX model and run it using Caffe2 + """ + + assert not args.export_onnx + + import onnx + import onnx_caffe2.backend + + model = onnx.load(args.model) + + prepared_backend = onnx_caffe2.backend.prepare(model, device='CUDA' if args.cuda else 'CPU') + inp = {model.graph.input[0].name: content_image.numpy()} + c2_out = prepared_backend.run(inp)[0] + + return torch.from_numpy(c2_out) + + +def main(): + main_arg_parser = argparse.ArgumentParser(description="parser for fast-neural-style") + subparsers = main_arg_parser.add_subparsers(title="subcommands", dest="subcommand") + + train_arg_parser = subparsers.add_parser("train", help="parser for training arguments") + train_arg_parser.add_argument("--epochs", type=int, default=2, + help="number of training epochs, default is 2") + train_arg_parser.add_argument("--batch-size", type=int, default=4, + help="batch size for training, default is 4") + train_arg_parser.add_argument("--dataset", type=str, required=True, + help="path to training dataset, the path should point to a folder " + "containing another folder with all the training images") + train_arg_parser.add_argument("--style-image", type=str, default="images/style-images/mosaic.jpg", + help="path to style-image") + train_arg_parser.add_argument("--save-model-dir", type=str, required=True, + help="path to folder where trained model will be saved.") + train_arg_parser.add_argument("--checkpoint-model-dir", type=str, default=None, + help="path to folder where checkpoints of trained models will be saved") + train_arg_parser.add_argument("--image-size", type=int, default=256, + help="size of training images, default is 256 X 256") + train_arg_parser.add_argument("--style-size", type=int, default=None, + help="size of style-image, default is the original size of style image") + train_arg_parser.add_argument("--cuda", type=int, required=True, + help="set it to 1 for running on GPU, 0 for CPU") + train_arg_parser.add_argument("--seed", type=int, default=42, + help="random seed for training") + train_arg_parser.add_argument("--content-weight", type=float, default=1e5, + help="weight for content-loss, default is 1e5") + train_arg_parser.add_argument("--style-weight", type=float, default=1e10, + help="weight for style-loss, default is 1e10") + train_arg_parser.add_argument("--lr", type=float, default=1e-3, + help="learning rate, default is 1e-3") + train_arg_parser.add_argument("--log-interval", type=int, default=500, + help="number of images after which the training loss is logged, default is 500") + train_arg_parser.add_argument("--checkpoint-interval", type=int, default=2000, + help="number of batches after which a checkpoint of the trained model will be created") + + eval_arg_parser = subparsers.add_parser("eval", help="parser for evaluation/stylizing arguments") + eval_arg_parser.add_argument("--content-image", type=str, required=True, + help="path to content image you want to stylize") + eval_arg_parser.add_argument("--content-scale", type=float, default=None, + help="factor for scaling down the content image") + eval_arg_parser.add_argument("--output-image", type=str, required=True, + help="path for saving the output image") + eval_arg_parser.add_argument("--model", type=str, required=True, + help="saved model to be used for stylizing the image. If file ends in .pth - PyTorch path is used, if in .onnx - Caffe2 path") + eval_arg_parser.add_argument("--cuda", type=int, required=True, + help="set it to 1 for running on GPU, 0 for CPU") + eval_arg_parser.add_argument("--export_onnx", type=str, + help="export ONNX model to a given file") + + args = main_arg_parser.parse_args() + + if args.subcommand is None: + print("ERROR: specify either train or eval") + sys.exit(1) + if args.cuda and not torch.cuda.is_available(): + print("ERROR: cuda is not available, try running on CPU") + sys.exit(1) + + if args.subcommand == "train": + check_paths(args) + train(args) + else: + stylize(args) + + +if __name__ == "__main__": + main() diff --git a/iso/fast-neural-style/neural_style/transformer_net.py b/iso/fast-neural-style/neural_style/transformer_net.py new file mode 100644 index 00000000..2cb06971 --- /dev/null +++ b/iso/fast-neural-style/neural_style/transformer_net.py @@ -0,0 +1,99 @@ +import torch + + +class TransformerNet(torch.nn.Module): + def __init__(self): + super(TransformerNet, self).__init__() + # Initial convolution layers + self.conv1 = ConvLayer(3, 32, kernel_size=9, stride=1) + self.in1 = torch.nn.InstanceNorm2d(32, affine=True) + self.conv2 = ConvLayer(32, 64, kernel_size=3, stride=2) + self.in2 = torch.nn.InstanceNorm2d(64, affine=True) + self.conv3 = ConvLayer(64, 128, kernel_size=3, stride=2) + self.in3 = torch.nn.InstanceNorm2d(128, affine=True) + # Residual layers + self.res1 = ResidualBlock(128) + self.res2 = ResidualBlock(128) + self.res3 = ResidualBlock(128) + self.res4 = ResidualBlock(128) + self.res5 = ResidualBlock(128) + # Upsampling Layers + self.deconv1 = UpsampleConvLayer(128, 64, kernel_size=3, stride=1, upsample=2) + self.in4 = torch.nn.InstanceNorm2d(64, affine=True) + self.deconv2 = UpsampleConvLayer(64, 32, kernel_size=3, stride=1, upsample=2) + self.in5 = torch.nn.InstanceNorm2d(32, affine=True) + self.deconv3 = ConvLayer(32, 3, kernel_size=9, stride=1) + # Non-linearities + self.relu = torch.nn.ReLU() + + def forward(self, X): + y = self.relu(self.in1(self.conv1(X))) + y = self.relu(self.in2(self.conv2(y))) + y = self.relu(self.in3(self.conv3(y))) + y = self.res1(y) + y = self.res2(y) + y = self.res3(y) + y = self.res4(y) + y = self.res5(y) + y = self.relu(self.in4(self.deconv1(y))) + y = self.relu(self.in5(self.deconv2(y))) + y = self.deconv3(y) + return y + + +class ConvLayer(torch.nn.Module): + def __init__(self, in_channels, out_channels, kernel_size, stride): + super(ConvLayer, self).__init__() + reflection_padding = kernel_size // 2 + self.reflection_pad = torch.nn.ReflectionPad2d(reflection_padding) + self.conv2d = torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride) + + def forward(self, x): + out = self.reflection_pad(x) + out = self.conv2d(out) + return out + + +class ResidualBlock(torch.nn.Module): + """ResidualBlock + introduced in: https://arxiv.org/abs/1512.03385 + recommended architecture: http://torch.ch/blog/2016/02/04/resnets.html + """ + + def __init__(self, channels): + super(ResidualBlock, self).__init__() + self.conv1 = ConvLayer(channels, channels, kernel_size=3, stride=1) + self.in1 = torch.nn.InstanceNorm2d(channels, affine=True) + self.conv2 = ConvLayer(channels, channels, kernel_size=3, stride=1) + self.in2 = torch.nn.InstanceNorm2d(channels, affine=True) + self.relu = torch.nn.ReLU() + + def forward(self, x): + residual = x + out = self.relu(self.in1(self.conv1(x))) + out = self.in2(self.conv2(out)) + out = out + residual + return out + + +class UpsampleConvLayer(torch.nn.Module): + """UpsampleConvLayer + Upsamples the input and then does a convolution. This method gives better results + compared to ConvTranspose2d. + ref: http://distill.pub/2016/deconv-checkerboard/ + """ + + def __init__(self, in_channels, out_channels, kernel_size, stride, upsample=None): + super(UpsampleConvLayer, self).__init__() + self.upsample = upsample + reflection_padding = kernel_size // 2 + self.reflection_pad = torch.nn.ReflectionPad2d(reflection_padding) + self.conv2d = torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride) + + def forward(self, x): + x_in = x + if self.upsample: + x_in = torch.nn.functional.interpolate(x_in, mode='nearest', scale_factor=self.upsample) + out = self.reflection_pad(x_in) + out = self.conv2d(out) + return out diff --git a/iso/fast-neural-style/neural_style/utils.py b/iso/fast-neural-style/neural_style/utils.py new file mode 100644 index 00000000..36b9bd0d --- /dev/null +++ b/iso/fast-neural-style/neural_style/utils.py @@ -0,0 +1,34 @@ +import torch +from PIL import Image + + +def load_image(filename, size=None, scale=None): + img = Image.open(filename) + if size is not None: + img = img.resize((size, size), Image.ANTIALIAS) + elif scale is not None: + img = img.resize((int(img.size[0] / scale), int(img.size[1] / scale)), Image.ANTIALIAS) + return img + + +def save_image(filename, data): + img = data.clone().clamp(0, 255).numpy() + img = img.transpose(1, 2, 0).astype("uint8") + img = Image.fromarray(img) + img.save(filename) + + +def gram_matrix(y): + (b, ch, h, w) = y.size() + features = y.view(b, ch, w * h) + features_t = features.transpose(1, 2) + gram = features.bmm(features_t) / (ch * h * w) + return gram + + +def normalize_batch(batch): + # normalize using imagenet mean and std + mean = batch.new_tensor([0.485, 0.456, 0.406]).view(-1, 1, 1) + std = batch.new_tensor([0.229, 0.224, 0.225]).view(-1, 1, 1) + batch = batch.div_(255.0) + return (batch - mean) / std diff --git a/iso/fast-neural-style/neural_style/vgg.py b/iso/fast-neural-style/neural_style/vgg.py new file mode 100644 index 00000000..17ef6632 --- /dev/null +++ b/iso/fast-neural-style/neural_style/vgg.py @@ -0,0 +1,38 @@ +from collections import namedtuple + +import torch +from torchvision import models + + +class Vgg16(torch.nn.Module): + def __init__(self, requires_grad=False): + super(Vgg16, self).__init__() + vgg_pretrained_features = models.vgg16(pretrained=True).features + self.slice1 = torch.nn.Sequential() + self.slice2 = torch.nn.Sequential() + self.slice3 = torch.nn.Sequential() + self.slice4 = torch.nn.Sequential() + for x in range(4): + self.slice1.add_module(str(x), vgg_pretrained_features[x]) + for x in range(4, 9): + self.slice2.add_module(str(x), vgg_pretrained_features[x]) + for x in range(9, 16): + self.slice3.add_module(str(x), vgg_pretrained_features[x]) + for x in range(16, 23): + self.slice4.add_module(str(x), vgg_pretrained_features[x]) + if not requires_grad: + for param in self.parameters(): + param.requires_grad = False + + def forward(self, X): + h = self.slice1(X) + h_relu1_2 = h + h = self.slice2(h) + h_relu2_2 = h + h = self.slice3(h) + h_relu3_3 = h + h = self.slice4(h) + h_relu4_3 = h + vgg_outputs = namedtuple("VggOutputs", ['relu1_2', 'relu2_2', 'relu3_3', 'relu4_3']) + out = vgg_outputs(h_relu1_2, h_relu2_2, h_relu3_3, h_relu4_3) + return out diff --git a/iso/fast-neural-style/saved_models/candy.pth b/iso/fast-neural-style/saved_models/candy.pth new file mode 100644 index 00000000..f7767f70 Binary files /dev/null and b/iso/fast-neural-style/saved_models/candy.pth differ diff --git a/iso/fast-neural-style/saved_models/mosaic.pth b/iso/fast-neural-style/saved_models/mosaic.pth new file mode 100644 index 00000000..7b75d0d8 Binary files /dev/null and b/iso/fast-neural-style/saved_models/mosaic.pth differ diff --git a/iso/fast-neural-style/saved_models/rain_princess.pth b/iso/fast-neural-style/saved_models/rain_princess.pth new file mode 100644 index 00000000..3a20f171 Binary files /dev/null and b/iso/fast-neural-style/saved_models/rain_princess.pth differ diff --git a/iso/fast-neural-style/saved_models/udnie.pth b/iso/fast-neural-style/saved_models/udnie.pth new file mode 100644 index 00000000..85e38456 Binary files /dev/null and b/iso/fast-neural-style/saved_models/udnie.pth differ