PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.7
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.7
4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 4.2.1 All 138 releases
learnpress / inc / AI / Assistant / LanguageResolver.php

LanguageResolver.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.4.7, at inc/AI/Assistant/LanguageResolver.php

153 lines 4.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace LearnPress\AI\Assistant;
4
5 /**
6 * LanguageResolver — detects learner language and generates instruction for the model.
7 *
8 * Completely stateless utility; can be reused across Agent and QuickQuizEngine.
9 *
10 * @package LearnPress\AI\Assistant
11 * @since 4.3.5
12 */
13 class LanguageResolver {
14
15 /**
16 * Build strict language guidance so the model replies in the learner's language.
17 *
18 * @param string $user_message Current learner input.
19 * @param array $history Conversation history.
20 * @param int $user_id Current user ID.
21 *
22 * @return string
23 */
24 public function build_instruction( string $user_message, array $history, int $user_id ): string {
25
26 $sample = $this->resolve_language_sample( $user_message, $history );
27 $locale_hint = $this->resolve_locale_hint( $user_id );
28
29 if ( $sample !== '' ) {
30 return sprintf(
31 /* translators: 1: learner message sample, 2: locale hint. */
32 __( 'Language policy: reply strictly in the same language as the learner. Do not default to English. Learner sample: "%1$s". Locale fallback: %2$s.', 'learnpress' ),
33 $sample,
34 $locale_hint !== '' ? $locale_hint : 'n/a'
35 );
36 }
37
38 return sprintf(
39 /* translators: %s: locale hint. */
40 __( 'Language policy: reply strictly in the learner language and do not default to English. If the latest learner message is language-neutral, use locale fallback: %s.', 'learnpress' ),
41 $locale_hint !== '' ? $locale_hint : 'n/a'
42 );
43 }
44
45 // ----------------------------------------------------------------
46 // Private helpers
47 // ----------------------------------------------------------------
48
49 /**
50 * Pick the best text sample to infer learner language.
51 *
52 * Prefers the current message; falls back to previous user turns.
53 *
54 * @param string $user_message Current learner input.
55 * @param array $history Conversation history.
56 *
57 * @return string
58 */
59 private function resolve_language_sample( string $user_message, array $history ): string {
60
61 $current = $this->trim_text_for_prompt( $user_message );
62 if ( $this->has_letters( $current ) && ! $this->is_language_neutral_command( $current ) ) {
63 return $current;
64 }
65
66 for ( $index = count( $history ) - 1; $index >= 0; $index-- ) {
67 $item = $history[ $index ] ?? array();
68 if ( ( $item['role'] ?? '' ) !== 'user' || ! isset( $item['content'] ) ) {
69 continue;
70 }
71
72 $content = $this->trim_text_for_prompt( (string) $item['content'] );
73 if ( ! $this->has_letters( $content ) || $this->is_language_neutral_command( $content ) ) {
74 continue;
75 }
76
77 return $content;
78 }
79
80 return '';
81 }
82
83 /**
84 * Resolve locale hint from WordPress user/site settings.
85 *
86 * @param int $user_id Current user ID.
87 *
88 * @return string
89 */
90 private function resolve_locale_hint( int $user_id ): string {
91 $locale = (string) get_user_locale( $user_id );
92 if ( $locale !== '' ) {
93 return $locale;
94 }
95
96 $locale = (string) determine_locale();
97 if ( $locale !== '' ) {
98 return $locale;
99 }
100
101 return (string) get_locale();
102 }
103
104 /**
105 * Determine if input is a language-neutral command (e.g. /quick-quiz, "1", "A", ...).
106 *
107 * @param string $text Input text.
108 *
109 * @return bool
110 */
111 private function is_language_neutral_command( string $text ): bool {
112
113 $normalized = trim( $text );
114 if ( $normalized === '' ) {
115 return true;
116 }
117
118 if ( str_starts_with( $normalized, '/' ) ) {
119 return true;
120 }
121
122 return preg_match( '/^[\d\W_]+$/u', $normalized ) === 1;
123 }
124
125 /**
126 * Check whether input contains at least one letter character.
127 *
128 * @param string $text Input text.
129 *
130 * @return bool
131 */
132 private function has_letters( string $text ): bool {
133 return preg_match( '/\p{L}/u', $text ) === 1;
134 }
135
136 /**
137 * Trim and cap text length for safe system prompt injection.
138 *
139 * @param string $text Input text.
140 *
141 * @return string
142 */
143 private function trim_text_for_prompt( string $text ): string {
144
145 $clean = trim( preg_replace( '/\s+/', ' ', $text ) ?? '' );
146 if ( $clean === '' ) {
147 return '';
148 }
149
150 return mb_substr( $clean, 0, 220, 'UTF-8' );
151 }
152 }
153