├── .swift-version
├── NewsClassifier
├── Screenshot.png
├── Assets.xcassets
│ ├── Contents.json
│ ├── AppIcon.appiconset
│ │ ├── icon_20.png
│ │ ├── icon_29.png
│ │ ├── icon_40.png
│ │ ├── icon_58.png
│ │ ├── icon_60.png
│ │ ├── icon_76.png
│ │ ├── icon_80.png
│ │ ├── icon_87.png
│ │ ├── icon_1024.png
│ │ ├── icon_120-1.png
│ │ ├── icon_120.png
│ │ ├── icon_152.png
│ │ ├── icon_167.png
│ │ ├── icon_180.png
│ │ ├── icon_40-1.png
│ │ ├── icon_40-2.png
│ │ ├── icon_58-1.png
│ │ ├── icon_80-1.png
│ │ └── Contents.json
│ ├── App.colorset
│ │ └── Contents.json
│ ├── Business.colorset
│ │ └── Contents.json
│ ├── Politics.colorset
│ │ └── Contents.json
│ ├── Sports.colorset
│ │ └── Contents.json
│ ├── Technology.colorset
│ │ └── Contents.json
│ └── Entertainment.colorset
│ │ └── Contents.json
├── AppDelegate.swift
├── Info.plist
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
└── ViewController.swift
├── Sources
├── DocumentClassification.mlmodel
├── Info.plist
├── DocumentClassifier.h
├── Classification.swift
└── DocumentClassifier.swift
├── DocumentClassifier.xcodeproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ └── IDEWorkspaceChecks.plist
├── xcshareddata
│ └── xcschemes
│ │ ├── DocumentClassifierWatch.xcscheme
│ │ ├── DocumentClassifierTV.xcscheme
│ │ ├── DocumentClassifierMac.xcscheme
│ │ └── DocumentClassifierMobile.xcscheme
└── project.pbxproj
├── DocumentClassifier.podspec
├── Tests
├── Info.plist
├── Resources
│ ├── Entertainment.txt
│ ├── Business.txt
│ ├── Sports.txt
│ ├── Politics.txt
│ └── Technology.txt
└── DocumentClassifierTests.swift
├── LICENSE
├── .gitignore
└── README.md
/.swift-version:
--------------------------------------------------------------------------------
1 | 5.0
2 |
--------------------------------------------------------------------------------
/NewsClassifier/Screenshot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toddkramer/DocumentClassifier/HEAD/NewsClassifier/Screenshot.png
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/Sources/DocumentClassification.mlmodel:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toddkramer/DocumentClassifier/HEAD/Sources/DocumentClassification.mlmodel
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_20.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toddkramer/DocumentClassifier/HEAD/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_20.png
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_29.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toddkramer/DocumentClassifier/HEAD/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_29.png
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_40.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toddkramer/DocumentClassifier/HEAD/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_40.png
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_58.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toddkramer/DocumentClassifier/HEAD/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_58.png
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toddkramer/DocumentClassifier/HEAD/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_60.png
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toddkramer/DocumentClassifier/HEAD/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_76.png
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_80.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toddkramer/DocumentClassifier/HEAD/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_80.png
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_87.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toddkramer/DocumentClassifier/HEAD/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_87.png
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_1024.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toddkramer/DocumentClassifier/HEAD/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_1024.png
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_120-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toddkramer/DocumentClassifier/HEAD/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_120-1.png
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toddkramer/DocumentClassifier/HEAD/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_120.png
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toddkramer/DocumentClassifier/HEAD/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_152.png
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_167.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toddkramer/DocumentClassifier/HEAD/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_167.png
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toddkramer/DocumentClassifier/HEAD/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_180.png
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_40-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toddkramer/DocumentClassifier/HEAD/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_40-1.png
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_40-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toddkramer/DocumentClassifier/HEAD/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_40-2.png
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_58-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toddkramer/DocumentClassifier/HEAD/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_58-1.png
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_80-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/toddkramer/DocumentClassifier/HEAD/NewsClassifier/Assets.xcassets/AppIcon.appiconset/icon_80-1.png
--------------------------------------------------------------------------------
/DocumentClassifier.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/DocumentClassifier.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/App.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | },
6 | "colors" : [
7 | {
8 | "idiom" : "universal",
9 | "color" : {
10 | "color-space" : "srgb",
11 | "components" : {
12 | "red" : "0.000",
13 | "alpha" : "1.000",
14 | "blue" : "1.000",
15 | "green" : "0.498"
16 | }
17 | }
18 | }
19 | ]
20 | }
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/Business.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | },
6 | "colors" : [
7 | {
8 | "idiom" : "universal",
9 | "color" : {
10 | "color-space" : "srgb",
11 | "components" : {
12 | "red" : "0.000",
13 | "alpha" : "1.000",
14 | "blue" : "0.000",
15 | "green" : "0.357"
16 | }
17 | }
18 | }
19 | ]
20 | }
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/Politics.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | },
6 | "colors" : [
7 | {
8 | "idiom" : "universal",
9 | "color" : {
10 | "color-space" : "srgb",
11 | "components" : {
12 | "red" : "0.889",
13 | "alpha" : "1.000",
14 | "blue" : "0.000",
15 | "green" : "0.789"
16 | }
17 | }
18 | }
19 | ]
20 | }
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/Sports.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | },
6 | "colors" : [
7 | {
8 | "idiom" : "universal",
9 | "color" : {
10 | "color-space" : "srgb",
11 | "components" : {
12 | "red" : "0.608",
13 | "alpha" : "1.000",
14 | "blue" : "0.000",
15 | "green" : "0.000"
16 | }
17 | }
18 | }
19 | ]
20 | }
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/Technology.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | },
6 | "colors" : [
7 | {
8 | "idiom" : "universal",
9 | "color" : {
10 | "color-space" : "srgb",
11 | "components" : {
12 | "red" : "1.000",
13 | "alpha" : "1.000",
14 | "blue" : "0.000",
15 | "green" : "0.498"
16 | }
17 | }
18 | }
19 | ]
20 | }
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/Entertainment.colorset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | },
6 | "colors" : [
7 | {
8 | "idiom" : "universal",
9 | "color" : {
10 | "color-space" : "srgb",
11 | "components" : {
12 | "red" : "0.373",
13 | "alpha" : "1.000",
14 | "blue" : "0.749",
15 | "green" : "0.000"
16 | }
17 | }
18 | }
19 | ]
20 | }
--------------------------------------------------------------------------------
/DocumentClassifier.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |s|
2 | s.name = 'DocumentClassifier'
3 | s.version = '1.2.0'
4 | s.license = 'MIT'
5 | s.summary = 'Swift framework for document classification using a Core ML model.'
6 | s.homepage = 'https://github.com/toddkramer/DocumentClassifier'
7 | s.social_media_url = 'http://twitter.com/_toddkramer'
8 | s.author = 'Todd Kramer'
9 | s.source = { :git => 'https://github.com/toddkramer/DocumentClassifier.git', :tag => s.version }
10 |
11 | s.module_name = 'DocumentClassifier'
12 | s.ios.deployment_target = '11.0'
13 | s.osx.deployment_target = '10.13'
14 | s.tvos.deployment_target = '11.0'
15 | s.watchos.deployment_target = '4.0'
16 |
17 | s.source_files = 'Sources/*.{swift,mlmodel}'
18 | end
19 |
--------------------------------------------------------------------------------
/Tests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/Sources/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.2.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Todd Kramer
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Sources/DocumentClassifier.h:
--------------------------------------------------------------------------------
1 | //
2 | // DocumentClassifier.h
3 | //
4 | // Copyright (c) 2017 Todd Kramer (http://www.tekramer.com)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | @import Foundation;
26 |
27 | FOUNDATION_EXPORT double DocumentClassifierVersionNumber;
28 | FOUNDATION_EXPORT const unsigned char DocumentClassifierVersionString[];
29 |
--------------------------------------------------------------------------------
/NewsClassifier/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | //
4 | // Copyright (c) 2017 Todd Kramer (http://www.tekramer.com)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import UIKit
26 |
27 | @UIApplicationMain
28 | class AppDelegate: UIResponder, UIApplicationDelegate {
29 |
30 | var window: UIWindow?
31 |
32 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
33 | return true
34 | }
35 |
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 | .DS_Store
9 |
10 | ## Various settings
11 | *.pbxuser
12 | !default.pbxuser
13 | *.mode1v3
14 | !default.mode1v3
15 | *.mode2v3
16 | !default.mode2v3
17 | *.perspectivev3
18 | !default.perspectivev3
19 | xcuserdata/
20 |
21 | ## Other
22 | *.moved-aside
23 | *.xccheckout
24 | *.xcscmblueprint
25 |
26 | ## Obj-C/Swift specific
27 | *.hmap
28 | *.ipa
29 | *.dSYM.zip
30 | *.dSYM
31 |
32 | ## Playgrounds
33 | timeline.xctimeline
34 | playground.xcworkspace
35 |
36 | # Swift Package Manager
37 | #
38 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
39 | # Packages/
40 | # Package.pins
41 | .build/
42 |
43 | # CocoaPods
44 | #
45 | # We recommend against adding the Pods directory to your .gitignore. However
46 | # you should judge for yourself, the pros and cons are mentioned at:
47 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
48 | #
49 | # Pods/
50 |
51 | # Carthage
52 | #
53 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
54 | # Carthage/Checkouts
55 |
56 | Carthage/Build
57 |
58 | # fastlane
59 | #
60 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
61 | # screenshots whenever they are needed.
62 | # For more information about the recommended setup visit:
63 | # https://docs.fastlane.tools/best-practices/source-control/#source-control
64 |
65 | fastlane/report.xml
66 | fastlane/Preview.html
67 | fastlane/screenshots
68 | fastlane/test_output
69 |
--------------------------------------------------------------------------------
/Tests/Resources/Entertainment.txt:
--------------------------------------------------------------------------------
1 | Hollywood hunts hits at Sundance
2 |
3 | The Sundance Film Festival, the movie industry's top destination for uncovering the next independent hits and new talent, opens on Thursday.
4 |
5 | The event will see screen executives decamp from Hollywood to Park City, Utah, for 11 days to search for low-key movies that could make it big in 2005. Open Water, Napoleon Dynamite, Garden State and Super-Size Me were all snapped up at last year's festival. But stars like Keanu Reeves and Pierce Brosnan also have films showing there. The festival is being opened by a screening of quirky comedy Happy Endings, starring former Friends actress Lisa Kudrow and Maggie Gyllenhaal, on Thursday.
6 |
7 | Kudrow's Friends co-star, David Schwimmer, plays a divorced drunkard in Duane Hopwood, while Brosnan stars as a hit man in comedy The Matador. Keanu Reeves appears in coming-of-age tale Thumbsucker while Kevin Costner and Michael Keaton are among the other big names whose films are involved. Robert Redford founded Sundance in 1981 and it has gone on to showcase future successes such as Reservoir Dogs, The Blair Witch Project and The Full Monty. But it has received criticism that it has become more commercial and mainstream over the years. "As much as the press argues that Sundance has completely changed, it hasn't changed that much," festival director Geoffrey Gilmore said. "It's still a place for discovery. It's a place for common ground among film-makers and audiences more than it is the celebrity stuff." Other films generating interest before this year's festival include Hustle & Flow, about an aspiring rapper, The Squid and the Whale, an autobiographical film by writer-director Noah Baumbach, and comedy/drama Pretty Persuasion. It also has two new international cinema competitions.
8 |
--------------------------------------------------------------------------------
/NewsClassifier/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | $(DEVELOPMENT_LANGUAGE)
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | NSAppTransportSecurity
20 |
21 | NSAllowsArbitraryLoadsInWebContent
22 |
23 |
24 | CFBundleVersion
25 | 1
26 | LSRequiresIPhoneOS
27 |
28 | UILaunchStoryboardName
29 | LaunchScreen
30 | UIMainStoryboardFile
31 | Main
32 | UIRequiredDeviceCapabilities
33 |
34 | armv7
35 |
36 | UISupportedInterfaceOrientations
37 |
38 | UIInterfaceOrientationPortrait
39 | UIInterfaceOrientationLandscapeLeft
40 | UIInterfaceOrientationLandscapeRight
41 |
42 | UISupportedInterfaceOrientations~ipad
43 |
44 | UIInterfaceOrientationPortrait
45 | UIInterfaceOrientationPortraitUpsideDown
46 | UIInterfaceOrientationLandscapeLeft
47 | UIInterfaceOrientationLandscapeRight
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/Tests/Resources/Business.txt:
--------------------------------------------------------------------------------
1 | Brazil plays down Varig rescue
2 |
3 | The Brazilian government has played down claims that it could step in to save the country's biggest airline.
4 |
5 | Brazil's airport authority chief Carlos Wilson had claimed the government was on the brink of stepping in to save Varig, Brazil's flagship airline. However, the country's vice president Jose Alencar has said the government still is looking for a solution. Varig is struggling under a huge debt burden of an estimated debt of 6.5 billion reais ($2.3bn or £1.2bn). Asked whether a rescue was on the cards following a meeting of the country's Congress to discuss the airline's crisis, Mr Alencar replied: "No, I don't think so. We will see."
6 |
7 | Earlier, Mr Wilson had said that president Luiz Inacio Lula da Silva has decided to step in and a decree of some kind of intervention could be signed this week. "In practice, it will be an intervention, although this is not the technical name used", he said. An intervention means that the government would take administrative control of the company and its finances. For that to happen Varig's main shareholder, the non-profit Ruben Berta Foundation which represents the airline's employees, would have to be removed, Mr Wilson said. However, no jobs would be lost and the airline would keep on flying, he added. Varig, which operates in 18 countries apart from Brazil, has been driven to the brink of collapse because of the country's economic downturn.
8 |
9 | The depreciation of Brazil's currency has had a direct impact on the airline's dollar debt as well as some of its costs. Business has improved recently with demand for air travel increasing and a recovery in the Brazilian economy. The airline could also win a sizeable windfall from a compensation claim against the government. On Tuesday the courts awarded Varig 2bn reais ($725m), after ruling in favour of its compensation claim against the government for freezing tariffs from 1985 to 1992. But the government can appeal the decision.
10 |
--------------------------------------------------------------------------------
/Tests/Resources/Sports.txt:
--------------------------------------------------------------------------------
1 | Jones happy with Henson heroics
2 |
3 | Wales fly-half Stephen Jones admitted he was happy to hand Gavin Henson responsibility for taking the match-winning kick against England.
4 |
5 | Jones had missed three earlier shots at goal when Wales, 9-8 down, were awarded a long-range penalty with four minutes left in Cardiff. "I knew the percentages of Gavin reaching it were far higher than me," Jones said. "When he said he wanted it, there were no problems." Jones had seen a long-range effort fall a whisker under the crossbar on the hour, before Charlie Hodgson put England in front with 10 minutes left. "I looked at where it was and I knew I was going to struggle to make it," Jones added. "I said to Gareth (Thomas, the Wales captain) 'This is touch and go.' It was out of my range and obviously Gavin is phenomenal when it comes to distance. He was confident and fancied it. "There were no questions that he'd miss it the way he was playing. He had a superb game." Jones was happy to hail Henson's heroic contribution to Wales' first win over England in Cardiff since 1993. "Physically he's a specimen: he's a balanced player, he glides when he runs and obviously he's got a great kicking game as well," Jones said.
6 |
7 | "His defence was superb, he made some great hits and he had a great game. "I'm glad he's Welsh." Victory over England for the first time since 1999 will no doubt fuel expectations of what Wales might achieve in this year's Six Nations. But they now face three away fixtures in Italy, France and Scotland before completing their campaign against Ireland in Cardiff. "People all over the world want to see Wales back at the top table of world rugby," said a proud coach Mike Ruddock. "But we are not there yet. The next step is finding the consistency to get further wins. "We have to travel this week and we can't afford to get too giddy about this result. "We have got to be professional and keep focused on facing Italy."
8 |
9 | None more so than Henson, who can now expect to have the same sort of spotlight thrust upon him as the likes of Jonny Wilkinson and Brian O'Driscoll. The confident 23-year-old is undaunted by the prospect of dealing with such weighty expectations however. "I'm the sort of player who likes pressure on me," he said. "It makes me more concentrated and I think I perform better under more pressure. "I set a high standard against England and I've got to back it up next week. "Two years ago when we played Italy I wasn't involved and we lost, so we've got to put that right next week."
10 |
--------------------------------------------------------------------------------
/Tests/DocumentClassifierTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DocumentClassifierTests.swift
3 | //
4 | // Copyright (c) 2017 Todd Kramer (http://www.tekramer.com)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import XCTest
26 | @testable import DocumentClassifier
27 |
28 | class DocumentClassifierTests: XCTestCase {
29 |
30 | let classifier = DocumentClassifier()
31 | let categories = ["Business", "Entertainment", "Politics", "Sports", "Technology"]
32 |
33 | let bundle = Bundle(for: DocumentClassifierTests.self)
34 |
35 | func testClassifiy() {
36 | categories.forEach {
37 | let path = bundle.path(forResource: $0, ofType: "txt")!
38 | let url = URL(fileURLWithPath: path)
39 | let text = try! String(contentsOf: url)
40 | let classification = classifier.classify(text)!
41 | let expectedCategory = Classification.Category(rawValue: $0)!
42 | XCTAssertEqual(classification.prediction.category, expectedCategory)
43 | }
44 | XCTAssertNil(classifier.classify("technology"))
45 | }
46 |
47 | func testNilClassificationFromOutput() {
48 | let output = DocumentClassificationOutput(classLabel: "random", classProbability: ["random": 0.4])
49 | XCTAssertNil(Classification(output: output))
50 | }
51 |
52 | func testNilResultFromClassProbability() {
53 | XCTAssertNil(Classification.result(from: ("random", 0.4)))
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/Sources/Classification.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Classification.swift
3 | //
4 | // Copyright (c) 2017 Todd Kramer (http://www.tekramer.com)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | public struct Classification {
28 |
29 | public enum Category: String {
30 | case business = "Business"
31 | case entertainment = "Entertainment"
32 | case politics = "Politics"
33 | case sports = "Sports"
34 | case technology = "Technology"
35 | }
36 |
37 | public struct Result {
38 | public let category: Category
39 | public let probability: Double
40 | }
41 |
42 | public let prediction: Result
43 | public let allResults: [Result]
44 |
45 | }
46 |
47 | extension Classification {
48 |
49 | init?(output: DocumentClassificationOutput) {
50 | guard let category = Category(rawValue: output.classLabel),
51 | let probability = output.classProbability[output.classLabel]
52 | else { return nil }
53 | let prediction = Result(category: category, probability: probability)
54 | let allResults = output.classProbability.compactMap(Classification.result)
55 | self.init(prediction: prediction, allResults: allResults)
56 | }
57 |
58 | static func result(from classProbability: (key: String, value: Double)) -> Result? {
59 | guard let category = Category(rawValue: classProbability.key) else { return nil }
60 | return Result(category: category, probability: classProbability.value)
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Sources/DocumentClassifier.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DocumentClassifier.swift
3 | //
4 | // Copyright (c) 2017 Todd Kramer (http://www.tekramer.com)
5 | //
6 | // Permission is hereby granted, free of charge, to any person obtaining a copy
7 | // of this software and associated documentation files (the "Software"), to deal
8 | // in the Software without restriction, including without limitation the rights
9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | // copies of the Software, and to permit persons to whom the Software is
11 | // furnished to do so, subject to the following conditions:
12 | //
13 | // The above copyright notice and this permission notice shall be included in
14 | // all copies or substantial portions of the Software.
15 | //
16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 | // THE SOFTWARE.
23 | //
24 |
25 | import Foundation
26 |
27 | public final class DocumentClassifier {
28 |
29 | public init() {}
30 |
31 | private let model = DocumentClassification()
32 | private let options: NSLinguisticTagger.Options = [.omitWhitespace, .omitPunctuation, .omitOther]
33 | private lazy var tagger: NSLinguisticTagger = {
34 | let tagSchemes = NSLinguisticTagger.availableTagSchemes(forLanguage: "en")
35 | return NSLinguisticTagger(tagSchemes: tagSchemes, options: Int(self.options.rawValue))
36 | }()
37 |
38 | public func classify(_ text: String) -> Classification? {
39 | let features = extractFeatures(from: text)
40 | guard
41 | features.count > 2,
42 | let output = try? model.prediction(input: features) else { return nil }
43 | return Classification(output: output)
44 | }
45 |
46 | func extractFeatures(from text: String) -> [String: Double] {
47 | var wordCounts = [String: Double]()
48 | tagger.string = text
49 | let range = NSRange(location: 0, length: text.count)
50 | tagger.enumerateTags(in: range, scheme: .tokenType, options: options) { _, tokenRange, _, _ in
51 | let token = (text as NSString).substring(with: tokenRange).lowercased()
52 | guard token.count >= 3 else { return }
53 | guard let value = wordCounts[token] else {
54 | wordCounts[token] = 1.0
55 | return
56 | }
57 | wordCounts[token] = value + 1.0
58 | }
59 | return wordCounts
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/NewsClassifier/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "size" : "20x20",
5 | "idiom" : "iphone",
6 | "filename" : "icon_40-2.png",
7 | "scale" : "2x"
8 | },
9 | {
10 | "size" : "20x20",
11 | "idiom" : "iphone",
12 | "filename" : "icon_60.png",
13 | "scale" : "3x"
14 | },
15 | {
16 | "size" : "29x29",
17 | "idiom" : "iphone",
18 | "filename" : "icon_58.png",
19 | "scale" : "2x"
20 | },
21 | {
22 | "size" : "29x29",
23 | "idiom" : "iphone",
24 | "filename" : "icon_87.png",
25 | "scale" : "3x"
26 | },
27 | {
28 | "size" : "40x40",
29 | "idiom" : "iphone",
30 | "filename" : "icon_80-1.png",
31 | "scale" : "2x"
32 | },
33 | {
34 | "size" : "40x40",
35 | "idiom" : "iphone",
36 | "filename" : "icon_120-1.png",
37 | "scale" : "3x"
38 | },
39 | {
40 | "size" : "60x60",
41 | "idiom" : "iphone",
42 | "filename" : "icon_120.png",
43 | "scale" : "2x"
44 | },
45 | {
46 | "size" : "60x60",
47 | "idiom" : "iphone",
48 | "filename" : "icon_180.png",
49 | "scale" : "3x"
50 | },
51 | {
52 | "size" : "20x20",
53 | "idiom" : "ipad",
54 | "filename" : "icon_20.png",
55 | "scale" : "1x"
56 | },
57 | {
58 | "size" : "20x20",
59 | "idiom" : "ipad",
60 | "filename" : "icon_40-1.png",
61 | "scale" : "2x"
62 | },
63 | {
64 | "size" : "29x29",
65 | "idiom" : "ipad",
66 | "filename" : "icon_29.png",
67 | "scale" : "1x"
68 | },
69 | {
70 | "size" : "29x29",
71 | "idiom" : "ipad",
72 | "filename" : "icon_58-1.png",
73 | "scale" : "2x"
74 | },
75 | {
76 | "size" : "40x40",
77 | "idiom" : "ipad",
78 | "filename" : "icon_40.png",
79 | "scale" : "1x"
80 | },
81 | {
82 | "size" : "40x40",
83 | "idiom" : "ipad",
84 | "filename" : "icon_80.png",
85 | "scale" : "2x"
86 | },
87 | {
88 | "size" : "76x76",
89 | "idiom" : "ipad",
90 | "filename" : "icon_76.png",
91 | "scale" : "1x"
92 | },
93 | {
94 | "size" : "76x76",
95 | "idiom" : "ipad",
96 | "filename" : "icon_152.png",
97 | "scale" : "2x"
98 | },
99 | {
100 | "size" : "83.5x83.5",
101 | "idiom" : "ipad",
102 | "filename" : "icon_167.png",
103 | "scale" : "2x"
104 | },
105 | {
106 | "size" : "1024x1024",
107 | "idiom" : "ios-marketing",
108 | "filename" : "icon_1024.png",
109 | "scale" : "1x"
110 | }
111 | ],
112 | "info" : {
113 | "version" : 1,
114 | "author" : "xcode"
115 | }
116 | }
--------------------------------------------------------------------------------
/Tests/Resources/Politics.txt:
--------------------------------------------------------------------------------
1 | Taxes must be trusted - Kennedy
2 |
3 | Public trust in taxes is breaking down because Labour and Tories are not being straight with people on the issue, Lib Dem leader Charles Kennedy has said.
4 |
5 | A day ahead of the government's pre-Budget report, Mr Kennedy used a speech to say his party was facing up to "painful economic realities". He said the current level of taxation was about right, although he would put a new 50% tax on top earners. Other parties have accused the Lib Dems of making uncosted promises. Mr Kennedy made it clear he was determined to counter that accusation. The Lib Dems have already published what they say are the full costings for all their plans and Wednesday's speech did not announce new policies.
6 |
7 | Speaking at the Commonwealth Club, Mr Kennedy said it was critical for a political party to have economic credibility, both on what it promised and what it was expected to deliver. He said. "Budgets have to add up. Tough choices are needed in public spending." The Lib Dems would cut "low priority" spending, including the government's ID cards scheme and the Child Trust Fund.
8 |
9 | Those cutbacks would free up funds for increasing basic state pensions for over-75s, putting more police on the streets and reintroducing fee eye and dental checks, he said. The Lib Dems argue they were honest about taxes in the past by calling for a 1p rise on income tax. Now they say the only simple tax rise they want is a new 50% tax band for top earners to pay for scrapping university tuition fees, providing free personal care for elderly and disabled people and keeping local taxes down. There would also be a local income tax to replace council tax and a number of changes to environmental taxes to ensure it is the "polluter who pays".
10 |
11 | The Lib Dems say the Tories have only laid out possible options for cutting taxes to grab headlines while Labour has hidden most of its tax rises. Mr Kennedy said: "That contract with the people - that the government will only tax fairly and will spend their money wisely - can only be sustained if the political parties are straightforward about their plans. "With the stealth tax strategy of Gordon Brown, the obvious unfairness of our current tax system - especially the council tax, and the empty promises of the Conservative party on this issue - it is no wonder that trust in taxation is breaking down." He challenged the Treasury to open up its books so the National Audit Office can report on the government's performance.
12 |
13 | Conservative co-chairman Liam Fox said: Liam Fox said "If Charles Kennedy is serious about making his budgets add up he should start by explaining how they would fund their 100 spending commitments. "The reality is, the Lib Dems lack the courage to tackle waste and bureaucracy, and the only people who would face 'tough choices' would be the families who would be £630 worse off a year. " And Chancellor Gordon Brown said the Lib Dem figures did not add up. He accused the party of claiming it would spend less while across the country committing itself to spend more.
14 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DocumentClassifier
2 |
3 |  [](https://developer.apple.com/swift/) 
4 |
5 | ## Overview
6 |
7 | DocumentClassifier is a Swift framework for classifying documents into one of five categories (Business, Entertainment, Politics, Sports, and Technology). It uses a CoreML model trained with 1,500 news articles from the BBC.
8 |
9 | ## Features
10 |
11 | - iOS 11.0+, macOS 10.13+, tvOS 11.0+, watchOS 4.0+
12 | - 100% Test Coverage
13 | - Best CV Score: 0.965333333333
14 |
15 | ## Usage
16 |
17 | [Swift 4 Released (Sample Article](https://swift.org/blog/swift-4-0-released/))
18 |
19 | ```swift
20 | let text = articleText
21 | guard let classification = classifier.classify(text) else { return }
22 | print(classification.prediction) // Technology: 0.42115752953489294
23 | print(classification.allResults) // Business: 0.141, Entertainment: 0.138, Politics: 0.113, Sports: 0.187, Technology: 0.421
24 | ```
25 |
26 | ## Installation
27 |
28 | ### CocoaPods
29 |
30 | [CocoaPods][] is a centralized dependency manager for Cocoa projects. To install
31 | DocumentClassifier with CocoaPods:
32 |
33 | 1. Make sure the latest version of CocoaPods is [installed](https://guides.cocoapods.org/using/getting-started.html#getting-started).
34 |
35 |
36 | 2. Add DocumentClassifier to your Podfile:
37 |
38 | ``` ruby
39 | use_frameworks!
40 |
41 | pod 'DocumentClassifier', '1.2.0'
42 | ```
43 |
44 | 3. Run `pod install`.
45 |
46 | [CocoaPods]: https://cocoapods.org
47 |
48 | ## Example App
49 |
50 | NewsClassifier is an example app using the framework.
51 |
52 |