Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
What's new
7
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Open sidebar
Joel Oksanen
individual_project
Commits
21fae9ef
Commit
21fae9ef
authored
Jun 21, 2020
by
Joel Oksanen
Browse files
Options
Browse Files
Download
Plain Diff
Merge branch 'master' of
https://gitlab.doc.ic.ac.uk/jjo2317/individual_project
parents
8416bbe7
20127e20
Changes
63
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
63 changed files
with
4085 additions
and
212 deletions
+4085
-212
ADA/.gitignore
ADA/.gitignore
+1
-0
ADA/server/agent/SA/annotated_5_products_reviews_2.xml
ADA/server/agent/SA/annotated_5_products_reviews_2.xml
+2203
-0
ADA/server/agent/prep_metadata.py
ADA/server/agent/prep_metadata.py
+1
-8
ADA/server/agent/target_extraction/concept_net.py
ADA/server/agent/target_extraction/concept_net.py
+6
-3
ADAbot/ADAbot.xcodeproj/project.pbxproj
ADAbot/ADAbot.xcodeproj/project.pbxproj
+12
-0
ADAbot/ADAbot.xcodeproj/project.xcworkspace/xcuserdata/joeloksanen.xcuserdatad/UserInterfaceState.xcuserstate
...ta/joeloksanen.xcuserdatad/UserInterfaceState.xcuserstate
+0
-0
ADAbot/ADAbot/ADAView.swift
ADAbot/ADAbot/ADAView.swift
+30
-0
ADAbot/ADAbot/Chat/ADAMessage.swift
ADAbot/ADAbot/Chat/ADAMessage.swift
+27
-2
ADAbot/ADAbot/Chat/ArgumentText.swift
ADAbot/ADAbot/Chat/ArgumentText.swift
+24
-0
ADAbot/ADAbot/Chat/Message.swift
ADAbot/ADAbot/Chat/Message.swift
+4
-2
ADAbot/ADAbot/Chat/MessageView.swift
ADAbot/ADAbot/Chat/MessageView.swift
+21
-5
ADAbot/ADAbot/Chat/UserMessage.swift
ADAbot/ADAbot/Chat/UserMessage.swift
+8
-2
ADAbot/ADAbot/ConnectionManager.swift
ADAbot/ADAbot/ConnectionManager.swift
+51
-12
ADAbot/ADAbot/ContentView.swift
ADAbot/ADAbot/ContentView.swift
+6
-5
ADAbot/ADAbot/Product/Product.swift
ADAbot/ADAbot/Product/Product.swift
+2
-7
ADAbot/ADAbot/Product/ProductInfo.swift
ADAbot/ADAbot/Product/ProductInfo.swift
+1
-1
ADAbot/ADAbot/Product/ProductView.swift
ADAbot/ADAbot/Product/ProductView.swift
+3
-3
ADAbot/ADAbot/Product/RatingView.swift
ADAbot/ADAbot/Product/RatingView.swift
+1
-1
ADAbot/ADAbot/SearchView.swift
ADAbot/ADAbot/SearchView.swift
+66
-0
ADAgraph/ADAgraph.xcodeproj/project.pbxproj
ADAgraph/ADAgraph.xcodeproj/project.pbxproj
+433
-0
ADAgraph/ADAgraph.xcodeproj/project.xcworkspace/contents.xcworkspacedata
...ph.xcodeproj/project.xcworkspace/contents.xcworkspacedata
+7
-0
ADAgraph/ADAgraph.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
...project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
+8
-0
ADAgraph/ADAgraph.xcodeproj/project.xcworkspace/xcuserdata/joeloksanen.xcuserdatad/UserInterfaceState.xcuserstate
...ta/joeloksanen.xcuserdatad/UserInterfaceState.xcuserstate
+0
-0
ADAgraph/ADAgraph.xcodeproj/xcuserdata/joeloksanen.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
...loksanen.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
+24
-0
ADAgraph/ADAgraph.xcodeproj/xcuserdata/joeloksanen.xcuserdatad/xcschemes/xcschememanagement.plist
...oeloksanen.xcuserdatad/xcschemes/xcschememanagement.plist
+14
-0
ADAgraph/ADAgraph/AppDelegate.swift
ADAgraph/ADAgraph/AppDelegate.swift
+35
-0
ADAgraph/ADAgraph/Argument.swift
ADAgraph/ADAgraph/Argument.swift
+48
-0
ADAgraph/ADAgraph/Assets.xcassets/AppIcon.appiconset/Contents.json
...ADAgraph/Assets.xcassets/AppIcon.appiconset/Contents.json
+98
-0
ADAgraph/ADAgraph/Assets.xcassets/Contents.json
ADAgraph/ADAgraph/Assets.xcassets/Contents.json
+6
-0
ADAgraph/ADAgraph/Assets.xcassets/star_border.imageset/Contents.json
...Agraph/Assets.xcassets/star_border.imageset/Contents.json
+0
-0
ADAgraph/ADAgraph/Assets.xcassets/star_border.imageset/star_border.png
...raph/Assets.xcassets/star_border.imageset/star_border.png
+0
-0
ADAgraph/ADAgraph/Assets.xcassets/star_fill.imageset/Contents.json
...ADAgraph/Assets.xcassets/star_fill.imageset/Contents.json
+0
-0
ADAgraph/ADAgraph/Assets.xcassets/star_fill.imageset/star_fill.png
...ADAgraph/Assets.xcassets/star_fill.imageset/star_fill.png
+0
-0
ADAgraph/ADAgraph/Base.lproj/LaunchScreen.storyboard
ADAgraph/ADAgraph/Base.lproj/LaunchScreen.storyboard
+25
-0
ADAgraph/ADAgraph/ConnectionManager.swift
ADAgraph/ADAgraph/ConnectionManager.swift
+58
-0
ADAgraph/ADAgraph/ContentView.swift
ADAgraph/ADAgraph/ContentView.swift
+24
-0
ADAgraph/ADAgraph/Info.plist
ADAgraph/ADAgraph/Info.plist
+60
-0
ADAgraph/ADAgraph/Preview Content/Preview Assets.xcassets/Contents.json
...aph/Preview Content/Preview Assets.xcassets/Contents.json
+6
-0
ADAgraph/ADAgraph/ProductData.swift
ADAgraph/ADAgraph/ProductData.swift
+16
-0
ADAgraph/ADAgraph/SceneDelegate.swift
ADAgraph/ADAgraph/SceneDelegate.swift
+66
-0
individual_project_report/SA/SA.tex
individual_project_report/SA/SA.tex
+151
-4
individual_project_report/appendix/appendix.tex
individual_project_report/appendix/appendix.tex
+63
-57
individual_project_report/background/background.tex
individual_project_report/background/background.tex
+36
-31
individual_project_report/bibs/references.bib
individual_project_report/bibs/references.bib
+9
-0
individual_project_report/conclusion/conclusion.tex
individual_project_report/conclusion/conclusion.tex
+27
-2
individual_project_report/feature_extraction/feature_extraction.tex
..._project_report/feature_extraction/feature_extraction.tex
+94
-44
individual_project_report/feature_extraction/selection_screen.png
...al_project_report/feature_extraction/selection_screen.png
+0
-0
individual_project_report/images/ada_architecture.png
individual_project_report/images/ada_architecture.png
+0
-0
individual_project_report/images/ada_graph.png
individual_project_report/images/ada_graph.png
+0
-0
individual_project_report/images/exp1.png
individual_project_report/images/exp1.png
+0
-0
individual_project_report/images/exp2.png
individual_project_report/images/exp2.png
+0
-0
individual_project_report/images/exp3.png
individual_project_report/images/exp3.png
+0
-0
individual_project_report/images/mixer_example_1.png
individual_project_report/images/mixer_example_1.png
+0
-0
individual_project_report/images/mixer_example_2.png
individual_project_report/images/mixer_example_2.png
+0
-0
individual_project_report/images/selection_screen.png
individual_project_report/images/selection_screen.png
+0
-0
individual_project_report/images/sentiment_annotation.png
individual_project_report/images/sentiment_annotation.png
+0
-0
individual_project_report/images/sentiment_annotator.png
individual_project_report/images/sentiment_annotator.png
+0
-0
individual_project_report/images/sentiment_bert.png
individual_project_report/images/sentiment_bert.png
+0
-0
individual_project_report/images/watch_screenshot.png
individual_project_report/images/watch_screenshot.png
+0
-0
individual_project_report/introduction/introduction.tex
individual_project_report/introduction/introduction.tex
+17
-16
individual_project_report/main.pdf
individual_project_report/main.pdf
+0
-0
individual_project_report/main.tex
individual_project_report/main.tex
+17
-3
individual_project_report/system/system.tex
individual_project_report/system/system.tex
+276
-4
No files found.
ADA/.gitignore
View file @
21fae9ef
...
...
@@ -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/
...
...
ADA/server/agent/SA/annotated_5_products_reviews_2.xml
0 → 100644
View file @
21fae9ef
This diff is collapsed.
Click to expand it.
ADA/server/agent/prep_metadata.py
View file @
21fae9ef
...
...
@@ -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
ADA/server/agent/target_extraction/concept_net.py
View file @
21fae9ef
...
...
@@ -6,7 +6,7 @@ import time
class
ConceptNet
:
url
=
'http://api.conceptnet.io'
limit
=
5
limit
=
5
0
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'
))
ADAbot/ADAbot.xcodeproj/project.pbxproj
View file @
21fae9ef
...
...
@@ -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 */
,
...
...
ADAbot/ADAbot.xcodeproj/project.xcworkspace/xcuserdata/joeloksanen.xcuserdatad/UserInterfaceState.xcuserstate
View file @
21fae9ef
No preview for this file type
ADAbot/ADAbot/ADAView.swift
0 → 100644
View file @
21fae9ef
//
// 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
)
}
}
ADAbot/ADAbot/Chat/ADAMessage.swift
View file @
21fae9ef
...
...
@@ -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
}
}
ADAbot/ADAbot/Chat/ArgumentText.swift
0 → 100644
View file @
21fae9ef
//
// 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
}
ADAbot/ADAbot/Chat/Message.swift
View file @
21fae9ef
...
...
@@ -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
}
ADAbot/ADAbot/Chat/MessageView.swift
View file @
21fae9ef
...
...
@@ -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
=
30
0
let
maxWidth
:
CGFloat
=
26
0
let
message
:
Message
let
query
:
ArgumentQuery
?
...
...
@@ -43,13 +43,11 @@ struct MessageView: View {
Spacer
()
}
Text
(
message
.
t
ext
)
Label
(
maxWidth
:
maxWidth
,
attributedText
:
self
.
message
.
getAttributedT
ext
()
)
.
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
)
{
}
}
ADAbot/ADAbot/Chat/UserMessage.swift
View file @
21fae9ef
...
...
@@ -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
)
}
}
ADAbot/ADAbot/ConnectionManager.swift
View file @
21fae9ef
...
...
@@ -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"
)
requestProduct
s
()
// 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
requestProduct
s
()
{
let
url
=
URL
(
string
:
"http://"
+
ip
+
":"
+
port
+
"/ios_server/product
s"
)
!
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"
)
}
...
...
ADAbot/ADAbot/ContentView.swift
View file @
21fae9ef
...
...
@@ -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
)
}
}
...
...
ADAbot/ADAbot/Product/Product.swift
View file @
21fae9ef
...
...
@@ -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
()
}
}
ADAbot/ADAbot/Product/ProductInfo.swift
View file @
21fae9ef
//
// Product.swift
// Product
Info
.swift
// ADAbot
//
// Created by Joel Oksanen on 23.2.2020.
...
...
ADAbot/ADAbot/Product/ProductView.swift
View file @
21fae9ef
...
...
@@ -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
)
}
}
}
ADAbot/ADAbot/Product/RatingView.swift
View file @
21fae9ef
...
...
@@ -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
))
...
...
ADAbot/ADAbot/SearchView.swift
0 → 100644
View file @
21fae9ef
//
// 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
{