@linxiraos/pi-stats 1.1.27 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +10 -7
- package/build.ts +4 -0
- package/dist/client/favicon.ico +0 -0
- package/dist/client/index.css +1 -1
- package/dist/client/index.html +1 -0
- package/dist/client/index.js +96 -96
- package/dist/types/aggregator.d.ts +4 -1
- package/dist/types/client/api.d.ts +5 -1
- package/dist/types/client/app/nav.d.ts +5 -2
- package/dist/types/client/data/formatters.d.ts +5 -2
- package/dist/types/client/data/live.d.ts +16 -11
- package/dist/types/client/data/query-store.d.ts +39 -0
- package/dist/types/client/data/query.d.ts +10 -5
- package/dist/types/client/data/range.d.ts +4 -3
- package/dist/types/client/i18n/format.d.ts +9 -0
- package/dist/types/client/i18n/index.d.ts +18 -0
- package/dist/types/client/i18n/messages/charts.d.ts +8 -0
- package/dist/types/client/i18n/messages/common.d.ts +153 -0
- package/dist/types/client/i18n/messages/costs.d.ts +92 -0
- package/dist/types/client/i18n/messages/en.d.ts +1255 -0
- package/dist/types/client/i18n/messages/errors.d.ts +78 -0
- package/dist/types/client/i18n/messages/frustration.d.ts +191 -0
- package/dist/types/client/i18n/messages/gain.d.ts +54 -0
- package/dist/types/client/i18n/messages/models.d.ts +94 -0
- package/dist/types/client/i18n/messages/nav.d.ts +46 -0
- package/dist/types/client/i18n/messages/overview.d.ts +80 -0
- package/dist/types/client/i18n/messages/projects.d.ts +84 -0
- package/dist/types/client/i18n/messages/providers.d.ts +142 -0
- package/dist/types/client/i18n/messages/requests.d.ts +72 -0
- package/dist/types/client/i18n/messages/tools.d.ts +119 -0
- package/dist/types/client/i18n/messages/traces.d.ts +144 -0
- package/dist/types/client/i18n/messages/ui.d.ts +44 -0
- package/dist/types/client/i18n/messages/zh-CN.d.ts +13 -0
- package/dist/types/client/i18n/types.d.ts +15 -0
- package/dist/types/client/traces/Minimap.d.ts +2 -0
- package/dist/types/client/traces/TimelineCanvas.d.ts +29 -8
- package/dist/types/client/traces/TranscriptList.d.ts +3 -1
- package/dist/types/db.d.ts +14 -21
- package/dist/types/embedded-client.d.ts +5 -0
- package/dist/types/frustration.d.ts +18 -9
- package/dist/types/live.d.ts +5 -3
- package/dist/types/locale.d.ts +16 -0
- package/dist/types/parser.d.ts +0 -17
- package/dist/types/rollup.d.ts +9 -1
- package/dist/types/server.d.ts +6 -0
- package/dist/types/shared-types.d.ts +7 -0
- package/dist/types/trace.d.ts +18 -6
- package/dist/types/types.d.ts +12 -0
- package/dist/types/user-metrics.d.ts +23 -1
- package/package.json +4 -4
- package/src/aggregator.ts +28 -11
- package/src/client/api.ts +40 -5
- package/src/client/app/LiveChip.tsx +14 -13
- package/src/client/app/Shell.tsx +19 -13
- package/src/client/app/ThemeToggle.tsx +4 -3
- package/src/client/app/nav.ts +19 -16
- package/src/client/data/formatters.ts +73 -13
- package/src/client/data/live.tsx +85 -45
- package/src/client/data/query-store.ts +108 -0
- package/src/client/data/query.ts +47 -56
- package/src/client/data/range.ts +34 -14
- package/src/client/data/series.ts +7 -1
- package/src/client/favicon.ico +0 -0
- package/src/client/i18n/format.ts +28 -0
- package/src/client/i18n/index.ts +53 -0
- package/src/client/i18n/messages/charts.ts +8 -0
- package/src/client/i18n/messages/common.ts +157 -0
- package/src/client/i18n/messages/costs.ts +104 -0
- package/src/client/i18n/messages/en.ts +40 -0
- package/src/client/i18n/messages/errors.ts +80 -0
- package/src/client/i18n/messages/frustration.ts +198 -0
- package/src/client/i18n/messages/gain.ts +54 -0
- package/src/client/i18n/messages/models.ts +94 -0
- package/src/client/i18n/messages/nav.ts +46 -0
- package/src/client/i18n/messages/overview.ts +90 -0
- package/src/client/i18n/messages/projects.ts +84 -0
- package/src/client/i18n/messages/providers.ts +165 -0
- package/src/client/i18n/messages/requests.ts +73 -0
- package/src/client/i18n/messages/tools.ts +120 -0
- package/src/client/i18n/messages/traces.ts +160 -0
- package/src/client/i18n/messages/ui.ts +46 -0
- package/src/client/i18n/messages/zh-CN.ts +43 -0
- package/src/client/i18n/types.ts +19 -0
- package/src/client/index.tsx +4 -0
- package/src/client/routes/CostsRoute.tsx +61 -48
- package/src/client/routes/ErrorsRoute.tsx +71 -47
- package/src/client/routes/FrustrationRoute.tsx +131 -116
- package/src/client/routes/GainRoute.tsx +42 -30
- package/src/client/routes/ModelsRoute.tsx +87 -71
- package/src/client/routes/OverviewRoute.tsx +107 -62
- package/src/client/routes/ProjectsRoute.tsx +71 -45
- package/src/client/routes/ProvidersRoute.tsx +149 -113
- package/src/client/routes/RequestsRoute.tsx +68 -45
- package/src/client/routes/ToolsRoute.tsx +105 -92
- package/src/client/routes/TracesRoute.tsx +25 -23
- package/src/client/styles.css +4 -2
- package/src/client/traces/AggregatesPanel.tsx +19 -8
- package/src/client/traces/Minimap.tsx +65 -27
- package/src/client/traces/SpanDrawer.tsx +46 -21
- package/src/client/traces/SummaryStrip.tsx +27 -11
- package/src/client/traces/TimelineCanvas.tsx +245 -116
- package/src/client/traces/TraceView.tsx +51 -36
- package/src/client/traces/TranscriptList.tsx +20 -11
- package/src/client/traces/traces.css +26 -0
- package/src/client/ui/JsonBlock.tsx +3 -2
- package/src/client/ui/Modal.tsx +3 -2
- package/src/client/ui/RequestDrawer.tsx +33 -30
- package/src/client/ui/SearchInput.tsx +2 -1
- package/src/client/ui/States.tsx +3 -2
- package/src/client/ui/Table.tsx +7 -3
- package/src/db.ts +150 -135
- package/src/embedded-client.ts +9 -0
- package/src/frustration.ts +9 -30
- package/src/live.ts +36 -11
- package/src/locale.ts +29 -0
- package/src/parser.ts +37 -72
- package/src/port-conflict.ts +1 -1
- package/src/prompts/judge/frustration.json +19 -0
- package/src/rollup.ts +41 -20
- package/src/server.ts +67 -27
- package/src/shared-types.ts +7 -0
- package/src/trace.ts +54 -40
- package/src/types.ts +12 -0
- package/src/user-metrics.ts +220 -6
package/src/user-metrics.ts
CHANGED
|
@@ -61,6 +61,10 @@ export interface UserMessageMetrics {
|
|
|
61
61
|
*
|
|
62
62
|
* Bare `still` / `again` are too ambiguous to count alone (they show up
|
|
63
63
|
* in normal speech like "try again" or "still works").
|
|
64
|
+
*
|
|
65
|
+
* Also counts the Chinese recall/still markers (`我说过`, `还是不行`, `又错了`)
|
|
66
|
+
* and whole-message repetition of the previous user message (`prevText`),
|
|
67
|
+
* which is the signal that survives both languages and voice input.
|
|
64
68
|
*/
|
|
65
69
|
repetition: number;
|
|
66
70
|
/**
|
|
@@ -69,8 +73,24 @@ export interface UserMessageMetrics {
|
|
|
69
73
|
* - `you (didn't|did not|broke|missed|forgot|keep|always|never|still|ignored)`
|
|
70
74
|
* - `why (would|did) (you|u)`
|
|
71
75
|
* - sentence-leading `stop <verb>ing` imperatives
|
|
76
|
+
* - the Chinese forms (`你怎么又`, `你没改`, `我明明说过`, `不是让你`)
|
|
72
77
|
*/
|
|
73
78
|
blame: number;
|
|
79
|
+
/**
|
|
80
|
+
* Emphatic markers the caps-based {@link yelling} cannot see, because they
|
|
81
|
+
* are how Chinese - and any voice-transcribed text - shouts: full-width
|
|
82
|
+
* `!?` bursts, a Han character or short word repeated three or more times
|
|
83
|
+
* (`不不不`, `不对不对不对`), and elongated interjections (`啊啊啊`).
|
|
84
|
+
* English text scores 0 here; its shouting is already in {@link yelling}.
|
|
85
|
+
*/
|
|
86
|
+
emphasis: number;
|
|
87
|
+
/**
|
|
88
|
+
* 1 when the prose is dominated by a script no shipped lexicon covers
|
|
89
|
+
* (Kana, Hangul, Cyrillic, Arabic, …). The other counts are then *not*
|
|
90
|
+
* evidence of calm - they are evidence of a missing lexicon, and the
|
|
91
|
+
* dashboard reports those messages as unscored rather than as content.
|
|
92
|
+
*/
|
|
93
|
+
unsupportedScript: number;
|
|
74
94
|
}
|
|
75
95
|
|
|
76
96
|
/**
|
|
@@ -517,6 +537,171 @@ const BLAME_WHY_RE = /\bwhy\s+(?:would|did)\s+(?:you|u)\b/gi;
|
|
|
517
537
|
// to start a sentence (line start or after a sentence-terminating punctuator).
|
|
518
538
|
const BLAME_STOP_RE = /(?:^|(?<=[.!?\n]))\s*stop\s+\w+ing\b/gim;
|
|
519
539
|
|
|
540
|
+
// --- Chinese and voice-input signals ----------------------------------------
|
|
541
|
+
// Chinese has no word boundaries and no letter case, so every pattern below is
|
|
542
|
+
// boundary-free (`\b` never fires between two Han characters) and independent
|
|
543
|
+
// of punctuation. That independence is the point: most Chinese traffic reaches
|
|
544
|
+
// the agent through voice transcription, which emits one long unpunctuated
|
|
545
|
+
// line and renders swearing as whichever homophone the recognizer chose
|
|
546
|
+
// (`卧槽`/`我艹`/`淦`). A pattern that needed `!` or a space would score zero on
|
|
547
|
+
// exactly the messages this layer exists for.
|
|
548
|
+
//
|
|
549
|
+
// Every list is deliberately narrow: a term earns its place only when its
|
|
550
|
+
// dominant use in a coding chat is frustration. So `沙雕` (playful) and `呵呵`
|
|
551
|
+
// (merely dry) are out, bare `草`/`靠` are out (`草莓`, `草稿`, `依靠` are far
|
|
552
|
+
// more common), and repeated agreement forms (`好好好`, `对对对`, `哈哈哈`) are
|
|
553
|
+
// out because they are at least as often genuine.
|
|
554
|
+
const ZH_PROFANITY: readonly string[] = [
|
|
555
|
+
"傻逼",
|
|
556
|
+
"傻b",
|
|
557
|
+
"煞笔",
|
|
558
|
+
"傻x",
|
|
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
|
+
const ZH_PROFANITY_RE = new RegExp(ZH_PROFANITY.join("|"), "gi");
|
|
586
|
+
|
|
587
|
+
// Exasperation. `唉`/`哎` are the Chinese `ugh`; the internet registers
|
|
588
|
+
// (`服了`, `醉了`, `无语`, `离谱`, `逆天`, `绝了`) are what a Chinese user
|
|
589
|
+
// actually types when the agent has failed twice in a row. `干什么` is out on
|
|
590
|
+
// purpose: `这个是干什么用的` is an ordinary question, while its exasperated twin
|
|
591
|
+
// `搞什么呢` is in.
|
|
592
|
+
const ZH_ANGUISH: readonly string[] = [
|
|
593
|
+
"哎呀",
|
|
594
|
+
"哎哟",
|
|
595
|
+
"哎呦",
|
|
596
|
+
"天哪",
|
|
597
|
+
"天啊",
|
|
598
|
+
"妈呀",
|
|
599
|
+
"我的天",
|
|
600
|
+
"不是吧",
|
|
601
|
+
"不会吧",
|
|
602
|
+
"救命",
|
|
603
|
+
"崩溃",
|
|
604
|
+
"崩了",
|
|
605
|
+
"麻了",
|
|
606
|
+
"服了",
|
|
607
|
+
"服气",
|
|
608
|
+
"醉了",
|
|
609
|
+
"无语",
|
|
610
|
+
"离谱",
|
|
611
|
+
"逆天",
|
|
612
|
+
"绝了",
|
|
613
|
+
"要命",
|
|
614
|
+
"疯了",
|
|
615
|
+
"烦死",
|
|
616
|
+
"气死",
|
|
617
|
+
"急死",
|
|
618
|
+
"完蛋",
|
|
619
|
+
"搞什么",
|
|
620
|
+
"什么鬼",
|
|
621
|
+
"咋回事",
|
|
622
|
+
];
|
|
623
|
+
const ZH_ANGUISH_RE = new RegExp(ZH_ANGUISH.join("|"), "g");
|
|
624
|
+
|
|
625
|
+
// Corrective negation. Anchored to the start of the prose body like the
|
|
626
|
+
// English lead (`不对`, `错了`, `搞错`); mid-sentence occurrences are usually
|
|
627
|
+
// ordinary description. Bare `不是` only counts as the interjection form -
|
|
628
|
+
// when nothing Han follows it - so the very common `不是我做的` / `不是这个
|
|
629
|
+
// 问题` stay neutral.
|
|
630
|
+
const ZH_NEGATION_LEAD_RE =
|
|
631
|
+
/^[ \t]*(?:不对|不是(?![\p{Script=Han}])|错了|搞错|弄错|怎么可能|怎么会|咋会|什么鬼|不可能|哪里对|哪儿对)/gu;
|
|
632
|
+
const ZH_NEGATION_PHRASE_RE =
|
|
633
|
+
/(?:不是(?:这个|这|那个|那)?意思|搞错(?:了|了吧)?|弄错(?:了)?|我说的是|我指的是|我要的是|不应该(?:是)?这样|不该这样|(?:又|还是)(?:错|不对)(?:了)?)/g;
|
|
634
|
+
|
|
635
|
+
// "You already made me say this." Pronoun-free forms (`又错了`, `还是不行`)
|
|
636
|
+
// matter more than the ones that need `你`, because a recognizer may drop the
|
|
637
|
+
// subject entirely.
|
|
638
|
+
const ZH_REPETITION_RE =
|
|
639
|
+
/(?:我说过|我说了|我早就说|我已经说|跟你说过?|重复(?:了)?|又(?:错|来|是|搞|弄|要|不)|还是(?:不行|不对|没|这样|那样|一样|老样子)|(?:依旧|依然|仍然)(?:没|不|一样|这样|错|是)|老样子|没变|没改|又来了|第[二三]次|再来一次|重来|重新来过?|白做|白干|白弄|浪费时间)/g;
|
|
640
|
+
|
|
641
|
+
// Direct reproach. `你怎么` needs a follow-up that only a complaint uses -
|
|
642
|
+
// `你怎么看` (what do you think?) is neutral - and `你能不能` needs the
|
|
643
|
+
// exasperated tail (`认真点`, `别…`).
|
|
644
|
+
const ZH_BLAME_RE =
|
|
645
|
+
/(?:你怎么(?:又|还|这么|那么|回事|搞|弄|能|不|没|老是|总是)|你干嘛|你干吗|你搞的|你弄的|你没(?:有)?(?:改|做|弄|看|听|按)|你(?:又|老是|总是)|谁让你|我让你|我明明(?:说|要|让|告诉|讲)|不是让你|我是不是(?:说|讲)过|你到底(?:想|要|在)|你能不能(?:认真|好好|别))/g;
|
|
646
|
+
|
|
647
|
+
// Shouting without capital letters: a denial/vent character run (`不不不`,
|
|
648
|
+
// `啊啊啊`, `唉唉唉`) or a repeated short denial (`不对不对`, `不是不是`).
|
|
649
|
+
// Long vowel-free Han runs are unambiguous; 2x repeats of ordinary words
|
|
650
|
+
// (`谢谢`) are common, so runs need three in a row and words come from a
|
|
651
|
+
// negative list.
|
|
652
|
+
const ZH_REPEAT_CHAR_RE = /([不别没错唉哎啊呀呜])\1{2,}/gu;
|
|
653
|
+
const ZH_REPEAT_WORD_RE = /(不对|不是|不行|不要|没用|没变|又错)(?:\1)+/gu;
|
|
654
|
+
// Full-width bursts (`???`, `?!?`). The first mark must be full-width so a
|
|
655
|
+
// pure-ASCII `!!!` stays where it belongs, in the English `anguish` bucket.
|
|
656
|
+
const ZH_DRAMA_RE = /[!?][!?!?]{2,}/g;
|
|
657
|
+
|
|
658
|
+
// Scripts no shipped lexicon covers. Kana/Hangul/Cyrillic/Arabic/… text scores
|
|
659
|
+
// zero on every signal above, and a dashboard that reported those zeros as
|
|
660
|
+
// "not annoyed" would be lying about its coverage.
|
|
661
|
+
const SCRIPT_LETTER_RE = /\p{L}/gu;
|
|
662
|
+
const UNSUPPORTED_SCRIPT_RE =
|
|
663
|
+
/[\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Script=Cyrillic}\p{Script=Arabic}\p{Script=Hebrew}\p{Script=Thai}\p{Script=Devanagari}\p{Script=Greek}]/gu;
|
|
664
|
+
const UNSUPPORTED_SCRIPT_SHARE = 0.3;
|
|
665
|
+
|
|
666
|
+
/** 1 when the prose leans on a script the lexicons do not cover. */
|
|
667
|
+
function detectUnsupportedScript(prose: string): number {
|
|
668
|
+
const letters = countMatches(prose, SCRIPT_LETTER_RE);
|
|
669
|
+
if (letters < 4) return 0;
|
|
670
|
+
return countMatches(prose, UNSUPPORTED_SCRIPT_RE) / letters > UNSUPPORTED_SCRIPT_SHARE ? 1 : 0;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
/** Whole-message repetition: normalised character-bigram Jaccard similarity. */
|
|
674
|
+
const REPEATED_MESSAGE_SIMILARITY = 0.7;
|
|
675
|
+
const REPEATED_MESSAGE_MIN_CHARS = 8;
|
|
676
|
+
|
|
677
|
+
function normalizeForComparison(text: string): string {
|
|
678
|
+
return text.replace(/[\s\p{P}\p{S}]/gu, "").toLowerCase();
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
function bigrams(normalized: string): Set<string> {
|
|
682
|
+
const grams = new Set<string>();
|
|
683
|
+
for (let i = 0; i + 1 < normalized.length; i++) grams.add(normalized.slice(i, i + 2));
|
|
684
|
+
return grams;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
/**
|
|
688
|
+
* 1 when the message says essentially the same thing as the one before it -
|
|
689
|
+
* the one frustration signal that needs no lexicon and therefore works for
|
|
690
|
+
* any language and survives every transcription error.
|
|
691
|
+
*/
|
|
692
|
+
function detectRepeatedMessage(prose: string, prevProse: string): number {
|
|
693
|
+
const current = normalizeForComparison(prose);
|
|
694
|
+
const previous = normalizeForComparison(prevProse);
|
|
695
|
+
if (current.length < REPEATED_MESSAGE_MIN_CHARS || previous.length < REPEATED_MESSAGE_MIN_CHARS) return 0;
|
|
696
|
+
if (current === previous) return 1;
|
|
697
|
+
const a = bigrams(current);
|
|
698
|
+
const b = bigrams(previous);
|
|
699
|
+
if (a.size === 0 || b.size === 0) return 0;
|
|
700
|
+
let shared = 0;
|
|
701
|
+
for (const gram of a) if (b.has(gram)) shared++;
|
|
702
|
+
return shared / (a.size + b.size - shared) >= REPEATED_MESSAGE_SIMILARITY ? 1 : 0;
|
|
703
|
+
}
|
|
704
|
+
|
|
520
705
|
// Stripped from the analyzed body before scoring so that structured
|
|
521
706
|
// content (code, XML/HTML, URLs, file mentions, quoted blocks) doesn't
|
|
522
707
|
// pollute behavior signals. We replace with a newline so line counts
|
|
@@ -637,7 +822,12 @@ function countNonEmptyLines(text: string): number {
|
|
|
637
822
|
*
|
|
638
823
|
* `text` may be empty or whitespace; in that case every metric is 0.
|
|
639
824
|
*/
|
|
640
|
-
export function computeUserMessageMetrics(
|
|
825
|
+
export function computeUserMessageMetrics(
|
|
826
|
+
text: string,
|
|
827
|
+
options: {
|
|
828
|
+
/** The user message before this one in the same session, for whole-message repetition. */ prevText?: string;
|
|
829
|
+
} = {},
|
|
830
|
+
): UserMessageMetrics {
|
|
641
831
|
const trimmed = text.trim();
|
|
642
832
|
if (!trimmed) {
|
|
643
833
|
return {
|
|
@@ -649,6 +839,8 @@ export function computeUserMessageMetrics(text: string): UserMessageMetrics {
|
|
|
649
839
|
negation: 0,
|
|
650
840
|
repetition: 0,
|
|
651
841
|
blame: 0,
|
|
842
|
+
emphasis: 0,
|
|
843
|
+
unsupportedScript: 0,
|
|
652
844
|
};
|
|
653
845
|
}
|
|
654
846
|
|
|
@@ -669,6 +861,8 @@ export function computeUserMessageMetrics(text: string): UserMessageMetrics {
|
|
|
669
861
|
negation: 0,
|
|
670
862
|
repetition: 0,
|
|
671
863
|
blame: 0,
|
|
864
|
+
emphasis: 0,
|
|
865
|
+
unsupportedScript: detectUnsupportedScript(prose),
|
|
672
866
|
};
|
|
673
867
|
}
|
|
674
868
|
|
|
@@ -676,22 +870,40 @@ export function computeUserMessageMetrics(text: string): UserMessageMetrics {
|
|
|
676
870
|
countMatches(prose, DRAMA_RE) +
|
|
677
871
|
countMatches(prose, ANGUISH_RE) +
|
|
678
872
|
countMatches(prose, DUDE_RE) +
|
|
679
|
-
countMatches(prose, SAD_EMOTICON_RE)
|
|
873
|
+
countMatches(prose, SAD_EMOTICON_RE) +
|
|
874
|
+
countMatches(prose, ZH_ANGUISH_RE);
|
|
680
875
|
|
|
681
|
-
const negation =
|
|
682
|
-
|
|
876
|
+
const negation =
|
|
877
|
+
countMatches(prose, NEGATION_LEAD_RE) +
|
|
878
|
+
countMatches(prose, NEGATION_PHRASE_RE) +
|
|
879
|
+
countMatches(prose, ZH_NEGATION_LEAD_RE) +
|
|
880
|
+
countMatches(prose, ZH_NEGATION_PHRASE_RE);
|
|
881
|
+
const repetition =
|
|
882
|
+
countMatches(prose, REPETITION_RECALL_RE) +
|
|
883
|
+
countMatches(prose, REPETITION_STILL_RE) +
|
|
884
|
+
countMatches(prose, ZH_REPETITION_RE) +
|
|
885
|
+
detectRepeatedMessage(prose, options.prevText ?? "");
|
|
683
886
|
const blame =
|
|
684
|
-
countMatches(prose, BLAME_YOU_RE) +
|
|
887
|
+
countMatches(prose, BLAME_YOU_RE) +
|
|
888
|
+
countMatches(prose, BLAME_WHY_RE) +
|
|
889
|
+
countMatches(prose, BLAME_STOP_RE) +
|
|
890
|
+
countMatches(prose, ZH_BLAME_RE);
|
|
891
|
+
const emphasis =
|
|
892
|
+
countMatches(prose, ZH_REPEAT_CHAR_RE) +
|
|
893
|
+
countMatches(prose, ZH_REPEAT_WORD_RE) +
|
|
894
|
+
countMatches(prose, ZH_DRAMA_RE);
|
|
685
895
|
|
|
686
896
|
return {
|
|
687
897
|
chars,
|
|
688
898
|
words,
|
|
689
899
|
yelling: countYellingSentences(prose),
|
|
690
|
-
profanity: countMatches(prose, PROFANITY_RE),
|
|
900
|
+
profanity: countMatches(prose, PROFANITY_RE) + countMatches(prose, ZH_PROFANITY_RE),
|
|
691
901
|
anguish,
|
|
692
902
|
negation,
|
|
693
903
|
repetition,
|
|
694
904
|
blame,
|
|
905
|
+
emphasis,
|
|
906
|
+
unsupportedScript: detectUnsupportedScript(prose),
|
|
695
907
|
};
|
|
696
908
|
}
|
|
697
909
|
|
|
@@ -705,4 +917,6 @@ export const EMPTY_USER_METRICS: UserMessageMetrics = Object.freeze({
|
|
|
705
917
|
negation: 0,
|
|
706
918
|
repetition: 0,
|
|
707
919
|
blame: 0,
|
|
920
|
+
emphasis: 0,
|
|
921
|
+
unsupportedScript: 0,
|
|
708
922
|
});
|