├── template ├── pages │ ├── index │ │ ├── index.wxss │ │ ├── index.json │ │ ├── index.wxml │ │ └── index.js │ └── chat │ │ ├── chat.json │ │ ├── chat.wxml │ │ ├── chat.wxss │ │ └── chat.js ├── app.wxss ├── colorui │ ├── components │ │ ├── cu-custom.wxss │ │ ├── cu-custom.json │ │ ├── cu-custom.wxml │ │ └── cu-custom.js │ ├── animation.wxss │ └── icon.wxss ├── sitemap.json ├── app.json ├── utils │ ├── util.js │ └── until.js ├── project.config.json └── app.js ├── img ├── 1.png ├── 2.png ├── 3.png └── 4.png ├── .mvn └── wrapper │ ├── maven-wrapper.jar │ ├── maven-wrapper.properties │ └── MavenWrapperDownloader.java ├── src ├── main │ ├── resources │ │ ├── application.properties │ │ └── hanlp.properties │ └── java │ │ └── com │ │ └── example │ │ └── hanlp │ │ ├── service │ │ ├── QuestionService.java │ │ └── impl │ │ │ └── QuestionServiceImpl.java │ │ ├── controller │ │ ├── PageIndexController.java │ │ ├── QuestionController.java │ │ ├── PersonController.java │ │ ├── GenreController.java │ │ └── MovieController.java │ │ ├── HanlpApplication.java │ │ ├── repository │ │ ├── PersonRepository.java │ │ ├── GenreRepository.java │ │ ├── MovieRepository.java │ │ └── QuestionRepository.java │ │ ├── node │ │ ├── Genre.java │ │ ├── BaseEntity.java │ │ ├── Movie.java │ │ └── Person.java │ │ ├── result │ │ ├── ResponseMessage.java │ │ ├── ResultData.java │ │ └── ResponseResult.java │ │ └── process │ │ └── ModelProcess.java └── test │ └── java │ └── com │ └── example │ └── hanlp │ └── HanlpApplicationTests.java ├── .gitignore ├── readme.md ├── pom.xml ├── mvnw.cmd ├── mvnw └── LICENSE /template/pages/index/index.wxss: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NTDXYG/Neo4j/HEAD/img/1.png -------------------------------------------------------------------------------- /img/2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NTDXYG/Neo4j/HEAD/img/2.png -------------------------------------------------------------------------------- /img/3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NTDXYG/Neo4j/HEAD/img/3.png -------------------------------------------------------------------------------- /img/4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NTDXYG/Neo4j/HEAD/img/4.png -------------------------------------------------------------------------------- /template/pages/chat/chat.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": {} 3 | } -------------------------------------------------------------------------------- /template/pages/index/index.json: -------------------------------------------------------------------------------- 1 | { 2 | "usingComponents": {} 3 | } -------------------------------------------------------------------------------- /template/app.wxss: -------------------------------------------------------------------------------- 1 | @import "colorui/main.wxss"; 2 | @import "colorui/icon.wxss"; 3 | -------------------------------------------------------------------------------- /template/colorui/components/cu-custom.wxss: -------------------------------------------------------------------------------- 1 | /* colorui/components/cu-custom.wxss */ -------------------------------------------------------------------------------- /template/colorui/components/cu-custom.json: -------------------------------------------------------------------------------- 1 | { 2 | "component": true, 3 | "usingComponents": {} 4 | } -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NTDXYG/Neo4j/HEAD/.mvn/wrapper/maven-wrapper.jar -------------------------------------------------------------------------------- /src/main/resources/application.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/NTDXYG/Neo4j/HEAD/src/main/resources/application.properties -------------------------------------------------------------------------------- /template/sitemap.json: -------------------------------------------------------------------------------- 1 | { 2 | "desc": "关于本文件的更多信息,请参考文档 https://developers.weixin.qq.com/miniprogram/dev/framework/sitemap.html", 3 | "rules": [{ 4 | "action": "allow", 5 | "page": "*" 6 | }] 7 | } -------------------------------------------------------------------------------- /src/main/java/com/example/hanlp/service/QuestionService.java: -------------------------------------------------------------------------------- 1 | package com.example.hanlp.service; 2 | 3 | public interface QuestionService { 4 | 5 | void showDictPath(); 6 | String answer(String question) throws Exception; 7 | } 8 | -------------------------------------------------------------------------------- /.mvn/wrapper/maven-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.6.2/apache-maven-3.6.2-bin.zip 2 | wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar 3 | -------------------------------------------------------------------------------- /template/app.json: -------------------------------------------------------------------------------- 1 | { 2 | "pages": [ 3 | "pages/index/index", 4 | "pages/chat/chat" 5 | ], 6 | "window": { 7 | "backgroundTextStyle": "light", 8 | "navigationBarBackgroundColor": "#fff", 9 | "navigationBarTitleText": "聊天机器人", 10 | "navigationBarTextStyle": "black" 11 | }, 12 | "sitemapLocation": "sitemap.json" 13 | } -------------------------------------------------------------------------------- /src/main/java/com/example/hanlp/controller/PageIndexController.java: -------------------------------------------------------------------------------- 1 | package com.example.hanlp.controller; 2 | 3 | import org.springframework.stereotype.Controller; 4 | import org.springframework.web.bind.annotation.RequestMapping; 5 | 6 | @Controller 7 | public class PageIndexController { 8 | 9 | @RequestMapping("/") 10 | public String index() { 11 | return "index"; 12 | } 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/example/hanlp/HanlpApplication.java: -------------------------------------------------------------------------------- 1 | package com.example.hanlp; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | 6 | @SpringBootApplication 7 | public class HanlpApplication { 8 | 9 | public static void main(String[] args) { 10 | SpringApplication.run(HanlpApplication.class, args); 11 | } 12 | 13 | } 14 | -------------------------------------------------------------------------------- /src/main/java/com/example/hanlp/repository/PersonRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.hanlp.repository; 2 | 3 | import com.example.hanlp.node.Person; 4 | import org.springframework.data.neo4j.repository.Neo4jRepository; 5 | import org.springframework.data.repository.query.Param; 6 | 7 | import java.util.List; 8 | 9 | public interface PersonRepository extends Neo4jRepository{ 10 | List findByName(@Param("name") String name); 11 | } 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | HELP.md 2 | target/ 3 | !.mvn/wrapper/maven-wrapper.jar 4 | !**/src/main/** 5 | !**/src/test/** 6 | 7 | ### STS ### 8 | .apt_generated 9 | .classpath 10 | .factorypath 11 | .project 12 | .settings 13 | .springBeans 14 | .sts4-cache 15 | 16 | ### IntelliJ IDEA ### 17 | .idea 18 | *.iws 19 | *.iml 20 | *.ipr 21 | 22 | ### NetBeans ### 23 | /nbproject/private/ 24 | /nbbuild/ 25 | /dist/ 26 | /nbdist/ 27 | /.nb-gradle/ 28 | build/ 29 | 30 | ### VS Code ### 31 | .vscode/ 32 | -------------------------------------------------------------------------------- /template/utils/util.js: -------------------------------------------------------------------------------- 1 | const formatTime = date => { 2 | const year = date.getFullYear() 3 | const month = date.getMonth() + 1 4 | const day = date.getDate() 5 | const hour = date.getHours() 6 | const minute = date.getMinutes() 7 | const second = date.getSeconds() 8 | 9 | return [year, month, day].map(formatNumber).join('/') + ' ' + [hour, minute, second].map(formatNumber).join(':') 10 | } 11 | 12 | const formatNumber = n => { 13 | n = n.toString() 14 | return n[1] ? n : '0' + n 15 | } 16 | 17 | module.exports = { 18 | formatTime: formatTime 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/example/hanlp/node/Genre.java: -------------------------------------------------------------------------------- 1 | package com.example.hanlp.node; 2 | 3 | import org.neo4j.ogm.annotation.NodeEntity; 4 | 5 | @NodeEntity 6 | public class Genre extends BaseEntity{ 7 | 8 | 9 | private Long gid; 10 | private String name; 11 | 12 | public Genre(){ 13 | 14 | } 15 | 16 | public Long getGid() { 17 | return gid; 18 | } 19 | 20 | public void setGid(Long gid) { 21 | this.gid = gid; 22 | } 23 | 24 | public String getName() { 25 | return name; 26 | } 27 | 28 | public void setName(String name) { 29 | this.name = name; 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /src/main/java/com/example/hanlp/repository/GenreRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.hanlp.repository; 2 | 3 | import com.example.hanlp.node.Genre; 4 | import org.springframework.data.neo4j.annotation.Query; 5 | import org.springframework.data.neo4j.repository.Neo4jRepository; 6 | import org.springframework.data.repository.query.Param; 7 | 8 | import java.util.List; 9 | 10 | public interface GenreRepository extends Neo4jRepository{ 11 | 12 | @Query("MATCH (n:Genre) where n.name='日本AV' return n") 13 | List getGenres(@Param("name") String name); 14 | 15 | List findByName(@Param("name") String name); 16 | } 17 | -------------------------------------------------------------------------------- /src/main/java/com/example/hanlp/repository/MovieRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.hanlp.repository; 2 | 3 | import com.example.hanlp.node.Movie; 4 | import org.springframework.data.neo4j.annotation.Query; 5 | import org.springframework.data.neo4j.repository.Neo4jRepository; 6 | import org.springframework.data.repository.query.Param; 7 | 8 | import java.util.List; 9 | 10 | public interface MovieRepository extends Neo4jRepository{ 11 | 12 | List findByTitle(@Param("title") String title); 13 | @Query("match(n:Person)-[:actedin]->(m:Movie) where n.name='章子怡' return m.title") 14 | List getMovieTiles(); 15 | } 16 | -------------------------------------------------------------------------------- /src/main/java/com/example/hanlp/node/BaseEntity.java: -------------------------------------------------------------------------------- 1 | package com.example.hanlp.node; 2 | 3 | import org.neo4j.ogm.annotation.Id; 4 | import com.fasterxml.jackson.annotation.JsonIdentityInfo; 5 | import com.fasterxml.jackson.annotation.ObjectIdGenerators; 6 | 7 | /** 8 | * 抽取共同的属性字段 9 | */ 10 | @JsonIdentityInfo(generator=ObjectIdGenerators.PropertyGenerator.class, property="id") 11 | public abstract class BaseEntity { 12 | 13 | /** 14 | * Neo4j会分配的ID(节点唯一标识 当前类中有效) 15 | */ 16 | @Id 17 | private Long id; 18 | public Long getId() { 19 | return id; 20 | } 21 | 22 | public void setId(Long id) { 23 | this.id = id; 24 | } 25 | 26 | 27 | } 28 | -------------------------------------------------------------------------------- /template/pages/index/index.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | {{userInfo.nickName}} 9 | 10 | 11 | 12 | 13 | 14 | 15 | {{motto}} 16 | -------------------------------------------------------------------------------- /template/colorui/components/cu-custom.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/main/java/com/example/hanlp/controller/QuestionController.java: -------------------------------------------------------------------------------- 1 | package com.example.hanlp.controller; 2 | 3 | import com.example.hanlp.service.QuestionService; 4 | import org.springframework.beans.factory.annotation.Autowired; 5 | import org.springframework.web.bind.annotation.RequestMapping; 6 | import org.springframework.web.bind.annotation.RequestParam; 7 | import org.springframework.web.bind.annotation.RestController; 8 | 9 | import java.util.HashMap; 10 | import java.util.Map; 11 | 12 | 13 | @RestController 14 | public class QuestionController { 15 | 16 | @Autowired 17 | QuestionService questService; 18 | 19 | @RequestMapping("/chat") 20 | public Map query(@RequestParam(value = "msg") String question) throws Exception { 21 | HashMap map = new HashMap(); 22 | map.put("msg",questService.answer(question)); 23 | map.put("ischatbot",1); 24 | return map; 25 | } 26 | 27 | @RequestMapping("/path") 28 | public void checkPath(){ 29 | questService.showDictPath(); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /template/colorui/components/cu-custom.js: -------------------------------------------------------------------------------- 1 | const app = getApp(); 2 | Component({ 3 | /** 4 | * 组件的一些选项 5 | */ 6 | options: { 7 | addGlobalClass: true, 8 | multipleSlots: true 9 | }, 10 | /** 11 | * 组件的对外属性 12 | */ 13 | properties: { 14 | bgColor: { 15 | type: String, 16 | default: '' 17 | }, 18 | isCustom: { 19 | type: [Boolean, String], 20 | default: false 21 | }, 22 | isBack: { 23 | type: [Boolean, String], 24 | default: false 25 | }, 26 | bgImage: { 27 | type: String, 28 | default: '' 29 | }, 30 | }, 31 | /** 32 | * 组件的初始数据 33 | */ 34 | data: { 35 | StatusBar: app.globalData.StatusBar, 36 | CustomBar: app.globalData.CustomBar, 37 | Custom: app.globalData.Custom 38 | }, 39 | /** 40 | * 组件的方法列表 41 | */ 42 | methods: { 43 | BackPage() { 44 | wx.navigateBack({ 45 | delta: 1 46 | }); 47 | }, 48 | toHome(){ 49 | wx.reLaunch({ 50 | url: '/pages/index/index', 51 | }) 52 | } 53 | } 54 | }) -------------------------------------------------------------------------------- /src/main/java/com/example/hanlp/result/ResponseMessage.java: -------------------------------------------------------------------------------- 1 | package com.example.hanlp.result; 2 | 3 | 4 | /** 5 | * 6 | * @blob http://blog.csdn.net/appleyk 7 | * @date 2018年5月10日-下午3:44:37 8 | * @param <> 9 | */ 10 | public enum ResponseMessage { 11 | 12 | /** 13 | * 成功 14 | */ 15 | OK(200,"成功"), 16 | 17 | /** 18 | * 错误的请求 19 | */ 20 | BAD_REQUEST(400,"错误的请求"), 21 | 22 | /** 23 | * 错误的请求 24 | */ 25 | NOTNULL_ID(400,"请求ID不能为空"), 26 | 27 | /** 28 | * 错误的请求 29 | */ 30 | NOTNULL_NAME(400,"名称不能为空"), 31 | 32 | 33 | /** 34 | * 内部错误 35 | */ 36 | INTERNAL_SERVER_ERROR(500, "内部错误"), 37 | 38 | 39 | /** 40 | * 操作太頻繁! 41 | */ 42 | FREQUENT_FEEDBACK(515, "操作太频繁,请五分钟后再提交!"); 43 | 44 | 45 | 46 | private final int status; 47 | 48 | private final String message; 49 | 50 | ResponseMessage(int status, String message){ 51 | this.status = status; 52 | this.message = message; 53 | } 54 | 55 | public int getStatus() { 56 | return status; 57 | } 58 | 59 | public String getMessage() { 60 | return message; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /template/project.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "description": "项目配置文件", 3 | "packOptions": { 4 | "ignore": [] 5 | }, 6 | "setting": { 7 | "urlCheck": false, 8 | "es6": true, 9 | "postcss": true, 10 | "minified": true, 11 | "newFeature": true, 12 | "coverView": true, 13 | "autoAudits": false, 14 | "showShadowRootInWxmlPanel": true, 15 | "scopeDataCheck": false, 16 | "checkInvalidKey": true, 17 | "checkSiteMap": true, 18 | "uploadWithSourceMap": true, 19 | "babelSetting": { 20 | "ignore": [], 21 | "disablePlugins": [], 22 | "outputPath": "" 23 | } 24 | }, 25 | "compileType": "miniprogram", 26 | "libVersion": "2.4.2", 27 | "appid": "wxab5278ec69df396c", 28 | "projectname": "ColorUI-template", 29 | "debugOptions": { 30 | "hidedInDevtools": [] 31 | }, 32 | "isGameTourist": false, 33 | "simulatorType": "wechat", 34 | "simulatorPluginLibVersion": {}, 35 | "condition": { 36 | "search": { 37 | "current": -1, 38 | "list": [] 39 | }, 40 | "conversation": { 41 | "current": -1, 42 | "list": [] 43 | }, 44 | "game": { 45 | "currentL": -1, 46 | "list": [] 47 | }, 48 | "miniprogram": { 49 | "current": -1, 50 | "list": [] 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /src/main/java/com/example/hanlp/result/ResultData.java: -------------------------------------------------------------------------------- 1 | /** 2 | * 3 | */ 4 | package com.example.hanlp.result; 5 | 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | 11 | /** 12 | * 13 | * @blob http://blog.csdn.net/appleyk 14 | * @date 2018年5月10日-下午3:44:37 15 | * @param 16 | */ 17 | public class ResultData { 18 | 19 | private ResponseMessage state; 20 | private Object data; 21 | private List dataList; 22 | 23 | 24 | public ResultData(ResponseMessage state) { 25 | 26 | this.state = state; 27 | } 28 | 29 | public ResultData(ResponseMessage state, Object data) { 30 | this.data = data; 31 | this.state = state; 32 | } 33 | 34 | public ResultData(ResponseMessage state, long data, boolean isId){ 35 | this.state = state; 36 | Map map = new HashMap(); 37 | map.put("id", data); 38 | this.data = map; 39 | } 40 | 41 | public ResultData(ResponseMessage state, long id){ 42 | this.state = state; 43 | Map map = new HashMap(); 44 | map.put("id", id); 45 | this.data = map; 46 | } 47 | 48 | /** 49 | * @return the data 50 | */ 51 | public Object getData() { 52 | return data; 53 | } 54 | 55 | public ResponseMessage getState(){ 56 | return state; 57 | } 58 | 59 | public List getDataList(){ 60 | return dataList; 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/main/java/com/example/hanlp/controller/PersonController.java: -------------------------------------------------------------------------------- 1 | package com.example.hanlp.controller; 2 | 3 | import java.util.List; 4 | 5 | import com.example.hanlp.node.Person; 6 | import com.example.hanlp.repository.PersonRepository; 7 | import com.example.hanlp.result.ResponseMessage; 8 | import com.example.hanlp.result.ResponseResult; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestBody; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RequestParam; 14 | import org.springframework.web.bind.annotation.RestController; 15 | 16 | 17 | @RestController 18 | @RequestMapping("/rest/appleyk/person") 19 | public class PersonController { 20 | 21 | @Autowired 22 | PersonRepository personRepository; 23 | 24 | /** 25 | * 根据演员名查询Person实体 26 | * 27 | * @param title 28 | * @return 29 | */ 30 | @RequestMapping("/get") 31 | public List getPersons(@RequestParam(value = "name") String name) { 32 | return personRepository.findByName(name); 33 | } 34 | 35 | /** 36 | * 创建一个演员节点 37 | * 38 | * @param genre 39 | * @return 40 | */ 41 | @PostMapping("/save") 42 | public ResponseResult savePerson(@RequestBody Person person) { 43 | personRepository.save(person); 44 | return new ResponseResult(ResponseMessage.OK); 45 | } 46 | 47 | 48 | } 49 | -------------------------------------------------------------------------------- /src/main/java/com/example/hanlp/controller/GenreController.java: -------------------------------------------------------------------------------- 1 | package com.example.hanlp.controller; 2 | 3 | import java.util.List; 4 | 5 | import com.example.hanlp.node.Genre; 6 | import com.example.hanlp.repository.GenreRepository; 7 | import com.example.hanlp.result.ResponseMessage; 8 | import com.example.hanlp.result.ResponseResult; 9 | import org.springframework.beans.factory.annotation.Autowired; 10 | import org.springframework.web.bind.annotation.PostMapping; 11 | import org.springframework.web.bind.annotation.RequestBody; 12 | import org.springframework.web.bind.annotation.RequestMapping; 13 | import org.springframework.web.bind.annotation.RequestParam; 14 | import org.springframework.web.bind.annotation.RestController; 15 | 16 | @RestController 17 | @RequestMapping("/rest/appleyk/genre") 18 | public class GenreController { 19 | 20 | @Autowired 21 | GenreRepository genreRepository; 22 | 23 | 24 | /** 25 | * 根据类型名查询Genre实体 26 | * @param title 27 | * @return 28 | */ 29 | @RequestMapping("/get") 30 | public List getGenres(@RequestParam(value="name") String name){ 31 | return genreRepository.findByName(name); 32 | } 33 | 34 | /** 35 | * 创建一个电影类型节点 36 | * @param genre 37 | * @return 38 | */ 39 | @PostMapping("/save") 40 | public ResponseResult saveGenre(@RequestBody Genre genre){ 41 | genreRepository.save(genre); 42 | return new ResponseResult(ResponseMessage.OK); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /template/app.js: -------------------------------------------------------------------------------- 1 | //app.js 2 | App({ 3 | onLaunch: function() { 4 | // 展示本地存储能力 5 | var logs = wx.getStorageSync('logs') || [] 6 | logs.unshift(Date.now()) 7 | wx.setStorageSync('logs', logs) 8 | 9 | // 登录 10 | wx.login({ 11 | success: res => { 12 | // 发送 res.code 到后台换取 openId, sessionKey, unionId 13 | } 14 | }) 15 | // 获取用户信息 16 | wx.getSetting({ 17 | success: res => { 18 | if (res.authSetting['scope.userInfo']) { 19 | // 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框 20 | wx.getUserInfo({ 21 | success: res => { 22 | // 可以将 res 发送给后台解码出 unionId 23 | this.globalData.userInfo = res.userInfo 24 | 25 | // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 26 | // 所以此处加入 callback 以防止这种情况 27 | if (this.userInfoReadyCallback) { 28 | this.userInfoReadyCallback(res) 29 | } 30 | } 31 | }) 32 | } 33 | } 34 | }) 35 | // 获取系统状态栏信息 36 | wx.getSystemInfo({ 37 | success: e => { 38 | this.globalData.StatusBar = e.statusBarHeight; 39 | let capsule = wx.getMenuButtonBoundingClientRect(); 40 | if (capsule) { 41 | this.globalData.Custom = capsule; 42 | this.globalData.CustomBar = capsule.bottom + capsule.top - e.statusBarHeight; 43 | } else { 44 | this.globalData.CustomBar = e.statusBarHeight + 50; 45 | } 46 | } 47 | }) 48 | }, 49 | globalData: { 50 | userInfo: null 51 | } 52 | }) -------------------------------------------------------------------------------- /src/main/java/com/example/hanlp/node/Movie.java: -------------------------------------------------------------------------------- 1 | package com.example.hanlp.node; 2 | 3 | import java.util.List; 4 | 5 | import org.neo4j.ogm.annotation.NodeEntity; 6 | import org.neo4j.ogm.annotation.Relationship; 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty; 9 | 10 | @NodeEntity 11 | public class Movie extends BaseEntity{ 12 | 13 | private Long mid; 14 | private Double rating; 15 | private String releasedate; 16 | private String title; 17 | private String introduction; 18 | 19 | @Relationship(type = "is") 20 | @JsonProperty("电影类型") 21 | private List genres; 22 | 23 | 24 | public Movie() { 25 | 26 | } 27 | 28 | public Long getMid() { 29 | return mid; 30 | } 31 | 32 | public void setMid(Long mid) { 33 | this.mid = mid; 34 | } 35 | 36 | public Double getRating() { 37 | return rating; 38 | } 39 | 40 | public void setRating(Double rating) { 41 | this.rating = rating; 42 | } 43 | 44 | public String getReleasedate() { 45 | return releasedate; 46 | } 47 | 48 | public void setReleasedate(String releasedate) { 49 | this.releasedate = releasedate; 50 | } 51 | 52 | public String getTitle() { 53 | return title; 54 | } 55 | 56 | public void setTitle(String title) { 57 | this.title = title; 58 | } 59 | 60 | public String getIntroduction() { 61 | return introduction; 62 | } 63 | 64 | public void setIntroduction(String introduction) { 65 | this.introduction = introduction; 66 | } 67 | 68 | public List getGenres() { 69 | return genres; 70 | } 71 | 72 | public void setGenres(List genres) { 73 | this.genres = genres; 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /template/pages/index/index.js: -------------------------------------------------------------------------------- 1 | //index.js 2 | //获取应用实例 3 | const app = getApp() 4 | 5 | Page({ 6 | data: { 7 | StatusBar: app.globalData.StatusBar, 8 | CustomBar: app.globalData.CustomBar, 9 | motto: 'Hi 开发者!', 10 | userInfo: {}, 11 | hasUserInfo: false, 12 | canIUse: wx.canIUse('button.open-type.getUserInfo') 13 | }, 14 | //事件处理函数 15 | bindViewTap: function() { 16 | wx.navigateTo({ 17 | url: '../logs/logs' 18 | }) 19 | }, 20 | tochat: function(){ 21 | wx.navigateTo({ 22 | url: '../chat/chat', 23 | }) 24 | }, 25 | onLoad: function () { 26 | if (app.globalData.userInfo) { 27 | this.setData({ 28 | userInfo: app.globalData.userInfo, 29 | hasUserInfo: true 30 | }) 31 | } else if (this.data.canIUse){ 32 | // 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回 33 | // 所以此处加入 callback 以防止这种情况 34 | app.userInfoReadyCallback = res => { 35 | this.setData({ 36 | userInfo: res.userInfo, 37 | hasUserInfo: true 38 | }) 39 | } 40 | } else { 41 | // 在没有 open-type=getUserInfo 版本的兼容处理 42 | wx.getUserInfo({ 43 | success: res => { 44 | app.globalData.userInfo = res.userInfo 45 | this.setData({ 46 | userInfo: res.userInfo, 47 | hasUserInfo: true 48 | }) 49 | } 50 | }) 51 | } 52 | }, 53 | getUserInfo: function(e) { 54 | console.log(e) 55 | app.globalData.userInfo = e.detail.userInfo 56 | this.setData({ 57 | userInfo: e.detail.userInfo, 58 | hasUserInfo: true 59 | }) 60 | } 61 | }) 62 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 关于项目 2 | 3 | ## 项目功能 4 | 5 | 1. 电影介绍 6 | 2. 电影评分 7 | 3. 电影演员列表 8 | 4. 演员A和B合作过哪些电影 9 | 5. 某演员出演过那种类型的电影或演过某种类型的电影有哪些 10 | 11 | ## 项目介绍 12 | 13 | 参考:https://github.com/kobeyk/Spring-Boot-Neo4j-Movies 14 | 15 | 本项目基于知识图谱进行问答,因此使用图数据库neo4j。 16 | 17 | (1)首先我们简单说一下什么是Neo4j? 18 | 19 | Neo4j是一个NoSQL的图数据库管理系统,它存储的结构和redis、mongodb一样,都是key-value的形式,因此查询性能是非常棒的,同样是查询电影和电影类别之间的关系,mysql需要用到select连接查询,而neo4j只需要一条cypher语句既能搞定。 20 | 21 | (2)什么是cypher呢? 22 | 23 | Neo4j使用Cypher查询图形数据,Cypher是描述性的图形查询语言,语法简单,功能强大,由于Neo4j在图形数据库家族中处于绝对的领先地位,拥有众多的用户基数,使得Cypher成为图形查询语言事实上的标准。 24 | 25 | (3)为什么不使用MySql数据库呢? 26 | 27 | 上面第一点已经说过了,不是mysql干不了neo4j的工作,而是neo4j在处理节点(对象)关系这方面性能比较棒,而且查询语句简单,更容易构建我们的电影知识图谱,我们也可以将二者结合起来用,比如,mysql存储对象的详细信息,而对象之间的关系,我们可以存储到neo4j中,二者配合起来使用也是很不错的。 28 | 29 | neo4j数据效果截图如下 30 | 31 | ![img](/img/4.png) 32 | 33 | ## How to use 34 | 35 | 在idea中导入spring boot后台项目,然后pom文件会自己下载的,如果下载失败,建议翻。去下载。 36 | 37 | 需要用到:neo4j,spark。具体的安装包会放在下面。 38 | 39 | ### ***微信小程序在template目录下。** 40 | 41 | 在微信小程序中修改pages/chat/chat.js中send函数里的wx.request的url。 42 | 43 | ## 数据软件包 44 | 45 | https://blog.csdn.net/appleyk/article/details/80331997 46 | 47 | 根据博客一步一步来就行 48 | 49 | SQL文件:https://pan.baidu.com/s/1f0ytkiN7jkwcpbbOzId71Q 50 | 51 | CSV文件:https://pan.baidu.com/s/1QJRS8eyZXQt44wBwNyZ6eQ 52 | 53 | Spark文件:https://pan.baidu.com/s/10XUKpYBXqQ16UqDRTFerWg 54 | 55 | neo4j:官网自行下载 56 | 57 | HanLP:https://github.com/hankcs/HanLP/releases 58 | 59 | 样本数据集和贝叶斯分类器核心代码:https://pan.baidu.com/s/1APqPbehoSZHIsFgcswPygw 60 | 61 | 自定义词典:https://pan.baidu.com/s/1jayxGTyfP3PDrv21mA9o6g 62 | 63 | ## 项目截图 64 | 65 | ![img](/img/1.png) 66 | 67 | ![2](/img/2.png) 68 | 69 | ![3](/img/3.png) 70 | -------------------------------------------------------------------------------- /src/main/java/com/example/hanlp/node/Person.java: -------------------------------------------------------------------------------- 1 | package com.example.hanlp.node; 2 | 3 | import java.util.List; 4 | 5 | import org.neo4j.ogm.annotation.NodeEntity; 6 | import org.neo4j.ogm.annotation.Relationship; 7 | 8 | import com.fasterxml.jackson.annotation.JsonProperty; 9 | 10 | @NodeEntity 11 | public class Person extends BaseEntity { 12 | 13 | private Long pid; 14 | private String name; 15 | private String birth; 16 | private String birthplace; 17 | private String death; 18 | private String biography; 19 | 20 | @Relationship(type = "actedin") 21 | @JsonProperty("参演电影") 22 | private List movies; 23 | 24 | public Person(){ 25 | 26 | } 27 | 28 | public Long getPid() { 29 | return pid; 30 | } 31 | 32 | public void setPid(Long pid) { 33 | this.pid = pid; 34 | } 35 | 36 | public String getName() { 37 | return name; 38 | } 39 | 40 | public void setName(String name) { 41 | this.name = name; 42 | } 43 | 44 | public String getBirth() { 45 | return birth; 46 | } 47 | 48 | public void setBirth(String birth) { 49 | this.birth = birth; 50 | } 51 | 52 | public String getBirthplace() { 53 | return birthplace; 54 | } 55 | 56 | public void setBirthplace(String birthplace) { 57 | this.birthplace = birthplace; 58 | } 59 | 60 | public String getDeath() { 61 | return death; 62 | } 63 | 64 | public void setDeath(String death) { 65 | this.death = death; 66 | } 67 | 68 | public String getBiography() { 69 | return biography; 70 | } 71 | 72 | public void setBiography(String biography) { 73 | this.biography = biography; 74 | } 75 | 76 | public List getMovies() { 77 | return movies; 78 | } 79 | 80 | public void setMovies(List movies) { 81 | this.movies = movies; 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/main/resources/hanlp.properties: -------------------------------------------------------------------------------- 1 | #本配置文件中的路径的根目录,根目录+其他路径=完整路径(支持相对路径,请参考:https://github.com/hankcs/HanLP/pull/254) 2 | #Windows用户请注意,路径分隔符统一使用/ 3 | root=D:/BaiduNetdiskDownload/data-for-1.7.5/ 4 | 5 | #好了,以上为唯一需要修改的部分,以下配置项按需反注释编辑。 6 | 7 | #核心词典路径 8 | CoreDictionaryPath=data/dictionary/CoreNatureDictionary.txt 9 | #2元语法词典路径 10 | BiGramDictionaryPath=data/dictionary/CoreNatureDictionary.ngram.txt 11 | #自定义词典路径,用;隔开多个自定义词典,空格开头表示在同一个目录,使用“文件名 词性”形式则表示这个词典的词性默认是该词性。优先级递减。 12 | #所有词典统一使用UTF-8编码,每一行代表一个单词,格式遵从[单词] [词性A] [A的频次] [词性B] [B的频次] ... 如果不填词性则表示采用词典的默认词性。 13 | CustomDictionaryPath=data/dictionary/custom/CustomDictionary.txt; 现代汉语补充词库.txt; 全国地名大全.txt ns; 人名词典.txt; 机构名词典.txt; 上海地名.txt ns;data/dictionary/person/nrf.txt nrf; 14 | #停用词词典路径 15 | CoreStopWordDictionaryPath=data/dictionary/stopwords.txt 16 | #同义词词典路径 17 | CoreSynonymDictionaryDictionaryPath=data/dictionary/synonym/CoreSynonym.txt 18 | #人名词典路径 19 | PersonDictionaryPath=data/dictionary/person/nr.txt 20 | #人名词典转移矩阵路径 21 | PersonDictionaryTrPath=data/dictionary/person/nr.tr.txt 22 | #繁简词典根目录 23 | tcDictionaryRoot=data/dictionary/tc 24 | #HMM分词模型 25 | HMMSegmentModelPath=data/model/segment/HMMSegmentModel.bin 26 | #分词结果是否展示词性 27 | ShowTermNature=true 28 | #IO适配器,实现com.hankcs.hanlp.corpus.io.IIOAdapter接口以在不同的平台(Hadoop、Redis等)上运行HanLP 29 | #默认的IO适配器如下,该适配器是基于普通文件系统的。 30 | IOAdapter=com.hankcs.hanlp.corpus.io.FileIOAdapter 31 | #感知机词法分析器 32 | PerceptronCWSModelPath=data/model/perceptron/pku1998/cws.bin 33 | PerceptronPOSModelPath=data/model/perceptron/pku1998/pos.bin 34 | PerceptronNERModelPath=data/model/perceptron/pku1998/ner.bin 35 | #CRF词法分析器 36 | CRFCWSModelPath=data/model/crf/pku199801/cws.txt 37 | CRFPOSModelPath=data/model/crf/pku199801/pos.txt 38 | CRFNERModelPath=data/model/crf/pku199801/ner.txt 39 | #更多配置项请参考 https://github.com/hankcs/HanLP/blob/master/src/main/java/com/hankcs/hanlp/HanLP.java#L59 自行添加 -------------------------------------------------------------------------------- /template/utils/until.js: -------------------------------------------------------------------------------- 1 | let emojiChar = "☺-😋-😌-😍-😏-😜-😝-😞-😔-😪-😭-😁-😂-😃-😅-😆-👿-😒-😓-😔-😏-😖-😘-😚-😒-😡-😢-😣-😤-😢-😨-😳-😵-😷-😸-😻-😼-😽-😾-😿-🙊-🙋-🙏-✈-🚇-🚃-🚌-🍄-🍅-🍆-🍇-🍈-🍉-🍑-🍒-🍓-🐔-🐶-🐷-👦-👧-👱-👩-👰-👨-👲-👳-💃-💄-💅-💆-💇-🌹-💑-💓-💘-🚲"; 2 | //0x1f--- 3 | let emoji = [ 4 | "60a", "60b", "60c", "60d", "60f", 5 | "61b", "61d", "61e", "61f", 6 | "62a", "62c", "62e", 7 | "602", "603", "605", "606", "608", 8 | "612", "613", "614", "615", "616", "618", "619", "620", "621", "623", "624", "625", "627", "629", "633", "635", "637", 9 | "63a", "63b", "63c", "63d", "63e", "63f", 10 | "64a", "64b", "64f", "681", 11 | "68a", "68b", "68c", 12 | "344", "345", "346", "347", "348", "349", "351", "352", "353", 13 | "414", "415", "416", 14 | "466", "467", "468", "469", "470", "471", "472", "473", 15 | "483", "484", "485", "486", "487", "490", "491", "493", "498", "6b4" 16 | ]; 17 | 18 | function changeEmoji(chatLists) { 19 | let emojiChars = emojiChar.split('-'); 20 | chatLists.map(v => { 21 | let content = v["content"]; 22 | if(content.includes('[0x1f')){ 23 | let contents = content.split('[0x1f'); 24 | for(let i = 0; i < contents.length; i++) { 25 | if(contents[i]){ 26 | let code = contents[i]; 27 | code = code.split(']')[0]; 28 | let index = emoji.findIndex(v => {return v === code}); 29 | if(index !== -1) { 30 | content = content.replace(/\[0x1f[a-zA-Z0-9]{3}\]/, emojiChars[index]) 31 | } 32 | 33 | } 34 | } 35 | 36 | } 37 | v["content"] = content; 38 | return v 39 | }) 40 | return chatLists 41 | } 42 | 43 | 44 | exports.changeEmoji = changeEmoji -------------------------------------------------------------------------------- /src/main/java/com/example/hanlp/controller/MovieController.java: -------------------------------------------------------------------------------- 1 | package com.example.hanlp.controller; 2 | 3 | import java.util.List; 4 | 5 | import com.example.hanlp.node.Movie; 6 | import com.example.hanlp.repository.MovieRepository; 7 | import com.example.hanlp.result.ResponseMessage; 8 | import com.example.hanlp.result.ResponseResult; 9 | import com.example.hanlp.result.ResultData; 10 | import org.springframework.beans.factory.annotation.Autowired; 11 | import org.springframework.web.bind.annotation.PostMapping; 12 | import org.springframework.web.bind.annotation.RequestBody; 13 | import org.springframework.web.bind.annotation.RequestMapping; 14 | import org.springframework.web.bind.annotation.RequestParam; 15 | import org.springframework.web.bind.annotation.RestController; 16 | 17 | 18 | @RestController 19 | @RequestMapping("/rest/appleyk/movie") //restful风格的api接口 20 | public class MovieController { 21 | 22 | @Autowired 23 | MovieRepository movieRepository; 24 | 25 | /** 26 | * 根据电影名查询电影实体 27 | * @param title 28 | * @return 29 | */ 30 | @RequestMapping("/get") 31 | public List getMovies(@RequestParam(value="title") String title){ 32 | return movieRepository.findByTitle(title); 33 | } 34 | 35 | /** 36 | * 创建一个电影节点 37 | * @param genre 38 | * @return 39 | */ 40 | @PostMapping("/save") 41 | public ResponseResult saveMovie(@RequestBody Movie movie){ 42 | movieRepository.save(movie); 43 | return new ResponseResult(ResponseMessage.OK); 44 | } 45 | 46 | 47 | @RequestMapping("/query") 48 | public ResponseResult queryMovieTiles(){ 49 | List movieTiles = movieRepository.getMovieTiles(); 50 | ResultData result = new ResultData(ResponseMessage.OK, movieTiles); 51 | return new ResponseResult(result); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /template/pages/chat/chat.wxml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | {{item.msg}} 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | {{item.msg}} 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 44 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | org.springframework.boot 7 | spring-boot-starter-parent 8 | 2.2.2.RELEASE 9 | 10 | 11 | com.example 12 | hanlp 13 | 0.0.1-SNAPSHOT 14 | hanlp 15 | Demo project for Spring Boot 16 | 17 | 18 | 1.8 19 | 20 | 21 | 22 | 23 | org.springframework.boot 24 | spring-boot-starter-web 25 | 26 | 27 | org.springframework.boot 28 | spring-boot-starter-data-neo4j 29 | 30 | 31 | org.projectlombok 32 | lombok 33 | true 34 | 35 | 36 | com.hankcs 37 | hanlp 38 | portable-1.7.6 39 | 40 | 41 | org.apache.spark 42 | spark-core_2.11 43 | 2.3.0 44 | 45 | 46 | org.slf4j 47 | slf4j-log4j12 48 | 49 | 50 | 51 | 52 | 53 | org.apache.spark 54 | spark-mllib_2.11 55 | 2.3.0 56 | 57 | 58 | org.codehaus.janino 59 | janino 60 | 3.0.8 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-starter-test 65 | test 66 | 67 | 68 | org.junit.vintage 69 | junit-vintage-engine 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | org.springframework.boot 79 | spring-boot-maven-plugin 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /template/colorui/animation.wxss: -------------------------------------------------------------------------------- 1 | /* 2 | Animation 微动画 3 | 基于ColorUI组建库的动画模块 by 文晓港 2019年3月26日19:52:28 4 | */ 5 | 6 | /* css 滤镜 控制黑白底色gif的 */ 7 | .gif-black{ 8 | mix-blend-mode: screen; 9 | } 10 | .gif-white{ 11 | mix-blend-mode: multiply; 12 | } 13 | 14 | 15 | /* Animation css */ 16 | [class*=animation-] { 17 | animation-duration: .5s; 18 | animation-timing-function: ease-out; 19 | animation-fill-mode: both 20 | } 21 | 22 | .animation-fade { 23 | animation-name: fade; 24 | animation-duration: .8s; 25 | animation-timing-function: linear 26 | } 27 | 28 | .animation-scale-up { 29 | animation-name: scale-up 30 | } 31 | 32 | .animation-scale-down { 33 | animation-name: scale-down 34 | } 35 | 36 | .animation-slide-top { 37 | animation-name: slide-top 38 | } 39 | 40 | .animation-slide-bottom { 41 | animation-name: slide-bottom 42 | } 43 | 44 | .animation-slide-left { 45 | animation-name: slide-left 46 | } 47 | 48 | .animation-slide-right { 49 | animation-name: slide-right 50 | } 51 | 52 | .animation-shake { 53 | animation-name: shake 54 | } 55 | 56 | .animation-reverse { 57 | animation-direction: reverse 58 | } 59 | 60 | @keyframes fade { 61 | 0% { 62 | opacity: 0 63 | } 64 | 65 | 100% { 66 | opacity: 1 67 | } 68 | } 69 | 70 | @keyframes scale-up { 71 | 0% { 72 | opacity: 0; 73 | transform: scale(.2) 74 | } 75 | 76 | 100% { 77 | opacity: 1; 78 | transform: scale(1) 79 | } 80 | } 81 | 82 | @keyframes scale-down { 83 | 0% { 84 | opacity: 0; 85 | transform: scale(1.8) 86 | } 87 | 88 | 100% { 89 | opacity: 1; 90 | transform: scale(1) 91 | } 92 | } 93 | 94 | @keyframes slide-top { 95 | 0% { 96 | opacity: 0; 97 | transform: translateY(-100%) 98 | } 99 | 100 | 100% { 101 | opacity: 1; 102 | transform: translateY(0) 103 | } 104 | } 105 | 106 | @keyframes slide-bottom { 107 | 0% { 108 | opacity: 0; 109 | transform: translateY(100%) 110 | } 111 | 112 | 100% { 113 | opacity: 1; 114 | transform: translateY(0) 115 | } 116 | } 117 | 118 | @keyframes shake { 119 | 120 | 0%, 121 | 100% { 122 | transform: translateX(0) 123 | } 124 | 125 | 10% { 126 | transform: translateX(-9px) 127 | } 128 | 129 | 20% { 130 | transform: translateX(8px) 131 | } 132 | 133 | 30% { 134 | transform: translateX(-7px) 135 | } 136 | 137 | 40% { 138 | transform: translateX(6px) 139 | } 140 | 141 | 50% { 142 | transform: translateX(-5px) 143 | } 144 | 145 | 60% { 146 | transform: translateX(4px) 147 | } 148 | 149 | 70% { 150 | transform: translateX(-3px) 151 | } 152 | 153 | 80% { 154 | transform: translateX(2px) 155 | } 156 | 157 | 90% { 158 | transform: translateX(-1px) 159 | } 160 | } 161 | 162 | @keyframes slide-left { 163 | 0% { 164 | opacity: 0; 165 | transform: translateX(-100%) 166 | } 167 | 168 | 100% { 169 | opacity: 1; 170 | transform: translateX(0) 171 | } 172 | } 173 | 174 | @keyframes slide-right { 175 | 0% { 176 | opacity: 0; 177 | transform: translateX(100%) 178 | } 179 | 180 | 100% { 181 | opacity: 1; 182 | transform: translateX(0) 183 | } 184 | } -------------------------------------------------------------------------------- /template/pages/chat/chat.wxss: -------------------------------------------------------------------------------- 1 | /* pages/chat/chat.wxss */ 2 | 3 | 4 | .cu-chat .cu-item.self>.main .content::after { 5 | left: auto; 6 | right: -12rpx; 7 | } 8 | 9 | .cu-chat .cu-item>.main .content::before { 10 | content: ""; 11 | top: 30rpx; 12 | transform: rotate(45deg); 13 | position: absolute; 14 | z-index: -1; 15 | display: inline-block; 16 | overflow: hidden; 17 | width: 24rpx; 18 | height: 24rpx; 19 | left: -12rpx; 20 | right: initial; 21 | background-color: inherit; 22 | filter: blur(5rpx); 23 | opacity: 0.3; 24 | } 25 | 26 | .cu-chat .cu-item>.main .content:not([class*="bg-"])::before { 27 | background-color: var(--black); 28 | opacity: 0.1; 29 | } 30 | 31 | .cu-chat .cu-item.self>.main .content::before { 32 | left: auto; 33 | right: -12rpx; 34 | } 35 | 36 | 37 | .page { 38 | height: 100Vh; 39 | width: 100vw; 40 | } 41 | 42 | .page.show { 43 | overflow: hidden; 44 | } 45 | 46 | .switch-sex::after { 47 | content: "\e716"; 48 | } 49 | 50 | .switch-sex::before { 51 | content: "\e7a9"; 52 | } 53 | 54 | .switch-music::after { 55 | content: "\e66a"; 56 | } 57 | 58 | .switch-music::before { 59 | content: "\e6db"; 60 | } 61 | 62 | 63 | 64 | .scrollPage { 65 | height: 100vh; 66 | } 67 | 68 | .nav-list { 69 | display: flex; 70 | flex-wrap: wrap; 71 | padding: 0px 40rpx 0px; 72 | justify-content: space-between; 73 | } 74 | 75 | .nav-li { 76 | padding: 30rpx; 77 | border-radius: 12rpx; 78 | width: 45%; 79 | margin: 0 2.5% 40rpx; 80 | background-image: url(https://image.weilanwl.com/color2.0/cardBg.png); 81 | background-size: cover; 82 | background-position: center; 83 | position: relative; 84 | z-index: 1; 85 | } 86 | 87 | .nav-li::after { 88 | content: ""; 89 | position: absolute; 90 | z-index: -1; 91 | background-color: inherit; 92 | width: 100%; 93 | height: 100%; 94 | left: 0; 95 | bottom: -10%; 96 | border-radius: 10rpx; 97 | opacity: 0.2; 98 | transform: scale(0.9, 0.9); 99 | } 100 | 101 | .nav-li.cur { 102 | color: #fff; 103 | background: rgb(94, 185, 94); 104 | box-shadow: 4rpx 4rpx 6rpx rgba(94, 185, 94, 0.4); 105 | } 106 | 107 | .nav-title { 108 | font-size: 32rpx; 109 | font-weight: 300; 110 | } 111 | 112 | .nav-title::first-letter { 113 | font-size: 40rpx; 114 | margin-right: 4rpx; 115 | } 116 | 117 | .nav-name { 118 | font-size: 28rpx; 119 | text-transform: Capitalize; 120 | margin-top: 20rpx; 121 | position: relative; 122 | } 123 | 124 | .nav-name::before { 125 | content: ""; 126 | position: absolute; 127 | display: block; 128 | width: 40rpx; 129 | height: 6rpx; 130 | background: #fff; 131 | bottom: 0; 132 | right: 0; 133 | opacity: 0.5; 134 | } 135 | 136 | .nav-name::after { 137 | content: ""; 138 | position: absolute; 139 | display: block; 140 | width: 100rpx; 141 | height: 1px; 142 | background: #fff; 143 | bottom: 0; 144 | right: 40rpx; 145 | opacity: 0.3; 146 | } 147 | 148 | .nav-name::first-letter { 149 | font-weight: bold; 150 | font-size: 36rpx; 151 | margin-right: 1px; 152 | } 153 | 154 | .nav-li text { 155 | position: absolute; 156 | right: 30rpx; 157 | top: 30rpx; 158 | font-size: 52rpx; 159 | width: 60rpx; 160 | height: 60rpx; 161 | text-align: center; 162 | line-height: 60rpx; 163 | } 164 | 165 | .text-light { 166 | font-weight: 300; 167 | } 168 | 169 | page{ 170 | padding-bottom: 100rpx; 171 | } 172 | 173 | .chat-emoji{ 174 | position: fixed; 175 | width: 750rpx; 176 | bottom: 0rpx; 177 | left: 0; 178 | } 179 | .chat-emoji-list{ 180 | display: inline-flex; 181 | flex-flow: wrap; 182 | } 183 | .chat-emoji-icon{ 184 | width: 90rpx; 185 | height: 90rpx; 186 | padding: 20rpx; 187 | border-radius: 18rpx; 188 | } -------------------------------------------------------------------------------- /template/pages/chat/chat.js: -------------------------------------------------------------------------------- 1 | const app = getApp() 2 | const until = require("../../utils/until.js"); 3 | Page({ 4 | data: { 5 | isInList: 0, 6 | newsList: [], 7 | isPage: 1, 8 | InputBottom: 0, 9 | EmojiBottom: 0, 10 | isShow: false, //emoji是否显示 11 | emojiChar: "☺-😋-😌-😍-😏-😜-😝-😞-😔-😪-😭-😁-😂-😃-😅-😆-👿-😒-😓-😔-😏-😖-😘-😚-😒-😡-😢-😣-😤-😢-😨-😳-😵-😷-😸-😻-😼-😽-😾-😿-🙊-🙋-🙏-✈-🚇-🚃-🚌-🍄-🍅-🍆-🍇-🍈-🍉-🍑-🍒-🍓-🐔-🐶-🐷-👦-👧-👱-👩-👰-👨-👲-👳-💃-💄-💅-💆-💇-🌹-💑-💓-💘-🚲", 12 | //0x1f--- 13 | emoji: [ 14 | "60a", "60b", "60c", "60d", "60f", 15 | "61b", "61d", "61e", "61f", 16 | "62a", "62c", "62e", 17 | "602", "603", "605", "606", "608", 18 | "612", "613", "614", "615", "616", "618", "619", "620", "621", "623", "624", "625", "627", "629", "633", "635", "637", 19 | "63a", "63b", "63c", "63d", "63e", "63f", 20 | "64a", "64b", "64f", "681", 21 | "68a", "68b", "68c", 22 | "344", "345", "346", "347", "348", "349", "351", "352", "353", 23 | "414", "415", "416", 24 | "466", "467", "468", "469", "470", "471", "472", "473", 25 | "483", "484", "485", "486", "487", "490", "491", "493", "498", "6b4" 26 | ], 27 | emojis: [], //qq、微信原始表情, 28 | emojiUnicode: [], 29 | InputValue: '', 30 | toView: 'id_0', 31 | 32 | }, 33 | onLoad: function (options) { 34 | this.setData({ 35 | avatarUrl: app.globalData.userInfo.avatarUrl 36 | }) 37 | //emoji表情 38 | let em = {}, 39 | emChar = this.data.emojiChar.split("-"); 40 | let emojis = [] 41 | this.data.emoji.forEach((v, i) => { 42 | em = { 43 | char: emChar[i], 44 | emoji: "0x1f" + v 45 | }; 46 | emojis.push(em) 47 | }); 48 | console.log(options) 49 | this.setData({ 50 | emojis: emojis 51 | }); 52 | }, 53 | onUnload: function () { 54 | this.setData({ 55 | isPage: 0 56 | }) 57 | }, 58 | //选择emoji表情 59 | emojiChoose(e) { 60 | let emojiUnicode = this.data.emojiUnicode; 61 | let value = this.data.InputValue; 62 | emojiUnicode.push(`[${e.currentTarget.dataset.oxf}]`) 63 | this.setData({ 64 | InputValue: value + e.currentTarget.dataset.emoji, 65 | emojiUnicode: emojiUnicode 66 | }) 67 | }, 68 | 69 | InputFocus(e) { 70 | this.setData({ 71 | isShow: false, 72 | InputBottom: e.detail.height, 73 | InputValue: e.detail.value, 74 | EmojiBottom: 0 75 | }) 76 | }, 77 | InputBlur(e) { 78 | this.setData({ 79 | InputBottom: 0 80 | }) 81 | }, 82 | bindKeyInput(e) { 83 | this.setData({ 84 | InputValue: e.detail.value 85 | }) 86 | }, 87 | showEmoji(e) { 88 | if (this.data.isShow) { 89 | this.setData({ 90 | isShow: false, 91 | EmojiBottom: 0 92 | }) 93 | } else { 94 | this.setData({ 95 | isShow: true, 96 | EmojiBottom: 160 97 | }) 98 | } 99 | }, 100 | 101 | send: function () { 102 | var _this = this; 103 | if (this.data.InputValue) { 104 | var list = []; 105 | list = this.data.newsList; 106 | var temp = { 107 | msg: this.data.InputValue, 108 | ischatbot: 0 109 | }; 110 | list.push(temp) 111 | this.setData({ 112 | newsList: list, 113 | InputValue: '', 114 | toView: 'id_' + list.length 115 | }) 116 | wx.request({ 117 | url: 'https://ntdxyg.mynatapp.cc/chat', 118 | method: 'get', 119 | data: temp, 120 | success(res) { 121 | list.push(res.data), 122 | _this.setData({ 123 | toView: 'id_' + list.length, 124 | newsList: list 125 | }) 126 | } 127 | }) 128 | } 129 | } 130 | }) 131 | -------------------------------------------------------------------------------- /src/main/java/com/example/hanlp/repository/QuestionRepository.java: -------------------------------------------------------------------------------- 1 | package com.example.hanlp.repository; 2 | 3 | import com.example.hanlp.node.Movie; 4 | import org.springframework.data.neo4j.annotation.Query; 5 | import org.springframework.data.neo4j.repository.Neo4jRepository; 6 | import org.springframework.data.repository.query.Param; 7 | 8 | import java.util.List; 9 | 10 | 11 | /** 12 | * 基于电影知识图谱的自问自答的查询接口 13 | * @author yukun24@126.com 14 | * @blob http://blog.csdn.net/appleyk 15 | * @date 2018年5月10日-下午3:48:51 16 | */ 17 | public interface QuestionRepository extends Neo4jRepository { 18 | 19 | /** 20 | * 0 对应问题模板0 == nm(电影) 评分 21 | * 22 | * @param title 23 | * 电影标题 24 | * @return 返回电影的评分 25 | */ 26 | @Query("match(n:Movie) where n.title={title} return n.rating") 27 | Double getMovieRating(@Param("title") String title); 28 | 29 | /** 30 | * 1 对应问题模板1 == nm(电影) 上映时间 31 | * 32 | * @param title 33 | * 电影标题 34 | * @return 返回电影的上映日期 35 | */ 36 | @Query("match(n:Movie) where n.title={title} return n.releasedate") 37 | String getMovieReleaseDate(@Param("title") String title); 38 | 39 | /** 40 | * 2 对应问题模板2 == nm(电影) 类型 41 | * 42 | * @param title 43 | * 电影标题 44 | * @return 返回电影的类型、风格 45 | */ 46 | @Query("match(n:Movie)-[r:is]->(b:Genre) where n.title={title} return b.name") 47 | List getMovieTypes(@Param("title") String title); 48 | 49 | /** 50 | * 3 对应问题模板3 == nm(电影) 简介 51 | * 52 | * @param title 53 | * 电影标题 54 | * @return 返回电影的剧情、简介 55 | */ 56 | @Query("match(n:Movie) where n.title ={title} return n.introduction") 57 | String getMovieInfo(@Param("title") String title); 58 | 59 | /** 60 | * 4 对应问题模板4 == nm(电影) 简介 61 | * 62 | * @param title 63 | * 电影标题 64 | * @return 返回电影中出演的演员都有哪些 65 | */ 66 | @Query("match(n:Person)-[:actedin]-(m:Movie) where m.title ={title} return n.name") 67 | List getMovieActors(@Param("title") String title); 68 | 69 | /** 70 | * 5 对应问题模板5 == nnt(演员) 简介 71 | * 72 | * @param name 73 | * 演员名 74 | * @return 返回演员的出生日期 75 | */ 76 | @Query("match(n:Person) where n.name={name} return n.birthplace") 77 | String getActorInfo(@Param("name") String name); 78 | 79 | /** 80 | * 6 对应问题模板6 == nnt(演员) ng(电影类型) 电影作品 81 | * 82 | * @param name 83 | * 演员名 84 | * @param gname 85 | * 电影类型名称 86 | * @return 返回电影名称列表 87 | */ 88 | @Query("match(n:Person)-[:actedin]-(m:Movie) where n.name ={name} " 89 | + "match(g:Genre)-[:is]-(m) where g.name=~{gname} return distinct m.title") 90 | List getActorMoviesByType(@Param("name") String name, @Param("gname") String gname); 91 | 92 | /** 93 | * 7对应问题模板7 == nnt(演员) 电影作品 94 | * 95 | * @param name 96 | * @return 97 | */ 98 | @Query("match(n:Person)-[:actedin]->(m:Movie) where n.name={name} return m.title") 99 | List getActorMovies(@Param("name") String name); 100 | 101 | /** 102 | * 8对应问题模板8 == nnt 参演评分 大于 x(电影评分) 103 | * 104 | * @param name 演员姓名 105 | * @param score 电影分数 106 | * @return 107 | */ 108 | @Query("match(n:Person)-[:actedin]-(m:Movie) where n.name ={name} and m.rating > {score} return m.title") 109 | List getActorMoviesByHScore(@Param("name") String name, @Param("score") Double score); 110 | 111 | 112 | /** 113 | * 9对应问题模板9 == nnt 参演评分 小于 x(电影评分) 114 | * 115 | * @param name 演员姓名 116 | * @param score 电影分数 117 | * @return 118 | */ 119 | @Query("match(n:Person)-[:actedin]-(m:Movie) where n.name ={name} and m.rating < {score} return m.title") 120 | List getActorMoviesByLScore(@Param("name") String name, @Param("score") Double score); 121 | 122 | 123 | /** 124 | * 10 对应问题模板10 == nnt(演员) 电影类型 125 | * 126 | * @param name 127 | * 演员名 128 | * @return 返回演员出演过的所有电影的类型集合【不重复的】 129 | */ 130 | @Query("match(n:Person)-[:actedin]-(m:Movie) where n.name ={name} " 131 | + "match(p:Genre)-[:is]-(m) return distinct p.name") 132 | List getActorMoviesType(@Param("name") String name); 133 | 134 | 135 | /** 136 | * 12 对应问题模板12 == nnt(演员) 电影数量 137 | * 138 | * @param name 139 | * 演员名 140 | * @return 返回演员出演过的所有电影的类型集合【不重复的】 141 | */ 142 | @Query("match(n)-[:actedin]-(m) where n.name ={name} return count(*)") 143 | Integer getMoviesCount(@Param("name") String name); 144 | 145 | /** 146 | * 13 对应问题模板13 == nnt(演员) 出生日期 147 | * 148 | * @param name 149 | * 演员名 150 | * @return 返回演员的出生日期 151 | */ 152 | @Query("match(n:Person) where n.name={name} return n.birth") 153 | String getActorBirth(@Param("name") String name); 154 | 155 | } 156 | -------------------------------------------------------------------------------- /.mvn/wrapper/MavenWrapperDownloader.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2019 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * https://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | import java.net.*; 18 | import java.io.*; 19 | import java.nio.channels.*; 20 | import java.util.Properties; 21 | 22 | public class MavenWrapperDownloader { 23 | 24 | private static final String WRAPPER_VERSION = "0.5.5"; 25 | /** 26 | * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. 27 | */ 28 | private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" 29 | + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; 30 | 31 | /** 32 | * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to 33 | * use instead of the default one. 34 | */ 35 | private static final String MAVEN_WRAPPER_PROPERTIES_PATH = 36 | ".mvn/wrapper/maven-wrapper.properties"; 37 | 38 | /** 39 | * Path where the maven-wrapper.jar will be saved to. 40 | */ 41 | private static final String MAVEN_WRAPPER_JAR_PATH = 42 | ".mvn/wrapper/maven-wrapper.jar"; 43 | 44 | /** 45 | * Name of the property which should be used to override the default download url for the wrapper. 46 | */ 47 | private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; 48 | 49 | public static void main(String args[]) { 50 | System.out.println("- Downloader started"); 51 | File baseDirectory = new File(args[0]); 52 | System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); 53 | 54 | // If the maven-wrapper.properties exists, read it and check if it contains a custom 55 | // wrapperUrl parameter. 56 | File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); 57 | String url = DEFAULT_DOWNLOAD_URL; 58 | if (mavenWrapperPropertyFile.exists()) { 59 | FileInputStream mavenWrapperPropertyFileInputStream = null; 60 | try { 61 | mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); 62 | Properties mavenWrapperProperties = new Properties(); 63 | mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); 64 | url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); 65 | } catch (IOException e) { 66 | System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); 67 | } finally { 68 | try { 69 | if (mavenWrapperPropertyFileInputStream != null) { 70 | mavenWrapperPropertyFileInputStream.close(); 71 | } 72 | } catch (IOException e) { 73 | // Ignore ... 74 | } 75 | } 76 | } 77 | System.out.println("- Downloading from: " + url); 78 | 79 | File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); 80 | if (!outputFile.getParentFile().exists()) { 81 | if (!outputFile.getParentFile().mkdirs()) { 82 | System.out.println( 83 | "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); 84 | } 85 | } 86 | System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); 87 | try { 88 | downloadFileFromURL(url, outputFile); 89 | System.out.println("Done"); 90 | System.exit(0); 91 | } catch (Throwable e) { 92 | System.out.println("- Error downloading"); 93 | e.printStackTrace(); 94 | System.exit(1); 95 | } 96 | } 97 | 98 | private static void downloadFileFromURL(String urlString, File destination) throws Exception { 99 | if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { 100 | String username = System.getenv("MVNW_USERNAME"); 101 | char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); 102 | Authenticator.setDefault(new Authenticator() { 103 | @Override 104 | protected PasswordAuthentication getPasswordAuthentication() { 105 | return new PasswordAuthentication(username, password); 106 | } 107 | }); 108 | } 109 | URL website = new URL(urlString); 110 | ReadableByteChannel rbc; 111 | rbc = Channels.newChannel(website.openStream()); 112 | FileOutputStream fos = new FileOutputStream(destination); 113 | fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); 114 | fos.close(); 115 | rbc.close(); 116 | } 117 | 118 | } 119 | -------------------------------------------------------------------------------- /src/test/java/com/example/hanlp/HanlpApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.example.hanlp; 2 | 3 | import com.example.hanlp.process.ModelProcess; 4 | import com.hankcs.hanlp.HanLP; 5 | import com.hankcs.hanlp.dictionary.CustomDictionary; 6 | import com.hankcs.hanlp.seg.Segment; 7 | import com.hankcs.hanlp.seg.common.Term; 8 | 9 | import org.apache.spark.SparkConf; 10 | import org.apache.spark.api.java.JavaRDD; 11 | import org.apache.spark.api.java.JavaSparkContext; 12 | import org.apache.spark.mllib.classification.NaiveBayes; 13 | import org.apache.spark.mllib.classification.NaiveBayesModel; 14 | import org.apache.spark.mllib.linalg.Vector; 15 | import org.apache.spark.mllib.linalg.Vectors; 16 | import org.apache.spark.mllib.regression.LabeledPoint; 17 | import org.junit.jupiter.api.Test; 18 | import org.springframework.boot.test.context.SpringBootTest; 19 | 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | @SpringBootTest 24 | class HanlpApplicationTests { 25 | 26 | @Test 27 | void contextLoads() { 28 | } 29 | @Test 30 | public void TestA(){ 31 | String lineStr = "明天虽然会下雨,但是我还是会看周杰伦的演唱会。"; 32 | try{ 33 | Segment segment = HanLP.newSegment(); 34 | segment.enableCustomDictionary(true); 35 | /** 36 | * 自定义分词+词性 37 | */ 38 | CustomDictionary.add("好热","ng 0"); 39 | List seg = segment.seg(lineStr); 40 | for (Term term : seg) { 41 | System.out.println(term.toString()); 42 | } 43 | }catch(Exception ex){ 44 | System.out.println(ex.getClass()+","+ex.getMessage()); 45 | } 46 | } 47 | @Test 48 | public void TestC() throws Exception{ 49 | ModelProcess query = new ModelProcess("D:\\BaiduNetdiskDownload\\data-for-1.7.5\\data"); 50 | String[] questionArr = new String[] {"卧虎藏龙的分数是多少"}; 51 | for(String que: questionArr){ 52 | ArrayList question = query.analyQuery(que); 53 | System.err.println(question); 54 | } 55 | } 56 | 57 | @Test 58 | public void TestB(){ 59 | 60 | /** 61 | * 本地模式,*表示启用多个线程并行计算 62 | */ 63 | SparkConf conf = new SparkConf().setAppName("NaiveBayesTest").setMaster("local[*]"); 64 | JavaSparkContext sc = new JavaSparkContext(conf); 65 | 66 | 67 | /** 68 | * MLlib的本地向量主要分为两种,DenseVector和SparseVector 69 | * 前者是用来保存稠密向量,后者是用来保存稀疏向量 70 | */ 71 | 72 | /** 73 | * 两种方式分别创建向量 == 其实创建稀疏向量的方式有两种,本文只讲一种 74 | * (1.0, 0.0, 1.0, 0.0, 1.0, 0.0) 75 | * (1.0, 1.0, 1.0, 1.0, 0.0, 1.0) 76 | */ 77 | 78 | //稠密向量 == 连续的 79 | Vector vMale = Vectors.dense(1,0,1,0,1,0); 80 | 81 | 82 | //稀疏向量 == 间隔的、指定的,未指定位置的向量值默认 = 0.0 83 | int len = 6; 84 | int[] index = new int[]{0,1,2,3,5}; 85 | double[] values = new double[]{1,1,1,1,1}; 86 | //索引0、1、2、3、5位置上的向量值=1,索引4没给出,默认0 87 | Vector vFemale = Vectors.sparse(len, index, values); 88 | //System.err.println("vFemale == "+vFemale); 89 | /** 90 | * labeled point 是一个局部向量,要么是密集型的要么是稀疏型的 91 | * 用一个label/response进行关联 92 | * 在MLlib里,labeled points 被用来监督学习算法 93 | * 我们使用一个double数来存储一个label,因此我们能够使用labeled points进行回归和分类 94 | * 在二进制分类里,一个label可以是 0(负数)或者 1(正数) 95 | * 在多级分类中,labels可以是class的索引,从0开始:0,1,2,...... 96 | */ 97 | 98 | //训练集生成 ,规定数据结构为LabeledPoint == 构建方式:稠密向量模式 ,1.0:类别编号 == 男性 99 | LabeledPoint train_one = new LabeledPoint(1.0,vMale); //(1.0, 0.0, 1.0, 0.0, 1.0, 0.0) 100 | //训练集生成 ,规定数据结构为LabeledPoint == 构建方式:稀疏向量模式 ,2.0:类别编号 == 女性 101 | LabeledPoint train_two = new LabeledPoint(2.0,vFemale); //(1.0, 1.0, 1.0, 1.0, 0.0, 1.0) 102 | //我们也可以给同一个类别增加多个训练集 103 | LabeledPoint train_three = new LabeledPoint(2.0,Vectors.dense(0,1,1,1,0,1)); 104 | 105 | //List存放训练集【三个训练样本数据】 106 | List trains = new ArrayList<>(); 107 | trains.add(train_one); 108 | trains.add(train_two); 109 | trains.add(train_three); 110 | 111 | /** 112 | * SPARK的核心是RDD(弹性分布式数据集) 113 | * Spark是Scala写的,JavaRDD就是Spark为Java写的一套API 114 | * JavaSparkContext sc = new JavaSparkContext(sparkConf); //对应JavaRDD 115 | * SparkContext sc = new SparkContext(sparkConf) ; //对应RDD 116 | * 数据类型为LabeledPoint 117 | */ 118 | JavaRDD trainingRDD = sc.parallelize(trains); 119 | 120 | /** 121 | * 利用Spark进行数据分析时,数据一般要转化为RDD 122 | * JavaRDD转Spark的RDD 123 | */ 124 | NaiveBayesModel nb_model = NaiveBayes.train(trainingRDD.rdd()); 125 | 126 | //测试集生成 == 以下的向量表示,这个人具有特征:短发(1),运动鞋(3) 127 | double [] dTest = {1,0,1,0,0,0}; 128 | Vector vTest = Vectors.dense(dTest);//测试对象为单个vector,或者是RDD化后的vector 129 | 130 | //朴素贝叶斯用法 131 | int modelIndex =(int) nb_model.predict(vTest); 132 | System.out.println("标签分类编号:"+modelIndex);// 分类结果 == 返回分类的标签值 133 | /** 134 | * 计算测试目标向量与训练样本数据集里面对应的各个分类标签匹配的概率结果 135 | */ 136 | System.out.println(nb_model.predictProbabilities(vTest)); 137 | if(modelIndex == 1){ 138 | System.out.println("答案:贝叶斯分类器推断这个人的性别是男性"); 139 | }else if(modelIndex == 2){ 140 | System.out.println("答案:贝叶斯分类器推断这个人的性别是女性"); 141 | } 142 | //最后不要忘了释放资源 143 | sc.close(); 144 | 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /src/main/java/com/example/hanlp/result/ResponseResult.java: -------------------------------------------------------------------------------- 1 | package com.example.hanlp.result; 2 | 3 | import java.io.Serializable; 4 | import java.util.ArrayList; 5 | import java.util.Date; 6 | import java.util.HashMap; 7 | import java.util.List; 8 | import java.util.Map; 9 | 10 | import org.springframework.context.support.DefaultMessageSourceResolvable; 11 | import org.springframework.validation.BindingResult; 12 | 13 | import com.fasterxml.jackson.annotation.JsonFormat; 14 | import com.fasterxml.jackson.annotation.JsonInclude; 15 | import com.fasterxml.jackson.annotation.JsonInclude.Include; 16 | 17 | /** 18 | * 19 | * @blob http://blog.csdn.net/appleyk 20 | * @date 2018年5月10日-下午3:44:37 21 | * @param <> 22 | */ 23 | public class ResponseResult implements Serializable { 24 | 25 | private static final long serialVersionUID = 2719931935414658118L; 26 | 27 | private final Integer status; 28 | 29 | private final String message; 30 | 31 | @JsonInclude(value = Include.NON_NULL) 32 | private final Object data; 33 | 34 | @JsonInclude(value = Include.NON_EMPTY) 35 | private final String[] exceptions; 36 | 37 | @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8") 38 | private final Date timestamp; 39 | 40 | public ResponseResult(Integer status, String message) { 41 | 42 | super(); 43 | this.status = status; 44 | this.message = message; 45 | this.data = null; 46 | this.timestamp = new Date(); 47 | this.exceptions = null; 48 | 49 | } 50 | 51 | /** 52 | * 处理返回的resultData 53 | * @param result 54 | */ 55 | public ResponseResult(ResultData result) { 56 | 57 | super(); 58 | 59 | this.status = result.getState().getStatus(); 60 | this.message = result.getState().getMessage(); 61 | this.data = result.getData(); 62 | this.timestamp = new Date(); 63 | this.exceptions = null; 64 | } 65 | 66 | public ResponseResult(ResponseMessage rm){ 67 | super(); 68 | 69 | this.status = rm.getStatus(); 70 | this.message = rm.getMessage(); 71 | this.data = null; 72 | this.timestamp = new Date(); 73 | this.exceptions = null; 74 | } 75 | 76 | //UnauthorizedMessage 为自定义的消息---未认证 77 | // public ResponseResult(UnauthorizedMessage um){ 78 | // super(); 79 | // 80 | // this.status = um.getStatus(); 81 | // this.message = um.getMessage(); 82 | // this.data = null; 83 | // this.timestamp = new Date(); 84 | // this.exceptions = null; 85 | // } 86 | 87 | public ResponseResult(Integer status, String message, Object data) { 88 | 89 | super(); 90 | 91 | this.status = status; 92 | 93 | this.message = message; 94 | 95 | this.data = data; 96 | this.timestamp = new Date(); 97 | this.exceptions = null; 98 | 99 | } 100 | 101 | /** 102 | * 验证失败返回结果 103 | * @param responseMessage 104 | * @param result 105 | */ 106 | public ResponseResult(ResponseMessage responseMessage, BindingResult result) { 107 | 108 | super(); 109 | 110 | /** 111 | * 解析BindingResult,放入map 112 | */ 113 | List> errors = new ArrayList>(); 114 | 115 | for(int i=0;i map = new HashMap(); 117 | DefaultMessageSourceResolvable dm = (DefaultMessageSourceResolvable) result.getAllErrors().get(i).getArguments()[0]; 118 | map.put("field", dm.getDefaultMessage()); 119 | map.put("message", result.getAllErrors().get(i).getDefaultMessage()); 120 | errors.add(map); 121 | } 122 | 123 | this.status = responseMessage.getStatus(); 124 | 125 | this.message = responseMessage.getMessage(); 126 | 127 | this.data = errors; 128 | this.timestamp = new Date(); 129 | this.exceptions = null; 130 | 131 | } 132 | 133 | public ResponseResult(Integer status, String message, String key, Object value) { 134 | 135 | super(); 136 | 137 | this.status = status; 138 | 139 | this.message = message; 140 | 141 | Map map = new HashMap(); 142 | 143 | if (key == null || ("").equals(key)) { 144 | map.put("key", value); 145 | } else { 146 | map.put(key, value); 147 | } 148 | 149 | this.data = map; 150 | 151 | this.timestamp = new Date(); 152 | this.exceptions = null; 153 | 154 | } 155 | 156 | public ResponseResult(Integer status, Throwable ex) { 157 | 158 | super(); 159 | 160 | this.status = status; 161 | this.message = ex.getMessage(); 162 | this.data = null; 163 | StackTraceElement[] stackTeanceElement = ex.getStackTrace(); 164 | this.exceptions = new String[stackTeanceElement.length]; 165 | for (int i = 0; i < stackTeanceElement.length; i++) { 166 | this.exceptions[i] = stackTeanceElement[i].toString(); 167 | } 168 | this.timestamp = new Date(); 169 | } 170 | 171 | public ResponseResult(Integer status, String message, Throwable ex) { 172 | 173 | super(); 174 | 175 | this.status = status; 176 | 177 | this.message = message; 178 | 179 | this.data = null; 180 | 181 | StackTraceElement[] stackTeanceElement = ex.getStackTrace(); 182 | this.exceptions = new String[stackTeanceElement.length]; 183 | for (int i = 0; i < stackTeanceElement.length; i++) { 184 | this.exceptions[i] = stackTeanceElement[i].toString(); 185 | } 186 | 187 | this.timestamp = new Date(); 188 | 189 | } 190 | 191 | public Integer getStatus() { 192 | return status; 193 | } 194 | 195 | public String getMessage() { 196 | return message; 197 | } 198 | 199 | public Object getData() { 200 | return data; 201 | } 202 | 203 | public String[] getExceptions() { 204 | return exceptions; 205 | } 206 | 207 | public Date getTimestamp() { 208 | return timestamp; 209 | } 210 | } 211 | -------------------------------------------------------------------------------- /mvnw.cmd: -------------------------------------------------------------------------------- 1 | @REM ---------------------------------------------------------------------------- 2 | @REM Licensed to the Apache Software Foundation (ASF) under one 3 | @REM or more contributor license agreements. See the NOTICE file 4 | @REM distributed with this work for additional information 5 | @REM regarding copyright ownership. The ASF licenses this file 6 | @REM to you under the Apache License, Version 2.0 (the 7 | @REM "License"); you may not use this file except in compliance 8 | @REM with the License. You may obtain a copy of the License at 9 | @REM 10 | @REM https://www.apache.org/licenses/LICENSE-2.0 11 | @REM 12 | @REM Unless required by applicable law or agreed to in writing, 13 | @REM software distributed under the License is distributed on an 14 | @REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | @REM KIND, either express or implied. See the License for the 16 | @REM specific language governing permissions and limitations 17 | @REM under the License. 18 | @REM ---------------------------------------------------------------------------- 19 | 20 | @REM ---------------------------------------------------------------------------- 21 | @REM Maven2 Start Up Batch script 22 | @REM 23 | @REM Required ENV vars: 24 | @REM JAVA_HOME - location of a JDK home dir 25 | @REM 26 | @REM Optional ENV vars 27 | @REM M2_HOME - location of maven2's installed home dir 28 | @REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands 29 | @REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a key stroke before ending 30 | @REM MAVEN_OPTS - parameters passed to the Java VM when running Maven 31 | @REM e.g. to debug Maven itself, use 32 | @REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 33 | @REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files 34 | @REM ---------------------------------------------------------------------------- 35 | 36 | @REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' 37 | @echo off 38 | @REM set title of command window 39 | title %0 40 | @REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' 41 | @if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% 42 | 43 | @REM set %HOME% to equivalent of $HOME 44 | if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") 45 | 46 | @REM Execute a user defined script before this one 47 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre 48 | @REM check for pre script, once with legacy .bat ending and once with .cmd ending 49 | if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" 50 | if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" 51 | :skipRcPre 52 | 53 | @setlocal 54 | 55 | set ERROR_CODE=0 56 | 57 | @REM To isolate internal variables from possible post scripts, we use another setlocal 58 | @setlocal 59 | 60 | @REM ==== START VALIDATION ==== 61 | if not "%JAVA_HOME%" == "" goto OkJHome 62 | 63 | echo. 64 | echo Error: JAVA_HOME not found in your environment. >&2 65 | echo Please set the JAVA_HOME variable in your environment to match the >&2 66 | echo location of your Java installation. >&2 67 | echo. 68 | goto error 69 | 70 | :OkJHome 71 | if exist "%JAVA_HOME%\bin\java.exe" goto init 72 | 73 | echo. 74 | echo Error: JAVA_HOME is set to an invalid directory. >&2 75 | echo JAVA_HOME = "%JAVA_HOME%" >&2 76 | echo Please set the JAVA_HOME variable in your environment to match the >&2 77 | echo location of your Java installation. >&2 78 | echo. 79 | goto error 80 | 81 | @REM ==== END VALIDATION ==== 82 | 83 | :init 84 | 85 | @REM Find the project base dir, i.e. the directory that contains the folder ".mvn". 86 | @REM Fallback to current working directory if not found. 87 | 88 | set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% 89 | IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir 90 | 91 | set EXEC_DIR=%CD% 92 | set WDIR=%EXEC_DIR% 93 | :findBaseDir 94 | IF EXIST "%WDIR%"\.mvn goto baseDirFound 95 | cd .. 96 | IF "%WDIR%"=="%CD%" goto baseDirNotFound 97 | set WDIR=%CD% 98 | goto findBaseDir 99 | 100 | :baseDirFound 101 | set MAVEN_PROJECTBASEDIR=%WDIR% 102 | cd "%EXEC_DIR%" 103 | goto endDetectBaseDir 104 | 105 | :baseDirNotFound 106 | set MAVEN_PROJECTBASEDIR=%EXEC_DIR% 107 | cd "%EXEC_DIR%" 108 | 109 | :endDetectBaseDir 110 | 111 | IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig 112 | 113 | @setlocal EnableExtensions EnableDelayedExpansion 114 | for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a 115 | @endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% 116 | 117 | :endReadAdditionalConfig 118 | 119 | SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" 120 | set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" 121 | set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 122 | 123 | set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" 124 | 125 | FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( 126 | IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B 127 | ) 128 | 129 | @REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 130 | @REM This allows using the maven wrapper in projects that prohibit checking in binary data. 131 | if exist %WRAPPER_JAR% ( 132 | if "%MVNW_VERBOSE%" == "true" ( 133 | echo Found %WRAPPER_JAR% 134 | ) 135 | ) else ( 136 | if not "%MVNW_REPOURL%" == "" ( 137 | SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" 138 | ) 139 | if "%MVNW_VERBOSE%" == "true" ( 140 | echo Couldn't find %WRAPPER_JAR%, downloading it ... 141 | echo Downloading from: %DOWNLOAD_URL% 142 | ) 143 | 144 | powershell -Command "&{"^ 145 | "$webclient = new-object System.Net.WebClient;"^ 146 | "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ 147 | "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ 148 | "}"^ 149 | "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ 150 | "}" 151 | if "%MVNW_VERBOSE%" == "true" ( 152 | echo Finished downloading %WRAPPER_JAR% 153 | ) 154 | ) 155 | @REM End of extension 156 | 157 | @REM Provide a "standardized" way to retrieve the CLI args that will 158 | @REM work with both Windows and non-Windows executions. 159 | set MAVEN_CMD_LINE_ARGS=%* 160 | 161 | %MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* 162 | if ERRORLEVEL 1 goto error 163 | goto end 164 | 165 | :error 166 | set ERROR_CODE=1 167 | 168 | :end 169 | @endlocal & set ERROR_CODE=%ERROR_CODE% 170 | 171 | if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost 172 | @REM check for post script, once with legacy .bat ending and once with .cmd ending 173 | if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" 174 | if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" 175 | :skipRcPost 176 | 177 | @REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' 178 | if "%MAVEN_BATCH_PAUSE%" == "on" pause 179 | 180 | if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% 181 | 182 | exit /B %ERROR_CODE% 183 | -------------------------------------------------------------------------------- /src/main/java/com/example/hanlp/service/impl/QuestionServiceImpl.java: -------------------------------------------------------------------------------- 1 | package com.example.hanlp.service.impl; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileReader; 7 | import java.io.IOException; 8 | import java.math.BigDecimal; 9 | import java.util.ArrayList; 10 | import java.util.List; 11 | 12 | import com.example.hanlp.process.ModelProcess; 13 | import com.example.hanlp.repository.QuestionRepository; 14 | import com.example.hanlp.service.QuestionService; 15 | import org.springframework.beans.factory.annotation.Autowired; 16 | import org.springframework.beans.factory.annotation.Value; 17 | import org.springframework.context.annotation.Primary; 18 | import org.springframework.stereotype.Service; 19 | 20 | import com.hankcs.hanlp.dictionary.CustomDictionary; 21 | 22 | @Service 23 | @Primary 24 | public class QuestionServiceImpl implements QuestionService { 25 | 26 | @Value("${rootDirPath}") 27 | private String rootDictPath; 28 | 29 | @Value("${HanLP.CustomDictionary.path.movieDict}") 30 | private String movieDictPath; 31 | 32 | @Value("${HanLP.CustomDictionary.path.genreDict}") 33 | private String genreDictPath; 34 | 35 | @Value("${HanLP.CustomDictionary.path.scoreDict}") 36 | private String scoreDictPath; 37 | 38 | @Autowired 39 | private QuestionRepository questionRepository; 40 | 41 | @Override 42 | public void showDictPath() { 43 | System.out.println("HanLP分词字典及自定义问题模板根目录:" + rootDictPath); 44 | System.out.println("用户自定义扩展词库【电影】:" + movieDictPath); 45 | } 46 | 47 | @Override 48 | public String answer(String question) throws Exception { 49 | 50 | ModelProcess queryProcess = new ModelProcess(rootDictPath); 51 | 52 | /** 53 | * 加载自定义的电影字典 == 设置词性 nm 0 54 | */ 55 | 56 | loadMovieDict(movieDictPath); 57 | 58 | /** 59 | * 加载自定义的类型字典 == 设置词性 ng 0 60 | */ 61 | loadGenreDict(genreDictPath); 62 | 63 | /** 64 | * 加载自定义的评分字典 == 设置词性 x 0 65 | */ 66 | loadScoreDict(scoreDictPath); 67 | ArrayList reStrings = queryProcess.analyQuery(question); 68 | int modelIndex = Integer.valueOf(reStrings.get(0)); 69 | String answer = null; 70 | String title = ""; 71 | String name = ""; 72 | String type = ""; 73 | Double score = 0.0; 74 | /** 75 | * 匹配问题模板 76 | */ 77 | switch (modelIndex) { 78 | case 0: 79 | /** 80 | * nm 评分 == 电影评分 81 | */ 82 | title = reStrings.get(1); 83 | score = questionRepository.getMovieRating(title); 84 | if (score != null) { 85 | BigDecimal b = new BigDecimal(score); 86 | // 四舍五入取两位小数 87 | answer = String.valueOf(b.setScale(2, BigDecimal.ROUND_HALF_UP).floatValue()); 88 | } else { 89 | answer = null; 90 | } 91 | break; 92 | case 1: 93 | /** 94 | * nm 上映时间 == 电影上映时间 95 | */ 96 | title = reStrings.get(1); 97 | String releaseDate = questionRepository.getMovieReleaseDate(title); 98 | if (releaseDate != null) { 99 | answer = releaseDate; 100 | } else { 101 | answer = null; 102 | } 103 | break; 104 | case 2: 105 | /** 106 | * nm 类型 == 电影类型 107 | */ 108 | title = reStrings.get(1); 109 | List types = questionRepository.getMovieTypes(title); 110 | if (types.size() == 0) { 111 | answer = null; 112 | } else { 113 | answer = types.toString().replace("[", "").replace("]", ""); 114 | } 115 | break; 116 | case 3: 117 | /** 118 | * nm 简介 == 电影简介、详情 119 | */ 120 | title = reStrings.get(1); 121 | answer = questionRepository.getMovieInfo(title); 122 | break; 123 | case 4: 124 | /** 125 | * nm 演员列表 == 电影演员列表 126 | */ 127 | title = reStrings.get(1); 128 | List actors = questionRepository.getMovieActors(title); 129 | if (actors.size() == 0) { 130 | answer = null; 131 | } else { 132 | answer = actors.toString().replace("[", "").replace("]", ""); 133 | } 134 | break; 135 | case 5: 136 | /** 137 | * nnt 介绍 == 演员简介 138 | */ 139 | name = reStrings.get(1); 140 | answer = questionRepository.getActorInfo(name); 141 | break; 142 | case 6: 143 | /** 144 | * nnt 电影类型 ng == 演员演过的x类型的电影有哪些 145 | */ 146 | name = reStrings.get(1); 147 | type = reStrings.get(2); 148 | if (type.indexOf("片") > 0) { 149 | type = type.substring(0, type.indexOf("片")); 150 | } 151 | // 模糊查询拼接参数 == 包含type的电影都查出来 152 | type = ".*" + type + "*."; 153 | List movies = questionRepository.getActorMoviesByType(name, type); 154 | if (movies.size() == 0) { 155 | answer = null; 156 | } else { 157 | answer = movies.toString().replace("[", "").replace("]", ""); 158 | } 159 | break; 160 | case 7: 161 | /** 162 | * nnt 电影作品 == 演员的电影作品有哪些 163 | */ 164 | name = reStrings.get(1); 165 | List actorMovies = questionRepository.getActorMovies(name); 166 | if (actorMovies.size() == 0) { 167 | answer = null; 168 | } else { 169 | answer = actorMovies.toString().replace("[", "").replace("]", ""); 170 | } 171 | break; 172 | case 8: 173 | /** 174 | * 1 2 3 4 nnt 参演评分 大于 x == 演员参演的电影评分大于x的有哪些 175 | */ 176 | name = reStrings.get(1); 177 | score = Double.parseDouble(reStrings.get(4)); 178 | List actorMoviesByScore = questionRepository.getActorMoviesByHScore(name, score); 179 | if (actorMoviesByScore.size() == 0) { 180 | answer = null; 181 | } else { 182 | answer = actorMoviesByScore.toString().replace("[", "").replace("]", ""); 183 | } 184 | break; 185 | case 9: 186 | /** 187 | * 1 2 3 4 nnt 参演评分 小于 x == 演员参演的电影评分小于x的有哪些 188 | */ 189 | name = reStrings.get(1); 190 | score = Double.parseDouble(reStrings.get(4)); 191 | List actorMoviesByLScore = questionRepository.getActorMoviesByLScore(name, score); 192 | if (actorMoviesByLScore.size() == 0) { 193 | answer = null; 194 | } else { 195 | answer = actorMoviesByLScore.toString().replace("[", "").replace("]", ""); 196 | } 197 | 198 | break; 199 | case 10: 200 | /** 201 | * nnt 电影类型 == 演员参演的电影类型有哪些 202 | */ 203 | name = reStrings.get(1); 204 | List movieTypes = questionRepository.getActorMoviesType(name); 205 | if (movieTypes.size() == 0) { 206 | answer = null; 207 | } else { 208 | answer = movieTypes.toString().replace("[", "").replace("]", ""); 209 | } 210 | break; 211 | case 11: 212 | /** 213 | * 1 2 3 4 nnt nnr 合作 电影列表 == 演员A和演员B合作的电影有哪些 214 | */ 215 | name = reStrings.get(1); 216 | List actorMoviesA = questionRepository.getActorMovies(name); 217 | /** 218 | * 如果演员A的电影作品无,那么A和演员B无合作之谈 219 | */ 220 | if (actorMoviesA.size() == 0) { 221 | answer = null; 222 | break; 223 | } 224 | 225 | name = reStrings.get(2); 226 | List actorMoviesB = questionRepository.getActorMovies(name); 227 | /** 228 | * 如果演员B的电影作品无,那么B和演员A无合作之谈 229 | */ 230 | if (actorMoviesB.size() == 0) { 231 | answer = null; 232 | break; 233 | } 234 | 235 | /** 236 | * A的作品与B的作品求交集 237 | */ 238 | actorMoviesA.retainAll(actorMoviesB); 239 | 240 | if (actorMoviesA.size() == 0) { 241 | answer = null; 242 | } else { 243 | answer = actorMoviesA.toString().replace("[", "").replace("]", ""); 244 | } 245 | break; 246 | case 12: 247 | name = reStrings.get(1); 248 | Integer count = questionRepository.getMoviesCount(name); 249 | if (count == null) { 250 | answer = null; 251 | } else { 252 | answer = String.valueOf(count) + "部电影"; 253 | } 254 | break; 255 | case 13: 256 | /** 257 | * nnt 出生日期 == 演员出生日期 258 | */ 259 | name = reStrings.get(1); 260 | answer = questionRepository.getActorBirth(name); 261 | break; 262 | default: 263 | break; 264 | } 265 | 266 | System.out.println(answer); 267 | if (answer != null && !answer.equals("") && !answer.equals("\\N")) { 268 | return answer; 269 | } else { 270 | return "sorry,我没有找到你要的答案"; 271 | } 272 | } 273 | 274 | /** 275 | * 加载自定义电影字典 276 | * 277 | * @param path 278 | */ 279 | public void loadMovieDict(String path) { 280 | 281 | File file = new File(path); 282 | BufferedReader br = null; 283 | try { 284 | br = new BufferedReader(new FileReader(file)); 285 | addCustomDictionary(br, 0); 286 | } catch (FileNotFoundException e1) { 287 | e1.printStackTrace(); 288 | } 289 | 290 | } 291 | 292 | /** 293 | * 加载自定义电影类别字典 294 | * 295 | * @param path 296 | */ 297 | public void loadGenreDict(String path) { 298 | 299 | File file = new File(path); 300 | BufferedReader br = null; 301 | try { 302 | br = new BufferedReader(new FileReader(file)); 303 | addCustomDictionary(br, 1); 304 | } catch (FileNotFoundException e1) { 305 | e1.printStackTrace(); 306 | } 307 | } 308 | 309 | /** 310 | * 加载自定义电影评分字典 311 | * 312 | * @param path 313 | */ 314 | public void loadScoreDict(String path) { 315 | 316 | File file = new File(path); 317 | BufferedReader br = null; 318 | try { 319 | br = new BufferedReader(new FileReader(file)); 320 | addCustomDictionary(br, 2); 321 | } catch (FileNotFoundException e1) { 322 | e1.printStackTrace(); 323 | } 324 | } 325 | 326 | /** 327 | * 添加自定义分词及其词性,注意数字0表示频率,不能没有 328 | * 329 | * @param br 330 | * @param type 331 | */ 332 | public void addCustomDictionary(BufferedReader br, int type) { 333 | 334 | String word; 335 | try { 336 | while ((word = br.readLine()) != null) { 337 | switch (type) { 338 | /** 339 | * 设置电影名词词性 == nm 0 340 | */ 341 | case 0: 342 | CustomDictionary.add(word, "nm 0"); 343 | break; 344 | /** 345 | * 设置电影类型名词 词性 == ng 0 346 | */ 347 | case 1: 348 | CustomDictionary.add(word, "ng 0"); 349 | break; 350 | /** 351 | * 设置电影评分数词 词性 == x 0 352 | */ 353 | case 2: 354 | CustomDictionary.add(word, "x 0"); 355 | break; 356 | default: 357 | break; 358 | } 359 | } 360 | br.close(); 361 | } catch (NumberFormatException e) { 362 | e.printStackTrace(); 363 | } catch (IOException e) { 364 | e.printStackTrace(); 365 | } 366 | } 367 | } 368 | -------------------------------------------------------------------------------- /mvnw: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # ---------------------------------------------------------------------------- 3 | # Licensed to the Apache Software Foundation (ASF) under one 4 | # or more contributor license agreements. See the NOTICE file 5 | # distributed with this work for additional information 6 | # regarding copyright ownership. The ASF licenses this file 7 | # to you under the Apache License, Version 2.0 (the 8 | # "License"); you may not use this file except in compliance 9 | # with the License. You may obtain a copy of the License at 10 | # 11 | # https://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, 14 | # software distributed under the License is distributed on an 15 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | # KIND, either express or implied. See the License for the 17 | # specific language governing permissions and limitations 18 | # under the License. 19 | # ---------------------------------------------------------------------------- 20 | 21 | # ---------------------------------------------------------------------------- 22 | # Maven2 Start Up Batch script 23 | # 24 | # Required ENV vars: 25 | # ------------------ 26 | # JAVA_HOME - location of a JDK home dir 27 | # 28 | # Optional ENV vars 29 | # ----------------- 30 | # M2_HOME - location of maven2's installed home dir 31 | # MAVEN_OPTS - parameters passed to the Java VM when running Maven 32 | # e.g. to debug Maven itself, use 33 | # set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 34 | # MAVEN_SKIP_RC - flag to disable loading of mavenrc files 35 | # ---------------------------------------------------------------------------- 36 | 37 | if [ -z "$MAVEN_SKIP_RC" ]; then 38 | 39 | if [ -f /etc/mavenrc ]; then 40 | . /etc/mavenrc 41 | fi 42 | 43 | if [ -f "$HOME/.mavenrc" ]; then 44 | . "$HOME/.mavenrc" 45 | fi 46 | 47 | fi 48 | 49 | # OS specific support. $var _must_ be set to either true or false. 50 | cygwin=false 51 | darwin=false 52 | mingw=false 53 | case "$(uname)" in 54 | CYGWIN*) cygwin=true ;; 55 | MINGW*) mingw=true ;; 56 | Darwin*) 57 | darwin=true 58 | # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home 59 | # See https://developer.apple.com/library/mac/qa/qa1170/_index.html 60 | if [ -z "$JAVA_HOME" ]; then 61 | if [ -x "/usr/libexec/java_home" ]; then 62 | export JAVA_HOME="$(/usr/libexec/java_home)" 63 | else 64 | export JAVA_HOME="/Library/Java/Home" 65 | fi 66 | fi 67 | ;; 68 | esac 69 | 70 | if [ -z "$JAVA_HOME" ]; then 71 | if [ -r /etc/gentoo-release ]; then 72 | JAVA_HOME=$(java-config --jre-home) 73 | fi 74 | fi 75 | 76 | if [ -z "$M2_HOME" ]; then 77 | ## resolve links - $0 may be a link to maven's home 78 | PRG="$0" 79 | 80 | # need this for relative symlinks 81 | while [ -h "$PRG" ]; do 82 | ls=$(ls -ld "$PRG") 83 | link=$(expr "$ls" : '.*-> \(.*\)$') 84 | if expr "$link" : '/.*' >/dev/null; then 85 | PRG="$link" 86 | else 87 | PRG="$(dirname "$PRG")/$link" 88 | fi 89 | done 90 | 91 | saveddir=$(pwd) 92 | 93 | M2_HOME=$(dirname "$PRG")/.. 94 | 95 | # make it fully qualified 96 | M2_HOME=$(cd "$M2_HOME" && pwd) 97 | 98 | cd "$saveddir" 99 | # echo Using m2 at $M2_HOME 100 | fi 101 | 102 | # For Cygwin, ensure paths are in UNIX format before anything is touched 103 | if $cygwin; then 104 | [ -n "$M2_HOME" ] && 105 | M2_HOME=$(cygpath --unix "$M2_HOME") 106 | [ -n "$JAVA_HOME" ] && 107 | JAVA_HOME=$(cygpath --unix "$JAVA_HOME") 108 | [ -n "$CLASSPATH" ] && 109 | CLASSPATH=$(cygpath --path --unix "$CLASSPATH") 110 | fi 111 | 112 | # For Mingw, ensure paths are in UNIX format before anything is touched 113 | if $mingw; then 114 | [ -n "$M2_HOME" ] && 115 | M2_HOME="$( ( 116 | cd "$M2_HOME" 117 | pwd 118 | ))" 119 | [ -n "$JAVA_HOME" ] && 120 | JAVA_HOME="$( ( 121 | cd "$JAVA_HOME" 122 | pwd 123 | ))" 124 | fi 125 | 126 | if [ -z "$JAVA_HOME" ]; then 127 | javaExecutable="$(which javac)" 128 | if [ -n "$javaExecutable" ] && ! [ "$(expr \"$javaExecutable\" : '\([^ ]*\)')" = "no" ]; then 129 | # readlink(1) is not available as standard on Solaris 10. 130 | readLink=$(which readlink) 131 | if [ ! $(expr "$readLink" : '\([^ ]*\)') = "no" ]; then 132 | if $darwin; then 133 | javaHome="$(dirname \"$javaExecutable\")" 134 | javaExecutable="$(cd \"$javaHome\" && pwd -P)/javac" 135 | else 136 | javaExecutable="$(readlink -f \"$javaExecutable\")" 137 | fi 138 | javaHome="$(dirname \"$javaExecutable\")" 139 | javaHome=$(expr "$javaHome" : '\(.*\)/bin') 140 | JAVA_HOME="$javaHome" 141 | export JAVA_HOME 142 | fi 143 | fi 144 | fi 145 | 146 | if [ -z "$JAVACMD" ]; then 147 | if [ -n "$JAVA_HOME" ]; then 148 | if [ -x "$JAVA_HOME/jre/sh/java" ]; then 149 | # IBM's JDK on AIX uses strange locations for the executables 150 | JAVACMD="$JAVA_HOME/jre/sh/java" 151 | else 152 | JAVACMD="$JAVA_HOME/bin/java" 153 | fi 154 | else 155 | JAVACMD="$(which java)" 156 | fi 157 | fi 158 | 159 | if [ ! -x "$JAVACMD" ]; then 160 | echo "Error: JAVA_HOME is not defined correctly." >&2 161 | echo " We cannot execute $JAVACMD" >&2 162 | exit 1 163 | fi 164 | 165 | if [ -z "$JAVA_HOME" ]; then 166 | echo "Warning: JAVA_HOME environment variable is not set." 167 | fi 168 | 169 | CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher 170 | 171 | # traverses directory structure from process work directory to filesystem root 172 | # first directory with .mvn subdirectory is considered project base directory 173 | find_maven_basedir() { 174 | 175 | if [ -z "$1" ]; then 176 | echo "Path not specified to find_maven_basedir" 177 | return 1 178 | fi 179 | 180 | basedir="$1" 181 | wdir="$1" 182 | while [ "$wdir" != '/' ]; do 183 | if [ -d "$wdir"/.mvn ]; then 184 | basedir=$wdir 185 | break 186 | fi 187 | # workaround for JBEAP-8937 (on Solaris 10/Sparc) 188 | if [ -d "${wdir}" ]; then 189 | wdir=$( 190 | cd "$wdir/.." 191 | pwd 192 | ) 193 | fi 194 | # end of workaround 195 | done 196 | echo "${basedir}" 197 | } 198 | 199 | # concatenates all lines of a file 200 | concat_lines() { 201 | if [ -f "$1" ]; then 202 | echo "$(tr -s '\n' ' ' <"$1")" 203 | fi 204 | } 205 | 206 | BASE_DIR=$(find_maven_basedir "$(pwd)") 207 | if [ -z "$BASE_DIR" ]; then 208 | exit 1 209 | fi 210 | 211 | ########################################################################################## 212 | # Extension to allow automatically downloading the maven-wrapper.jar from Maven-central 213 | # This allows using the maven wrapper in projects that prohibit checking in binary data. 214 | ########################################################################################## 215 | if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then 216 | if [ "$MVNW_VERBOSE" = true ]; then 217 | echo "Found .mvn/wrapper/maven-wrapper.jar" 218 | fi 219 | else 220 | if [ "$MVNW_VERBOSE" = true ]; then 221 | echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." 222 | fi 223 | if [ -n "$MVNW_REPOURL" ]; then 224 | jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" 225 | else 226 | jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.5/maven-wrapper-0.5.5.jar" 227 | fi 228 | while IFS="=" read key value; do 229 | case "$key" in wrapperUrl) 230 | jarUrl="$value" 231 | break 232 | ;; 233 | esac 234 | done <"$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" 235 | if [ "$MVNW_VERBOSE" = true ]; then 236 | echo "Downloading from: $jarUrl" 237 | fi 238 | wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" 239 | if $cygwin; then 240 | wrapperJarPath=$(cygpath --path --windows "$wrapperJarPath") 241 | fi 242 | 243 | if command -v wget >/dev/null; then 244 | if [ "$MVNW_VERBOSE" = true ]; then 245 | echo "Found wget ... using wget" 246 | fi 247 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 248 | wget "$jarUrl" -O "$wrapperJarPath" 249 | else 250 | wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" 251 | fi 252 | elif command -v curl >/dev/null; then 253 | if [ "$MVNW_VERBOSE" = true ]; then 254 | echo "Found curl ... using curl" 255 | fi 256 | if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then 257 | curl -o "$wrapperJarPath" "$jarUrl" -f 258 | else 259 | curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f 260 | fi 261 | 262 | else 263 | if [ "$MVNW_VERBOSE" = true ]; then 264 | echo "Falling back to using Java to download" 265 | fi 266 | javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" 267 | # For Cygwin, switch paths to Windows format before running javac 268 | if $cygwin; then 269 | javaClass=$(cygpath --path --windows "$javaClass") 270 | fi 271 | if [ -e "$javaClass" ]; then 272 | if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 273 | if [ "$MVNW_VERBOSE" = true ]; then 274 | echo " - Compiling MavenWrapperDownloader.java ..." 275 | fi 276 | # Compiling the Java class 277 | ("$JAVA_HOME/bin/javac" "$javaClass") 278 | fi 279 | if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then 280 | # Running the downloader 281 | if [ "$MVNW_VERBOSE" = true ]; then 282 | echo " - Running MavenWrapperDownloader.java ..." 283 | fi 284 | ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") 285 | fi 286 | fi 287 | fi 288 | fi 289 | ########################################################################################## 290 | # End of extension 291 | ########################################################################################## 292 | 293 | export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} 294 | if [ "$MVNW_VERBOSE" = true ]; then 295 | echo $MAVEN_PROJECTBASEDIR 296 | fi 297 | MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" 298 | 299 | # For Cygwin, switch paths to Windows format before running java 300 | if $cygwin; then 301 | [ -n "$M2_HOME" ] && 302 | M2_HOME=$(cygpath --path --windows "$M2_HOME") 303 | [ -n "$JAVA_HOME" ] && 304 | JAVA_HOME=$(cygpath --path --windows "$JAVA_HOME") 305 | [ -n "$CLASSPATH" ] && 306 | CLASSPATH=$(cygpath --path --windows "$CLASSPATH") 307 | [ -n "$MAVEN_PROJECTBASEDIR" ] && 308 | MAVEN_PROJECTBASEDIR=$(cygpath --path --windows "$MAVEN_PROJECTBASEDIR") 309 | fi 310 | 311 | # Provide a "standardized" way to retrieve the CLI args that will 312 | # work with both Windows and non-Windows executions. 313 | MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" 314 | export MAVEN_CMD_LINE_ARGS 315 | 316 | WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain 317 | 318 | exec "$JAVACMD" \ 319 | $MAVEN_OPTS \ 320 | -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ 321 | "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ 322 | ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" 323 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /src/main/java/com/example/hanlp/process/ModelProcess.java: -------------------------------------------------------------------------------- 1 | package com.example.hanlp.process; 2 | 3 | import java.io.BufferedReader; 4 | import java.io.File; 5 | import java.io.FileNotFoundException; 6 | import java.io.FileReader; 7 | import java.io.IOException; 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import java.util.LinkedList; 11 | import java.util.List; 12 | import java.util.Map; 13 | import java.util.Set; 14 | 15 | import org.apache.spark.SparkConf; 16 | import org.apache.spark.api.java.JavaRDD; 17 | import org.apache.spark.api.java.JavaSparkContext; 18 | import org.apache.spark.mllib.classification.NaiveBayes; 19 | import org.apache.spark.mllib.classification.NaiveBayesModel; 20 | import org.apache.spark.mllib.linalg.Vector; 21 | import org.apache.spark.mllib.linalg.Vectors; 22 | import org.apache.spark.mllib.regression.LabeledPoint; 23 | 24 | import com.hankcs.hanlp.HanLP; 25 | import com.hankcs.hanlp.seg.Segment; 26 | import com.hankcs.hanlp.seg.common.Term; 27 | 28 | /** 29 | * Spark贝叶斯分类器 + HanLP分词器 + 实现问题语句的抽象+模板匹配+关键性语句还原 30 | * @blob http://blog.csdn.net/appleyk 31 | * @date 2018年5月9日-上午10:07:52 32 | */ 33 | public class ModelProcess { 34 | 35 | 36 | /** 37 | * 分类标签号和问句模板对应表 38 | */ 39 | Map questionsPattern; 40 | 41 | /** 42 | * Spark贝叶斯分类器 43 | */ 44 | NaiveBayesModel nbModel; 45 | 46 | /** 47 | * 词语和下标的对应表 == 词汇表 48 | */ 49 | Map vocabulary; 50 | 51 | /** 52 | * 关键字与其词性的map键值对集合 == 句子抽象 53 | */ 54 | Map abstractMap; 55 | 56 | /** 57 | * 指定问题question及字典的txt模板所在的根目录 58 | */ 59 | String rootDirPath = "D:/HanLP/data"; 60 | 61 | /** 62 | * 分类模板索引 63 | */ 64 | int modelIndex = 0; 65 | 66 | public ModelProcess() throws Exception{ 67 | questionsPattern = loadQuestionsPattern(); 68 | vocabulary = loadVocabulary(); 69 | nbModel = loadClassifierModel(); 70 | } 71 | 72 | 73 | public ModelProcess(String rootDirPath) throws Exception{ 74 | this.rootDirPath = rootDirPath+'/'; 75 | questionsPattern = loadQuestionsPattern(); 76 | vocabulary = loadVocabulary(); 77 | nbModel = loadClassifierModel(); 78 | } 79 | 80 | public ArrayList analyQuery(String queryString) throws Exception { 81 | 82 | /** 83 | * 打印问句 84 | */ 85 | System.out.println("原始句子:"+queryString); 86 | System.out.println("========HanLP开始分词========"); 87 | 88 | /** 89 | * 抽象句子,利用HanPL分词,将关键字进行词性抽象 90 | */ 91 | String abstr = queryAbstract(queryString); 92 | System.out.println("句子抽象化结果:"+abstr);// nm 的 导演 是 谁 93 | 94 | /** 95 | * 将抽象的句子与spark训练集中的模板进行匹配,拿到句子对应的模板 96 | */ 97 | String strPatt = queryClassify(abstr); 98 | System.out.println("句子套用模板结果:"+strPatt); // nm 制作 导演列表 99 | 100 | 101 | /** 102 | * 模板还原成句子,此时问题已转换为我们熟悉的操作 103 | */ 104 | String finalPattern = queryExtenstion(strPatt); 105 | System.out.println("原始句子替换成系统可识别的结果:"+finalPattern);// 但丁密码 制作 导演列表 106 | 107 | 108 | ArrayList resultList = new ArrayList(); 109 | resultList.add(String.valueOf(modelIndex)); 110 | String[] finalPattArray = finalPattern.split(" "); 111 | for (String word : finalPattArray) 112 | resultList.add(word); 113 | return resultList; 114 | } 115 | 116 | public String queryAbstract(String querySentence) { 117 | 118 | // 句子抽象化 119 | Segment segment = HanLP.newSegment().enableCustomDictionary(true); 120 | List terms = segment.seg(querySentence); 121 | String abstractQuery = ""; 122 | abstractMap = new HashMap(); 123 | int nrCount = 0; //nr 人名词性这个 词语出现的频率 124 | for (Term term : terms) { 125 | String word = term.word; 126 | String termStr = term.toString(); 127 | System.out.println(termStr); 128 | if (termStr.contains("nm")) { //nm 电影名 129 | abstractQuery += "nm "; 130 | abstractMap.put("nm", word); 131 | } else if (termStr.contains("nr") && nrCount == 0) { //nr 人名 132 | abstractQuery += "nnt "; 133 | abstractMap.put("nnt", word); 134 | nrCount++; 135 | }else if (termStr.contains("nr") && nrCount == 1) { //nr 人名 再出现一次,改成nnr 136 | abstractQuery += "nnr "; 137 | abstractMap.put("nnr", word); 138 | nrCount++; 139 | }else if (termStr.contains("x")) { //x 评分 140 | abstractQuery += "x "; 141 | abstractMap.put("x", word); 142 | } else if (termStr.contains("ng")) { //ng 类型 143 | abstractQuery += "ng "; 144 | abstractMap.put("ng", word); 145 | } 146 | else { 147 | abstractQuery += word + " "; 148 | } 149 | } 150 | System.out.println("========HanLP分词结束========"); 151 | return abstractQuery; 152 | } 153 | 154 | public String queryExtenstion(String queryPattern) { 155 | // 句子还原 156 | Set set = abstractMap.keySet(); 157 | for (String key : set) { 158 | /** 159 | * 如果句子模板中含有抽象的词性 160 | */ 161 | if (queryPattern.contains(key)) { 162 | 163 | /** 164 | * 则替换抽象词性为具体的值 165 | */ 166 | String value = abstractMap.get(key); 167 | queryPattern = queryPattern.replace(key, value); 168 | } 169 | } 170 | String extendedQuery = queryPattern; 171 | /** 172 | * 当前句子处理完,抽象map清空释放空间并置空,等待下一个句子的处理 173 | */ 174 | abstractMap.clear(); 175 | abstractMap = null; 176 | return extendedQuery; 177 | } 178 | 179 | 180 | /** 181 | * 加载词汇表 == 关键特征 == 与HanLP分词后的单词进行匹配 182 | * @return 183 | */ 184 | public Map loadVocabulary() { 185 | Map vocabulary = new HashMap(); 186 | File file = new File(rootDirPath + "question/vocabulary.txt"); 187 | BufferedReader br = null; 188 | try { 189 | br = new BufferedReader(new FileReader(file)); 190 | } catch (FileNotFoundException e) { 191 | e.printStackTrace(); 192 | } 193 | String line; 194 | try { 195 | while ((line = br.readLine()) != null) { 196 | String[] tokens = line.split(":"); 197 | int index = Integer.parseInt(tokens[0]); 198 | String word = tokens[1]; 199 | vocabulary.put(word, index); 200 | } 201 | } catch (NumberFormatException e) { 202 | e.printStackTrace(); 203 | } catch (IOException e) { 204 | e.printStackTrace(); 205 | } 206 | return vocabulary; 207 | } 208 | 209 | /** 210 | * 加载文件,并读取内容返回 211 | * @param filename 212 | * @return 213 | * @throws IOException 214 | */ 215 | public String loadFile(String filename) throws IOException { 216 | File file = new File(rootDirPath + filename); 217 | BufferedReader br = new BufferedReader(new FileReader(file)); 218 | String content = ""; 219 | String line; 220 | while ((line = br.readLine()) != null) { 221 | /** 222 | * 文本的换行符暂定用"`"代替 223 | */ 224 | content += line + "`"; 225 | } 226 | /** 227 | * 关闭资源 228 | */ 229 | br.close(); 230 | return content; 231 | } 232 | 233 | /** 234 | * 句子分词后与词汇表进行key匹配转换为double向量数组 235 | * @param sentence 236 | * @return 237 | * @throws Exception 238 | */ 239 | public double[] sentenceToArrays(String sentence) throws Exception { 240 | 241 | double[] vector = new double[vocabulary.size()]; 242 | /** 243 | * 模板对照词汇表的大小进行初始化,全部为0.0 244 | */ 245 | for (int i = 0; i < vocabulary.size(); i++) { 246 | vector[i] = 0; 247 | } 248 | 249 | /** 250 | * HanLP分词,拿分词的结果和词汇表里面的关键特征进行匹配 251 | */ 252 | Segment segment = HanLP.newSegment(); 253 | List terms = segment.seg(sentence); 254 | for (Term term : terms) { 255 | String word = term.word; 256 | /** 257 | * 如果命中,0.0 改为 1.0 258 | */ 259 | if (vocabulary.containsKey(word)) { 260 | int index = vocabulary.get(word); 261 | vector[index] = 1; 262 | } 263 | } 264 | return vector; 265 | } 266 | 267 | /** 268 | * Spark朴素贝叶斯(naiveBayes) 269 | * 对特定的模板进行加载并分类 270 | * 欲了解Spark朴素贝叶斯,可参考地址:https://blog.csdn.net/appleyk/article/details/80348912 271 | * @return 272 | * @throws Exception 273 | */ 274 | public NaiveBayesModel loadClassifierModel() throws Exception { 275 | 276 | /** 277 | * 生成Spark对象 278 | * 一、Spark程序是通过SparkContext发布到Spark集群的 279 | * Spark程序的运行都是在SparkContext为核心的调度器的指挥下进行的 280 | * Spark程序的结束是以SparkContext结束作为结束 281 | * JavaSparkContext对象用来创建Spark的核心RDD的 282 | * 注意:第一个RDD,一定是由SparkContext来创建的 283 | * 284 | * 二、SparkContext的主构造器参数为 SparkConf 285 | * SparkConf必须设置appname和master,否则会报错 286 | * spark.master 用于设置部署模式 287 | * local[*] == 本地运行模式[也可以是集群的形式],如果需要多个线程执行,可以设置为local[2],表示2个线程 ,*表示多个 288 | * spark.app.name 用于指定应用的程序名称 == 289 | */ 290 | 291 | /** 292 | * 题外话 293 | * 贝叶斯是谁? 294 | * 贝叶斯(约1701-1763) Thomas Bayes,英国数学家。 295 | * 1702年出生于伦敦,做过神甫。 296 | * 1742年成为英国皇家学会会员。 297 | * 1763年4月7日逝世。 298 | * 贝叶斯在数学方面主要研究概率论 == 贝叶斯公式是概率论中较为重要的公式 299 | */ 300 | SparkConf conf = new SparkConf().setAppName("NaiveBayesTest").setMaster("local[*]"); 301 | JavaSparkContext sc = new JavaSparkContext(conf); 302 | 303 | /** 304 | * 训练集生成 305 | * labeled point 是一个局部向量,要么是密集型的要么是稀疏型的 306 | * 用一个label/response进行关联。在MLlib里,labeled points 被用来监督学习算法 307 | * 我们使用一个double数来存储一个label,因此我们能够使用labeled points进行回归和分类 308 | */ 309 | List train_list = new LinkedList(); 310 | String[] sentences = null; 311 | 312 | 313 | /** 314 | * 英雄的评分是多少 315 | */ 316 | String scoreQuestions = loadFile("question/【0】评分.txt"); 317 | sentences = scoreQuestions.split("`"); 318 | for (String sentence : sentences) { 319 | double[] array = sentenceToArrays(sentence); 320 | LabeledPoint train_one = new LabeledPoint(0.0, Vectors.dense(array)); 321 | train_list.add(train_one); 322 | } 323 | 324 | /** 325 | * 英雄什么时候上映的 326 | */ 327 | String timeQuestions = loadFile("question/【1】上映.txt"); 328 | sentences = timeQuestions.split("`"); 329 | for (String sentence : sentences) { 330 | double[] array = sentenceToArrays(sentence); 331 | LabeledPoint train_one = new LabeledPoint(1.0, Vectors.dense(array)); 332 | train_list.add(train_one); 333 | } 334 | 335 | 336 | /** 337 | * 英雄是什么类型的 338 | */ 339 | String styleQuestions = loadFile("question/【2】风格.txt"); 340 | sentences = styleQuestions.split("`"); 341 | for (String sentence : sentences) { 342 | double[] array = sentenceToArrays(sentence); 343 | LabeledPoint train_one = new LabeledPoint(2.0, Vectors.dense(array)); 344 | train_list.add(train_one); 345 | } 346 | 347 | 348 | /** 349 | * 英雄的简介、英雄的剧情是什么 350 | */ 351 | String storyQuestions = loadFile("question/【3】剧情.txt"); 352 | sentences = storyQuestions.split("`"); 353 | for (String sentence : sentences) { 354 | double[] array = sentenceToArrays(sentence); 355 | LabeledPoint train_one = new LabeledPoint(3.0, Vectors.dense(array)); 356 | train_list.add(train_one); 357 | } 358 | 359 | /** 360 | * 英雄有哪些演员出演、出演英雄的演员都有哪些 361 | */ 362 | String actorsQuestion = loadFile("question/【4】某电影有哪些演员出演.txt"); 363 | sentences = actorsQuestion.split("`"); 364 | for (String sentence : sentences) { 365 | double[] array = sentenceToArrays(sentence); 366 | LabeledPoint train_one = new LabeledPoint(4.0, Vectors.dense(array)); 367 | train_list.add(train_one); 368 | } 369 | 370 | 371 | /** 372 | * 章子怡 373 | */ 374 | String actorInfos = loadFile("question/【5】演员简介.txt"); 375 | sentences = actorInfos.split("`"); 376 | for (String sentence : sentences) { 377 | double[] array = sentenceToArrays(sentence); 378 | LabeledPoint train_one = new LabeledPoint(5.0, Vectors.dense(array)); 379 | train_list.add(train_one); 380 | } 381 | 382 | /** 383 | * 周星驰出演的科幻类型的电影有哪些 384 | */ 385 | String genreMovies = loadFile("question/【6】某演员出演过的类型电影有哪些.txt"); 386 | sentences = genreMovies.split("`"); 387 | for (String sentence : sentences) { 388 | double[] array = sentenceToArrays(sentence); 389 | LabeledPoint train_one = new LabeledPoint(6.0, Vectors.dense(array)); 390 | train_list.add(train_one); 391 | } 392 | 393 | 394 | /** 395 | * 周星驰演了哪些电影 396 | */ 397 | String actorsMovie = loadFile("question/【7】某演员演了什么电影.txt"); 398 | sentences = actorsMovie.split("`"); 399 | for (String sentence : sentences) { 400 | double[] array = sentenceToArrays(sentence); 401 | LabeledPoint train_one = new LabeledPoint(7.0, Vectors.dense(array)); 402 | train_list.add(train_one); 403 | } 404 | 405 | /** 406 | * 巩俐参演的电影评分在8.5分以上的有哪些、巩俐参演的电影评分大于8.5分的有哪些 407 | */ 408 | String highScoreMovies = loadFile("question/【8】演员参演的电影评分【大于】.txt"); 409 | sentences = highScoreMovies.split("`"); 410 | for (String sentence : sentences) { 411 | double[] array = sentenceToArrays(sentence); 412 | LabeledPoint train_one = new LabeledPoint(8.0, Vectors.dense(array)); 413 | train_list.add(train_one); 414 | } 415 | 416 | 417 | /** 418 | * 巩俐参演的电影评分在8.5分以下的有哪些、巩俐参演的电影评分小于8.5分的有哪些 419 | */ 420 | String lowScoreMovies = loadFile("question/【9】演员参演的电影评分【小于】.txt"); 421 | sentences = lowScoreMovies.split("`"); 422 | for (String sentence : sentences) { 423 | double[] array = sentenceToArrays(sentence); 424 | LabeledPoint train_one = new LabeledPoint(9.0, Vectors.dense(array)); 425 | train_list.add(train_one); 426 | } 427 | 428 | 429 | /** 430 | * 章子怡演过哪些类型的电影 431 | */ 432 | String actorMovieGenres = loadFile("question/【10】某演员出演过哪些类型的电影.txt"); 433 | sentences = actorMovieGenres.split("`"); 434 | for (String sentence : sentences) { 435 | double[] array = sentenceToArrays(sentence); 436 | LabeledPoint train_one = new LabeledPoint(10.0, Vectors.dense(array)); 437 | train_list.add(train_one); 438 | } 439 | 440 | /** 441 | * 章子怡与李连杰合作过哪些电影、章子怡和巩俐一起演过什么电影 442 | */ 443 | String withMovies = loadFile("question/【11】演员A和演员B合作了哪些电影.txt"); 444 | sentences = withMovies.split("`"); 445 | for (String sentence : sentences) { 446 | double[] array = sentenceToArrays(sentence); 447 | LabeledPoint train_one = new LabeledPoint(11.0, Vectors.dense(array)); 448 | train_list.add(train_one); 449 | } 450 | 451 | 452 | /** 453 | * 章子怡与李连杰合作过哪些电影、章子怡和巩俐一起演过什么电影 454 | */ 455 | String countMovies = loadFile("question/【12】某演员一共演过多少电影.txt"); 456 | sentences = countMovies.split("`"); 457 | for (String sentence : sentences) { 458 | double[] array = sentenceToArrays(sentence); 459 | LabeledPoint train_one = new LabeledPoint(12.0, Vectors.dense(array)); 460 | train_list.add(train_one); 461 | } 462 | 463 | 464 | /** 465 | * 章子怡的生日是多少、章子怡的出生日期是什么时候 466 | */ 467 | String actorBirthdayQuestion = loadFile("question/【13】演员出生日期.txt"); 468 | sentences = actorBirthdayQuestion.split("`"); 469 | for (String sentence : sentences) { 470 | double[] array = sentenceToArrays(sentence); 471 | LabeledPoint train_one = new LabeledPoint(13.0, Vectors.dense(array)); 472 | train_list.add(train_one); 473 | } 474 | 475 | /** 476 | * SPARK的核心是RDD(弹性分布式数据集) 477 | * Spark是Scala写的,JavaRDD就是Spark为Java写的一套API 478 | * JavaSparkContext sc = new JavaSparkContext(sparkConf); //对应JavaRDD 479 | * SparkContext sc = new SparkContext(sparkConf) ; //对应RDD 480 | */ 481 | JavaRDD trainingRDD = sc.parallelize(train_list); 482 | NaiveBayesModel nb_model = NaiveBayes.train(trainingRDD.rdd()); 483 | 484 | /** 485 | * 记得关闭资源 486 | */ 487 | sc.close(); 488 | 489 | /** 490 | * 返回贝叶斯分类器 491 | */ 492 | return nb_model; 493 | 494 | } 495 | 496 | /** 497 | * 加载问题模板 == 分类器标签 498 | * @return 499 | */ 500 | public Map loadQuestionsPattern() { 501 | Map questionsPattern = new HashMap(); 502 | File file = new File(rootDirPath + "question/question_classification.txt"); 503 | BufferedReader br = null; 504 | try { 505 | br = new BufferedReader(new FileReader(file)); 506 | } catch (FileNotFoundException e1) { 507 | e1.printStackTrace(); 508 | } 509 | String line; 510 | try { 511 | while ((line = br.readLine()) != null) { 512 | String[] tokens = line.split(":"); 513 | double index = Double.valueOf(tokens[0]); 514 | String pattern = tokens[1]; 515 | questionsPattern.put(index, pattern); 516 | } 517 | } catch (NumberFormatException e) { 518 | e.printStackTrace(); 519 | } catch (IOException e) { 520 | e.printStackTrace(); 521 | } 522 | return questionsPattern; 523 | } 524 | 525 | /** 526 | * 贝叶斯分类器分类的结果,拿到匹配的分类标签号,并根据标签号返回问题的模板 527 | * @param sentence 528 | * @return 529 | * @throws Exception 530 | */ 531 | public String queryClassify(String sentence) throws Exception { 532 | 533 | double[] testArray = sentenceToArrays(sentence); 534 | Vector v = Vectors.dense(testArray); 535 | 536 | /** 537 | * 对数据进行预测predict 538 | * 句子模板在 spark贝叶斯分类器中的索引【位置】 539 | * 根据词汇使用的频率推断出句子对应哪一个模板 540 | */ 541 | double index = nbModel.predict(v); 542 | modelIndex = (int)index; 543 | System.out.println("the model index is " + index); 544 | Vector vRes = nbModel.predictProbabilities(v); 545 | System.out.println("问题模板分类【0】概率:"+vRes.toArray()[0]); 546 | System.out.println("问题模板分类【13】概率:"+vRes.toArray()[13]); 547 | return questionsPattern.get(index); 548 | } 549 | 550 | public static void main(String[] agrs) throws Exception { 551 | System.out.println("Hello World !"); 552 | } 553 | } 554 | -------------------------------------------------------------------------------- /template/colorui/icon.wxss: -------------------------------------------------------------------------------- 1 | @keyframes cuIcon-spin { 2 | 0% { 3 | -webkit-transform: rotate(0); 4 | transform: rotate(0); 5 | } 6 | 7 | 100% { 8 | -webkit-transform: rotate(359deg); 9 | transform: rotate(359deg); 10 | } 11 | } 12 | 13 | .iconfont-spin { 14 | -webkit-animation: cuIcon-spin 2s infinite linear; 15 | animation: cuIcon-spin 2s infinite linear; 16 | display: inline-block; 17 | } 18 | 19 | .iconfont-pulse { 20 | -webkit-animation: cuIcon-spin 1s infinite steps(8); 21 | animation: cuIcon-spin 1s infinite steps(8); 22 | display: inline-block; 23 | } 24 | 25 | [class*="cuIcon-"] { 26 | font-family: "cuIcon"; 27 | font-size: inherit; 28 | font-style: normal; 29 | } 30 | 31 | @font-face { 32 | font-family: "cuIcon"; 33 | src: url('//at.alicdn.com/t/font_533566_yfq2d9wdij.eot?t=1545239985831'); 34 | /* IE9*/ 35 | src: url('//at.alicdn.com/t/font_533566_yfq2d9wdij.eot?t=1545239985831#iefix') format('embedded-opentype'), 36 | /* IE6-IE8 */ 37 | url('data:application/x-font-woff;charset=utf-8;base64,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') format('woff'), 38 | url('//at.alicdn.com/t/font_533566_yfq2d9wdij.ttf?t=1545239985831') format('truetype'), 39 | /* chrome, firefox, opera, Safari, Android, iOS 4.2+*/ 40 | url('//at.alicdn.com/t/font_533566_yfq2d9wdij.svg?t=1545239985831#iconfont') format('svg'); 41 | /* iOS 4.1- */ 42 | } 43 | 44 | .cuIcon-appreciate:before { 45 | content: "\e644"; 46 | } 47 | 48 | .cuIcon-check:before { 49 | content: "\e645"; 50 | } 51 | 52 | .cuIcon-close:before { 53 | content: "\e646"; 54 | } 55 | 56 | .cuIcon-edit:before { 57 | content: "\e649"; 58 | } 59 | 60 | .cuIcon-emoji:before { 61 | content: "\e64a"; 62 | } 63 | 64 | .cuIcon-favorfill:before { 65 | content: "\e64b"; 66 | } 67 | 68 | .cuIcon-favor:before { 69 | content: "\e64c"; 70 | } 71 | 72 | .cuIcon-loading:before { 73 | content: "\e64f"; 74 | } 75 | 76 | .cuIcon-locationfill:before { 77 | content: "\e650"; 78 | } 79 | 80 | .cuIcon-location:before { 81 | content: "\e651"; 82 | } 83 | 84 | .cuIcon-phone:before { 85 | content: "\e652"; 86 | } 87 | 88 | .cuIcon-roundcheckfill:before { 89 | content: "\e656"; 90 | } 91 | 92 | .cuIcon-roundcheck:before { 93 | content: "\e657"; 94 | } 95 | 96 | .cuIcon-roundclosefill:before { 97 | content: "\e658"; 98 | } 99 | 100 | .cuIcon-roundclose:before { 101 | content: "\e659"; 102 | } 103 | 104 | .cuIcon-roundrightfill:before { 105 | content: "\e65a"; 106 | } 107 | 108 | .cuIcon-roundright:before { 109 | content: "\e65b"; 110 | } 111 | 112 | .cuIcon-search:before { 113 | content: "\e65c"; 114 | } 115 | 116 | .cuIcon-taxi:before { 117 | content: "\e65d"; 118 | } 119 | 120 | .cuIcon-timefill:before { 121 | content: "\e65e"; 122 | } 123 | 124 | .cuIcon-time:before { 125 | content: "\e65f"; 126 | } 127 | 128 | .cuIcon-unfold:before { 129 | content: "\e661"; 130 | } 131 | 132 | .cuIcon-warnfill:before { 133 | content: "\e662"; 134 | } 135 | 136 | .cuIcon-warn:before { 137 | content: "\e663"; 138 | } 139 | 140 | .cuIcon-camerafill:before { 141 | content: "\e664"; 142 | } 143 | 144 | .cuIcon-camera:before { 145 | content: "\e665"; 146 | } 147 | 148 | .cuIcon-commentfill:before { 149 | content: "\e666"; 150 | } 151 | 152 | .cuIcon-comment:before { 153 | content: "\e667"; 154 | } 155 | 156 | .cuIcon-likefill:before { 157 | content: "\e668"; 158 | } 159 | 160 | .cuIcon-like:before { 161 | content: "\e669"; 162 | } 163 | 164 | .cuIcon-notificationfill:before { 165 | content: "\e66a"; 166 | } 167 | 168 | .cuIcon-notification:before { 169 | content: "\e66b"; 170 | } 171 | 172 | .cuIcon-order:before { 173 | content: "\e66c"; 174 | } 175 | 176 | .cuIcon-samefill:before { 177 | content: "\e66d"; 178 | } 179 | 180 | .cuIcon-same:before { 181 | content: "\e66e"; 182 | } 183 | 184 | .cuIcon-deliver:before { 185 | content: "\e671"; 186 | } 187 | 188 | .cuIcon-evaluate:before { 189 | content: "\e672"; 190 | } 191 | 192 | .cuIcon-pay:before { 193 | content: "\e673"; 194 | } 195 | 196 | .cuIcon-send:before { 197 | content: "\e675"; 198 | } 199 | 200 | .cuIcon-shop:before { 201 | content: "\e676"; 202 | } 203 | 204 | .cuIcon-ticket:before { 205 | content: "\e677"; 206 | } 207 | 208 | .cuIcon-back:before { 209 | content: "\e679"; 210 | } 211 | 212 | .cuIcon-cascades:before { 213 | content: "\e67c"; 214 | } 215 | 216 | .cuIcon-discover:before { 217 | content: "\e67e"; 218 | } 219 | 220 | .cuIcon-list:before { 221 | content: "\e682"; 222 | } 223 | 224 | .cuIcon-more:before { 225 | content: "\e684"; 226 | } 227 | 228 | .cuIcon-scan:before { 229 | content: "\e689"; 230 | } 231 | 232 | .cuIcon-settings:before { 233 | content: "\e68a"; 234 | } 235 | 236 | .cuIcon-questionfill:before { 237 | content: "\e690"; 238 | } 239 | 240 | .cuIcon-question:before { 241 | content: "\e691"; 242 | } 243 | 244 | .cuIcon-shopfill:before { 245 | content: "\e697"; 246 | } 247 | 248 | .cuIcon-form:before { 249 | content: "\e699"; 250 | } 251 | 252 | .cuIcon-pic:before { 253 | content: "\e69b"; 254 | } 255 | 256 | .cuIcon-filter:before { 257 | content: "\e69c"; 258 | } 259 | 260 | .cuIcon-footprint:before { 261 | content: "\e69d"; 262 | } 263 | 264 | .cuIcon-top:before { 265 | content: "\e69e"; 266 | } 267 | 268 | .cuIcon-pulldown:before { 269 | content: "\e69f"; 270 | } 271 | 272 | .cuIcon-pullup:before { 273 | content: "\e6a0"; 274 | } 275 | 276 | .cuIcon-right:before { 277 | content: "\e6a3"; 278 | } 279 | 280 | .cuIcon-refresh:before { 281 | content: "\e6a4"; 282 | } 283 | 284 | .cuIcon-moreandroid:before { 285 | content: "\e6a5"; 286 | } 287 | 288 | .cuIcon-deletefill:before { 289 | content: "\e6a6"; 290 | } 291 | 292 | .cuIcon-refund:before { 293 | content: "\e6ac"; 294 | } 295 | 296 | .cuIcon-cart:before { 297 | content: "\e6af"; 298 | } 299 | 300 | .cuIcon-qrcode:before { 301 | content: "\e6b0"; 302 | } 303 | 304 | .cuIcon-remind:before { 305 | content: "\e6b2"; 306 | } 307 | 308 | .cuIcon-delete:before { 309 | content: "\e6b4"; 310 | } 311 | 312 | .cuIcon-profile:before { 313 | content: "\e6b7"; 314 | } 315 | 316 | .cuIcon-home:before { 317 | content: "\e6b8"; 318 | } 319 | 320 | .cuIcon-cartfill:before { 321 | content: "\e6b9"; 322 | } 323 | 324 | .cuIcon-discoverfill:before { 325 | content: "\e6ba"; 326 | } 327 | 328 | .cuIcon-homefill:before { 329 | content: "\e6bb"; 330 | } 331 | 332 | .cuIcon-message:before { 333 | content: "\e6bc"; 334 | } 335 | 336 | .cuIcon-addressbook:before { 337 | content: "\e6bd"; 338 | } 339 | 340 | .cuIcon-link:before { 341 | content: "\e6bf"; 342 | } 343 | 344 | .cuIcon-lock:before { 345 | content: "\e6c0"; 346 | } 347 | 348 | .cuIcon-unlock:before { 349 | content: "\e6c2"; 350 | } 351 | 352 | .cuIcon-vip:before { 353 | content: "\e6c3"; 354 | } 355 | 356 | .cuIcon-weibo:before { 357 | content: "\e6c4"; 358 | } 359 | 360 | .cuIcon-activity:before { 361 | content: "\e6c5"; 362 | } 363 | 364 | .cuIcon-friendaddfill:before { 365 | content: "\e6c9"; 366 | } 367 | 368 | .cuIcon-friendadd:before { 369 | content: "\e6ca"; 370 | } 371 | 372 | .cuIcon-friendfamous:before { 373 | content: "\e6cb"; 374 | } 375 | 376 | .cuIcon-friend:before { 377 | content: "\e6cc"; 378 | } 379 | 380 | .cuIcon-goods:before { 381 | content: "\e6cd"; 382 | } 383 | 384 | .cuIcon-selection:before { 385 | content: "\e6ce"; 386 | } 387 | 388 | .cuIcon-explore:before { 389 | content: "\e6d2"; 390 | } 391 | 392 | .cuIcon-present:before { 393 | content: "\e6d3"; 394 | } 395 | 396 | .cuIcon-squarecheckfill:before { 397 | content: "\e6d4"; 398 | } 399 | 400 | .cuIcon-square:before { 401 | content: "\e6d5"; 402 | } 403 | 404 | .cuIcon-squarecheck:before { 405 | content: "\e6d6"; 406 | } 407 | 408 | .cuIcon-round:before { 409 | content: "\e6d7"; 410 | } 411 | 412 | .cuIcon-roundaddfill:before { 413 | content: "\e6d8"; 414 | } 415 | 416 | .cuIcon-roundadd:before { 417 | content: "\e6d9"; 418 | } 419 | 420 | .cuIcon-add:before { 421 | content: "\e6da"; 422 | } 423 | 424 | .cuIcon-notificationforbidfill:before { 425 | content: "\e6db"; 426 | } 427 | 428 | .cuIcon-explorefill:before { 429 | content: "\e6dd"; 430 | } 431 | 432 | .cuIcon-fold:before { 433 | content: "\e6de"; 434 | } 435 | 436 | .cuIcon-game:before { 437 | content: "\e6df"; 438 | } 439 | 440 | .cuIcon-redpacket:before { 441 | content: "\e6e0"; 442 | } 443 | 444 | .cuIcon-selectionfill:before { 445 | content: "\e6e1"; 446 | } 447 | 448 | .cuIcon-similar:before { 449 | content: "\e6e2"; 450 | } 451 | 452 | .cuIcon-appreciatefill:before { 453 | content: "\e6e3"; 454 | } 455 | 456 | .cuIcon-infofill:before { 457 | content: "\e6e4"; 458 | } 459 | 460 | .cuIcon-info:before { 461 | content: "\e6e5"; 462 | } 463 | 464 | .cuIcon-forwardfill:before { 465 | content: "\e6ea"; 466 | } 467 | 468 | .cuIcon-forward:before { 469 | content: "\e6eb"; 470 | } 471 | 472 | .cuIcon-rechargefill:before { 473 | content: "\e6ec"; 474 | } 475 | 476 | .cuIcon-recharge:before { 477 | content: "\e6ed"; 478 | } 479 | 480 | .cuIcon-vipcard:before { 481 | content: "\e6ee"; 482 | } 483 | 484 | .cuIcon-voice:before { 485 | content: "\e6ef"; 486 | } 487 | 488 | .cuIcon-voicefill:before { 489 | content: "\e6f0"; 490 | } 491 | 492 | .cuIcon-friendfavor:before { 493 | content: "\e6f1"; 494 | } 495 | 496 | .cuIcon-wifi:before { 497 | content: "\e6f2"; 498 | } 499 | 500 | .cuIcon-share:before { 501 | content: "\e6f3"; 502 | } 503 | 504 | .cuIcon-wefill:before { 505 | content: "\e6f4"; 506 | } 507 | 508 | .cuIcon-we:before { 509 | content: "\e6f5"; 510 | } 511 | 512 | .cuIcon-lightauto:before { 513 | content: "\e6f6"; 514 | } 515 | 516 | .cuIcon-lightforbid:before { 517 | content: "\e6f7"; 518 | } 519 | 520 | .cuIcon-lightfill:before { 521 | content: "\e6f8"; 522 | } 523 | 524 | .cuIcon-camerarotate:before { 525 | content: "\e6f9"; 526 | } 527 | 528 | .cuIcon-light:before { 529 | content: "\e6fa"; 530 | } 531 | 532 | .cuIcon-barcode:before { 533 | content: "\e6fb"; 534 | } 535 | 536 | .cuIcon-flashlightclose:before { 537 | content: "\e6fc"; 538 | } 539 | 540 | .cuIcon-flashlightopen:before { 541 | content: "\e6fd"; 542 | } 543 | 544 | .cuIcon-searchlist:before { 545 | content: "\e6fe"; 546 | } 547 | 548 | .cuIcon-service:before { 549 | content: "\e6ff"; 550 | } 551 | 552 | .cuIcon-sort:before { 553 | content: "\e700"; 554 | } 555 | 556 | .cuIcon-down:before { 557 | content: "\e703"; 558 | } 559 | 560 | .cuIcon-mobile:before { 561 | content: "\e704"; 562 | } 563 | 564 | .cuIcon-mobilefill:before { 565 | content: "\e705"; 566 | } 567 | 568 | .cuIcon-copy:before { 569 | content: "\e706"; 570 | } 571 | 572 | .cuIcon-countdownfill:before { 573 | content: "\e707"; 574 | } 575 | 576 | .cuIcon-countdown:before { 577 | content: "\e708"; 578 | } 579 | 580 | .cuIcon-noticefill:before { 581 | content: "\e709"; 582 | } 583 | 584 | .cuIcon-notice:before { 585 | content: "\e70a"; 586 | } 587 | 588 | .cuIcon-upstagefill:before { 589 | content: "\e70e"; 590 | } 591 | 592 | .cuIcon-upstage:before { 593 | content: "\e70f"; 594 | } 595 | 596 | .cuIcon-babyfill:before { 597 | content: "\e710"; 598 | } 599 | 600 | .cuIcon-baby:before { 601 | content: "\e711"; 602 | } 603 | 604 | .cuIcon-brandfill:before { 605 | content: "\e712"; 606 | } 607 | 608 | .cuIcon-brand:before { 609 | content: "\e713"; 610 | } 611 | 612 | .cuIcon-choicenessfill:before { 613 | content: "\e714"; 614 | } 615 | 616 | .cuIcon-choiceness:before { 617 | content: "\e715"; 618 | } 619 | 620 | .cuIcon-clothesfill:before { 621 | content: "\e716"; 622 | } 623 | 624 | .cuIcon-clothes:before { 625 | content: "\e717"; 626 | } 627 | 628 | .cuIcon-creativefill:before { 629 | content: "\e718"; 630 | } 631 | 632 | .cuIcon-creative:before { 633 | content: "\e719"; 634 | } 635 | 636 | .cuIcon-female:before { 637 | content: "\e71a"; 638 | } 639 | 640 | .cuIcon-keyboard:before { 641 | content: "\e71b"; 642 | } 643 | 644 | .cuIcon-male:before { 645 | content: "\e71c"; 646 | } 647 | 648 | .cuIcon-newfill:before { 649 | content: "\e71d"; 650 | } 651 | 652 | .cuIcon-new:before { 653 | content: "\e71e"; 654 | } 655 | 656 | .cuIcon-pullleft:before { 657 | content: "\e71f"; 658 | } 659 | 660 | .cuIcon-pullright:before { 661 | content: "\e720"; 662 | } 663 | 664 | .cuIcon-rankfill:before { 665 | content: "\e721"; 666 | } 667 | 668 | .cuIcon-rank:before { 669 | content: "\e722"; 670 | } 671 | 672 | .cuIcon-bad:before { 673 | content: "\e723"; 674 | } 675 | 676 | .cuIcon-cameraadd:before { 677 | content: "\e724"; 678 | } 679 | 680 | .cuIcon-focus:before { 681 | content: "\e725"; 682 | } 683 | 684 | .cuIcon-friendfill:before { 685 | content: "\e726"; 686 | } 687 | 688 | .cuIcon-cameraaddfill:before { 689 | content: "\e727"; 690 | } 691 | 692 | .cuIcon-apps:before { 693 | content: "\e729"; 694 | } 695 | 696 | .cuIcon-paintfill:before { 697 | content: "\e72a"; 698 | } 699 | 700 | .cuIcon-paint:before { 701 | content: "\e72b"; 702 | } 703 | 704 | .cuIcon-picfill:before { 705 | content: "\e72c"; 706 | } 707 | 708 | .cuIcon-refresharrow:before { 709 | content: "\e72d"; 710 | } 711 | 712 | .cuIcon-colorlens:before { 713 | content: "\e6e6"; 714 | } 715 | 716 | .cuIcon-markfill:before { 717 | content: "\e730"; 718 | } 719 | 720 | .cuIcon-mark:before { 721 | content: "\e731"; 722 | } 723 | 724 | .cuIcon-presentfill:before { 725 | content: "\e732"; 726 | } 727 | 728 | .cuIcon-repeal:before { 729 | content: "\e733"; 730 | } 731 | 732 | .cuIcon-album:before { 733 | content: "\e734"; 734 | } 735 | 736 | .cuIcon-peoplefill:before { 737 | content: "\e735"; 738 | } 739 | 740 | .cuIcon-people:before { 741 | content: "\e736"; 742 | } 743 | 744 | .cuIcon-servicefill:before { 745 | content: "\e737"; 746 | } 747 | 748 | .cuIcon-repair:before { 749 | content: "\e738"; 750 | } 751 | 752 | .cuIcon-file:before { 753 | content: "\e739"; 754 | } 755 | 756 | .cuIcon-repairfill:before { 757 | content: "\e73a"; 758 | } 759 | 760 | .cuIcon-taoxiaopu:before { 761 | content: "\e73b"; 762 | } 763 | 764 | .cuIcon-weixin:before { 765 | content: "\e612"; 766 | } 767 | 768 | .cuIcon-attentionfill:before { 769 | content: "\e73c"; 770 | } 771 | 772 | .cuIcon-attention:before { 773 | content: "\e73d"; 774 | } 775 | 776 | .cuIcon-commandfill:before { 777 | content: "\e73e"; 778 | } 779 | 780 | .cuIcon-command:before { 781 | content: "\e73f"; 782 | } 783 | 784 | .cuIcon-communityfill:before { 785 | content: "\e740"; 786 | } 787 | 788 | .cuIcon-community:before { 789 | content: "\e741"; 790 | } 791 | 792 | .cuIcon-read:before { 793 | content: "\e742"; 794 | } 795 | 796 | .cuIcon-calendar:before { 797 | content: "\e74a"; 798 | } 799 | 800 | .cuIcon-cut:before { 801 | content: "\e74b"; 802 | } 803 | 804 | .cuIcon-magic:before { 805 | content: "\e74c"; 806 | } 807 | 808 | .cuIcon-backwardfill:before { 809 | content: "\e74d"; 810 | } 811 | 812 | .cuIcon-playfill:before { 813 | content: "\e74f"; 814 | } 815 | 816 | .cuIcon-stop:before { 817 | content: "\e750"; 818 | } 819 | 820 | .cuIcon-tagfill:before { 821 | content: "\e751"; 822 | } 823 | 824 | .cuIcon-tag:before { 825 | content: "\e752"; 826 | } 827 | 828 | .cuIcon-group:before { 829 | content: "\e753"; 830 | } 831 | 832 | .cuIcon-all:before { 833 | content: "\e755"; 834 | } 835 | 836 | .cuIcon-backdelete:before { 837 | content: "\e756"; 838 | } 839 | 840 | .cuIcon-hotfill:before { 841 | content: "\e757"; 842 | } 843 | 844 | .cuIcon-hot:before { 845 | content: "\e758"; 846 | } 847 | 848 | .cuIcon-post:before { 849 | content: "\e759"; 850 | } 851 | 852 | .cuIcon-radiobox:before { 853 | content: "\e75b"; 854 | } 855 | 856 | .cuIcon-rounddown:before { 857 | content: "\e75c"; 858 | } 859 | 860 | .cuIcon-upload:before { 861 | content: "\e75d"; 862 | } 863 | 864 | .cuIcon-writefill:before { 865 | content: "\e760"; 866 | } 867 | 868 | .cuIcon-write:before { 869 | content: "\e761"; 870 | } 871 | 872 | .cuIcon-radioboxfill:before { 873 | content: "\e763"; 874 | } 875 | 876 | .cuIcon-punch:before { 877 | content: "\e764"; 878 | } 879 | 880 | .cuIcon-shake:before { 881 | content: "\e765"; 882 | } 883 | 884 | .cuIcon-move:before { 885 | content: "\e768"; 886 | } 887 | 888 | .cuIcon-safe:before { 889 | content: "\e769"; 890 | } 891 | 892 | .cuIcon-activityfill:before { 893 | content: "\e775"; 894 | } 895 | 896 | .cuIcon-crownfill:before { 897 | content: "\e776"; 898 | } 899 | 900 | .cuIcon-crown:before { 901 | content: "\e777"; 902 | } 903 | 904 | .cuIcon-goodsfill:before { 905 | content: "\e778"; 906 | } 907 | 908 | .cuIcon-messagefill:before { 909 | content: "\e779"; 910 | } 911 | 912 | .cuIcon-profilefill:before { 913 | content: "\e77a"; 914 | } 915 | 916 | .cuIcon-sound:before { 917 | content: "\e77b"; 918 | } 919 | 920 | .cuIcon-sponsorfill:before { 921 | content: "\e77c"; 922 | } 923 | 924 | .cuIcon-sponsor:before { 925 | content: "\e77d"; 926 | } 927 | 928 | .cuIcon-upblock:before { 929 | content: "\e77e"; 930 | } 931 | 932 | .cuIcon-weblock:before { 933 | content: "\e77f"; 934 | } 935 | 936 | .cuIcon-weunblock:before { 937 | content: "\e780"; 938 | } 939 | 940 | .cuIcon-my:before { 941 | content: "\e78b"; 942 | } 943 | 944 | .cuIcon-myfill:before { 945 | content: "\e78c"; 946 | } 947 | 948 | .cuIcon-emojifill:before { 949 | content: "\e78d"; 950 | } 951 | 952 | .cuIcon-emojiflashfill:before { 953 | content: "\e78e"; 954 | } 955 | 956 | .cuIcon-flashbuyfill:before { 957 | content: "\e78f"; 958 | } 959 | 960 | .cuIcon-text:before { 961 | content: "\e791"; 962 | } 963 | 964 | .cuIcon-goodsfavor:before { 965 | content: "\e794"; 966 | } 967 | 968 | .cuIcon-musicfill:before { 969 | content: "\e795"; 970 | } 971 | 972 | .cuIcon-musicforbidfill:before { 973 | content: "\e796"; 974 | } 975 | 976 | .cuIcon-card:before { 977 | content: "\e624"; 978 | } 979 | 980 | .cuIcon-triangledownfill:before { 981 | content: "\e79b"; 982 | } 983 | 984 | .cuIcon-triangleupfill:before { 985 | content: "\e79c"; 986 | } 987 | 988 | .cuIcon-roundleftfill-copy:before { 989 | content: "\e79e"; 990 | } 991 | 992 | .cuIcon-font:before { 993 | content: "\e76a"; 994 | } 995 | 996 | .cuIcon-title:before { 997 | content: "\e82f"; 998 | } 999 | 1000 | .cuIcon-recordfill:before { 1001 | content: "\e7a4"; 1002 | } 1003 | 1004 | .cuIcon-record:before { 1005 | content: "\e7a6"; 1006 | } 1007 | 1008 | .cuIcon-cardboardfill:before { 1009 | content: "\e7a9"; 1010 | } 1011 | 1012 | .cuIcon-cardboard:before { 1013 | content: "\e7aa"; 1014 | } 1015 | 1016 | .cuIcon-formfill:before { 1017 | content: "\e7ab"; 1018 | } 1019 | 1020 | .cuIcon-coin:before { 1021 | content: "\e7ac"; 1022 | } 1023 | 1024 | .cuIcon-cardboardforbid:before { 1025 | content: "\e7af"; 1026 | } 1027 | 1028 | .cuIcon-circlefill:before { 1029 | content: "\e7b0"; 1030 | } 1031 | 1032 | .cuIcon-circle:before { 1033 | content: "\e7b1"; 1034 | } 1035 | 1036 | .cuIcon-attentionforbid:before { 1037 | content: "\e7b2"; 1038 | } 1039 | 1040 | .cuIcon-attentionforbidfill:before { 1041 | content: "\e7b3"; 1042 | } 1043 | 1044 | .cuIcon-attentionfavorfill:before { 1045 | content: "\e7b4"; 1046 | } 1047 | 1048 | .cuIcon-attentionfavor:before { 1049 | content: "\e7b5"; 1050 | } 1051 | 1052 | .cuIcon-titles:before { 1053 | content: "\e701"; 1054 | } 1055 | 1056 | .cuIcon-icloading:before { 1057 | content: "\e67a"; 1058 | } 1059 | 1060 | .cuIcon-full:before { 1061 | content: "\e7bc"; 1062 | } 1063 | 1064 | .cuIcon-mail:before { 1065 | content: "\e7bd"; 1066 | } 1067 | 1068 | .cuIcon-peoplelist:before { 1069 | content: "\e7be"; 1070 | } 1071 | 1072 | .cuIcon-goodsnewfill:before { 1073 | content: "\e7bf"; 1074 | } 1075 | 1076 | .cuIcon-goodsnew:before { 1077 | content: "\e7c0"; 1078 | } 1079 | 1080 | .cuIcon-medalfill:before { 1081 | content: "\e7c1"; 1082 | } 1083 | 1084 | .cuIcon-medal:before { 1085 | content: "\e7c2"; 1086 | } 1087 | 1088 | .cuIcon-newsfill:before { 1089 | content: "\e7c3"; 1090 | } 1091 | 1092 | .cuIcon-newshotfill:before { 1093 | content: "\e7c4"; 1094 | } 1095 | 1096 | .cuIcon-newshot:before { 1097 | content: "\e7c5"; 1098 | } 1099 | 1100 | .cuIcon-news:before { 1101 | content: "\e7c6"; 1102 | } 1103 | 1104 | .cuIcon-videofill:before { 1105 | content: "\e7c7"; 1106 | } 1107 | 1108 | .cuIcon-video:before { 1109 | content: "\e7c8"; 1110 | } 1111 | 1112 | .cuIcon-exit:before { 1113 | content: "\e7cb"; 1114 | } 1115 | 1116 | .cuIcon-skinfill:before { 1117 | content: "\e7cc"; 1118 | } 1119 | 1120 | .cuIcon-skin:before { 1121 | content: "\e7cd"; 1122 | } 1123 | 1124 | .cuIcon-moneybagfill:before { 1125 | content: "\e7ce"; 1126 | } 1127 | 1128 | .cuIcon-usefullfill:before { 1129 | content: "\e7cf"; 1130 | } 1131 | 1132 | .cuIcon-usefull:before { 1133 | content: "\e7d0"; 1134 | } 1135 | 1136 | .cuIcon-moneybag:before { 1137 | content: "\e7d1"; 1138 | } 1139 | 1140 | .cuIcon-redpacket_fill:before { 1141 | content: "\e7d3"; 1142 | } 1143 | 1144 | .cuIcon-subscription:before { 1145 | content: "\e7d4"; 1146 | } 1147 | 1148 | .cuIcon-loading1:before { 1149 | content: "\e633"; 1150 | } 1151 | 1152 | .cuIcon-github:before { 1153 | content: "\e692"; 1154 | } 1155 | 1156 | .cuIcon-global:before { 1157 | content: "\e7eb"; 1158 | } 1159 | 1160 | .cuIcon-settingsfill:before { 1161 | content: "\e6ab"; 1162 | } 1163 | 1164 | .cuIcon-back_android:before { 1165 | content: "\e7ed"; 1166 | } 1167 | 1168 | .cuIcon-expressman:before { 1169 | content: "\e7ef"; 1170 | } 1171 | 1172 | .cuIcon-evaluate_fill:before { 1173 | content: "\e7f0"; 1174 | } 1175 | 1176 | .cuIcon-group_fill:before { 1177 | content: "\e7f5"; 1178 | } 1179 | 1180 | .cuIcon-play_forward_fill:before { 1181 | content: "\e7f6"; 1182 | } 1183 | 1184 | .cuIcon-deliver_fill:before { 1185 | content: "\e7f7"; 1186 | } 1187 | 1188 | .cuIcon-notice_forbid_fill:before { 1189 | content: "\e7f8"; 1190 | } 1191 | 1192 | .cuIcon-fork:before { 1193 | content: "\e60c"; 1194 | } 1195 | 1196 | .cuIcon-pick:before { 1197 | content: "\e7fa"; 1198 | } 1199 | 1200 | .cuIcon-wenzi:before { 1201 | content: "\e6a7"; 1202 | } 1203 | 1204 | .cuIcon-ellipse:before { 1205 | content: "\e600"; 1206 | } 1207 | 1208 | .cuIcon-qr_code:before { 1209 | content: "\e61b"; 1210 | } 1211 | 1212 | .cuIcon-dianhua:before { 1213 | content: "\e64d"; 1214 | } 1215 | 1216 | .cuIcon-icon:before { 1217 | content: "\e602"; 1218 | } 1219 | 1220 | .cuIcon-loading2:before { 1221 | content: "\e7f1"; 1222 | } 1223 | 1224 | .cuIcon-btn:before { 1225 | content: "\e601"; 1226 | } 1227 | --------------------------------------------------------------------------------