├── .gitignore ├── Docs ├── fonts │ ├── slate-7b7da4fe.ttf │ ├── slate-cfc9d06b.eot │ ├── slate-e55b8307.svg │ ├── slate.woff │ └── slate.woff2 ├── images │ ├── KeyMoji_img01-c52f80f2.png │ ├── KeyMoji_img02-ad568a9a.png │ ├── KeyMoji_img03-f72c41bf.png │ ├── KeyMoji_img04-fa676223.png │ ├── KeyMoji_img05-16b589e1.png │ ├── KeyMoji_img05-f1e9ea3f.svg │ ├── KeyMoji_img06-9e9f01c9.png │ ├── KeyMoji_img07-f05d3a88.png │ ├── KeyMoji_img08-4862fcba.png │ ├── logo-e4b85fef.png │ ├── navbar-cad8cdcb.png │ ├── sense2-47eb5348.png │ ├── sense8-5454ca63.png │ └── tension-7473086b.png ├── index.html ├── javascripts │ ├── all-a9fde460.js │ └── all_nosearch-8f5ea5a5.js └── stylesheets │ ├── print-772a6e2a.css │ └── screen-849c4fff.css ├── KeyMojiAPI.py ├── KeyMojiAPI ├── KeyMojiAPI.py ├── __init__.py ├── jf-openhuninn-1.1.ttf ├── sense8_null.png └── sense_watermark.png ├── LICENSE ├── MANIFEST.in ├── README.md └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | .DS_Store 3 | *.info 4 | *.pyc 5 | *.json 6 | KeyMojiAPI.egg-info 7 | build.md 8 | /slate 9 | /build 10 | /dist 11 | -------------------------------------------------------------------------------- /Docs/fonts/slate-7b7da4fe.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Droidtown/KeyMojiAPI/ce05cd3acf20aaf08936e9c61fe31e5a65e457b6/Docs/fonts/slate-7b7da4fe.ttf -------------------------------------------------------------------------------- /Docs/fonts/slate-cfc9d06b.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Droidtown/KeyMojiAPI/ce05cd3acf20aaf08936e9c61fe31e5a65e457b6/Docs/fonts/slate-cfc9d06b.eot -------------------------------------------------------------------------------- /Docs/fonts/slate-e55b8307.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Generated by IcoMoon 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Docs/fonts/slate.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Droidtown/KeyMojiAPI/ce05cd3acf20aaf08936e9c61fe31e5a65e457b6/Docs/fonts/slate.woff -------------------------------------------------------------------------------- /Docs/fonts/slate.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Droidtown/KeyMojiAPI/ce05cd3acf20aaf08936e9c61fe31e5a65e457b6/Docs/fonts/slate.woff2 -------------------------------------------------------------------------------- /Docs/images/KeyMoji_img01-c52f80f2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Droidtown/KeyMojiAPI/ce05cd3acf20aaf08936e9c61fe31e5a65e457b6/Docs/images/KeyMoji_img01-c52f80f2.png -------------------------------------------------------------------------------- /Docs/images/KeyMoji_img02-ad568a9a.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Droidtown/KeyMojiAPI/ce05cd3acf20aaf08936e9c61fe31e5a65e457b6/Docs/images/KeyMoji_img02-ad568a9a.png -------------------------------------------------------------------------------- /Docs/images/KeyMoji_img03-f72c41bf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Droidtown/KeyMojiAPI/ce05cd3acf20aaf08936e9c61fe31e5a65e457b6/Docs/images/KeyMoji_img03-f72c41bf.png -------------------------------------------------------------------------------- /Docs/images/KeyMoji_img04-fa676223.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Droidtown/KeyMojiAPI/ce05cd3acf20aaf08936e9c61fe31e5a65e457b6/Docs/images/KeyMoji_img04-fa676223.png -------------------------------------------------------------------------------- /Docs/images/KeyMoji_img05-16b589e1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Droidtown/KeyMojiAPI/ce05cd3acf20aaf08936e9c61fe31e5a65e457b6/Docs/images/KeyMoji_img05-16b589e1.png -------------------------------------------------------------------------------- /Docs/images/KeyMoji_img05-f1e9ea3f.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | image/svg+xml 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | AlegriaJoy 47 | ConfiançaTrust 48 | MedoFear 49 | SurpresaSurprise 50 | TristezaSadness 51 | NojoDisgust 52 | RaivaAnger 53 | AntecipaçãoAnticipation 54 | OtimismoOptimism 55 | DesaprovaçãoDisapproval 56 | AmorLove 57 | RemorsoRemorse 58 | AgressividadeAggressiveness 59 | TemorAwe 60 | SubmissãoSubmission 61 | DeleiteDelight 62 | DominânciaDominance 63 | VergonhaShame 64 | AnsiedadeAnxiety 65 | Outrage 66 | Morbidness 67 | Sentimentality 68 | Contempt 69 | Pessimism 70 | Hope 71 | Unbelief 72 | Guilt 73 | Envy 74 | Pride 75 | Despair 76 | Curiosity 77 | Cynicism 78 | 79 | -------------------------------------------------------------------------------- /Docs/images/KeyMoji_img06-9e9f01c9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Droidtown/KeyMojiAPI/ce05cd3acf20aaf08936e9c61fe31e5a65e457b6/Docs/images/KeyMoji_img06-9e9f01c9.png -------------------------------------------------------------------------------- /Docs/images/KeyMoji_img07-f05d3a88.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Droidtown/KeyMojiAPI/ce05cd3acf20aaf08936e9c61fe31e5a65e457b6/Docs/images/KeyMoji_img07-f05d3a88.png -------------------------------------------------------------------------------- /Docs/images/KeyMoji_img08-4862fcba.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Droidtown/KeyMojiAPI/ce05cd3acf20aaf08936e9c61fe31e5a65e457b6/Docs/images/KeyMoji_img08-4862fcba.png -------------------------------------------------------------------------------- /Docs/images/logo-e4b85fef.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Droidtown/KeyMojiAPI/ce05cd3acf20aaf08936e9c61fe31e5a65e457b6/Docs/images/logo-e4b85fef.png -------------------------------------------------------------------------------- /Docs/images/navbar-cad8cdcb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Droidtown/KeyMojiAPI/ce05cd3acf20aaf08936e9c61fe31e5a65e457b6/Docs/images/navbar-cad8cdcb.png -------------------------------------------------------------------------------- /Docs/images/sense2-47eb5348.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Droidtown/KeyMojiAPI/ce05cd3acf20aaf08936e9c61fe31e5a65e457b6/Docs/images/sense2-47eb5348.png -------------------------------------------------------------------------------- /Docs/images/sense8-5454ca63.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Droidtown/KeyMojiAPI/ce05cd3acf20aaf08936e9c61fe31e5a65e457b6/Docs/images/sense8-5454ca63.png -------------------------------------------------------------------------------- /Docs/images/tension-7473086b.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Droidtown/KeyMojiAPI/ce05cd3acf20aaf08936e9c61fe31e5a65e457b6/Docs/images/tension-7473086b.png -------------------------------------------------------------------------------- /Docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | API Reference 9 | 10 | 11 | 200 | 286 | 287 | 288 | 289 | 290 | 293 | 294 | 295 | 296 | 297 | 298 | NAV 299 | 300 | 301 | 302 |
303 | 304 |
305 | Python 306 |
307 | 329 | 333 |
334 |
335 |
336 |
337 |

KeyMojiAPI

KeyMoji

338 |
339 |

範例程式:

340 |
341 |
from KeyMojiAPI import KeyMoji
 342 | # 若您是使用 Docker 版本,無須填入 username, username 參數
 343 | keymoji = KeyMoji(username="", keymojiKey="")
 344 | 
345 |

初始化 KeyMojiAPI。

346 |

參數說明

347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 |
參數型態預設功能
usernamestr""您在本站註冊時所使用的帳號 (email)。
KeyMoji Docker 版本無需設定此參數。
keymojiKeystr""在本站購買KeyMoji服務,完成付費後取得的一個具有 31 字符長度的字串。
KeyMoji Docker 版本無需設定此參數。
urlstr"https://api.droidtown.co"若您購買 KeyMoji Docker 版本,請設定自行架設 KeyMoji Docker 的服務網址。
374 |

sense2

375 |
376 |

範例程式:

377 |
378 |
inputSTR = "他逃離了危險的災難"
 379 | sense2Result = keymoji.sense2(inputSTR, model="general",
 380 |                               userDefinedDICT={"positive": [], "negative": [], "cursing": []})
 381 | 
382 |
383 |

回傳結果 (JSON 格式):

384 |
385 |
{
 386 |     "status": true,
 387 |     "msg": "Success!",
 388 |     "results": [
 389 |         {
 390 |             "score": 0.2798,
 391 |             "sentiment": "positive",
 392 |             "input_str": "他逃離了危險的災難",
 393 |             "cursing": false
 394 |         }
 395 |     ],
 396 |     "sense": "sense2",
 397 |     "model": "general",
 398 |     "version": "v101"
 399 | }
 400 | 

參數說明

401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 |
參數型態預設功能
inputSTRstr""將要送上 KeyMoji 情緒偵測處理的文字。
注意!每次最大長度不得超過 6000 個字符
contextSenitivityboolTrue語境敏感開關,預設為 True。此參數為 True 時,前句的句子若有分數,若此句計算的結果無分數,則前句的分數會延續影響此句分數,直到下一句計算的結果有分數。
例如:
contextSenitivity = True
inputSTR = "好不容易離開思念的軌跡,回憶將我聯繫到過去"
結果為:
"好不容易離開思念的軌跡" => -0.6043, "回憶將我聯繫到過去" => -0.4532
反之,參數為 False 時,"回憶將我聯繫到過去" => 0
modelstr"general"可為 "general"、"hotel"、"restaurant" 或 "shopping",預設為 "general"。
指定不同的計算模型,將情緒偵測結果投射到二維 (SENSE2)、八維 (SENSE8) 的情緒空間。
--general: 使用通用模型,依據 句型結構 計算文本的情緒分數。
--hotel: 使用旅館評價模型,依據 訓練模型 計算文本的情緒分數。
--restaurant: 使用餐廳評價模型,依據 訓練模型 計算文本的情緒分數。
--shopping: 使用購物評價模型,依據 訓練模型 計算文本的情緒分數。
context_sensitivityboolTrue語境敏感開關,預設為 True。此參數為 True 時,前句的句子若有分數,若此句計算的結果無分數,則前句的分數會延續影響此句分數,直到下一句計算的結果有分數。
例如:
context_sensitivity = True
input_str = "好不容易離開思念的軌跡,回憶將我聯繫到過去"
結果為:
"好不容易離開思念的軌跡" => -0.6043, "回憶將我聯繫到過去" => -0.4532
反之,參數為 False 時,"回憶將我聯繫到過去" => 0
將 model 指定為 "general" 時才有此功能
user_defineddict{}使用者自訂的正向 "positive"、負向 "negative""cursing" 字典,若使用此功能,會優先計算其字典內的詞彙分數。
例如:{"positive": ["邪惡", "地獄"], "negative": ["正義", "天堂"]} 。
若 positive 與 negative 有相同詞彙,則會相互抵銷其分數
464 |

回傳內容說明

465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 |
回傳訊息型態說明
statusbool若成功執行並收到情緒偵測結果,回傳 True;失敗,則回傳 False
msgstr可能為以下的文字:
- Success!: 順利完成情緒偵測作業。
- Invalid arguments.: 上傳參數錯誤,請重新檢查上傳時的參數是否符合規則名稱。
- Invalid content_type.: 上傳格式必須為 Json 格式 (application/json)。
- Your input_str is too long (over 6000 characters.): input_str 超過 6000 字符。
- Authentication Failed.: 無法驗証您的帳號,或是未購買KeyMoji方案。請再檢查一次您使用的帳號是否正確。
- Invalid KeyMoji_Key.: 無效的 keymoji_key。請再檢查一次您的 keymoji_key 是否正確。
- Invalid sense.: sense 所指定的參數不存在。
- request['context_sensitivity'] only takes True/False.: context_sensitivity 只能是 boolean 格式。
- request['sense'] should be set as 'tension', 'sense2' or 'sense8', other settings don't make any sense to KeyMoji.: sense 需要指定其參數為 'tension', 'sense2' 或 'sense8' 字串。
- request['model'] must be one of the models listed: 'general', 'hotel', 'shopping' or 'restaurant'.: model 需要指定其參數為 'general', 'hotel', 'shopping' 或 'restaurant' 字串。
- request['user_defined'] Parsing ERROR. (Please check your the format and encoding.): user_defined 必須是 DICT 格式,例如: {"positive": ["邪惡", "地獄"], "negative": ["正義", "天堂"]} 。
- Internal Server Error. (System will reboot in 5min, please try again later.): 嗯…似乎我們的伺服器出了點狀況。我們正在努力修復中,5 分鐘內會自動重啟,請稍後再試一次。
sensestr此次情緒偵測所使用的功能。
此範例為 sense2。
modelstr此次情緒偵測所使用的模型。
此範例為 general。
resultslist以句子為一個單位,將計算結果存儲至 dict,內容包含以下
- inputSTR: 單句的文字字串。
- cursing: input_str 是否含有國罵的文字內容,例:XX娘。
- score: 計算 input_str 的情緒分數。context_sensitivity == True時,會受到前句的結果影響,不同於單句計算的分數。
- sentiment: 依據語意計算結果判斷 input_str 的表述,屬於在人類情緒光譜上哪個分佈位置:
     --positive: 正向表述 (0.2, 1]
     --negative: 負向表述 [-1, -0.2)
     --neutral: 中性表述 [-0.2, -0.2]
593 |

sense8

594 |

情緒又稱「情感」,是動物出於本能與生俱來的多種感覺、思想和行為綜合產生的心理和生理狀態,並與我們生活息息相關。有些複雜情緒必須經過與他人互動才能學習到,因此每個人所擁有的情緒數量和對情緒的定義都不一樣。
595 | KeyMoji 依據美國心理學家 Robert Plutchik 提出八種主要的成對兩極核心情緒,分別為 AngerAnticipationDisgustFearJoySadnessSurpriseTrust 來做計算。
596 |

情緒輪

597 | 598 |
599 |

範例程式:

600 |
601 |
inputSTR = "他逃離了危險的災難"
 602 | sense8Result = keymoji.sense8(inputSTR, model="general",
 603 |                               userDefinedDICT={"positive": [], "negative": [], "cursing": []})
 604 | 
605 |
606 |

回傳結果 (JSON 格式):

607 |
608 |
{
 609 |     "status": true,
 610 |     "msg": "Success!",
 611 |     "results": [
 612 |         {
 613 |             "input_str": "他逃離了危險的災難",
 614 |             "Joy": 3.7486,
 615 |             "Trust": 5.1776,
 616 |             "Surprise": 6.7238,
 617 |             "Anticipation": 0.9618,
 618 |             "Fear": 0.9505,
 619 |             "Sadness": 0.9108,
 620 |             "Anger": 0.9516,
 621 |             "Disgust": 0.8876
 622 |         }
 623 |     ],
 624 |     "sense": "sense8",
 625 |     "model": "general",
 626 |     "version": "v101"
 627 | }
 628 | 

參數說明

629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 |
參數型態預設功能
inputSTRstr""將要送上 KeyMoji 情緒偵測處理的文字。
注意!每次最大長度不得超過 6000 個字符
modelstr"general"可為 "general"、"hotel"、"restaurant" 或 "shopping",預設為 "general"。
指定不同的計算模型,將情緒偵測結果投射到二維 (SENSE2)、八維 (SENSE8) 的情緒空間。
--general: 使用通用模型,依據 句型結構 計算文本的情緒分數。
--hotel: 使用旅館評價模型,依據 訓練模型 計算文本的情緒分數。
--restaurant: 使用餐廳評價模型,依據 訓練模型 計算文本的情緒分數。
--shopping: 使用購物評價模型,依據 訓練模型 計算文本的情緒分數。
user_defineddict{}使用者自訂的正向 "positive"、負向 "negative""cursing" 字典,若使用此功能,會優先計算其字典內的詞彙分數。
例如:{"positive": ["邪惡", "地獄"], "negative": ["正義", "天堂"]} 。
680 | 681 |

PS.關於SENSE8八個維度參考的來源。

682 |

回傳內容說明

683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | 713 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 |
回傳訊息型態說明
statusbool若成功執行並收到情緒偵測結果,回傳 True;失敗,則回傳 False
msgstr可能為以下的文字:
- Success!: 順利完成情緒偵測作業。
- Invalid arguments.: 上傳參數錯誤,請重新檢查上傳時的參數是否符合規則名稱。
- Invalid content_type.: 上傳格式必須為 Json 格式 (application/json)。
- Your input_str is too long (over 6000 characters.): input_str 超過 6000 字符。
- Authentication Failed.: 無法驗証您的帳號,或是未購買KeyMoji方案。請再檢查一次您使用的帳號是否正確。
- Invalid KeyMoji_Key.: 無效的 keymoji_key。請再檢查一次您的 keymoji_key 是否正確。
- Invalid sense.: sense 所指定的參數不存在。
- request['context_sensitivity'] only takes True/False.: context_sensitivity 只能是 boolean 格式。
- request['sense'] should be set as 'tension', 'sense2' or 'sense8', other settings don't make any sense to KeyMoji.: sense 需要指定其參數為 'tension', 'sense2' 或 'sense8' 字串。
- request['model'] must be one of the models listed: 'general', 'hotel', 'shopping' or 'restaurant'.: model 需要指定其參數為 'general', 'hotel', 'shopping' 或 'restaurant' 字串。
- request['user_defined'] Parsing ERROR. (Please check your the format and encoding.): user_defined 必須是 DICT 格式,例如: {"positive": ["邪惡", "地獄"], "negative": ["正義", "天堂"]} 。
- Internal Server Error. (System will reboot in 5min, please try again later.): 嗯…似乎我們的伺服器出了點狀況。我們正在努力修復中,5 分鐘內會自動重啟,請稍後再試一次。
sensestr此次情緒偵測所使用的功能。
此範例為 sense8。
modelstr此次情緒偵測所使用的模型。
此範例為 general。
resultslist以句子為一個單位,將計算結果存儲至 dict,內容包含四種 正/負向情緒,共八種情緒分數[0, 12.5]
- inputSTR: 單句的文字字串。
- Anger: 負向情緒分數,在 inputSTR 裡存在「憤怒」語意意涵的指數。
- Disgust: 負向情緒分數,在 inputSTR 裡存在「噁心」語意意涵的指數。
- Fear: 負向情緒分數,在 inputSTR 裡存在「恐懼」語意意涵的指數。
- Sadness: 負向情緒分數,在 inputSTR 裡存在「悲傷」語意意涵的指數。
- Joy: 正向情緒分數,在 inputSTR 裡存在「歡樂」語意意涵的指數。
- Anticipation: 正向情緒分數,在 inputSTR 裡存在「期待」語意意涵的指數。
- Surprise: 正向情緒分數,在 inputSTR 裡存在「驚喜」語意意涵的指數。
- Trust: 正向情緒分數,在 inputSTR 裡存在「信任」語意意涵的指數。
821 |

PS.八維度核心情緒分類請參考下表:

822 |

八維度核心情緒

823 |

tension

824 |
825 |

範例程式:

826 |
827 |
inputSTR = """我想向各位更新我們的努力成果,曝光在那荒謬、漫長的11月3日選舉中所發生的大面積選舉舞弊和各種不正常的現象。
 828 | 我們以前有所謂的「選舉日」,現在卻拖延成好幾個選舉週、選舉月,這段時間裡許多不好的事發生了,特別是我們得去證明那些原本我們不需要去驗證的事,才得以執行我們最偉大的特權——選舉權。
 829 | 作為總統,我責無旁貸,保護這個國家的法律和憲法,所以我決心保障我們的選舉系統。
 830 | 而這個系統正遭受合謀攻擊。在總統選舉前的幾個月,我們被多次警告,不要過早宣告我們的勝選;我們反覆被告知,這場選舉將耗時幾週甚至幾個月來分出勝、來數缺席者選票,並確認結果。
 831 | 我的對手被告知:「可以與選舉保持距離,不需要競選活動。我們不需要你。我們搞定了,這場選舉已經結束。」
 832 | 實際上,他們的表現得好像他們早已知道了這場選舉的結果。一切都在他們的掌控之中。很可能是這樣,這對我們的國家來說是非常悲哀的。
 833 | 這一切(發生的事情)都非常奇怪。在選舉後的幾天,我們見證了這場試圖決定勝者的操作。即使許多關鍵州仍然在計算選票。
 834 | 我們必須繼續依循憲法流程,為維護選舉的誠信,我們將確保計算每張合法選票,不計算任何一張非法選票。這不只是為了尊重那7,400萬選我的美國人,也是為了確保美國人能對這場選舉、以致未來的選舉還能保有信心。
 835 | 今天我將詳細說明我們近幾週所揭露的那些驚人、不符合常規的濫權舞弊行為,呈現給各位我們所發現的證據中的一小部分。事實上我們有大量的證據。
 836 | 我想先和各位解釋腐敗的郵寄選票系統。
 837 | 民主黨是如何系統性地策劃,特別使搖擺州的選票得以被修改。因為他們必須在(那幾個州)獲得勝選。他們不知道的是,事情比他們預期的要困難許多,因為我們在所有搖擺州都遙遙領先,比他們認為的多太多了。
 838 | 我們老早就知道,民主黨的政治機器是如何參與選舉舞弊。從底特律到費城,從密爾沃基市到亞特蘭大,太多地方。
 839 | 今年所不同的是,民主黨積極推動印刷並寄出數十、數百萬張郵寄選票。寄到不知名的收件人手裡,沒有任何保護措施。這讓舞弊和濫權演變到前所未見的程度。
 840 | 利用疫情作為藉口,民主黨的法官和政客,在投票前幾個月甚至幾週前大肆修改選舉章程。
 841 | 11月3號的選舉,我們的立法者很少參與其中,但按憲法要求他們是該參與其中。但非常罕見。不過,你會看到隨著我們持續提起訴訟,所發生的一切,這場選舉絕對都是違憲的。
 842 | 包括內華達和加州等許多州,向選民名單上的每個人郵寄了(總數)超百萬的有效選票,無論這些人是否要求郵寄選票,無論是死是活,他們都收到了選票。
 843 | 在其它州,如明尼蘇達、密歇根州或威斯康星州,在今年年中就發起了普遍缺席選票,(他們)向所有名單上的選民發送缺席選票申請表。無論這些人的身分為何,如此大量的擴充投票數量使欺詐的閘門大大敞開。
 844 | 眾所周知的事實是,這些選票中塞滿了沒有合法投票權的人的選票,包括那些死者、搬走的、甚至是在我們國家沒有公民身分的人。更有甚者,這些紀錄充斥著各種錯誤,錯誤地址、重複輸入和其它問題,而這些錯誤都沒有被質疑,從來沒有被質疑過。
 845 | 在搖擺州的許多縣內,登記選民的人數遠超出合格適齡的選民人數,包括密歇根州的67個縣。所有這些都是證據。
 846 | 在威斯康辛,該州的選舉委員會無法證實其中超過十萬人的居民身分,卻拒絕將這些人從選民名冊中移除。他們知道為什麼這樣。
 847 | 我知道,他們是非法選民。荒謬的是,儘管到了2020年,我們竟沒有任何方法來核實那些投票選民的合法性。
 848 | 而這是一次如此重要的選舉,我們無法確定他們是誰?是否是該州居民?甚或是他們是否是美國公民?
 849 | 我們無法得知。我們(發現)在所有搖擺州都有重大違規或徹底的欺詐行為。其票數遠遠超過反轉一個州的(選舉)結果所需的票數。
 850 | 換句話說,以威斯康星州為例。我們在選舉日當晚(得票)遠遠超前,他們最終使我們奇蹟般地輸掉了2萬票。
 851 | 我可以在這裡向您展示,在威斯康星州,我們領先了許多,然而在凌晨3點42分出現了這樣一個大量的灌票,大多數是拜登,幾乎全是給拜登。直到今天,每個人都在試圖弄清楚它的來源。
 852 | 但我從大贏變成小輸,就在這凌晨3點42分,就在威斯康星。
 853 | 這是一件糟糕、糟糕、非常糟糕的事。但是,我們將擁有超出許多倍的、與推翻該州所需的2萬張選票相比的票數。
 854 | 如果我們對舞弊的了解正確,喬·拜登不能當總統。
 855 | 我們談的是數十萬的選票。我們談論的數字是前所未見的。
 856 | 舉個例子,在某個州,我們落後7000票,但後來我們找到2萬、5萬、10萬、20萬的異議或舞弊選票,其中包括那些未經共和黨監票員驗證的選票。因為這些監票員被鎖在門外不被允許查看這些選票。
 857 | 還有那些11月3日參加現場投票的人,他們都為能投票感到興奮,他們很開心,以身為美國公民為傲。他們在現場表示他們想要投票,然而他們被告知他們不能投票。
 858 | 「很抱歉」,他們被告知,「很抱歉,你已經投過郵寄選票了。恭喜你,我們已經收到了你們的選票,你們不能投票。」他們不知道該如何是好,他們投訴無門,只好離開現場,說這很奇怪。但是也有許多人強烈地抗議、投訴。
 859 | 在很多情況下,他們填寫了臨時選票,但他們的選票沒被用上。事實上,這些選票全是投給川普的。換句話說,他們去現場投票,卻被告知已經投過票了,但他們其實尚未投票,他們只好離開,感到非常喪氣。他們失去了對我們選舉系統的信心。"""
 860 | tensionResult = keymoji.tension(inputSTR, userDefinedDICT={"positive": [], "negative": [], "cursing": []})
 861 | 
862 |
863 |

回傳結果 (JSON 格式):

864 |
865 |
{
 866 |     "status": true,
 867 |     "msg": "Success!",
 868 |     "results": [0.1791, 0.1667, 0.1, 0.1622, 0.1558, 0.1528, 0.1061, 0.2083, 0.1026, 0.1951, 0.24],
 869 |     "sense": "tension",
 870 | }
 871 | 
872 |

在文章中修飾用詞「形容詞、副詞 MODIFIER」、「成語、諺語 IDIOM」 與「程度中心語 DegreeHead (e.g., 很、非常)」能提高整個句子的情緒張力 Tension
873 | KeyMoji 利用 Articut 斷詞後的 POS,取出每 180 個字符裡修飾用詞數除以句子的詞彙數 WordCount。試圖呈現文章中「平滑化後,每 180 個字符所呈現的情緒張力」係數。

874 |

情緒張力公式

875 |

情緒張力公式

876 |

參數說明

877 | 878 | 879 | 880 | 881 | 882 | 883 | 884 | 885 | 886 | 887 | 888 | 889 | 890 | 891 | 892 | 893 | 894 | 895 | 896 | 897 |
參數型態預設功能
inputSTRstr""將要送上 KeyMoji 情緒偵測處理的文字,至少 180 個字符。
注意!每次最大長度不得超過 6000 個字符
user_defineddict{}使用者自訂的正向 "positive"、負向 "negative""cursing" 字典,若使用此功能,會優先計算其字典內的詞彙分數。
例如:{"positive": ["邪惡", "地獄"], "negative": ["正義", "天堂"]} 。
898 |

回傳內容說明

899 | 900 | 901 | 902 | 903 | 904 | 905 | 906 | 907 | 908 | 909 | 910 | 911 | 912 | 913 | 914 | 915 | 916 | 917 | 918 | 919 | 920 | 921 | 922 | 923 | 924 | 925 | 926 | 927 | 928 | 929 | 930 | 931 | 932 | 933 | 934 | 935 | 936 | 937 | 938 | 939 | 940 | 941 | 942 | 943 | 944 | 945 | 946 | 947 | 948 | 949 | 950 | 951 | 952 | 953 | 954 | 955 | 956 | 957 | 958 | 959 | 960 | 961 | 962 | 963 | 964 | 965 | 966 | 967 | 968 | 969 | 970 | 971 | 972 | 973 | 974 | 975 | 976 |
回傳訊息型態說明
statusbool若成功執行並收到情緒偵測結果,回傳 True;失敗,則回傳 False
msgstr可能為以下的文字:
- Success!: 順利完成情緒偵測作業。
- Invalid arguments.: 上傳參數錯誤,請重新檢查上傳時的參數是否符合規則名稱。
- Invalid content_type.: 上傳格式必須為 Json 格式 (application/json)。
- Your input_str is too long (over 6000 characters.): input_str 超過 6000 字符。
- Authentication Failed.: 無法驗証您的帳號,或是未購買KeyMoji方案。請再檢查一次您使用的帳號是否正確。
- Invalid KeyMoji_Key.: 無效的 keymoji_key。請再檢查一次您的 keymoji_key 是否正確。
- Invalid sense.: sense 所指定的參數不存在。
- request['sense'] should be set as 'tension', 'sense2' or 'sense8', other settings don't make any sense to KeyMoji.: sense 需要指定其參數為 'tension', 'sense2' 或 'sense8' 字串。
- request['user_defined'] Parsing ERROR. (Please check your the format and encoding.): user_defined 必須是 DICT 格式,例如: {"positive": ["邪惡", "地獄"], "negative": ["正義", "天堂"]} 。
- Internal Server Error. (System will reboot in 5min, please try again later.): 嗯…似乎我們的伺服器出了點狀況。我們正在努力修復中,5 分鐘內會自動重啟,請稍後再試一次。
sensestr此次情緒偵測所使用的功能。
此範例為 Tension。
resultslist以 180 個字符為一個單位,將計算結果存儲至 list,分數區間為 [0, 1]。
977 |

keymoji2visual

978 |
979 |

範例程式:

980 |
981 |
# sense2Result / sense8Result / tensionResult
 982 | result = keymoji.keymoji2visual(sense2Result)
 983 | 
984 |
985 |

回傳結果 (JSON 格式):

986 |
987 |
{
 988 |     "status": true,
 989 |     "msg": "sense2/sense2.png saved."
 990 | }
 991 | 

參數說明

992 | 993 | 994 | 995 | 996 | 997 | 998 | 999 | 1000 | 1001 | 1002 | 1003 | 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | 1010 | 1011 | 1012 | 1013 | 1014 | 1015 | 1016 | 1017 | 1018 |
參數型態預設功能
resultDICTlist[]填入 sense2, sense8, tension 分析的結果。
pathstr""指定圖片的目錄位置。
filenamestr""指定儲存的圖片名稱。
1019 |

回傳內容說明

1020 | 1021 | 1022 | 1023 | 1024 | 1025 | 1026 | 1027 | 1028 | 1029 | 1030 | 1031 | 1032 | 1033 | 1034 | 1035 | 1036 | 1037 | 1038 | 1039 | 1040 | 1041 | 1042 | 1043 | 1044 | 1045 | 1046 | 1047 | 1048 | 1049 | 1050 | 1051 | 1052 | 1053 | 1054 | 1055 | 1056 | 1057 | 1058 | 1059 | 1060 | 1061 | 1062 | 1063 | 1064 | 1065 | 1066 | 1067 | 1068 | 1069 | 1070 | 1071 | 1072 | 1073 | 1074 | 1075 | 1076 | 1077 | 1078 | 1079 | 1080 | 1081 | 1082 |
回傳訊息型態說明
statusbool若成功執行並收到情緒偵測結果,回傳 True;失敗,則回傳 False
msgstr可能為以下的文字:
- {path}/{filename}.png saved.: 圖片順利儲存。
- Invalid arguments.: 上傳參數錯誤,請重新檢查上傳時的參數是否符合規則名稱。
- Invalid content_type.: 上傳格式必須為 Json 格式 (application/json)。
- Your input_str is too long (over 6000 characters.): input_str 超過 6000 字符。
- Authentication Failed.: 無法驗証您的帳號,或是未購買KeyMoji方案。請再檢查一次您使用的帳號是否正確。
- Invalid KeyMoji_Key.: 無效的 keymoji_key。請再檢查一次您的 keymoji_key 是否正確。
- Invalid result.: results內容不符合指定參數sense
- Invalid sense.: sense 所指定的參數不存在。
modelstr此次情緒偵測所使用的模型。
1083 |

sense2

1084 |

sense2

1085 |

sense8

1086 |

sense8

1087 |

tension

1088 |

tension

1089 | 1090 |
1091 |
1092 |
1093 | Python 1094 |
1095 |
1096 |
1097 | 1098 | 1099 | -------------------------------------------------------------------------------- /Docs/stylesheets/print-772a6e2a.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}.content h1,.content h2,.content h3,.content h4,body{font-family:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size:18px}.content h1,.content h2,.content h3,.content h4{font-weight:bold}.content pre,.content code{font-family:Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace, serif;font-size:14px;line-height:1.5}.content pre,.content code{word-break:break-all;-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto}@font-face{font-family:'slate';src:url(../fonts/slate-cfc9d06b.eot?-syv14m);src:url(../fonts/slate-cfc9d06b.eot?#iefix-syv14m) format("embedded-opentype"),url(../fonts/slate.woff2?-syv14m) format("woff2"),url(../fonts/slate.woff?-syv14m) format("woff"),url(../fonts/slate-7b7da4fe.ttf?-syv14m) format("truetype"),url(../fonts/slate-e55b8307.svg?-syv14m#slate) format("svg");font-weight:normal;font-style:normal}.content aside.warning:before,.content aside.notice:before,.content aside.success:before{font-family:'slate';speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1}.content aside.warning:before{content:"\e600"}.content aside.notice:before{content:"\e602"}.content aside.success:before{content:"\e606"}.tocify,.toc-footer,.lang-selector,.search,#nav-button{display:none}.tocify-wrapper>img{margin:0 auto;display:block}.content{font-size:12px}.content pre,.content code{border:1px solid #999;border-radius:5px;font-size:0.8em}.content pre code{border:0}.content pre{padding:1.3em}.content code{padding:0.2em}.content table{border:1px solid #999}.content table tr{border-bottom:1px solid #999}.content table td,.content table th{padding:0.7em}.content p{line-height:1.5}.content a{text-decoration:none;color:#000}.content h1{font-size:3em;padding-top:0.5em;padding-bottom:0.5em;margin-top:1em;margin-bottom:21px;border:2px solid #ccc;border-width:2px 0;text-align:center}.content h2{font-size:2.2em;margin-top:2em;border-top:2px solid #ccc;padding-top:0.8em}.content h1+h2,.content h1+div+h2{border-top:none;padding-top:0;margin-top:0}.content h3,.content h4{font-size:0.8em;margin-top:1.5em;margin-bottom:0.8em;text-transform:uppercase}.content h5,.content h6{text-transform:uppercase}.content aside{padding:1em;border:1px solid #ccc;border-radius:5px;margin-top:1.5em;margin-bottom:1.5em;line-height:1.6}.content aside:before{vertical-align:middle;padding-right:0.5em;font-size:14px}@media print{.copy-clipboard{display:none}} -------------------------------------------------------------------------------- /Docs/stylesheets/screen-849c4fff.css: -------------------------------------------------------------------------------- 1 | /*! normalize.css v3.0.2 | MIT License | git.io/normalize */html{font-family:sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,details,figcaption,figure,footer,header,hgroup,main,menu,nav,section,summary{display:block}audio,canvas,progress,video{display:inline-block;vertical-align:baseline}audio:not([controls]){display:none;height:0}[hidden],template{display:none}a{background-color:transparent}a:active,a:hover{outline:0}abbr[title]{border-bottom:1px dotted}b,strong{font-weight:bold}dfn{font-style:italic}h1{font-size:2em;margin:0.67em 0}mark{background:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-0.5em}sub{bottom:-0.25em}img{border:0}svg:not(:root){overflow:hidden}figure{margin:1em 40px}hr{-webkit-box-sizing:content-box;box-sizing:content-box;height:0}pre{overflow:auto}code,kbd,pre,samp{font-family:monospace, monospace;font-size:1em}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0}button{overflow:visible}button,select{text-transform:none}button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer}button[disabled],html input[disabled]{cursor:default}button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0}input{line-height:normal}input[type="checkbox"],input[type="radio"]{-webkit-box-sizing:border-box;box-sizing:border-box;padding:0}input[type="number"]::-webkit-inner-spin-button,input[type="number"]::-webkit-outer-spin-button{height:auto}input[type="search"]{-webkit-appearance:textfield;-webkit-box-sizing:content-box;box-sizing:content-box}input[type="search"]::-webkit-search-cancel-button,input[type="search"]::-webkit-search-decoration{-webkit-appearance:none}fieldset{border:1px solid #c0c0c0;margin:0 2px;padding:0.35em 0.625em 0.75em}legend{border:0;padding:0}textarea{overflow:auto}optgroup{font-weight:bold}table{border-collapse:collapse;border-spacing:0}td,th{padding:0}.content h1,.content h2,.content h3,.content h4,.content h5,.content h6,html,body{font-family:-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";font-size:18px}.content h1,.content h2,.content h3,.content h4,.content h5,.content h6{font-weight:bold}.content code,.content pre{font-family:Consolas, Menlo, Monaco, "Lucida Console", "Liberation Mono", "DejaVu Sans Mono", "Bitstream Vera Sans Mono", "Courier New", monospace, serif;font-size:14px;line-height:1.5}.content code{word-break:break-all;-webkit-hyphens:auto;-ms-hyphens:auto;hyphens:auto}@font-face{font-family:'slate';src:url(../fonts/slate-cfc9d06b.eot?-syv14m);src:url(../fonts/slate-cfc9d06b.eot?#iefix-syv14m) format("embedded-opentype"),url(../fonts/slate.woff2?-syv14m) format("woff2"),url(../fonts/slate.woff?-syv14m) format("woff"),url(../fonts/slate-7b7da4fe.ttf?-syv14m) format("truetype"),url(../fonts/slate-e55b8307.svg?-syv14m#slate) format("svg");font-weight:normal;font-style:normal}.content aside.warning:before,.content aside.notice:before,.content aside.success:before,.toc-wrapper>.search:before{font-family:'slate';speak:none;font-style:normal;font-weight:normal;font-variant:normal;text-transform:none;line-height:1}.content aside.warning:before{content:"\e600"}.content aside.notice:before{content:"\e602"}.content aside.success:before{content:"\e606"}.toc-wrapper>.search:before{content:"\e607"}@font-face{font-family:FakePearl-Regular;src:url("/static/vendor/FakePearl/webfont/FakePearl-Regular.woff2") format("woff2"),url("/static/vendor/FakePearl/webfont/FakePearl-Regular.woff") format("woff")}html,body{color:#333;padding:0;margin:0;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;background-color:#F3F7F9;height:100%;-webkit-text-size-adjust:none;font-family:FakePearl-Regular}#toc>ul>li>a>span{float:right;background-color:#2484FF;border-radius:40px;width:20px}.toc-wrapper{-webkit-transition:left 0.3s ease-in-out;transition:left 0.3s ease-in-out;overflow-y:auto;overflow-x:hidden;position:fixed;z-index:30;top:0;left:0;bottom:0;width:230px;background-color:#2E3336;font-size:13px;font-weight:bold}.toc-wrapper .lang-selector{display:none}.toc-wrapper .lang-selector a{padding-top:0.5em;padding-bottom:0.5em}.toc-wrapper .logo{display:block;max-width:100%;margin-bottom:0px}.toc-wrapper>.search{position:relative}.toc-wrapper>.search input{background:#2E3336;border-width:0 0 1px 0;border-color:#666;padding:6px 0 6px 20px;-webkit-box-sizing:border-box;box-sizing:border-box;margin:10px 15px;width:200px;outline:none;color:#fff;border-radius:0}.toc-wrapper>.search:before{position:absolute;top:17px;left:15px;color:#fff}.toc-wrapper .search-results{margin-top:0;-webkit-box-sizing:border-box;box-sizing:border-box;height:0;overflow-y:auto;overflow-x:hidden;-webkit-transition-property:height, margin;transition-property:height, margin;-webkit-transition-duration:180ms;transition-duration:180ms;-webkit-transition-timing-function:ease-in-out;transition-timing-function:ease-in-out;background:#1E2224}.toc-wrapper .search-results.visible{height:30%;margin-bottom:1em}.toc-wrapper .search-results li{margin:1em 15px;line-height:1}.toc-wrapper .search-results a{color:#fff;text-decoration:none}.toc-wrapper .search-results a:hover{text-decoration:underline}.toc-wrapper ul,.toc-wrapper li{list-style:none;margin:0;padding:0;line-height:28px}.toc-wrapper li{color:#fff;-webkit-transition-property:background;transition-property:background;-webkit-transition-timing-function:linear;transition-timing-function:linear;-webkit-transition-duration:200ms;transition-duration:200ms}.toc-wrapper .toc-link.active{background-color:#0F75D4;color:#fff}.toc-wrapper .toc-link.active-parent{background-color:#1E2224;color:#fff}.toc-wrapper .toc-list-h2{display:none;background-color:#1E2224;font-weight:500}.toc-wrapper .toc-h2{padding-left:25px;font-size:12px}.toc-wrapper .toc-footer{padding:1em 0;margin-top:1em;border-top:1px dashed #666}.toc-wrapper .toc-footer li,.toc-wrapper .toc-footer a{color:#fff;text-decoration:none}.toc-wrapper .toc-footer a:hover{text-decoration:underline}.toc-wrapper .toc-footer li{font-size:0.8em;line-height:1.7;text-decoration:none}.toc-link,.toc-footer li{padding:0 15px 0 15px;display:block;overflow-x:hidden;white-space:nowrap;text-overflow:ellipsis;text-decoration:none;color:#fff;-webkit-transition-property:background;transition-property:background;-webkit-transition-timing-function:linear;transition-timing-function:linear;-webkit-transition-duration:130ms;transition-duration:130ms}#nav-button{padding:0 1.5em 5em 0;display:none;position:fixed;top:0;left:0;z-index:100;color:#000;text-decoration:none;font-weight:bold;opacity:0.7;line-height:16px;-webkit-transition:left 0.3s ease-in-out;transition:left 0.3s ease-in-out}#nav-button span{display:block;padding:6px 6px 6px;background-color:rgba(243,247,249,0.7);-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:rotate(-90deg) translate(-100%, 0);transform:rotate(-90deg) translate(-100%, 0);border-radius:0 0 0 5px}#nav-button img{height:16px;vertical-align:bottom}#nav-button:hover{opacity:1}#nav-button.open{left:230px}.page-wrapper{margin-left:230px;position:relative;z-index:10;background-color:#F3F7F9;min-height:100%;padding-bottom:1px}.page-wrapper .dark-box{width:30%;background-color:#2E3336;position:absolute;right:0;top:0;bottom:0}.page-wrapper .lang-selector{position:fixed;z-index:50;border-bottom:5px solid #2E3336}.lang-selector{display:flex;background-color:#1E2224;width:100%;font-weight:bold;overflow-x:auto}.lang-selector a{display:inline;color:#fff;text-decoration:none;padding:0 10px;line-height:30px;outline:0}.lang-selector a:active,.lang-selector a:focus{background-color:#111;color:#fff}.lang-selector a.active{background-color:#2E3336;color:#fff}.lang-selector:after{content:'';clear:both;display:block}.content{-webkit-transform:translateZ(0);position:relative;z-index:30}.content:after{content:'';display:block;clear:both}.content>h1,.content>h2,.content>h3,.content>h4,.content>h5,.content>h6,.content>p,.content>table,.content>ul,.content>ol,.content>aside,.content>dl{margin-right:30%;padding:0 28px;-webkit-box-sizing:border-box;box-sizing:border-box;display:block}.content>ul,.content>ol{padding-left:43px}.content>h1,.content>h2,.content>div{clear:both}.content h1{font-size:25px;padding-top:0.5em;padding-bottom:0.5em;margin-bottom:21px;margin-top:2em;border-top:1px solid #ccc;border-bottom:1px solid #ccc;background-color:#fdfdfd}.content h1:first-child,.content div:first-child+h1{border-top-width:0;margin-top:0}.content h2{font-size:19px;margin-top:4em;margin-bottom:0;border-top:1px solid #ccc;padding-top:1.2em;padding-bottom:1.2em;background-image:-webkit-gradient(linear, left top, left bottom, from(rgba(255,255,255,0.2)), to(rgba(255,255,255,0)));background-image:linear-gradient(to bottom, rgba(255,255,255,0.2), rgba(255,255,255,0))}.content h1+h2,.content h1+div+h2{margin-top:-21px;border-top:none}.content h3,.content h4,.content h5,.content h6{font-size:15px;margin-top:2.5em;margin-bottom:0.8em}.content h4,.content h5,.content h6{font-size:10px}.content hr{margin:2em 0;border-top:2px solid #2E3336;border-bottom:2px solid #F3F7F9}.content table{margin-bottom:1em;overflow:auto}.content table th,.content table td{text-align:left;vertical-align:top;line-height:1.6}.content table th code,.content table td code{white-space:nowrap}.content table th{padding:5px 10px;border-bottom:1px solid #ccc;vertical-align:bottom}.content table td{padding:10px}.content table tr:last-child{border-bottom:1px solid #ccc}.content table tr:nth-child(odd)>td{background-color:white}.content table tr:nth-child(even)>td{background-color:#fbfcfd}.content dt{font-weight:bold}.content dd{margin-left:15px}.content p,.content li,.content dt,.content dd{line-height:1.6;margin-top:0}.content img{max-width:100%;-webkit-filter:drop-shadow(5px 5px 5px rgba(0,0,0,0.7));filter:drop-shadow(5px 5px 5px rgba(0,0,0,0.7))}.content code{background-color:rgba(0,0,0,0.05);padding:3px;border-radius:3px}.content pre>code{background-color:transparent;padding:0}.content aside{padding-top:1em;padding-bottom:1em;margin-top:1.5em;margin-bottom:1.5em;background:#8fbcd4;line-height:1.6}.content aside.warning{background-color:#c97a7e}.content aside.success{background-color:#6ac174}.content aside:before{vertical-align:middle;padding-right:0.5em;font-size:14px}.content .search-highlight{padding:2px;margin:-3px;border-radius:4px;border:1px solid #F7E633;background:-webkit-gradient(linear, right bottom, left top, from(#F7E633), to(#F1D32F));background:linear-gradient(to top left, #F7E633 0%, #F1D32F 100%)}.content>div.highlight{clear:none}.content pre,.content blockquote{background-color:#1E2224;color:#fff;margin:0;width:30%;float:right;clear:right;-webkit-box-sizing:border-box;box-sizing:border-box}.content pre>p,.content blockquote>p{margin:0}.content pre a,.content blockquote a{color:#fff;text-decoration:none;border-bottom:dashed 1px #ccc}.content pre{padding-top:2em;padding-bottom:2em;padding:2em 28px}.content blockquote>p{background-color:#191D1F;padding:13px 2em;color:#eee}@media (max-width: 930px){.toc-wrapper{left:-230px}.toc-wrapper.open{left:0}.page-wrapper{margin-left:0}#nav-button{display:block}.toc-link{padding-top:0.3em;padding-bottom:0.3em}}@media (max-width: 700px){.dark-box{display:none}.content>h1,.content>h2,.content>h3,.content>h4,.content>h5,.content>h6,.content>p,.content>table,.content>ul,.content>ol,.content>aside,.content>dl{margin-right:0}.toc-wrapper .lang-selector{display:block}.page-wrapper .lang-selector{display:none}.content pre,.content blockquote{width:auto;float:none}.content>pre+h1,.content>blockquote+h1,.content>pre+h2,.content>blockquote+h2,.content>pre+h3,.content>blockquote+h3,.content>pre+h4,.content>blockquote+h4,.content>pre+h5,.content>blockquote+h5,.content>pre+h6,.content>blockquote+h6,.content>pre+p,.content>blockquote+p,.content>pre+table,.content>blockquote+table,.content>pre+ul,.content>blockquote+ul,.content>pre+ol,.content>blockquote+ol,.content>pre+aside,.content>blockquote+aside,.content>pre+dl,.content>blockquote+dl{margin-top:28px}}.highlight .c,.highlight .cm,.highlight .c1,.highlight .cs{color:#909090}.highlight,.highlight .w{background-color:#1E2224}.copy-clipboard{float:right;fill:#9DAAB6;cursor:pointer;opacity:0.4;height:18px;width:18px}.copy-clipboard:hover{opacity:0.8} -------------------------------------------------------------------------------- /KeyMojiAPI.py: -------------------------------------------------------------------------------- 1 | KeyMojiAPI/KeyMojiAPI.py -------------------------------------------------------------------------------- /KeyMojiAPI/KeyMojiAPI.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # -*- coding:utf-8 -*- 3 | 4 | from pprint import pprint 5 | from requests import post 6 | from matplotlib import pyplot as plt 7 | from matplotlib import cbook 8 | from matplotlib import image 9 | from matplotlib.font_manager import FontProperties 10 | from matplotlib.patches import Patch 11 | from numpy import linspace 12 | from scipy.interpolate import make_interp_spline 13 | from math import pi 14 | import rapidjson as json 15 | import os 16 | 17 | class KeyMoji: 18 | def __init__(self, username="", keymojiKey="", url="https://api.droidtown.co"): 19 | ''' 20 | username = "" # 你註冊時的 email。 21 | keymoji_key = "" # 您完成付費後取得的 keymoji_key 值。 22 | ''' 23 | try: 24 | with open("./account.info", "r") as f: 25 | userDICT = json.loads(f.read()) 26 | self.username = userDICT["email"] 27 | self.keymojiKey = userDICT["keymoji_key"] 28 | except: 29 | self.username = username 30 | self.keymojiKey = keymojiKey 31 | 32 | self.url = url 33 | self.strLenLimit = 6000 34 | 35 | basePath = os.path.dirname(os.path.abspath(__file__)) 36 | 37 | fontPath = "" 38 | if os.path.exists(os.path.join(basePath, "jf-openhuninn-1.1.ttf")): 39 | fontPath = os.path.join(basePath, "jf-openhuninn-1.1.ttf") 40 | if os.path.exists(os.path.join(basePath, "KeyMojiAPI", "jf-openhuninn-1.1.ttf")): 41 | fontPath = os.path.join(basePath, "KeyMojiAPI", "jf-openhuninn-1.1.ttf") 42 | if fontPath: 43 | self.font = FontProperties(fname=fontPath) 44 | else: 45 | print("[ERROR] jf-openhuninn-1.1.ttf not found!") 46 | 47 | self.watermark = "" 48 | if self.username == "" and self.keymojiKey == "": 49 | if os.path.exists(os.path.join(basePath, "sense_watermark.png")): 50 | self.watermark = os.path.join(basePath, "sense_watermark.png") 51 | if os.path.exists(os.path.join(basePath, "KeyMojiAPI", "sense_watermark.png")): 52 | self.watermark = os.path.join(basePath, "KeyMojiAPI", "sense_watermark.png") 53 | 54 | self.sense8Null = "" 55 | if os.path.exists(os.path.join(basePath, "sense8_null.png")): 56 | self.sense8Null = os.path.join(basePath, "sense8_null.png") 57 | if os.path.exists(os.path.join(basePath, "KeyMojiAPI", "sense8_null.png")): 58 | self.sense8Null = os.path.join(basePath, "KeyMojiAPI", "sense8_null.png") 59 | 60 | 61 | def sense2(self, inputSTR, contextSenitivity=True, model="general", userDefinedDICT={}): 62 | if len(inputSTR) > self.strLenLimit: 63 | return {"status": False, "msg": "Your input_str is too long. (over {} characters.)".format(self.strLenLimit)} 64 | payload = {"username": self.username, "keymoji_key": self.keymojiKey, 65 | "input_str": inputSTR, "sense": "sense2", "model": model, "context_sensitivity": contextSenitivity, "user_defined": userDefinedDICT} 66 | sense2Result = post("{}/KeyMoji/API/".format(self.url), json=payload) 67 | try: 68 | resultDICT = sense2Result.json() 69 | return resultDICT 70 | except Exception as e: 71 | return {"status": False, "msg": e} 72 | 73 | 74 | def sense8(self, inputSTR, model="general", userDefinedDICT={}): 75 | if len(inputSTR) > self.strLenLimit: 76 | return {"status": False, "msg": "Your input_str is too long. (over {} characters.)".format(self.strLenLimit)} 77 | payload = {"username": self.username, "keymoji_key": self.keymojiKey, 78 | "input_str": inputSTR, "sense": "sense8", "model": model, "user_defined": userDefinedDICT} 79 | sense8Result = post("{}/KeyMoji/API/".format(self.url), json=payload) 80 | try: 81 | resultDICT = sense8Result.json() 82 | return resultDICT 83 | except Exception as e: 84 | return {"status": False, "msg": e} 85 | 86 | 87 | def tension(self, inputSTR, userDefinedDICT={}): 88 | inputStrLen = len(inputSTR) 89 | if inputStrLen > self.strLenLimit: 90 | return {"status": False, "msg": "Your input_str is too long. (over {} characters.)".format(self.strLenLimit)} 91 | if inputStrLen < 180: 92 | return {"status": False, "msg": "Your length of input_str must contain at least 180 characters."} 93 | payload = {"username": self.username, "keymoji_key": self.keymojiKey, 94 | "input_str": inputSTR, "sense": "tension", "user_defined": userDefinedDICT} 95 | tensionResult = post("{}/KeyMoji/API/".format(self.url), json=payload) 96 | try: 97 | resultDICT = tensionResult.json() 98 | return resultDICT 99 | except Exception as e: 100 | return {"status": False, "msg": e} 101 | 102 | 103 | def keymoji2visual(self, resultDICT, path="", filename=""): 104 | if "sense" not in resultDICT or "results" not in resultDICT: 105 | return {"status": False, "msg": "Invalid arguments."} 106 | 107 | if resultDICT["results"]: 108 | if resultDICT["sense"] == "sense2": 109 | path = "sense2" if path == "" else path 110 | filename = "sense2" if filename == "" else filename 111 | return self._sense2Visual(resultDICT, path, filename) 112 | 113 | if resultDICT["sense"] == "sense8": 114 | path = "sense8" if path == "" else path 115 | filename = "sense8" if filename == "" else filename 116 | return self._sense8Visual(resultDICT, path, filename) 117 | 118 | if resultDICT["sense"] == "tension": 119 | path = "tension" if path == "" else path 120 | filename = "tension" if filename == "" else filename 121 | return self._tensionVisual(resultDICT, path, filename) 122 | 123 | else: 124 | return {"status": False, "msg": "Invalid arguments."} 125 | 126 | 127 | def _sense2Visual(self, resultDICT, path, filename): 128 | if not os.path.exists(path): 129 | os.mkdir(path) 130 | if not os.path.exists(path): 131 | return {"status": False, "msg": "Invalid path."} 132 | 133 | try: 134 | paddingLIST = [-1, -0.75, -0.5, -0.25, 0, 0.25, 0.5, 0.75, 1] 135 | positiveColor = "#006EFE" 136 | negativeColor = "#cb4a44" 137 | neutralColor = "#1fab34" 138 | colorAlpha = 0.2 139 | borderWidth = 1 140 | 141 | labelLIST = ["\n".join("{}¦{}".format(r["input_str"][:3], r["input_str"][-3:]) if len(r["input_str"]) > 7 else r["input_str"]) for r in resultDICT["results"]] 142 | valueLIST = [r["score"] for r in resultDICT["results"]] 143 | edgeColorLIST = [] 144 | for v in valueLIST: 145 | if v > 0.2: 146 | edgeColorLIST.append(positiveColor) 147 | elif v < -0.2: 148 | edgeColorLIST.append(negativeColor) 149 | else: 150 | edgeColorLIST.append(neutralColor) 151 | colorLIST = [self._hex2rgb(c, colorAlpha) for c in edgeColorLIST] 152 | 153 | # Bar Plot 154 | fig, ax = plt.subplots(figsize=(10, 5)) 155 | fig.subplots_adjust(bottom=0.35, right=0.95) 156 | ax.bar([i for i in range(1, len(valueLIST)+1)], valueLIST, linewidth=borderWidth, linestyle="solid", color=colorLIST, edgecolor=edgeColorLIST) 157 | ax.grid(color="gray", alpha=colorAlpha, linewidth=borderWidth) 158 | 159 | # X 軸 160 | ax.set_xticks(range(1, len(valueLIST)+1, 1)) 161 | ax.set_xticklabels(labelLIST, fontproperties=self.font) 162 | # 確保每個 label 的字型正確 163 | for label in ax.get_xticklabels(): 164 | label.set_fontproperties(self.font) 165 | 166 | # Y 軸 167 | ax.set_ylim(paddingLIST[0], paddingLIST[-1]) 168 | ax.set_yticks(paddingLIST) 169 | 170 | # Legend 171 | legendLIST = [ 172 | Patch(facecolor=self._hex2rgb(positiveColor, colorAlpha), edgecolor=positiveColor, label="Positive"), 173 | Patch(facecolor=self._hex2rgb(neutralColor, colorAlpha), edgecolor=neutralColor, label="Neutral"), 174 | Patch(facecolor=self._hex2rgb(negativeColor, colorAlpha), edgecolor=negativeColor, label="Negative") 175 | ] 176 | ax.legend(handles=legendLIST, bbox_to_anchor=(0.015, -0.07)) 177 | 178 | # Watermark 179 | if self.watermark: 180 | fig.figimage(image.imread(cbook.get_sample_data(self.watermark)), 1680, 775, zorder=3, alpha=0.1) 181 | 182 | # Plot to PNG 183 | fig.savefig(os.path.join(path, "{}.png".format(filename)), format="png", dpi=200) 184 | return {"status": True, "msg": "{}.png saved.".format(os.path.join(path, filename))} 185 | 186 | except Exception as e: 187 | return {"status": False, "msg": str(e)} 188 | 189 | 190 | def _sense8Visual(self, resultDICT, path, filename): 191 | if not os.path.exists(path): 192 | os.mkdir(path) 193 | if not os.path.exists(path): 194 | return {"status": False, "msg": "Invalid path."} 195 | 196 | try: 197 | labelLIST = ["Trust", "Joy", "Surprise", "Anticipation", "Fear", "Anger", "Disgust", "Sadness"] 198 | angleLIST = [0.0, 0.7853981633974483, 1.5707963267948966, 2.356194490192345, 3.141592653589793, 3.9269908169872414, 4.71238898038469, 5.497787143782138] 199 | degreeLIST = [0.0, 45.0, 90.0, 135.0, 180.0, 225.0, 270.0, 315.0] 200 | paddingLIST = [2.5, 5, 7.5, 10, 12.5] 201 | positiveLabelColor = "#006EFE" 202 | negativeLabelColor = "#cb4a44" 203 | gridColor = "#000000" 204 | radarWidth = 2 205 | radarColor = "#f18d00" 206 | colorAlpha = 0.2 207 | 208 | divide = int(len(labelLIST) / 2) 209 | for i, r in enumerate(resultDICT["results"]): 210 | noStr = "{:04d}".format(i + 1) 211 | dataLIST = [r[k] for k in labelLIST] 212 | 213 | # Radar Plot 214 | fig, ax = plt.subplots(figsize=(12, 9), subplot_kw=dict(polar=True)) 215 | fig.subplots_adjust(bottom=0.05) 216 | fig.suptitle(r["input_str"], fontproperties=self.font, y=0.99, fontsize=30, verticalalignment="top") 217 | 218 | # Draw Sense 8 Negative Label 219 | # 角度由 -90 度順時鐘 220 | ax.set_theta_offset(-(pi / 2)) 221 | ax.set_theta_direction(-1) 222 | 223 | # Negative Label 224 | ax.set_thetagrids(degreeLIST[:divide], labelLIST[divide:]) 225 | for label, angle in zip(ax.get_xticklabels(), angleLIST[divide:]): 226 | if angle in (0, pi): 227 | label.set_horizontalalignment("center") 228 | elif 0 < angle < pi: 229 | label.set_horizontalalignment("left") 230 | else: 231 | label.set_horizontalalignment("right") 232 | 233 | # Negative Label params 234 | ax.tick_params(axis="x", labelsize=26, labelcolor=negativeLabelColor, grid_color=gridColor) 235 | 236 | # Sense 8 Radar and Positive Label 237 | ax2 = fig.add_subplot(111, projection="polar") 238 | ax2.plot( angleLIST + angleLIST[:1], dataLIST + dataLIST[:1], linewidth=radarWidth, linestyle="solid", color=radarColor) 239 | ax2.fill( angleLIST + angleLIST[:1], dataLIST + dataLIST[:1], radarColor, alpha=colorAlpha) 240 | ax2.scatter(angleLIST + angleLIST[:1], dataLIST + dataLIST[:1], color=radarColor, s=30) 241 | 242 | # 角度由 90 度順時鐘 243 | ax2.set_theta_offset(pi / 2) 244 | ax2.set_theta_direction(-1) 245 | 246 | # Positive Label + Empty Negative Label 247 | ax2.set_thetagrids(degreeLIST, labelLIST[:divide] + [""]*4) 248 | for label, angle in zip(ax2.get_xticklabels(), angleLIST[:divide]): 249 | if angle in (0, pi): 250 | label.set_horizontalalignment("center") 251 | elif 0 < angle < pi: 252 | label.set_horizontalalignment("left") 253 | else: 254 | label.set_horizontalalignment("right") 255 | 256 | # 設定範圍與間距 257 | ax2.set_ylim(0, paddingLIST[-1]) 258 | ax2.set_rgrids(paddingLIST) 259 | 260 | # Positive Label params and grid params 261 | ax2.tick_params(axis="x", labelsize=26, labelcolor=positiveLabelColor, grid_color=gridColor) 262 | ax2.tick_params(axis="y", labelsize=16, grid_color=gridColor) 263 | ax2.spines["polar"].set_color(gridColor) 264 | 265 | # Watermark 266 | if all(data == 0 for data in dataLIST): 267 | if self.sense8Null: 268 | fig.figimage(image.imread(cbook.get_sample_data(self.sense8Null)), 120, 220, zorder=3, alpha=0.5) 269 | else: 270 | if self.watermark: 271 | fig.figimage(image.imread(cbook.get_sample_data(self.watermark)), 825, 600, zorder=3, alpha=0.1) 272 | 273 | # Plot to PNG 274 | fig.savefig(os.path.join(path, "{}_{}.png".format(filename, noStr)), format="png", dpi=150) 275 | 276 | return {"status": True, "msg": "{}.png".format(os.path.join(path, filename))} 277 | 278 | except Exception as e: 279 | return {"status": False, "msg": str(e)} 280 | 281 | 282 | def _tensionVisual(self, resultDICT, path, filename): 283 | if not os.path.exists(path): 284 | os.mkdir(path) 285 | if not os.path.exists(path): 286 | return {"status": False, "msg": "Invalid path."} 287 | 288 | try: 289 | lineColor = "#36A2EB" 290 | lineWidth = 2 291 | gridColor = "gray" 292 | gridWidth = 1 293 | gridAlpha = 0.2 294 | 295 | # Line Plot 296 | fig, ax = plt.subplots(figsize=(10, 5)) 297 | 298 | dataLIST = resultDICT["results"] 299 | xDataLIST = [i for i in range(1, len(dataLIST) + 1)] 300 | if len(xDataLIST) >= 4: 301 | spline = make_interp_spline(xDataLIST, dataLIST) 302 | splineXData = linspace(xDataLIST[0], xDataLIST[-1], len(dataLIST)*10) 303 | splineYData = spline(splineXData) 304 | ax.plot(splineXData, splineYData, color=lineColor, linewidth=lineWidth) 305 | ax.grid(axis="y", color=gridColor, alpha=gridAlpha, linewidth=gridWidth) 306 | else: 307 | ax.plot(xDataLIST, dataLIST, color=lineColor, linewidth=lineWidth) 308 | ax.grid(axis="y", color=gridColor, alpha=gridAlpha, linewidth=gridWidth) 309 | 310 | # X 軸 311 | ax.set_xticks([i for i in range(1, len(dataLIST)+1)]) 312 | ax.set_xlim(0, len(dataLIST)+1) 313 | 314 | # Watermark 315 | if self.watermark: 316 | fig.figimage(image.imread(cbook.get_sample_data(self.watermark)), 1580, 775, zorder=3, alpha=0.1) 317 | 318 | # Plot to PNG 319 | fig.savefig(os.path.join(path, "{}.png".format(filename)), format="png", dpi=200) 320 | return {"status": True, "msg": "{}.png saved.".format(os.path.join(path, filename))} 321 | 322 | except Exception as e: 323 | return {"status": False, "msg": str(e)} 324 | 325 | 326 | def _hex2rgb(self, colorHex, alpha=0): 327 | return (int(colorHex[1:3], 16) / 256, int(colorHex[3:5], 16) / 256, int(colorHex[5:7], 16) / 256, alpha) 328 | 329 | 330 | if __name__ == "__main__": 331 | inputSTR = "不要逃啊,卑鄙的傢伙。鬼殺隊一直在對你們有利的黑夜中戰鬥,我們都是有血有肉之軀的人,受傷之後無法簡單治好,失去的性命也無法挽回⋯⋯大哥沒有輸,他真的到了最後、守護到了最後。是你輸了,大哥才沒有輸!謝謝你,我心中的煉獄大哥。一直以來你在我面前擋住了很多攻擊、一直以來你都沒有放棄要成為更好的自己、一直以來有一個懦弱的我,一直躲在你後面,覺得自己很沒用,但你的任務圓滿結束了,從今天起,你可以好好休息。謝謝你一直以來的照顧,沒有讓在場的任何一個人死去。" 332 | 333 | keymoji = KeyMoji() 334 | 335 | sense2Result = keymoji.sense2(inputSTR, model="general", userDefinedDICT={"positive": ["戰鬥"]}) 336 | pprint(sense2Result) 337 | #print(keymoji.keymoji2visual(sense2Result, filename="kimetsu.png")) 338 | 339 | #sense8Result = keymoji.sense8(inputSTR) 340 | #pprint(sense8Result) 341 | #print(keymoji.keymoji2visual(sense8Result)) 342 | 343 | #tensionResult = keymoji.tension(inputSTR) 344 | #pprint(tensionResult) 345 | #print(keymoji.keymoji2visual(tensionResult)) -------------------------------------------------------------------------------- /KeyMojiAPI/__init__.py: -------------------------------------------------------------------------------- 1 | try: 2 | from KeyMojiAPI import KeyMoji 3 | except: 4 | from .KeyMojiAPI import KeyMoji 5 | -------------------------------------------------------------------------------- /KeyMojiAPI/jf-openhuninn-1.1.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Droidtown/KeyMojiAPI/ce05cd3acf20aaf08936e9c61fe31e5a65e457b6/KeyMojiAPI/jf-openhuninn-1.1.ttf -------------------------------------------------------------------------------- /KeyMojiAPI/sense8_null.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Droidtown/KeyMojiAPI/ce05cd3acf20aaf08936e9c61fe31e5a65e457b6/KeyMojiAPI/sense8_null.png -------------------------------------------------------------------------------- /KeyMojiAPI/sense_watermark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Droidtown/KeyMojiAPI/ce05cd3acf20aaf08936e9c61fe31e5a65e457b6/KeyMojiAPI/sense_watermark.png -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Droidtown Linguistic. Tech. Co., Ltd. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include KeyMojiAPI/jf-openhuninn-1.1.ttf 2 | include KeyMojiAPI/sense8_null.png 3 | include KeyMojiAPI/sense_watermark.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # KeyMoji [Emotions in Formula] 2 | 3 | KeyMoji 關鍵情緒偵測 (**SENSE2、SENSE8、Tension**) 採用不同於其它「素人標記」和「純機器學習」的文本情緒偵測分析工具,結合了「**句型**」、「**邏輯語意**」和「**詞彙模型**」,設計出一個完整的「情緒計算過程」。 4 | 5 | [完整介紹](https://api.droidtown.co/document/#KeyMoji) 6 | 7 | ## 安裝方法 8 | 9 | ```sh 10 | pip3 install KeyMojiAPI 11 | ``` 12 | or 13 | ```sh 14 | python3 -m pip install KeyMojiAPI 15 | ``` 16 | 17 | ## 使用方法 18 | [KeyMoji Website Demo](https://api.droidtown.co/#keymoji) 19 | [KeyMojiAPI Documentation](https://api.droidtown.co/KeyMojiAPI/document/) 20 | 21 | ### SENSE2 22 | ```python 23 | from KeyMojiAPI import KeyMoji 24 | # 若您是使用 Docker 版本,無須填入 username, keymoji_key 參數 25 | keymoji = KeyMoji(username="", keymojiKey="") 26 | 27 | inputSTR = "他逃離了危險的災難" 28 | # Sense2 29 | sense2Result = keymoji.sense2(inputSTR, model="general", userDefinedDICT={"positive":[], "negative":[], "cursing":[]}) 30 | print(sense2Result) 31 | # Sense2 Visualization 32 | status = keymoji.keymoji2visual(sense2Result, filename="kimetsu.png") 33 | ``` 34 | 35 | ```json 36 | { 37 | "status": true, 38 | "msg": "Success!", 39 | "results": [ 40 | { 41 | "score": 0.2798, 42 | "sentiment": "positive", 43 | "input_str": "他逃離了危險的災難", 44 | "cursing": false 45 | } 46 | ], 47 | "sense": "sense2", 48 | "version": "v101" 49 | } 50 | ``` 51 | 52 | ### Visualization 53 | 54 | ![sense2](https://www.droidtown.co/static/public_img/sense2.png?raw=true) 55 | 56 | ### SENSE8 57 | ```python 58 | from KeyMojiAPI import KeyMoji 59 | # 若您是使用 Docker 版本,無須填入 username, keymoji_key 參數 60 | keymoji = KeyMoji(username="", keymojiKey="") 61 | 62 | inputSTR = "他逃離了危險的災難" 63 | sense8Result = keymoji.sense8(inputSTR, model="general", userDefinedDICT={"positive":[], "negative":[], "cursing":[]}) 64 | print(sense8Result) 65 | # Sense8 Visualization 66 | status = keymoji.keymoji2visual(sense8Result, filename="kimetsu.zip") 67 | ``` 68 | 69 | ```json 70 | { 71 | "status": True, 72 | "msg": "Success!", 73 | "results": [ 74 | { 75 | "input_str": "他逃離了危險的災難", 76 | "Joy": 3.7486, 77 | "Trust": 5.1776, 78 | "Surprise": 6.7238, 79 | "Anticipation": 0.9618, 80 | "Fear": 0.9505, 81 | "Sadness": 0.9108, 82 | "Anger": 0.9516, 83 | "Disgust": 0.8876 84 | } 85 | ], 86 | "sense": "sense8", 87 | "version": "v101" 88 | } 89 | ``` 90 | 91 | ### Visualization 92 | 93 | ![sense8](https://www.droidtown.co/static/public_img/sense8.png) 94 | 95 | 96 | ### Tension Visualization 97 | 98 | ![tension](https://www.droidtown.co/static/public_img/tension.png) 99 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | with open("README.md", "r", encoding="utf-8") as fh: 4 | long_description = fh.read() 5 | 6 | setuptools.setup( 7 | name="KeyMojiAPI", 8 | version="1.0.5", 9 | author="Droidtown Linguistic Tech. Co. Ltd.", 10 | author_email="info@droidtown.co", 11 | description="""KeyMoji sentimental analysis system differs from other "amature-tagged" and "pure-ML/DL" text sentimental analysis solutions in many ways. KeyMoji combines "syntactic structure information", "formal semantics" and "lexical semantic model" in one calculating process to estimate the sentimental bias and distributions of sentiments in texts.""", 12 | long_description=long_description, 13 | long_description_content_type="text/markdown", 14 | url="https://github.com/Droidtown/KeyMojiAPI", 15 | project_urls={ 16 | "Documentation": "https://api.droidtown.co/KeyMojiAPI/document/", 17 | "Source": "https://github.com/Droidtown/KeyMojiAPI", 18 | }, 19 | license="MIT License", 20 | keywords=[ 21 | "emotion", 22 | "emotion recognition", 23 | "emotions in formula", 24 | "sentiment" 25 | "sentiment analyzer", 26 | "sentiment analysis", 27 | "sentiment detection", 28 | "NLP", "NLU", "AI", 29 | "artificial intelligence", 30 | "computational linguistics", 31 | "language", 32 | "linguistics", 33 | "natural language", 34 | "natural language processing", 35 | "natural language understanding", 36 | "parsing", 37 | "syntax", 38 | "text analytics" 39 | ], 40 | packages=setuptools.find_packages(), 41 | include_package_data=True, 42 | install_requires=[ 43 | "requests >= 2.25.1", 44 | "python-rapidjson >= 0.9.4", 45 | "matplotlib >= 3.3.3", 46 | "numpy >= 1.19.5", 47 | "scipy >= 1.5.4" 48 | ], 49 | classifiers=[ 50 | "Programming Language :: Python :: 3", 51 | "Programming Language :: Python :: 3 :: Only", 52 | "Programming Language :: Python :: 3.6", 53 | "Programming Language :: Python :: 3.7", 54 | "Programming Language :: Python :: 3.8", 55 | "Programming Language :: Python :: 3.9", 56 | "License :: OSI Approved :: MIT License", 57 | "Operating System :: OS Independent", 58 | "Development Status :: 5 - Production/Stable", 59 | #"Environment :: Console", 60 | "Intended Audience :: Developers", 61 | "Intended Audience :: Customer Service", 62 | "Intended Audience :: Information Technology", 63 | "Natural Language :: Chinese (Traditional)", 64 | "Topic :: Software Development :: Libraries :: Python Modules", 65 | "Topic :: Text Processing", 66 | "Topic :: Text Processing :: Linguistic", 67 | "Topic :: Text Processing :: Filters", 68 | "Topic :: Utilities", 69 | ], 70 | python_requires=">=3.6.1", 71 | ) 72 | --------------------------------------------------------------------------------