Skip to content
This repository was archived by the owner on Apr 26, 2022. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
4c952b3
Initial commit of Session.java and SessionService.java
cabishop Jul 24, 2017
4f25684
Initial commit of SimpleSessionService component
cabishop Jul 24, 2017
bdafc5e
Initializing the session service components and tests
cabishop Aug 30, 2017
44d3614
Updating the Request and Response classes to include sessions (for bo…
cabishop Aug 30, 2017
624f597
Updating the AgentRequest and AgentResponse to include sessions (for …
cabishop Aug 30, 2017
63dedc2
Updating Session, SessionObject, SessionService
cabishop Aug 30, 2017
6f5c87e
Updating process method to include sessions
cabishop Aug 30, 2017
1fe98b9
Fixing formatting issues
cabishop Aug 30, 2017
ddb6d72
Updating copyright header from 2016 to 2017
cabishop Sep 1, 2017
0470ab8
Cleaning up SimpleSessionService
cabishop Sep 1, 2017
880fcd5
separating process(request) from process(request, sessionService) to …
cabishop Sep 1, 2017
252c1df
Adding sessionId to session on create() in SimpleSessionService
cabishop Sep 1, 2017
5783529
Cleaning up some comments
cabishop Sep 1, 2017
3c7639b
Updating primaryAgent to be an Agent rather than a String in Session …
cabishop Sep 5, 2017
722906d
Updating Session to include constructors
cabishop Sep 5, 2017
2805fb1
Cleaning up Session formatting
cabishop Sep 5, 2017
c855c6f
Removing imports that are not being used
cabishop Sep 5, 2017
b015f7d
Updating the Response(AgentResponse response) constructor to include …
cabishop Sep 5, 2017
5526876
Removing the retrieve method for the session service
cabishop Sep 5, 2017
eb771e6
First cut of session tests in ApplicationTest.java
cabishop Sep 5, 2017
85e5a44
Cleaning up formatting
cabishop Sep 5, 2017
c73ed49
Updating sessionHistory to be an ArrayList
cabishop Sep 5, 2017
b80f6cb
Updating SimpleSessionService to fix bug and use ArrayLists for sessi…
cabishop Sep 5, 2017
4d65405
Renaming SessionObject to Exchange
cabishop Sep 6, 2017
b026df1
Updating name change from SessionObject to Exchange in Application.java
cabishop Sep 6, 2017
987d65c
Updating name change from SessionObject to Exchange in SimpleSessionS…
cabishop Sep 6, 2017
764499a
organizing the web-api stock agent
cabishop Sep 19, 2017
cfb3b00
organizing duckduckgo web-api agent
cabishop Sep 19, 2017
6e07a4c
Updating ResponseStatus to include a session and a session status
cabishop Sep 25, 2017
f48669d
Updating SimpleSessionService to use 'NEW' SessionStatus
cabishop Sep 25, 2017
2652065
Updating Session to include NEW session status
cabishop Sep 25, 2017
f1f2d73
Updating duckduckgo agent to include sessions for disambiguations
cabishop Sep 25, 2017
09a2408
Organizing methods in DuckDuckGoSmartForm and SmartFormService
cabishop Sep 26, 2017
129cb49
Updating the formatDisambiguation method
cabishop Sep 26, 2017
fcf6ce9
Updating javadoc to pass mvn checkstyle:check
cabishop Sep 26, 2017
d7e81af
Cleaning up process() method
cabishop Sep 26, 2017
7786d8e
Updating copyright statements and cleaning up comments/imports
cabishop Sep 26, 2017
6c8c09d
small clean up changes
cabishop Sep 26, 2017
3974e2a
Adding NEEDS_REFINEMENT status
cabishop Sep 26, 2017
ae82322
Updating unit test
cabishop Sep 26, 2017
a0b6c7b
Updating DDG agent and SmartFormService
cabishop Sep 26, 2017
64ae081
Cleaning up process method
cabishop Sep 26, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
/*
* Copyright 2017 The Johns Hopkins University Applied Physics Laboratory LLC
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package edu.jhuapl.dorset.agents.duckduckgo;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.gson.Gson;
import com.google.gson.JsonObject;

import edu.jhuapl.dorset.ResponseStatus;
import edu.jhuapl.dorset.agents.AbstractAgent;
import edu.jhuapl.dorset.agents.AgentRequest;
import edu.jhuapl.dorset.agents.AgentResponse;
import edu.jhuapl.dorset.agents.Description;
import edu.jhuapl.dorset.http.HttpClient;
import edu.jhuapl.dorset.http.HttpRequest;
import edu.jhuapl.dorset.http.HttpResponse;
import edu.jhuapl.dorset.nlp.RuleBasedTokenizer;
import edu.jhuapl.dorset.nlp.Tokenizer;
import edu.jhuapl.dorset.sessions.Session;
import edu.jhuapl.dorset.sessions.Session.SessionStatus;

/**
* DuckduckGo agent
*
* Duckduckgo has an instant answers API. It scrapes entity information from data sources like
* Wikipedia and CrunchBase. Documentation on the api here: https://duckduckgo.com/api
*/
public class DuckDuckGoAgent extends AbstractAgent {
private static final Logger logger = LoggerFactory.getLogger(DuckDuckGoAgent.class);

private static final String SUMMARY =
"Get information about famous people, places, organizations.";
private static final String EXAMPLE = "Who is Barack Obama?";

private HttpClient client;
private SmartFormService smartFormService;
private int numFollowUpAttemptsThreshold = 2;
private int numFollowUpAttempts;

private Set<String> dictionary = new HashSet<String>(
Arrays.asList("what", "who", "is", "are", "a", "an", "the"));

/**
* Create a duckduckgo agent
*
* @param client http client
*/
public DuckDuckGoAgent(HttpClient client) {
this.client = client;
this.setDescription(new Description("general answers", SUMMARY, EXAMPLE));
this.smartFormService = new SmartFormService();
}

@Override
public AgentResponse process(AgentRequest request) {
logger.debug("Handling the request: " + request.getText());
String requestText = request.getText();
Session session = request.getSession();

// check if session is a new session or a follow-up
AgentResponse agentResponse = null;
String entityText = extractEntity(requestText);
String data = null;
if (session != null) {

if (session.getSessionStatus() == SessionStatus.NEW) {
data = requestData(entityText);
agentResponse = createResponse(data);
agentResponse.setSession(session);

} else if (session.getSessionStatus() == SessionStatus.OPEN) {
this.numFollowUpAttempts = this.numFollowUpAttempts + 1;
String smartResponse = this.smartFormService.querySmartFormHistory(session.getId(),
entityText);

if (smartResponse != null) {
agentResponse = new AgentResponse(smartResponse);
agentResponse.setSessionStatus(SessionStatus.CLOSED);
agentResponse.setSession(session);
return agentResponse;
} else {
// could not find answer in history

if (this.numFollowUpAttempts < this.numFollowUpAttemptsThreshold) {
// send the disambiguation response again
String disambiguationResponse =
this.smartFormService.getLastDisambiguationResponse();

ResponseStatus responseStatus =
new ResponseStatus(ResponseStatus.Code.NEEDS_REFINEMENT,
"I am sorry, I am still unsure what you are asking about."
+ " The options are: "
+ disambiguationResponse);
agentResponse = new AgentResponse(responseStatus);
agentResponse.setSessionStatus(SessionStatus.OPEN);
agentResponse.setSession(session);

return agentResponse;

} else {
// send could not answer request message
ResponseStatus responseStatus = new ResponseStatus(
ResponseStatus.Code.AGENT_DID_NOT_KNOW_ANSWER,
"The agent did not know the answer. Session is now closed, please try again.");
agentResponse = new AgentResponse(responseStatus);
agentResponse.setSessionStatus(SessionStatus.CLOSED);
agentResponse.setSession(session);

return agentResponse;
}
}
}
} else {
data = requestData(entityText);
agentResponse = createResponse(data);
}
this.smartFormService.updateHistory(request, data);
this.numFollowUpAttempts = 0;
return agentResponse;
}

protected String requestData(String entity) {
HttpResponse response = client.execute(HttpRequest.get(createUrl(entity)));
if (response == null || response.isError()) {
return null;
}
return response.asString();
}

protected AgentResponse createResponse(String json) {
Gson gson = new Gson();
JsonObject jsonObj = gson.fromJson(json, JsonObject.class);
String heading = jsonObj.get("Heading").getAsString();
if (heading.equals("")) {
// duckduckgo does not know
AgentResponse agentResponse =
new AgentResponse(ResponseStatus.Code.AGENT_DID_NOT_KNOW_ANSWER);
agentResponse.setSessionStatus(SessionStatus.CLOSED);
return agentResponse;
}
String abstractText = jsonObj.get("AbstractText").getAsString();
if (abstractText.equals("")) {
// most likely a disambiguation page
List<String> potentialEntities =
this.smartFormService.getCurrentExchangePotentialEntities(json);
String disambiguationResponse =
this.smartFormService.formatDisambiguationResponse(potentialEntities);

ResponseStatus responseStatus = new ResponseStatus(ResponseStatus.Code.NEEDS_REFINEMENT,
"Multiple answers for this question. " + disambiguationResponse);

AgentResponse agentResponse = new AgentResponse(responseStatus);
agentResponse.setSessionStatus(SessionStatus.OPEN);

return agentResponse;
}
AgentResponse agentResponse = new AgentResponse(abstractText);
agentResponse.setSessionStatus(SessionStatus.CLOSED);
return agentResponse;
}

/**
* Iterate over the words until we think we get to the name of the entity
*/
protected String extractEntity(String sentence) {
Tokenizer tokenizer = new RuleBasedTokenizer(true);
String[] words = tokenizer.tokenize(sentence);
int index = 0;
for (index = 0; index < words.length; index++) {
if (!dictionary.contains(words[index].toLowerCase())) {
break;
}
}
return joinStrings(Arrays.copyOfRange(words, index, words.length), " ");
}

protected String joinStrings(String[] strings, String separator) {
if (strings == null || strings.length == 0) {
return "";
}

StringBuilder sb = new StringBuilder();
sb.append(strings[0]);
for (int i = 1; i < strings.length; i++) {
sb.append(separator);
sb.append(strings[i]);
}
return sb.toString();
}

protected static String createUrl(String entity) {
try {
entity = URLEncoder.encode(entity, "UTF-8");
} catch (UnsupportedEncodingException e) {
// this isn't going to happen
logger.error("Unexpected exception when encoding url", e);
}
return "http://api.duckduckgo.com/?format=json&q=" + entity;
}

public int getNumFollowUpAttemptsThreshold() {
return this.numFollowUpAttemptsThreshold;
}

public void setNumFollowUpAttemptsThreshold(int numFollowUpAttemptsThreshold) {
this.numFollowUpAttemptsThreshold = numFollowUpAttemptsThreshold;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package edu.jhuapl.dorset.agents.duckduckgo;

import java.util.Date;
import java.util.List;

import com.google.gson.JsonObject;

import edu.jhuapl.dorset.agents.AgentRequest;

public class DuckDuckGoSmartForm {

public String sessionId;
public Date timestamp;
public String requestText;
public List<JsonObject> relatedTopics;
public String abstractText;

/**
*
* DuckDuckGoSmartForm
*
*
*/
public DuckDuckGoSmartForm() {

}

/**
*
* DuckDuckGoSmartForm
*
* @param request request
* @param relatedTopics related topics returned from DuckDuckGo given request
*
*/
public DuckDuckGoSmartForm(AgentRequest request, List<JsonObject> relatedTopics) {
try {
this.sessionId = request.getSession().getId();
} catch (NullPointerException e) {
this.sessionId = null;
}
this.requestText = request.getText();
this.relatedTopics = relatedTopics;

}

public String getSessionId() {
return sessionId;
}

public void setSessionId(String sessionId) {
this.sessionId = sessionId;
}

public Date getTimestamp() {
return this.timestamp;
}

public void setTimestamp(Date timestamp) {
this.timestamp = timestamp;
}

public String getRequestText() {
return requestText;
}

public void setRequestText(String requestText) {
this.requestText = requestText;
}

public List<JsonObject> getRelatedTopics() {
return relatedTopics;
}

public void setRelatedTopics(List<JsonObject> relatedTopics) {
this.relatedTopics = relatedTopics;
}

public String getAbstractText() {
return abstractText;
}

public void setAbstractText(String abstractText) {
this.abstractText = abstractText;
}

}
Loading