Commit 21fae9ef authored by Joel Oksanen's avatar Joel Oksanen
parents 8416bbe7 20127e20
......@@ -2,6 +2,7 @@
*.pt
__pycache__/
server/agent/amazon_data/
server/agent/SA/data/
server/agent/target_extraction/data/
server/agent/target_extraction/stanford-corenlp-full-2018-10-05
server/agent/target_extraction/BERT/data/
......
This diff is collapsed.
......@@ -3,7 +3,6 @@ import pandas as pd
pd.set_option('display.max_colwidth', None)
all_reviews_file = 'amazon_data/reviews.tsv'
def get_reviews(category, meta_file, review_file):
metadata_iter = pd.read_json(meta_file, lines=True, chunksize=1000)
metadata = pd.concat([metadata[metadata['category'].apply(lambda cl: type(cl) is list and category in cl)]
......@@ -48,21 +47,15 @@ def get_top_products_by_brand(n, brand, meta_file, review_file):
metadata_iter = pd.read_json(meta_file, lines=True, chunksize=1000)
metadata = pd.concat([metadata[metadata['brand'].apply(lambda b: type(b) is str and b == brand)]
for metadata in metadata_iter])
print(len(metadata.index))
print(metadata.head())
print(metadata.columns)
review_iter = pd.read_json(review_file, lines=True, chunksize=1000)
reviews = pd.concat([reviews[reviews['asin'].isin(metadata['asin'])] for reviews in review_iter])
print(len(reviews.index))
top_reviewed = reviews.groupby(['asin'], sort=False).size().sort_values(ascending=False).head(n)
return top_reviewed
def get_product_reviews_for_asin(asin, review_file, output_file):
review_iter = pd.read_json(review_file, lines=True, chunksize=1000)
reviews = pd.concat([reviews[reviews['asin'].apply(lambda p_asin: p_asin == asin)] for reviews in review_iter])
print(len(reviews.index))
reviews.to_csv(output_file, sep='\t', index=False)
reviews.to_csv(output_file, sep='\t', index=False)
\ No newline at end of file
......@@ -6,7 +6,7 @@ import time
class ConceptNet:
url = 'http://api.conceptnet.io'
limit = 5
limit = 50
def find_related(self, feature, rel):
uri = '/query?node=/c/en/{feature}&other=/c/en&rel=/r/{rel}&limit={limit}'.format(feature=feature, rel=rel, limit=self.limit)
......@@ -64,7 +64,7 @@ class ConceptNet:
synonyms.add(node.name)
return synonyms
def sub_features_for_node(self, node):
def sub_features_for_argument(self, argument):
rels = ['UsedFor', 'HasA', 'CapableOf', 'Causes', 'HasSubevent', 'HasProperty', 'MadeOf']
features = set()
......@@ -72,10 +72,13 @@ class ConceptNet:
threads = []
for rel in rels:
t = threading.Thread(target=self.append_result, args=(node.name, rel, features, lock))
t = threading.Thread(target=self.append_result, args=(argument, rel, features, lock))
t.start()
threads.append(t)
for t in threads:
t.join()
return features
cnet = ConceptNet()
print(cnet.find_related('sweater', 'MadeOf'))
......@@ -29,6 +29,9 @@
9449FE4D2404561400025F70 /* ArgumentQuery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9449FE4C2404561400025F70 /* ArgumentQuery.swift */; };
9449FE4F240533FD00025F70 /* QueryOptionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9449FE4E240533FD00025F70 /* QueryOptionView.swift */; };
9449FE5124053DA500025F70 /* ChatManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9449FE5024053DA500025F70 /* ChatManager.swift */; };
945E6BBD2493931300C0DCAC /* ArgumentText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 945E6BBC2493931300C0DCAC /* ArgumentText.swift */; };
945E6BC12494084C00C0DCAC /* SearchView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 945E6BC02494084C00C0DCAC /* SearchView.swift */; };
945E6BC32494097400C0DCAC /* ADAView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 945E6BC22494097400C0DCAC /* ADAView.swift */; };
94BE1EEB2407E26900741749 /* RatingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94BE1EEA2407E26900741749 /* RatingView.swift */; };
94BE1EED240800D800741749 /* InitResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 94BE1EEC240800D800741749 /* InitResponse.swift */; };
/* End PBXBuildFile section */
......@@ -58,6 +61,9 @@
9449FE4C2404561400025F70 /* ArgumentQuery.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArgumentQuery.swift; sourceTree = "<group>"; };
9449FE4E240533FD00025F70 /* QueryOptionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QueryOptionView.swift; sourceTree = "<group>"; };
9449FE5024053DA500025F70 /* ChatManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatManager.swift; sourceTree = "<group>"; };
945E6BBC2493931300C0DCAC /* ArgumentText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArgumentText.swift; sourceTree = "<group>"; };
945E6BC02494084C00C0DCAC /* SearchView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchView.swift; sourceTree = "<group>"; };
945E6BC22494097400C0DCAC /* ADAView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ADAView.swift; sourceTree = "<group>"; };
94BE1EEA2407E26900741749 /* RatingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RatingView.swift; sourceTree = "<group>"; };
94BE1EEC240800D800741749 /* InitResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InitResponse.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
......@@ -95,6 +101,8 @@
9449FE1A2402C84F00025F70 /* AppDelegate.swift */,
9449FE1C2402C84F00025F70 /* SceneDelegate.swift */,
9449FE1E2402C84F00025F70 /* ContentView.swift */,
945E6BC02494084C00C0DCAC /* SearchView.swift */,
945E6BC22494097400C0DCAC /* ADAView.swift */,
9449FE342402CCDA00025F70 /* ConnectionManager.swift */,
94BE1EEC240800D800741749 /* InitResponse.swift */,
9449FE3F2403EDD300025F70 /* Product */,
......@@ -122,6 +130,7 @@
9449FE442403F0A600025F70 /* Sender.swift */,
9449FE382403E9A400025F70 /* Message.swift */,
9449FE3A2403EC3800025F70 /* ADAMessage.swift */,
945E6BBC2493931300C0DCAC /* ArgumentText.swift */,
9449FE4A24042E8800025F70 /* Argument.swift */,
9449FE4C2404561400025F70 /* ArgumentQuery.swift */,
9449FE3C2403ED0200025F70 /* UserMessage.swift */,
......@@ -230,8 +239,11 @@
9449FE452403F0A600025F70 /* Sender.swift in Sources */,
9449FE4D2404561400025F70 /* ArgumentQuery.swift in Sources */,
9449FE4924042D6500025F70 /* FeatureView.swift in Sources */,
945E6BC12494084C00C0DCAC /* SearchView.swift in Sources */,
9449FE312402C90800025F70 /* ChatView.swift in Sources */,
9449FE5124053DA500025F70 /* ChatManager.swift in Sources */,
945E6BC32494097400C0DCAC /* ADAView.swift in Sources */,
945E6BBD2493931300C0DCAC /* ArgumentText.swift in Sources */,
9449FE352402CCDA00025F70 /* ConnectionManager.swift in Sources */,
9449FE1D2402C84F00025F70 /* SceneDelegate.swift in Sources */,
9449FE1F2402C84F00025F70 /* ContentView.swift in Sources */,
......
//
// ProductView.swift
// ADAbot
//
// Created by Joel Oksanen on 12.6.2020.
// Copyright © 2020 Joel Oksanen. All rights reserved.
//
import SwiftUI
struct ADAView: View {
@ObservedObject var connectionManager: ConnectionManager
var drag: some Gesture {
DragGesture()
.onEnded { _ in self.connectionManager.quitMessaging() }
}
var body: some View {
VStack(spacing: 0) {
ProductView(connectionManager: connectionManager)
.zIndex(10)
.gesture(drag)
ChatView(connectionManager: connectionManager)
.zIndex(0)
}
.edgesIgnoringSafeArea(.all)
.background(Color.black)
}
}
......@@ -11,12 +11,37 @@ import UIKit
struct ADAMessage: Message, Decodable, Equatable {
let id = UUID()
let sender = Sender.ADA
let text: String
let text: ArgumentText
let arguments: [Argument]
let sender: Sender = .ADA
static func == (lhs: ADAMessage, rhs: ADAMessage) -> Bool {
lhs.id == rhs.id
}
func getAttributedText() -> NSAttributedString {
let components = text.template.components(separatedBy: "*")
var argumentLocations = [(Int,Int)]()
var textWithArguments = ""
for (i, component) in components.enumerated() {
textWithArguments += component
if i < components.count - 1 {
argumentLocations.append((textWithArguments.count, text.arguments[i].count))
textWithArguments += text.arguments[i]
}
}
let attributes = [NSAttributedString.Key.font: UIFont(name: text.style == .QUOT ? "HelveticaNeue-Italic" : "Helvetica Neue", size: 14)!,
NSAttributedString.Key.foregroundColor: UIColor.white]
let attributedString = NSMutableAttributedString(string: textWithArguments, attributes: attributes)
for (start, len) in argumentLocations {
attributedString.addAttribute(NSAttributedString.Key.font,
value: UIFont(name: text.style == .QUOT ? "HelveticaNeue-BoldItalic" : "HelveticaNeue-Bold", size: 14)!,
range: NSMakeRange(start, len))
// attributedString.addAttribute(NSAttributedString.Key.foregroundColor,
// value: UIColor(red: 140/255, green: 100/255, blue: 15/255, alpha:1.0).cgColor,
// range: NSMakeRange(start, len))
}
return attributedString
}
}
//
// ADAText.swift
// ADAbot
//
// Created by Joel Oksanen on 12.6.2020.
// Copyright © 2020 Joel Oksanen. All rights reserved.
//
import UIKit
struct ArgumentText: Decodable {
let template: String
let arguments: [String]
let style: TextStyle
}
enum TextStyle: String, Decodable {
case ARG
case QUOT
}
......@@ -9,10 +9,12 @@
import UIKit
protocol Message {
var id: UUID { get }
var sender: Sender { get }
var text: String { get }
var arguments: [Argument] { get }
func getAttributedText() -> NSAttributedString
}
......@@ -15,7 +15,7 @@ struct MessageView: View {
Sender.ADA: Color(red: 242/255, green: 159/255, blue: 31/255),
Sender.USER: Color(red: 35/255, green: 45/255, blue: 62/255)
]
let maxWidth: CGFloat = 300
let maxWidth: CGFloat = 260
let message: Message
let query: ArgumentQuery?
......@@ -43,13 +43,11 @@ struct MessageView: View {
Spacer()
}
Text(message.text)
Label(maxWidth: maxWidth, attributedText: self.message.getAttributedText())
.foregroundColor(Color.white)
.font(Font.custom("Helvetica Neue", size: 14))
.fixedSize(horizontal: false, vertical: true)
.fixedSize(horizontal: true, vertical: true)
.padding(EdgeInsets(top: 10, leading: 20, bottom: 10, trailing: 20))
.background(MessageBubble(sender: message.sender).foregroundColor(sent ? bubbleColors[message.sender] : FeatureView.bubbleColor))
.frame(minWidth: 0, maxWidth: maxWidth, alignment: message.sender == .ADA ? .leading : .trailing)
.onTapGesture {
withAnimation(.easeInOut(duration: 0.3)) {
if self.message.sender == .ADA {
......@@ -75,3 +73,21 @@ struct MessageView: View {
.frame(width: UIScreen.main.bounds.width)
}
}
struct Label: UIViewRepresentable {
var maxWidth: CGFloat
var attributedText: NSAttributedString
func makeUIView(context: Context) -> UILabel {
let label = UILabel()
label.lineBreakMode = .byWordWrapping
label.attributedText = attributedText
label.numberOfLines = 0
label.preferredMaxLayoutWidth = maxWidth
return label
}
func updateUIView(_ view: UILabel, context: Context) {
}
}
......@@ -9,12 +9,12 @@
import UIKit
struct UserMessage: Message, Equatable {
let id = UUID()
let sender = Sender.USER
let text: String
let arguments = [Argument]()
let sent: Bool
let sender: Sender = .USER
init(text: String) {
self.text = text
......@@ -30,4 +30,10 @@ struct UserMessage: Message, Equatable {
lhs.id == rhs.id
}
func getAttributedText() -> NSAttributedString {
let attributes = [NSAttributedString.Key.font: UIFont(name: "Helvetica Neue", size: 14)!,
NSAttributedString.Key.foregroundColor: UIColor.white]
return NSAttributedString(string: text, attributes: attributes)
}
}
......@@ -9,34 +9,40 @@
import SwiftUI
class ConnectionManager: ObservableObject {
@Published var product = Product()
@Published var products = [Product]()
@Published var product: Product!
@Published var messaging: Bool = false
@Published var messages: [Message] = [Message]()
private let ip = "192.168.1.104"
private let port = "8000"
private var messageQueue: [Message]? = nil
private var productMap = [String: Product]()
init() {
requestProduct(id: "B000AYW0M2", type: "watch")
requestProducts()
// B00RTGK0N0 - red Canon camera
// B004J3V90Y - Canon T3i
// B0012YA85A - Canon Rebel XSI
// B003ZYF3LO - Nikon D3100
// B0075SUK14 - Backpack
// B000AYW0M2 - Watch
// B000ZKA0J6 - Starcraft game
// B00005UP2N - Silver Mixer
// B0001HLTTI - Another Mixer
}
private func requestProduct(id: String, type: String) {
let url = URL(string: "http://" + ip + ":" + port + "/ios_server/product/?id=" + id + "&type=" + type)!
private func requestProducts() {
let url = URL(string: "http://" + ip + ":" + port + "/ios_server/products")!
let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
guard let data = data else { return }
do {
let resp = try JSONDecoder().decode(InitResponse.self, from: data)
let resp = try JSONDecoder().decode([ProductInfo].self, from: data)
DispatchQueue.main.async {
self.requestImage(at: resp.productInfo.imageURL)
self.product.name = resp.productInfo.name
self.product.starRating = resp.productInfo.starRating
self.addMessage(resp.message)
for productInfo in resp {
self.requestImage(for: productInfo)
}
}
} catch let parseError {
print(parseError)
......@@ -48,20 +54,44 @@ class ConnectionManager: ObservableObject {
task.resume()
}
private func requestImage(at urlString: String) {
let url = URL(string: urlString)!
private func requestImage(for productInfo: ProductInfo) {
let url = URL(string: productInfo.imageURL)!
let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
guard let data = data else { return }
if let image = UIImage(data: data) {
DispatchQueue.main.async {
self.product.image = image
let product = Product(id: productInfo.id, name: productInfo.name, starRating: productInfo.starRating, image: image)
self.productMap[productInfo.id] = product
self.products.append(product)
}
}
}
task.resume()
}
func requestProduct(id: String) {
let url = URL(string: "http://" + ip + ":" + port + "/ios_server/product?id=" + id)!
let task = URLSession.shared.dataTask(with: url) {(data, response, error) in
guard let data = data else { return }
do {
let resp = try JSONDecoder().decode(ADAMessage.self, from: data)
DispatchQueue.main.async {
self.addMessage(resp)
self.product = self.productMap[id]
self.messaging = true
}
} catch let parseError {
print(parseError)
DispatchQueue.main.async {
// Handle error in UI
}
}
}
task.resume()
}
func sendQuery(_ query: ArgumentQuery) {
let url = URL(string: "http://" + ip + ":" + port + "/ios_server/message/")!
var request = URLRequest(url: url)
......@@ -86,6 +116,7 @@ class ConnectionManager: ObservableObject {
mimeType == "application/json",
let receivedData = receivedData {
do {
print(receivedData)
let resp = try JSONDecoder().decode(ADAMessage.self, from: receivedData)
DispatchQueue.main.async {
self.addMessage(resp)
......@@ -122,6 +153,14 @@ class ConnectionManager: ObservableObject {
}
}
func quitMessaging() {
self.messaging = false
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
self.messages = [Message]()
self.product = nil
}
}
private func handleClientError(error: Error) {
print("Client error occurred")
}
......
......@@ -10,15 +10,16 @@ import SwiftUI
struct ContentView: View {
@ObservedObject var connectionManager = ConnectionManager()
@State private var searching: Bool = true
var body: some View {
VStack(spacing: 0) {
ProductView(connectionManager: connectionManager)
.zIndex(10)
ChatView(connectionManager: connectionManager)
.zIndex(0)
if !connectionManager.messaging {
SearchView(connectionManager: connectionManager)
} else {
ADAView(connectionManager: connectionManager)
}
}
.edgesIgnoringSafeArea(.all)
.background(Color.black)
}
}
......
......@@ -8,16 +8,11 @@
import UIKit
struct Product {
struct Product: Identifiable {
var id: String
var name: String
var starRating: Double
var image: UIImage
init() {
self.name = ""
self.starRating = 0
self.image = UIImage()
}
}
//
// Product.swift
// ProductInfo.swift
// ADAbot
//
// Created by Joel Oksanen on 23.2.2020.
......
......@@ -22,11 +22,11 @@ struct ProductView: View {
VStack {
Spacer()
HStack(alignment: .top) {
VStack {
VStack(alignment: .leading) {
Text(connectionManager.product.name)
.font(Font.custom("Helvetica Neue", size: 14))
.foregroundColor(Color.gray)
RatingView(starRating: $connectionManager.product.starRating)
RatingView(starRating: connectionManager.product.starRating)
}
Spacer()
Image(uiImage: connectionManager.product.image)
......@@ -40,6 +40,6 @@ struct ProductView: View {
.frame(height: height)
}
}
}
......@@ -10,7 +10,7 @@ import SwiftUI
struct RatingView: View {
let dim: CGFloat = 16
@Binding var starRating: Double
var starRating: Double
var fullStars: Int {
get {
return Int(starRating.rounded(.down))
......
//
// SearchView.swift
// ADAbot
//
// Created by Joel Oksanen on 12.6.2020.
// Copyright © 2020 Joel Oksanen. All rights reserved.
//
import SwiftUI
struct SearchView: View {
@ObservedObject var connectionManager: ConnectionManager
let height: CGFloat = 120
var body: some View {
VStack(spacing: 0) {
ZStack {
Rectangle()
.foregroundColor(Color.white)
.frame(height: height)
.shadow(color: Color(.sRGB, white: 0, opacity: 0.1), radius: 10, x: 0, y: 0)
VStack {
Spacer()
.frame(height: 30)
HStack {
Text("Products")
.font(Font.custom("HelveticaNeue-Bold", size: 28))
.foregroundColor(Color.gray)
.padding(EdgeInsets(top: 0, leading: 30, bottom: 0, trailing: 0))
Spacer()
}
}
}
.zIndex(10)
List(connectionManager.products) { product in
ProductRow(product: product)
.onTapGesture {
self.connectionManager.requestProduct(id: product.id)
}
}
}
.edgesIgnoringSafeArea(.all)
}
}
struct ProductRow: View {
var product: Product
var body: some View {
HStack(spacing: 0) {
Image(uiImage: product.image)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 100, height: 100)
.border(Color(white: 0.85), width: 1)
.padding(EdgeInsets(top: 10, leading: 0, bottom: 10, trailing: 20))
VStack {
Text(product.name)
.font(Font.custom("Helvetica Neue", size: 14))
.foregroundColor(Color.gray)
RatingView(starRating: product.starRating)
}
}
}
}
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:ADAgraph.xcodeproj">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>